diff options
Diffstat (limited to 'engines/sci')
66 files changed, 2184 insertions, 858 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index a44c661561..9607a8e66d 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -860,14 +860,14 @@ bool Console::cmdVerifyScripts(int argc, const char **argv) { return true; } - Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeScript); - Common::sort(resources->begin(), resources->end()); - Common::List<ResourceId>::iterator itr = resources->begin(); + Common::List<ResourceId> resources = _engine->getResMan()->listResources(kResourceTypeScript); + Common::sort(resources.begin(), resources.end()); - DebugPrintf("%d SCI1.1-SCI3 scripts found, performing sanity checks...\n", resources->size()); + DebugPrintf("%d SCI1.1-SCI3 scripts found, performing sanity checks...\n", resources.size()); Resource *script, *heap; - while (itr != resources->end()) { + Common::List<ResourceId>::iterator itr; + for (itr = resources.begin(); itr != resources.end(); ++itr) { script = _engine->getResMan()->findResource(*itr, false); if (!script) DebugPrintf("Error: script %d couldn't be loaded\n", itr->getNumber()); @@ -885,12 +885,9 @@ bool Console::cmdVerifyScripts(int argc, const char **argv) { DebugPrintf("Error: script %d is larger than 64KB (%d bytes)\n", itr->getNumber(), script->size); } - - ++itr; } DebugPrintf("SCI1.1-SCI2.1 script check finished\n"); - delete resources; return true; } @@ -914,9 +911,8 @@ bool Console::cmdShowInstruments(int argc, const char **argv) { MidiParser_SCI *parser = new MidiParser_SCI(doSoundVersion, 0); parser->setMidiDriver(player); - Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeSound); - Common::sort(resources->begin(), resources->end()); - Common::List<ResourceId>::iterator itr = resources->begin(); + Common::List<ResourceId> resources = _engine->getResMan()->listResources(kResourceTypeSound); + Common::sort(resources.begin(), resources.end()); int instruments[128]; bool instrumentsSongs[128][1000]; @@ -928,26 +924,21 @@ bool Console::cmdShowInstruments(int argc, const char **argv) { instrumentsSongs[i][j] = false; if (songNumber == -1) { - DebugPrintf("%d sounds found, checking their instrument mappings...\n", resources->size()); + DebugPrintf("%d sounds found, checking their instrument mappings...\n", resources.size()); DebugPrintf("Instruments:\n"); DebugPrintf("============\n"); } - SoundResource *sound; - - while (itr != resources->end()) { - if (songNumber >= 0 && itr->getNumber() != songNumber) { - ++itr; + Common::List<ResourceId>::iterator itr; + for (itr = resources.begin(); itr != resources.end(); ++itr) { + if (songNumber >= 0 && itr->getNumber() != songNumber) continue; - } - sound = new SoundResource(itr->getNumber(), _engine->getResMan(), doSoundVersion); - int channelFilterMask = sound->getChannelFilterMask(player->getPlayId(), player->hasRhythmChannel()); - SoundResource::Track *track = sound->getTrackByType(player->getPlayId()); + SoundResource sound(itr->getNumber(), _engine->getResMan(), doSoundVersion); + int channelFilterMask = sound.getChannelFilterMask(player->getPlayId(), player->hasRhythmChannel()); + SoundResource::Track *track = sound.getTrackByType(player->getPlayId()); if (track->digitalChannelNr != -1) { // Skip digitized sound effects - delete sound; - ++itr; continue; } @@ -1027,9 +1018,6 @@ bool Console::cmdShowInstruments(int argc, const char **argv) { } while (!endOfTrack); DebugPrintf("\n"); - - delete sound; - ++itr; } delete parser; @@ -1069,7 +1057,6 @@ bool Console::cmdShowInstruments(int argc, const char **argv) { DebugPrintf("\n\n"); } - delete resources; return true; } @@ -1132,12 +1119,12 @@ bool Console::cmdList(int argc, const char **argv) { number = atoi(argv[2]); } - Common::List<ResourceId> *resources = _engine->getResMan()->listResources(res, number); - Common::sort(resources->begin(), resources->end()); - Common::List<ResourceId>::iterator itr = resources->begin(); + Common::List<ResourceId> resources = _engine->getResMan()->listResources(res, number); + Common::sort(resources.begin(), resources.end()); int cnt = 0; - while (itr != resources->end()) { + Common::List<ResourceId>::iterator itr; + for (itr = resources.begin(); itr != resources.end(); ++itr) { if (number == -1) { DebugPrintf("%8i", itr->getNumber()); if (++cnt % 10 == 0) @@ -1149,10 +1136,8 @@ bool Console::cmdList(int argc, const char **argv) { if (++cnt % 4 == 0) DebugPrintf("\n"); } - ++itr; } DebugPrintf("\n"); - delete resources; } return true; @@ -1448,7 +1433,7 @@ bool Console::cmdSaid(int argc, const char **argv) { _engine->getVocabulary()->dumpParseTree(); _engine->getVocabulary()->parserIsValid = true; - int ret = said((byte*)spec, true); + int ret = said((byte *)spec, true); DebugPrintf("kSaid: %s\n", (ret == SAID_NO_MATCH ? "No match" : "Match")); } @@ -1620,7 +1605,7 @@ bool Console::cmdWindowList(int argc, const char **argv) { bool Console::cmdSavedBits(int argc, const char **argv) { SegManager *segman = _engine->_gamestate->_segMan; SegmentId id = segman->findSegmentByType(SEG_TYPE_HUNK); - HunkTable* hunks = (HunkTable*)segman->getSegmentObj(id); + HunkTable* hunks = (HunkTable *)segman->getSegmentObj(id); if (!hunks) { DebugPrintf("No hunk segment found.\n"); return true; @@ -1632,7 +1617,7 @@ bool Console::cmdSavedBits(int argc, const char **argv) { uint16 offset = entries[i].offset; const Hunk& h = hunks->_table[offset]; if (strcmp(h.type, "SaveBits()") == 0) { - byte* memoryPtr = (byte*)h.mem; + byte* memoryPtr = (byte *)h.mem; if (memoryPtr) { DebugPrintf("%04x:%04x:", PRINT_REG(entries[i])); @@ -1686,7 +1671,7 @@ bool Console::cmdShowSavedBits(int argc, const char **argv) { SegManager *segman = _engine->_gamestate->_segMan; SegmentId id = segman->findSegmentByType(SEG_TYPE_HUNK); - HunkTable* hunks = (HunkTable*)segman->getSegmentObj(id); + HunkTable* hunks = (HunkTable *)segman->getSegmentObj(id); if (!hunks) { DebugPrintf("No hunk segment found.\n"); return true; @@ -1876,16 +1861,17 @@ bool Console::segmentInfo(int nr) { DebugPrintf(" Synonyms: %4d\n", scr->getSynonymsNr()); - if (scr->_localsBlock) - DebugPrintf(" Locals : %4d in segment 0x%x\n", scr->_localsBlock->_locals.size(), scr->_localsSegment); + if (scr->getLocalsCount() > 0) + DebugPrintf(" Locals : %4d in segment 0x%x\n", scr->getLocalsCount(), scr->getLocalsSegment()); else DebugPrintf(" Locals : none\n"); - DebugPrintf(" Objects: %4d\n", scr->_objects.size()); + ObjMap objects = scr->getObjectMap(); + DebugPrintf(" Objects: %4d\n", objects.size()); ObjMap::iterator it; - const ObjMap::iterator end = scr->_objects.end(); - for (it = scr->_objects.begin(); it != end; ++it) { + const ObjMap::iterator end = objects.end(); + for (it = objects.begin(); it != end; ++it) { DebugPrintf(" "); // Object header const Object *obj = _engine->_gamestate->_segMan->getObject(it->_value.getPos()); @@ -2914,12 +2900,11 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) { } void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { - Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeScript); - Common::sort(resources->begin(), resources->end()); - Common::List<ResourceId>::iterator itr = resources->begin(); + Common::List<ResourceId> resources = _engine->getResMan()->listResources(kResourceTypeScript); + Common::sort(resources.begin(), resources.end()); if (showFoundScripts) - DebugPrintf("%d scripts found, dissassembling...\n", resources->size()); + DebugPrintf("%d scripts found, dissassembling...\n", resources.size()); int scriptSegment; Script *script; @@ -2927,13 +2912,13 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { // manager won't be affected by loading and unloading scripts here. SegManager *customSegMan = new SegManager(_engine->getResMan()); - while (itr != resources->end()) { + Common::List<ResourceId>::iterator itr; + for (itr = resources.begin(); itr != resources.end(); ++itr) { // Ignore specific leftover scripts, which require other non-existing scripts if ((_engine->getGameId() == GID_HOYLE3 && itr->getNumber() == 995) || (_engine->getGameId() == GID_KQ5 && itr->getNumber() == 980) || (_engine->getGameId() == GID_SLATER && itr->getNumber() == 947) || (_engine->getGameId() == GID_MOTHERGOOSE256 && itr->getNumber() == 980)) { - itr++; continue; } @@ -2942,9 +2927,10 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { script = customSegMan->getScript(scriptSegment); // Iterate through all the script's objects + ObjMap objects = script->getObjectMap(); ObjMap::iterator it; - const ObjMap::iterator end = script->_objects.end(); - for (it = script->_objects.begin(); it != end; ++it) { + const ObjMap::iterator end = objects.end(); + for (it = objects.begin(); it != end; ++it) { const Object *obj = customSegMan->getObject(it->_value.getPos()); const char *objName = customSegMan->getObjectName(it->_value.getPos()); @@ -2976,7 +2962,8 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { // there is a jump after a ret, we don't stop processing if (opcode == op_bt || opcode == op_bnt || opcode == op_jmp) { uint16 curJmpOffset = offset + (uint16)opparams[0]; - if (curJmpOffset > maxJmpOffset) + // QFG2 has invalid jumps outside the script buffer in script 260 + if (curJmpOffset > maxJmpOffset && curJmpOffset < script->getScriptSize()) maxJmpOffset = curJmpOffset; } @@ -2990,12 +2977,9 @@ void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { } // for (it = script->_objects.begin(); it != end; ++it) customSegMan->uninstantiateScript(itr->getNumber()); - ++itr; } delete customSegMan; - - delete resources; } bool Console::cmdFindKernelFunctionCall(int argc, const char **argv) { diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 2d567a7fde..c43849056b 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -303,29 +303,29 @@ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, R if (sierraId == "fp" || sierraId == "gk" || sierraId == "pq4") demoThreshold = 150; - Common::ScopedPtr<Common::List<ResourceId> > resources(resMan.listResources(kResourceTypeScript, -1)); - if (resources->size() < demoThreshold) { + Common::List<ResourceId> resources = resMan.listResources(kResourceTypeScript, -1); + if (resources.size() < demoThreshold) { *gameFlags |= ADGF_DEMO; // Crazy Nick's Picks - if (sierraId == "lsl1" && resources->size() == 34) + if (sierraId == "lsl1" && resources.size() == 34) return "cnick-lsl"; - if (sierraId == "sq4" && resources->size() == 34) + if (sierraId == "sq4" && resources.size() == 34) return "cnick-sq"; - if (sierraId == "hoyle3" && resources->size() == 42) + if (sierraId == "hoyle3" && resources.size() == 42) return "cnick-kq"; - if (sierraId == "rh budget" && resources->size() == 39) + if (sierraId == "rh budget" && resources.size() == 39) return "cnick-longbow"; // TODO: cnick-laurabow (the name of the game object contains junk) // Handle Astrochicken 1 (SQ3) and 2 (SQ4) - if (sierraId == "sq3" && resources->size() == 20) + if (sierraId == "sq3" && resources.size() == 20) return "astrochicken"; if (sierraId == "sq4") return "msastrochicken"; } - if (sierraId == "torin" && resources->size() == 226) // Torin's Passage demo + if (sierraId == "torin" && resources.size() == 226) // Torin's Passage demo *gameFlags |= ADGF_DEMO; for (const OldNewIdTableEntry *cur = s_oldNewTable; cur->oldId[0]; ++cur) { @@ -350,7 +350,7 @@ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, R return "qfg4"; // qfg4 demo has less than 50 scripts - if (resources->size() < 50) + if (resources.size() < 50) return "qfg4"; // Otherwise it's qfg3 @@ -373,7 +373,7 @@ static ADGameDescription s_fallbackDesc = { Common::UNK_LANG, Common::kPlatformPC, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO0() }; static char s_fallbackGameIdBuf[256]; @@ -435,7 +435,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, s_fallbackDesc.flags = ADGF_NO_FLAGS; s_fallbackDesc.platform = Common::kPlatformPC; // default to PC platform s_fallbackDesc.gameid = "sci"; - s_fallbackDesc.guioptions = GUIO1(GUIO_NONE); + s_fallbackDesc.guioptions = GUIO0(); if (allFiles.contains("resource.map") || allFiles.contains("Data1") || allFiles.contains("resmap.001") || allFiles.contains("resmap.001")) { diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 4b1f36cda0..63eda1c348 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -42,7 +42,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "f3d1be7752d30ba60614533d531e2e98", 474}, {"resource.001", 0, "6fd05926c2199af0af6f72f90d0d7260", 126895}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Castle of Dr. Brain - English Amiga (from www.back2roots.org) // Executable scanning reports "1.005.000" @@ -98,7 +98,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.005", 0, "8a5ed3ba96e2eaf18e36fedfaab89419", 297838}, {"resource.006", 0, "dceed92e709cad1bd9582809a235b0a0", 266682}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Castle of Dr. Brain - English DOS 3.5" Floppy EGA (from nozomi77, bug report #3405307) {"castlebrain", "EGA", { @@ -108,7 +108,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "de2f182529efaad2c4b510b452ab77ac", 633662}, {"resource.003", 0, "38b4b37febc6b4f5061c461a283df148", 430388}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Castle of Dr. Brain - English DOS Floppy (from jvprat) // Executable scanning reports "1.000.044", Floppy label reports "1.0, 10.30.91", VERSION file reports "1.000" @@ -160,7 +160,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "39485580d34a72997f3d5b3aba4d24f1", 426}, {"resource.001", 0, "11391434f41c834090d7a1e9488ce936", 129739}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Christmas Card 1990: The Seasoned Professional - English DOS (16 Colors) // SCI interpreter version 1.000.172 @@ -198,7 +198,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "8613c45fc771d658e5a505b9a4a54f31", 713382}, {"resource.005", 0, "605b67a9ef199a9bb015745e7c004cf4", 478384}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Codename: Iceman - English DOS Non-Interactive Demo // Executable scanning reports "0.000.685" @@ -206,7 +206,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "782974f29d8a824782d2d4aea39964e3", 1056}, {"resource.001", 0, "d4b75e280d1c3a97cfef1b0bebff387c", 573647}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Codename: Iceman - English DOS (from jvprat) // Executable scanning reports "0.000.685", Floppy label reports "1.033, 6.8.90", VERSION file reports "1.033" @@ -219,7 +219,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "d97a96f1ab91b41cf46a02cc89b0a04e", 624303}, {"resource.004", 0, "8613c45fc771d658e5a505b9a4a54f31", 670883}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Codename: Iceman - English DOS (from FRG) // SCI interpreter version 0.000.668 @@ -231,7 +231,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "dc7c5280e7acfaffe6ef2a6c963c5f94", 622118}, {"resource.004", 0, "64f342463f6f35ba71b3509ef696ae3f", 669188}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Codename: Iceman - English DOS (supplied by ssburnout in bug report #3049193) // 1.022 9x5.25" (label: Int#0.000.668) @@ -246,7 +246,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "08050329aa113a9f14ed99cbfe3536ec", 232942}, {"resource.007", 0, "64f342463f6f35ba71b3509ef696ae3f", 267811}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Codename: Iceman - English DOS 1.023 (from abevi, bug report #2612718) {"iceman", "", { @@ -275,7 +275,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.005", 0, "c6e551bdc24f0acc193159038d4ca767", 605882}, {"resource.006", 0, "8f880a536908ab496bbc552f7f5c3738", 585255}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Conquests of Camelot - English DOS Non-Interactive Demo // SCI interpreter version 0.000.668 @@ -283,7 +283,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "f4cd75c15be75e04cdca3acda2c0b0ea", 468}, {"resource.001", 0, "4930708722f34bfbaa4945fb08f55f61", 232523}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Conquests of Camelot - English DOS (from jvprat) // Executable scanning reports "0.000.685", Floppy label reports "1.001, 0.000.685", VERSION file reports "1.001.000" @@ -295,7 +295,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "8e1a3a8c588007404b532b8dfacc1460", 723712}, {"resource.004", 0, "8e1a3a8c588007404b532b8dfacc1460", 729143}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Conquests of Camelot - English DOS // SCI interpreter version 0.000.685 @@ -309,7 +309,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "8e1a3a8c588007404b532b8dfacc1460", 332446}, {"resource.007", 0, "8e1a3a8c588007404b532b8dfacc1460", 358182}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Conquests of the Longbow - English Amiga (from www.back2roots.org) // Executable scanning reports "1.005.001" @@ -378,7 +378,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "b7bb35c027bb424ecefcd122768e5e60", 705631}, {"resource.005", 0, "58942b1aa6d6ffeb66e9f8897fd4435f", 469243}, {"resource.006", 0, "8c767b3939add63d11274065e46aad04", 713158}, - AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Conquests of the Longbow DOS 1.0 EGA (4 x 5.25" disks) // Provided by ssburnout in bug report #3046802 @@ -388,7 +388,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.001", 0, "76c729e563809170e6cc8b2f3f6cf0a4", 1196133}, {"resource.002", 0, "8c767b3939add63d11274065e46aad04", 1152478}, {"resource.003", 0, "7025b87e735b1df3f0e9488a621f4333", 1171439}, - AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Conquests of the Longbow - English DOS Non-Interactive Demo // SCI interpreter version 1.000.510 @@ -427,7 +427,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "a4b73d5d2b55bdb6e44345e99c8fbdd0", 4804}, {"resource.000", 0, "d908dbef56816ac6c60dd145fdeafb2b", 3536046}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Eco Quest - English DOS CD 1.1 // SCI interpreter version 1.001.064 @@ -541,7 +541,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "d46b282f228a67ba13bd4b4009e95f8f", 6058}, {"resource.000", 0, "ee3c64ffff0ba9fb08bea2624631c598", 5490246}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Freddy Pharkas - English DOS Floppy (updated information from markcoolio in bug reports #2723773 and #2724720) // Executable scanning reports "1.cfs.081" @@ -583,7 +583,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "05acdc256c742e79c50b9fe7ec2cc898", 863310}, {"resource.msg", 0, "45b5bf74933ac3727e4cc844446dc052", 796156}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::ES_ESP, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Freddy Pharkas - Spanish DOS (from jvprat) // Executable scanning reports "1.cfs.081", VERSION file reports "1.000, March 30, 1995" @@ -601,7 +601,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "a62a7eae85dd1e6b07f39662b278437e", 1918}, {"resource.000", 0, "4962a3c4dd44e36e78ea4a7a374c2220", 957382}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO0() }, // Freddy Pharkas - English Macintosh {"freddypharkas", "", { @@ -616,7 +616,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "7ee6859ef74314f6d91938c3595348a9", 282}, {"resource.001", 0, "f1e680095424e31f7fae1255d36bacba", 40692}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Gabriel Knight - English DOS CD Demo // SCI interpreter version 1.001.092 @@ -624,7 +624,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "39645952ae0ed8072c7e838f31b75464", 2490}, {"resource.000", 0, "eb3ed7477ca4110813fe1fcf35928561", 1718450}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO0() }, #ifdef ENABLE_SCI32 // Gabriel Knight - English DOS Floppy @@ -665,7 +665,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10996}, {"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 12581736}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO0() }, // Gabriel Knight - English Windows CD (from jvprat) // Executable scanning reports "2.000.000", VERSION file reports "01.100.000" @@ -673,7 +673,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10996}, {"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 12581736}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Gabriel Knight - German DOS CD (from Tobis87) // SCI interpreter version 2.000.000 @@ -681,7 +681,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "a7d3e55114c65647310373cb390815ba", 11392}, {"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13400497}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO0() }, // Gabriel Knight - Spanish DOS CD (from jvprat) // Executable scanning reports "2.000.000", VERSION file reports "1.000.000, April 13, 1995" @@ -689,7 +689,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "7cb6e9bba15b544ec7a635c45bde9953", 11404}, {"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13381599}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::ES_ESP, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO0() }, // Gabriel Knight - French DOS CD (from Hkz) // VERSION file reports "1.000.000, May 3, 1994" @@ -697,7 +697,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "55f909ba93a2515042a08d8a2da8414e", 11392}, {"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13325145}, AD_LISTEND}, - Common::FR_FRA, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::FR_FRA, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO0() }, // Gabriel Knight - German Windows CD (from Tobis87) // SCI interpreter version 2.000.000 @@ -705,7 +705,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "a7d3e55114c65647310373cb390815ba", 11392}, {"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13400497}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::DE_DEU, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Gabriel Knight - Spanish Windows CD (from jvprat) // Executable scanning reports "2.000.000", VERSION file reports "1.000.000, April 13, 1995" @@ -713,7 +713,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "7cb6e9bba15b544ec7a635c45bde9953", 11404}, {"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13381599}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::ES_ESP, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Gabriel Knight - English Macintosh {"gk1", "", { @@ -722,7 +722,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"Data3", 0, "f25068b408b09275d8b698866462f578", 3677599}, {"Data4", 0, "1cceebbe411b26c860a74f91c337fdf3", 3230086}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Gabriel Knight 2 - English Windows Non-Interactive Demo // Executable scanning reports "2.100.002" @@ -730,7 +730,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "e0effce11c4908f4b91838741716c83d", 1351}, {"resource.000", 0, "d04cfc7f04b6f74d13025378be49ec2b", 4640330}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Gabriel Knight 2 - English DOS (GOG version) - ressci.* merged in ressci.000 // using Enrico Rolfi's HD/DVD installer: http://gkpatches.vogons.zetafleet.com/ @@ -738,7 +738,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "b996fa1e57389a1e179a00a0049de1f4", 8110}, {"ressci.000", 0, "a19fc3604c6e5407abcf03d59ee87217", 168522221}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Gabriel Knight 2 - English DOS (from jvprat) // Executable scanning reports "2.100.002", VERSION file reports "1.1" @@ -756,7 +756,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.006", 0, "ce9359037277b7d7976da185c2fa0aad", 2977}, {"ressci.006", 0, "8e44e03890205a7be12f45aaba9644b4", 60659424}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Gabriel Knight 2 - French DOS (6-CDs Sierra Originals reedition) // Executable scanning reports "2.100.002", VERSION file reports "1.0" @@ -774,7 +774,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.006", 0, "11b2e722170b8c93fdaa5428e2c7676f", 3001}, {"ressci.006", 0, "4037d941aec39d2e654e20960429aefc", 60568486}, AD_LISTEND}, - Common::FR_FRA, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::FR_FRA, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Gabriel Knight 2 - English Macintosh // NOTE: This only contains disc 1 files (as well as the persistent file: @@ -786,7 +786,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"Data4", 0, "8b843c62eb53136a855d6e0087e3cb0d", 5889553}, {"Data5", 0, "f9fcf9ab2eb13b2125c33a1cda03a093", 14349984}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, #endif // ENABLE_SCI32 @@ -808,7 +808,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "e0dd44069a62a463fd124974b915f10d", 342309}, {"resource.003", 0, "e0dd44069a62a463fd124974b915f10d", 328912}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Hoyle 1 - English DOS (supplied by merkur in bug report #2719227) // SCI interpreter version 0.000.530 @@ -816,14 +816,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "1034a218943d12f1f36e753fa10c95b8", 4386}, {"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 518308}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Hoyle 1 3.5' - English DOS (supplied by eddydrama in bug report #3052366 and dinnerx in bug report #3090841) {"hoyle1", "", { {"resource.map", 0, "0af9a3dcd72a091960de070432e1f524", 4386}, {"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 518127}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, #if 0 // TODO: unknown if these files are corrupt // Hoyle 1 - English Amiga (from www.back2roots.org) @@ -843,7 +843,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.001", 0, "8f2dd70abe01112eca464cda818b5eb6", 98138}, {"resource.002", 0, "8f2dd70abe01112eca464cda818b5eb6", 196631}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Hoyle 2 - English DOS (supplied by ssburnout in bug report #3049193) // 1.000.011 1x3.5" (label:Int#6.21.90) @@ -851,7 +851,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "db0ba08b953e9904a4960ad99cd29c20", 1356}, {"resource.001", 0, "8f2dd70abe01112eca464cda818b5eb6", 216315}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Hoyle 2 - English Amiga (from www.back2roots.org) // Executable scanning reports "1.002.032" @@ -918,7 +918,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "6ef28cac094dcd97fdb461662ead6f92", 319905}, {"resource.001", 0, "0a98a268ee99b92c233a0d7187c1f0fa", 526438}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Hoyle 4 (Hoyle Classic Card Games) - English DOS Demo {"hoyle4", "Demo", { @@ -959,14 +959,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.001", 0, "bac3ec6cb3e3920984ab0f32becf5163", 202105}, {"resource.002", 0, "b86daa3ba2784d1502da881eedb80d9b", 341771}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Jones in the Fast Lane EGA - English DOS (supplied by EddyDrama in bug report #3038761) {"jones", "EGA", { {"resource.map", 0, "8e92cf319180cc8b5b87b2ce93a4fe22", 1602}, {"resource.001", 0, "bac3ec6cb3e3920984ab0f32becf5163", 511528}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Jones in the Fast Lane VGA - English DOS // SCI interpreter version 1.000.172 @@ -990,7 +990,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "459f5b04467bc2107aec02f5c4b71b37", 4878}, {"resource.001", 0, "3876da2ce16fb7dea2f5d943d946fa84", 1652150}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Jones in the Fast Lane - English DOS CD // Same entry as the DOS version above. This one is used for the alternate @@ -1019,7 +1019,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "59b13619078bd47011421468959ee5d4", 954}, {"resource.001", 0, "4cfb9040db152868f7cb6a1e8151c910", 296555}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 1 SCI Remake - English DOS (from the King's Quest Collection) // Executable scanning reports "S.old.010", VERSION file reports "1.000.051" @@ -1030,7 +1030,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "fed9e0072ffd511d248674e60dee2099", 714062}, {"resource.003", 0, "fed9e0072ffd511d248674e60dee2099", 717478}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 1 SCI Remake - English DOS (supplied by ssburnout in bug report #3049193) // 1.000.051 9x5.25" (label: INT#9.19.90) @@ -1057,7 +1057,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "fd16c9c223f7dc5b65f06447615224ff", 683016}, {"resource.004", 0, "3fac034c7d130e055d05bc43a1f8d5f8", 549993}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 4 - English DOS Non-Interactive Demo // Executable scanning reports "0.000.494" @@ -1065,7 +1065,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "992ac7cc31d3717fe53818a9bb6d1dae", 594}, {"resource.001", 0, "143e1c14f15ad0fbfc714f648a65f661", 205330}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 4 - English DOS (original boxed release, 3 1/2" disks) // SCI interpreter version 0.000.247 @@ -1076,7 +1076,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "851a62d00972dc4002f472cc0d84e71d", 683145}, {"resource.004", 0, "851a62d00972dc4002f472cc0d84e71d", 649441}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 4 - English DOS (from the King's Quest Collection) // Executable scanning reports "0.000.502" @@ -1088,7 +1088,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "77615c595388acf3d1df8e107bfb6b52", 707591}, {"resource.004", 0, "77615c595388acf3d1df8e107bfb6b52", 479562}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 4 - English DOS (supplied by ssburnout in bug report #3049193) // 1.006.003 8x5.25" (label: Int.#0.000.502) @@ -1102,7 +1102,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "6db7de6f93c6ea62dca78abee677f8c0", 324789}, {"resource.007", 0, "6db7de6f93c6ea62dca78abee677f8c0", 334441}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 4 - English DOS // SCI interpreter version 0.000.274 @@ -1116,7 +1116,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "851a62d00972dc4002f472cc0d84e71d", 333777}, {"resource.007", 0, "851a62d00972dc4002f472cc0d84e71d", 341038}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 4 - English DOS // SCI interpreter version 0.000.253 @@ -1130,7 +1130,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "0c8566848a76eea19a6d6220914030a7", 337288}, {"resource.007", 0, "0c8566848a76eea19a6d6220914030a7", 343882}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 4 - English Atari ST (double-sided diskettes) // Game version 1.003.006 (January 12, 1989) @@ -1143,7 +1143,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "a3cdb4848fb859fdd302976fff56490f", 705074}, {"resource.004", 0, "a3cdb4848fb859fdd302976fff56490f", 478366}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 5 - English Amiga (from www.back2roots.org) // Executable scanning reports "1.004.018" @@ -1201,7 +1201,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "449471bfd77be52f18a3773c7f7d843d", 571368}, {"resource.001", 0, "b45a581ff8751e052c7e364f58d3617f", 16800210}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO0() }, // King's Quest 5 - English DOS CD (from the King's Quest Collection) // Executable scanning reports "x.yyy.zzz", VERSION file reports "1.000.052" @@ -1259,7 +1259,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "698c698570cde9015e4d51eb8d2e9db1", 666527}, {"resource.007", 0, "703d8df30e89541af337d7706540d5c4", 541743}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 5 EGA 1.2M disk version (from LordHoto) // VERSION file reports "0.000.055" @@ -1271,7 +1271,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "53206afb4fd73871a484e83acab80f31", 7608}, {"resource.004", 0, "83568edf7fde18b3eed988bc5d22ceb1", 1188053}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 5 EGA (supplied by omer_mor in bug report #3035421) // VERSION file reports "0.000.062" @@ -1286,7 +1286,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "698c698570cde9015e4d51eb8d2e9db1", 666541}, {"resource.007", 0, "703d8df30e89541af337d7706540d5c4", 541762}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest V DOS 0.000.062 EGA (5 x 5.25" disks) // Supplied by ssburnout in bug report #3046780 @@ -1298,7 +1298,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "3cca5b2dae8afe94532edfdc98d7edbe", 1092325}, {"resource.004", 0, "8e5c1bc4d738cf7316ff506f59d265e2", 1187803}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // King's Quest 5 - German DOS Floppy (supplied by markcoolio in bug report #2727101, also includes english language) // SCI interpreter version 1.000.060 @@ -1382,7 +1382,13 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "71afd220d46bde1109c58e6acc0f3a01", 469094}, {"resource.001", 0, "72a569f46f1abf2d9d2b1526ad3799c3", 12808839}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO2(GUIO_NOASPECT, GUIO_MIDITOWNS) }, + {"kq5", "", { + {"resource.map", 0, "20c7cd248ff1a349ed354568eebd972b", 12733}, + {"resource.000", 0, "71afd220d46bde1109c58e6acc0f3a01", 469094}, + {"resource.001", 0, "72a569f46f1abf2d9d2b1526ad3799c3", 12808839}, + AD_LISTEND}, + Common::JA_JPN, Common::kPlatformFMTowns, 0, GUIO2(GUIO_NOASPECT, GUIO_MIDITOWNS) }, // King's Quest 5 - Japanese PC-98 Floppy 0.000.015 (supplied by omer_mor in bug report #3073583) {"kq5", "", { @@ -1394,7 +1400,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "e114ce8f884601c43308fb5cbbea4874", 1174129}, {"resource.005", 0, "349ad9438172265d00680075c5a988d0", 1019669}, AD_LISTEND}, - Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // King's Quest 6 - English DOS Non-Interactive Demo // Executable scanning reports "1.001.055", VERSION file reports "1.000.000" @@ -1431,7 +1437,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "7a550ebfeae2575ca00d47703a6a774c", 9215}, {"resource.000", 0, "233394a5f33b475ae5975e7e9a420865", 8376352}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO0() }, // King's Quest 6 - English Windows CD (from the King's Quest Collection) // Executable scanning reports "1.cfs.158", VERSION file reports "1.034 9/11/94 - KQ6 version 1.000.00G" @@ -1440,7 +1446,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "7a550ebfeae2575ca00d47703a6a774c", 9215}, {"resource.000", 0, "233394a5f33b475ae5975e7e9a420865", 8376352}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_CD, GUIO1(GUIO_NOASPECT) }, // King's Quest 6 - Spanish DOS CD (from jvprat) // Executable scanning reports "1.cfs.158", VERSION file reports "1.000.000, July 5, 1994" @@ -1450,7 +1456,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "4da3ad5868a775549a7cc4f72770a58e", 8537260}, {"resource.msg", 0, "41eed2d3893e1ca6c3695deba4e9d2e8", 267102}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::ES_ESP, Common::kPlatformPC, ADGF_CD, GUIO0() }, // King's Quest 6 - English Macintosh Floppy // VERSION file reports "1.0" @@ -1469,7 +1475,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "4948e4e1506f1e1c4e1d47abfa06b7f8", 204385195}, {"resource.map", 0, "40ccafb2195301504eba2e4f4f2c7f3d", 18925}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // King's Quest 7 - English Windows (from the King's Quest Collection) // Executable scanning reports "2.100.002", VERSION file reports "1.4" @@ -1477,7 +1483,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "2be9ab94429c721af8e05c507e048a15", 18697}, {"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 203882535}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // King's Quest 7 - English DOS (from FRG) // SCI interpreter version 2.100.002, VERSION file reports "2.00b" @@ -1485,7 +1491,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "8676b0fbbd7362989a029fe72fea14c6", 18709}, {"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // King's Quest 7 - English Windows (from FRG) // SCI interpreter version 2.100.002, VERSION file reports "2.00b" @@ -1493,7 +1499,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "8676b0fbbd7362989a029fe72fea14c6", 18709}, {"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // King's Quest 7 - German Windows (supplied by markcoolio in bug report #2727402) // SCI interpreter version 2.100.002 @@ -1501,7 +1507,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "838b9ff132bd6962026fee832e8a7ddb", 18697}, {"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // King's Quest 7 - Spanish DOS (from jvprat) // Executable scanning reports "2.100.002", VERSION file reports "2.00" @@ -1509,7 +1515,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "0b62693cbe87e3aaca3e8655a437f27f", 18709}, {"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::ES_ESP, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // King's Quest 7 - English DOS Non-Interactive Demo // SCI interpreter version 2.100.002 @@ -1517,7 +1523,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "b44f774108d63faa1d021101221c5a54", 1690}, {"resource.000", 0, "d9659d2cf0c269c6a9dc776707f5bea0", 2433827}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, #endif // ENABLE_SCI32 @@ -1533,7 +1539,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "aa553977f7e5804081de293800d3bcce", 695067}, {"resource.005", 0, "bfd870d51dc97729f0914095f58e6957", 676881}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Laura Bow - English Atari ST (from jvprat) // Executable scanning reports "1.002.030", Floppy label reports "1.000.062, 9.23.90" @@ -1545,7 +1551,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 667365}, {"resource.004", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 683737}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Laura Bow - English DOS Non-Interactive Demo // Executable scanning reports "x.yyy.zzz" @@ -1553,7 +1559,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "e625726268ff4e123ada11f31f0249f3", 768}, {"resource.001", 0, "0c8912290af0890f8d95faeb4ddb2d68", 333031}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Laura Bow - English DOS 3.5" Floppy (from "The Roberta Williams Anthology"/1996) // SCI interpreter version 0.000.631 @@ -1564,7 +1570,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 667468}, {"resource.004", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 683807}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Laura Bow - English DOS (from FRG) // SCI interpreter version 0.000.631 @@ -1578,7 +1584,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 328390}, {"resource.007", 0, "e45c888d9c7c04aec0a20e9f820b79ff", 317687}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Laura Bow 2 - English DOS Non-Interactive Demo (from FRG) // Executable scanning reports "x.yyy.zzz" @@ -1605,7 +1611,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "a70945e61ba7ac7bfea6b7bd72c6aec5", 7274}, {"resource.000", 0, "82578b8d5a7e09c4c58891ca49fae35b", 5598672}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Laura Bow 2 v1.1 - French DOS Floppy (from Hkz) {"laurabow2", "", { @@ -1631,7 +1637,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "57084910bc923bff5d6d9bc1b56e9604", 5028766}, {"resource.msg", 0, "71f1f0cd9f082da2e750c793a8ed9d84", 286141}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::ES_ESP, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Larry 1 EGA Remake - English DOS (from spookypeanut) // SCI interpreter version 0.000.510 (or 0.000.577?) @@ -1642,7 +1648,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "24c958bc922b07f91e25e8c93aa01fcf", 491230}, {"resource.003", 0, "685cd6c1e05a695ab1e0db826337ee2a", 553279}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, #if 0 // The resource.002 file, contained in disk 3, is broken in this version @@ -1742,7 +1748,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "a0d4a625311d307257da7fc43d00459d", 570356}, {"resource.004", 0, "a0d4a625311d307257da7fc43d00459d", 717844}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 2 - English DOS Non-Interactive Demo // Executable scanning reports "x.yyy.zzz" @@ -1751,7 +1757,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "03dba704bb77da55a91ad27b5a3cac09", 528}, {"resource.001", 0, "9f5520f0297206928df0b0b36493cd33", 127532}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 2 - English DOS // SCI interpreter version 0.000.409 @@ -1764,7 +1770,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.005", 0, "4a24443a25e2b1492462a52809605dc2", 277732}, {"resource.006", 0, "4a24443a25e2b1492462a52809605dc2", 345683}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 2 - English DOS // SCI interpreter version 0.000.343 @@ -1779,7 +1785,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { //{"resource.006", 0, "96033f57accfca903750413fd09193c8", 345818}, {"resource.006", 0, "96033f57accfca903750413fd09193c8", -1}, // 345818 or 208739 AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 2 - English DOS (supplied by ssburnout in bug report #3049193) // 1.000.011 3x3.5" (label: Int. #0.000.343) @@ -1789,7 +1795,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "96033f57accfca903750413fd09193c8", 407014}, {"resource.003", 0, "96033f57accfca903750413fd09193c8", 592834}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 2 - English DOS (supplied by ssburnout in bug report #3049193) // 1.002.000 3x3.5" (label: INT#0.000.409) @@ -1799,7 +1805,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "4a24443a25e2b1492462a52809605dc2", 406935}, {"resource.003", 0, "4a24443a25e2b1492462a52809605dc2", 592533}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 3 - English Amiga (from www.back2roots.org) // Executable scanning reports "1.002.032" @@ -1824,7 +1830,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "f18441027154292836b973c655fa3175", 506807}, {"resource.004", 0, "f18441027154292836b973c655fa3175", 513651}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 3 - English DOS (supplied by ssburnout in bug report #3049193) // 1.021 8x5.25" (label: Int#5.15.90) @@ -1838,7 +1844,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "f18441027154292836b973c655fa3175", 282649}, {"resource.007", 0, "f18441027154292836b973c655fa3175", 257178}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 3 - English DOS // SCI interpreter version 0.000.572 @@ -1852,7 +1858,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "f18441027154292836b973c655fa3175", 282465}, {"resource.007", 0, "f18441027154292836b973c655fa3175", 257174}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 3 - English DOS Non-Interactive Demo // SCI interpreter version 0.000.530 @@ -1861,7 +1867,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.001", 0, "f773d79b93dfd4052ec8c1cc64c1e6ab", 76525}, {"resource.002", 0, "f773d79b93dfd4052ec8c1cc64c1e6ab", 268299}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 3 - German DOS (from Tobis87, updated info from markcoolio in bug report #2723832, also includes english language) // Executable scanning reports "S.old.123" @@ -1873,7 +1879,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "3827a9b17b926e12dcc336860f50612a", 587036}, {"resource.004", 0, "3827a9b17b926e12dcc336860f50612a", 691932}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 3 - French DOS (provided by richiefs in bug report #2670691, also includes english language) // Executable scanning reports "S.old.123" @@ -1885,7 +1891,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "65f1bdaa20f6d0470e9d969f22473873", 586921}, {"resource.004", 0, "65f1bdaa20f6d0470e9d969f22473873", 690826}, AD_LISTEND}, - Common::FR_FRA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::FR_FRA, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 3 1.050 Fr/En (9 x 5.25" disks) // Provided by ssburnout in bug report #3046779 @@ -2037,7 +2043,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "f6046a8445422f17d40b1b10ab21ebf3", 568551}, {"resource.007", 0, "640ee65595d40372ef95462f2c1ae28a", 593429}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 5 EGA // Supplied by omer_mor in bug report #3049771 @@ -2048,7 +2054,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "5a55af4e40728b1a8103dc47ad2afa8d", 1100539}, {"resource.003", 0, "16f4d8fb1b526125edaca4fc6cbb7530", 1064563}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Larry 6 - English DOS (from spookypeanut) // SCI interpreter version 1.001.113 @@ -2064,7 +2070,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "0b91234b7112782962cb480b7791b6e2", 7263}, {"resource.000", 0, "57d5fe8bb9e044158514476ea7678eb0", 5754790}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Larry 6 - German DOS CD - LOWRES (provided by richiefs in bug report #2670691) // SCI interpreter version 1.001.115 @@ -2072,7 +2078,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "bafe85f32738854135991d4324ad147e", 7268}, {"resource.000", 0, "f6cbc6da7b90ea135883e0759848ca2c", 5773160}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Larry 6 - French DOS CD - LOWRES (provided by richiefs in bug report #2670691) // SCI interpreter version 1.001.115 @@ -2080,7 +2086,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "97797ea775baaf18a1907d357d3c0ea6", 7268}, {"resource.000", 0, "f6cbc6da7b90ea135883e0759848ca2c", 5776092}, AD_LISTEND}, - Common::FR_FRA, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::FR_FRA, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Larry 6 - Spanish DOS - LOWRES (from the Leisure Suit Larry Collection) // Executable scanning reports "1.001.113", VERSION file reports "1.000, 11.06.93, FIVE PATCHES ADDED TO DISK 6 ON 11-18-93" @@ -2133,7 +2139,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "0c0804434ea62278dd15032b1947426c", 8872}, {"resource.000", 0, "9a9f4870504444cda863dd14d077a680", 18520872}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Larry 6 - German DOS CD - HIRES (provided by richiefs in bug report #2670691) // SCI interpreter version 2.100.002 @@ -2141,7 +2147,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "badfdf446ffed569a310d2c63a249421", 8896}, {"resource.000", 0, "bd944d2b06614a5b39f1586906f0ee88", 18534274}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Larry 6 - French DOS CD - HIRES (provided by richiefs in bug report #2670691) // SCI interpreter version 2.100.002 @@ -2149,7 +2155,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "d184e9aa4f2d4b5670ddb3669db82cda", 8896}, {"resource.000", 0, "bd944d2b06614a5b39f1586906f0ee88", 18538987}, AD_LISTEND}, - Common::FR_FRA, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::FR_FRA, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Larry 7 - English DOS Demo (provided by richiefs in bug report #2670691) // SCI interpreter version 2.100.002 @@ -2157,7 +2163,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"ressci.000", 0, "5cc6159688b2dc03790a67c90ccc67f9", 10195878}, {"resmap.000", 0, "6a2b2811eef82e87cde91cf1de845af8", 2695}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, #ifdef ENABLE_SCI3_GAMES // Larry 7 - English DOS CD (from spookypeanut) @@ -2166,7 +2172,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "eae93e1b1d1ccc58b4691c371281c95d", 8188}, {"ressci.000", 0, "89353723488219e25589165d73ed663e", 66965678}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Larry 7 - German DOS (from Tobis87) // SCI interpreter version 3.000.000 @@ -2174,7 +2180,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "c11e6bfcfc2f2d05da47e5a7df3e9b1a", 8188}, {"ressci.000", 0, "a8c6817bb94f332ff498a71c8b47f893", 66971724}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Larry 7 - French DOS (provided by richiefs in bug report #2670691) // SCI interpreter version 3.000.000 @@ -2182,7 +2188,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "4407849fd52fe3efb0c30fba60cd5cd4", 8206}, {"ressci.000", 0, "dc37c3055fffbefb494ff22b145d377b", 66964472}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Larry 7 - Italian DOS CD (from glorifindel) // SCI interpreter version 3.000.000 @@ -2190,7 +2196,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "9852a97141f789413f29bf956052acdb", 8212}, {"ressci.000", 0, "440b9fed89590abb4e4386ed6f948ee2", 67140181}, AD_LISTEND}, - Common::IT_ITA, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::IT_ITA, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Larry 7 - Spanish DOS (from the Leisure Suit Larry Collection) // Executable scanning reports "3.000.000", VERSION file reports "1.0s" @@ -2198,7 +2204,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "8f3d603e1acc834a5d598b30cdfc93f3", 8188}, {"ressci.000", 0, "32792f9bc1bf3633a88b382bb3f6e40d", 67071418}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::ES_ESP, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, #endif // Lighthouse - English Windows Demo (from jvprat) @@ -2207,7 +2213,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "543124606352bfa5e07696ddf2a669be", 64}, {"resource.000", 0, "5d7714416b612463d750fb9c5690c859", 28952}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, #ifdef ENABLE_SCI3_GAMES // Lighthouse - English Windows Demo @@ -2216,7 +2222,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "3bdee7a16926975a4729f75cf6b80a92", 1525}, {"ressci.000", 0, "3c585827fa4a82f4c04a56a0bc52ccee", 11494351}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Lighthouse - English DOS (from jvprat) // Executable scanning reports "3.000.000", VERSION file reports "1.1" @@ -2226,7 +2232,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.002", 0, "c68db5333f152fea6ca2dfc75cad8b34", 7573}, {"ressci.002", 0, "175468431a979b9f317c294ce3bc1430", 94628315}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Lighthouse - Spanish DOS (from jvprat) // Executable scanning reports "3.000.000", VERSION file reports "1.1" @@ -2236,7 +2242,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.002", 0, "e7dc85884a2417e2eff9de0c63dd65fa", 7630}, {"ressci.002", 0, "3c8d627c555b0e3e4f1d9955bc0f0df4", 94631127}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::ES_ESP, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, #endif // ENABLE_SCI3_GAMES #endif // ENABLE_SCI32 @@ -2258,7 +2264,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "509b2467ba779100d5933ed51a9ae32f", 560255}, {"resource.004", 0, "93afc85d5ffa60ea555d6cc336d22c03", 651109}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Mixed-Up Fairy Tales v1.000 - English DOS (supplied by markcoolio in bug report #2723791) // Executable scanning reports "1.000.145" @@ -2299,7 +2305,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.001", 0, "d893892d62b3f061357291d66775e360", 239906}, {"resource.002", 0, "d893892d62b3f061357291d66775e360", 719398}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Mixed-Up Mother Goose - English DOS Floppy EGA (supplied by ssburnout in bug report #3049193) // 1.011 5x5.25" (label: Int#8.2.90) @@ -2312,7 +2318,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "dbbc22f124533ce308bc386b08956326", 146251}, {"resource.005", 0, "2ba5348e7fad641b9c4c7ff7c7cf4e68", 110979}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Mixed-Up Mother Goose v2.000 - English DOS Floppy (supplied by markcoolio in bug report #2723795) // Executable scanning reports "1.001.031" @@ -2329,7 +2335,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "1c7f311b0a2c927b2fbe81ae341fb2f6", 5790}, {"resource.001", 0, "5a0ed1d745855148364de1b3be099bac", 4369438}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Mixed-Up Mother Goose - English Windows Interactive Demo // Executable scanning reports "x.yyy.zzz" @@ -2344,7 +2350,12 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "b11e971ccd2040bebba59dfb409a08ef", 5772}, {"resource.001", 0, "d49625d9b8005ec01c852f8322a82867", 4330713}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformFMTowns, 0, GUIO1(GUIO_NOASPECT) }, + {"mothergoose256", "", { + {"resource.map", 0, "b11e971ccd2040bebba59dfb409a08ef", 5772}, + {"resource.001", 0, "d49625d9b8005ec01c852f8322a82867", 4330713}, + AD_LISTEND}, + Common::JA_JPN, Common::kPlatformFMTowns, 0, GUIO1(GUIO_NOASPECT) }, #ifdef ENABLE_SCI32 // Mixed-Up Mother Goose Deluxe - English Windows/DOS CD (supplied by markcoolio in bug report #2723810) @@ -2353,7 +2364,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "5159a1578c4306bfe070a3e4d8c2e1d3", 4741}, {"resource.000", 0, "1926925c95d82f0999590e93b02887c5", 15150768}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Mixed-Up Mother Goose Deluxe - Multilingual Windows CD (English/French/German/Spanish) // Executable scanning reports "2.100.002" @@ -2361,7 +2372,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "ef611af561898dcfea87846919ebf3eb", 4969}, {"ressci.000", 0, "227685bc59d90821978d330713e44a7a", 17205800}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, #endif // ENABLE_SCI32 // Ms. Astro Chicken - English DOS @@ -2391,7 +2402,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.007", 0, "afbd16ea77869a720afa1c5371de107d", 7972}, //{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 25859038}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Phantasmagoria - English DOS Demo // Executable scanning reports "2.100.002" @@ -2399,7 +2410,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.001", 0, "416138651ea828219ca454cae18341a3", 11518}, {"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 65844612}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Phantasmagoria - English DOS/Windows (GOG version) - ressci.* merged in ressci.000 // Windows executable scanning reports "2.100.002" - "Sep 19 1995 15:09:43" @@ -2410,7 +2421,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"ressci.000", 0, "cd5967f9b9586e3380645961c0765be3", 116822037}, {"resmap.000", 0, "3cafc1c6a53945c1f3babbfd6380c64c", 16468}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Phantasmagoria - English Macintosh // NOTE: This only contains disc 1 files (as well as the two persistent files: @@ -2426,7 +2437,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { // Data8-12 are empty {"Data13", 0, "6d2c450fca19a69b5af74ed5b03c0a17", 14923328}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, #ifdef ENABLE_SCI3_GAMES // Phantasmagoria 2 - English Windows (from jvprat) @@ -2443,7 +2454,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.005", 0, "8bd5ceeedcbe16dfe55d1b90dcd4be84", 1942}, {"ressci.005", 0, "05f9fe2bee749659acb3cd2c90252fc5", 67905112}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Phantasmagoria 2 - English DOS (GOG version) - ressci.* merged in ressci.000 // Executable scanning reports "3.000.000" - "Dec 07 1996 09:29:03" @@ -2453,7 +2464,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"ressci.000", 0, "c54f26d9f43f908151263254b6d97053", 108134481}, {"resmap.000", 0, "de154a223a9ef4ea7358b76adc38ef5b", 2956}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, #endif // ENABLE_SCI3_GAMES #endif // ENABLE_SCI32 @@ -2507,7 +2518,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "499737c21a28ac026e11ab817100d610", 511099}, {"resource.003", 0, "e008f5d6e2a7c4d4a0da0173e4fa8f8b", 553970}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Police Quest 2 - English DOS Non-Interactive Demo // Executable scanning reports "0.000.413" @@ -2515,7 +2526,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "8b77d0d4650c2052b356cece28294b58", 576}, {"resource.001", 0, "376ef6d6eaaeed66e1424bd219c4b9ab", 215398}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Police Quest 2 - English DOS (provided by richiefs in bug report #2670691) // SCI interpreter version 0.000.395 @@ -2528,7 +2539,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.005", 0, "77f02def3094af804fd2371db25b7100", 349899}, {"resource.006", 0, "77f02def3094af804fd2371db25b7100", 354991}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Police Quest 2 - English DOS (from the Police Quest Collection) // Executable scanning reports "0.000.490" @@ -2538,7 +2549,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "77f02def3094af804fd2371db25b7100", 546000}, {"resource.003", 0, "77f02def3094af804fd2371db25b7100", 591851}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Police Quest 2 - English DOS (from FRG) // SCI interpreter version 0.000.395 @@ -2548,7 +2559,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "77f02def3094af804fd2371db25b7100", 542897}, {"resource.003", 0, "77f02def3094af804fd2371db25b7100", 586857}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Police Quest 2 English DOS 1.001.006 (supplied by merkur-kun in bug report #3028479) {"pq2", "", { @@ -2557,7 +2568,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "77f02def3094af804fd2371db25b7100", 541261}, {"resource.003", 0, "77f02def3094af804fd2371db25b7100", 587511}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Police Quest 2 - Japanese PC-98 (also includes english language) // SCI interpreter version unknown @@ -2567,7 +2578,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "05fdee43a228dd6ea4d1a92ccae3f788", 637662}, {"resource.003", 0, "05fdee43a228dd6ea4d1a92ccae3f788", 684395}, AD_LISTEND}, - Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Police Quest 3 - English Amiga // Executable scanning reports "1.004.024" @@ -2643,7 +2654,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "b96a86ab681769e4cbb439670d967ca6", 449682}, {"resource.005", 0, "9e6c53a0e7eef53694d260fade8b1fc7", 724000}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Police Quest 4 - English DOS Non-Interactive Demo (from FRG) // SCI interpreter version 1.001.096 @@ -2660,7 +2671,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "379dfe80ed6bd16c47e4b950c4722eac", 11374}, {"resource.000", 0, "fd316a09b628b7032248139003369022", 18841068}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO0() }, // Police Quest 4 - German DOS CD (German text, English speech) // Supplied by markcoolio in bug report #3392955 @@ -2668,7 +2679,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "a398076371ed0e1e706c8f9fb9fc7ac5", 11386}, {"resource.000", 0, "6ff21954e0a2c5992279e7eb787c8d56", 18918747}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO0() }, // Police Quest 4 - English DOS // SCI interpreter version 2.000.000 (a guess?) @@ -2700,7 +2711,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "8c96733ef94c21526792f7ca4e3f2120", 1648}, {"resource.000", 0, "d8892f1b8c56c8f7704325460f49b300", 3676175}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Police Quest: SWAT - English DOS (from GOG.com) // Executable scanning reports "2.100.002", VERSION file reports "1.0c" @@ -2708,7 +2719,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "1c2563fee189885e29d9348f37306d94", 12175}, {"ressci.000", 0, "b2e1826ca81ce2e7e764587f5a14eee9", 127149181}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Police Quest: SWAT - English Windows (from the Police Quest Collection) // Executable scanning reports "2.100.002", VERSION file reports "1.0c" @@ -2723,7 +2734,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.004", 0, "4228038906f041623e65789500b22285", 6835}, {"ressci.004", 0, "b7e619e6ecf62fe65d5116a3a422e5f0", 46223872}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, #endif // ENABLE_SCI32 // Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by merkur in bug report #2718784) @@ -2736,7 +2747,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 642203}, {"resource.004", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 641688}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by alonzotg in bug report #3206006) {"qfg1", "", { @@ -2747,7 +2758,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 642203}, {"resource.004", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 641688}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Quest for Glory 1 / Hero's Quest - English DOS 5.25" Floppy (supplied by markcoolio in bug report #2723843) // Executable scanning reports "0.000.566" @@ -2762,7 +2773,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "69366c2a2f99917199fe1b60a4fee19d", 267852}, {"resource.007", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 272747}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Quest for Glory 1 / Hero's Quest - English DOS 5.25" Floppy (supplied by ssburnout in bug report #3049193) // 1.001 10x5.25" (label: INT.#0.000.566) @@ -2777,7 +2788,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "69366c2a2f99917199fe1b60a4fee19d", 267852}, {"resource.007", 0, "7ab2bf8e224b57f75e0cd6e4ba790761", 272747}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Quest for Glory 1 / Hero's Quest - English DOS 5.25" Floppy (supplied by ssburnout in bug report #3049193) // 1.200 10x5.25" (label: INT#9.10.90) @@ -2792,7 +2803,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "f46690dca714abc8c89357d30e363dd3", 278387}, {"resource.007", 0, "951299a82a8134ed12c5c18118d45c2f", 269173}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Quest for Glory 1 / Hero's Quest - English DOS Demo // Executable scanning reports "0.000.685" @@ -2800,7 +2811,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "df34c758cbb9026da175793ff686b0e6", 882}, {"resource.001", 0, "73fbaafdd313b39aeedb80fbf85ecef1", 389884}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Quest for Glory 1 - Japanese PC-98 5.25" Floppy (also includes English language) // Executable scanning reports "S.old.201" @@ -2810,7 +2821,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "a21451ef6fa8179bd4b22c4950004c44", 1136968}, {"resource.003", 0, "a21451ef6fa8179bd4b22c4950004c44", 769897}, AD_LISTEND}, - Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO3(GUIO_NOSPEECH, GUIO_NOASPECT, GUIO_EGAUNDITHER) }, // Quest for Glory 1 - Japanese PC-98 5.25" Floppy (also includes English language) // Executable scanning reports "S.old.201" @@ -2820,7 +2831,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "a21451ef6fa8179bd4b22c4950004c44", 1147121}, {"resource.003", 0, "a21451ef6fa8179bd4b22c4950004c44", 777575}, AD_LISTEND}, - Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO3(GUIO_NOSPEECH, GUIO_NOASPECT, GUIO_EGAUNDITHER) }, // Quest for Glory 1 - English Amiga // Executable scanning reports "1.002.020" @@ -2834,7 +2845,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "16cd4414c37ae3bb6d6da33dce8e25e8", 689124}, {"resource.005", 0, "5f3386ef2f2b1254e4a066f5d9027324", 609529}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Quest for Glory 1 (from abevi, bug report #2612718) {"qfg1", "", { @@ -2845,7 +2856,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "f0af87c60ec869946da442833aa5afa8", 640502}, {"resource.004", 0, "f0af87c60ec869946da442833aa5afa8", 644575}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Quest for Glory 1 - English DOS // SCI interpreter version 0.000.629 @@ -2857,7 +2868,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "951299a82a8134ed12c5c18118d45c2f", 640483}, {"resource.004", 0, "951299a82a8134ed12c5c18118d45c2f", 644443}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Quest for Glory 1 VGA Remake - English DOS // Executable scanning reports "2.000.411" @@ -3008,7 +3019,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "ba7ac86155e4c531e46cd73c86daa80a", 5884098}, {"resource.msg", 0, "a63974730d294dec0bea10057c36e506", 256014}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, 0, GUIO1(GUIO_NONE) }, + Common::ES_ESP, Common::kPlatformPC, 0, GUIO0() }, // Quest for Glory 3 - Italian DOS // Supplied by ghoost in bug report #3053457 @@ -3017,7 +3028,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.000", 0, "6178ad2e83e58e4671ca03315f7a6498", 5868000}, {"resource.msg", 0, "5a0a896ff3e4a628db38a75eb6c84114", 259018}, AD_LISTEND}, - Common::IT_ITA, Common::kPlatformPC, 0, GUIO1(GUIO_NONE) }, + Common::IT_ITA, Common::kPlatformPC, 0, GUIO0() }, // Quest for Glory 4 - English DOS Non-Interactive Demo (from FRG) // SCI interpreter version 1.001.069 (just a guess) @@ -3058,7 +3069,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "aba367f2102e81782d961b14fbe3d630", 10246}, {"resource.000", 0, "263dce4aa34c49d3ad29bec889007b1c", 11571394}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // RAMA - English DOS/Windows Demo // Executable scanning reports "2.100.002", VERSION file reports "000.000.008" @@ -3066,7 +3077,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.001", 0, "775304e9b2a545156be4d94209550094", 1393}, {"ressci.001", 0, "259437fd75fdf51e8207fda8c01fa4fd", 2334384}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, #ifdef ENABLE_SCI3_GAMES // RAMA - English Windows (from jvprat) @@ -3079,7 +3090,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.003", 0, "31ef4c0621711585d031f0ae81707251", 1636}, {"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6860492}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // RAMA - English Windows (from Quietust, in bug report #2850645) {"rama", "", { @@ -3090,7 +3101,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.003", 0, "48841e4b84ef1b98b48d43566fda9e13", 1636}, {"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6870356}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // RAMA - Italian Windows CD (from glorifindel) // SCI interpreter version 3.000.000 (a guess?) @@ -3098,7 +3109,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"ressci.001", 0, "2a68edd064e5e4937b5e9c74b38f2082", 70611091}, {"resmap.001", 0, "70ba2ff04a2b7fb2c52420ba7fbd47c2", 8338}, AD_LISTEND}, - Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, #endif // ENABLE_SCI3_GAMES // Shivers - English Windows (from jvprat) @@ -3107,14 +3118,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "f2ead37749ed8f6535a2445a7d05a0cc", 46525}, {"ressci.000", 0, "4294c6d7510935f2e0a52e302073c951", 262654836}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Shivers - German Windows (from Tobis87) {"shivers", "", { {"resmap.000", 0, "f483d0a1f78334c18052e92785c3086e", 46537}, {"ressci.000", 0, "6751b144671e2deed919eb9d284b07eb", 262390692}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Shivers - English Windows Demo // Executable scanning reports "2.100.002" @@ -3122,7 +3133,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "d9e0bc5eddefcbe47f528760085d8927", 1186}, {"ressci.000", 0, "3a93c6340b54e07e65d0e5583354d186", 10505469}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Shivers 2 doesn't contain SCI scripts. The whole game logic has // been reimplemented from SCI in native code placed in DLL files. @@ -3140,7 +3151,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "d8659188b84beaef076bd869837cd530", 634}, {"ressci.000", 0, "7fbac0807a044c9543e8ac376d200e59", 4925003}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Shivers 2 - English Windows (from abevi) // VERSION.TXT Version 1.0 (3/25/97) @@ -3148,7 +3159,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"ressci.001", 0, "a79d03d6eb75be0a79324f14e3d2ace4", 95346793}, {"resmap.001", 0, "a4804d436d90c4ec2e46b537f5e954db", 6268}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, #endif @@ -3180,6 +3191,13 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + // Slater & Charlie Go Camping - English Macintosh + {"slater", "", { + {"Data1", 0, "7243b4390e5f0182d8133fbcae4b50c5", 2298853}, + {"Data2", 0, "6b6f18f9b502dc0923eeae0ef47f02d5", 2276956}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO1(GUIO_NONE) }, + // Space Quest 1 VGA Remake - English Amiga (from www.back2roots.org) // SCI interpreter version 1.000.510 (just a guess) {"sq1sci", "SCI", { @@ -3250,7 +3268,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "975c6e81194ae6b65e960a248129ecaa", 684119}, {"resource.005", 0, "13d96f7905637552c0647175ff816145", 695589}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 3 - English Amiga (from www.back2roots.org) // SCI interpreter version 0.000.453 (just a guess) @@ -3261,7 +3279,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 746496}, {"resource.004", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 761984}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 3 - German Amiga (also includes english language) // Executable scanning reports "1.004.006" @@ -3274,7 +3292,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "6d8f34090503ce937e7dbef6cb6cdb6a", 545053}, {"resource.005", 0, "6d8f34090503ce937e7dbef6cb6cdb6a", 687507}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformAmiga, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::DE_DEU, Common::kPlatformAmiga, ADGF_ADDENGLISH, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 3 - English DOS Non-Interactive Demo // SCI interpreter version 0.000.453 @@ -3282,7 +3300,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "ec66ac2b1ce58b2575ba00b65058de1a", 612}, {"resource.001", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 180245}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 3 - English DOS (provided by richiefs in bug report #2670691) // SCI interpreter version 0.000.453 @@ -3292,7 +3310,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 720244}, {"resource.003", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 688367}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 3 - English DOS (from the Space Quest Collection) // Executable scanning reports "0.000.685", VERSION file reports "1.018" @@ -3302,7 +3320,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "8b55c4875298f45ea5696a5ee8f6a7fe", 715777}, {"resource.003", 0, "8b55c4875298f45ea5696a5ee8f6a7fe", 703370}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 3 - English DOS (from abevi, bug report #2612718) {"sq3", "", { @@ -3314,7 +3332,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.005", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 328278}, {"resource.006", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 356702}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 3 - English Mac (from Fingolfin) {"sq3", "", { @@ -3323,7 +3341,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.002", 0, "0d8dfe42683b46f3131823233a91ce6a", 794072}, {"resource.003", 0, "0d8dfe42683b46f3131823233a91ce6a", 776536}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformMacintosh, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 3 - German DOS (from Tobis87, also includes english language) // SCI interpreter version 0.000.453 (?) @@ -3337,7 +3355,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.006", 0, "9107c2aa5398e28b5c5406df13491f85", 320643}, {"resource.007", 0, "9107c2aa5398e28b5c5406df13491f85", 344287}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 3 v1.052 - German DOS (supplied by markcoolio in bug report #2723860, also includes english language) // Executable scanning reports "S.old.114" @@ -3433,7 +3451,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "9a673e33c3f6dd560b993ffed77eeb49", 534994}, {"resource.005", 0, "3c4841d0a3ebba4404af588c93620c22", 595465}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO2(GUIO_NOSPEECH, GUIO_EGAUNDITHER) }, // Space Quest 4 - German DOS (from Tobis87, also includes english language) // SCI interpreter version 1.000.200 (just a guess) @@ -3470,7 +3488,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.001", 0, "454684e3a7a68cbca073945e50778447", 1187088}, {"resource.002", 0, "6dc668326cc22cb9e8bd8ca9e68d2a66", 1181249}, AD_LISTEND}, - Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::JA_JPN, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Space Quest 4 - Japanese PC-98 5.25" Floppy (also includes english language) // SCI interpreter version 1.000.1068 @@ -3480,7 +3498,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.001", 0, "454684e3a7a68cbca073945e50778447", 1187088}, {"resource.002", 0, "6dc668326cc22cb9e8bd8ca9e68d2a66", 1181249}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC98, ADGF_ADDENGLISH, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Space Quest 4 - English DOS CD (from the Space Quest Collection) // Executable scanning reports "1.001.064", VERSION file reports "1.0" @@ -3488,7 +3506,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "ed90a8e3ccc53af6633ff6ab58392bae", 7054}, {"resource.000", 0, "63247e3901ab8963d4eece73747832e0", 5157378}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD, GUIO0() }, // Space Quest 4 - English Windows CD (from the Space Quest Collection) // Executable scanning reports "1.001.064", VERSION file reports "1.0" @@ -3512,7 +3530,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.004", 0, "776fba81c110d1908776232cbe190e20", 1253752}, {"resource.005", 0, "55fae26c2a92f16ef72c1e216e827c0f", 1098328}, AD_LISTEND}, - Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO1(GUIO_NONE) }, + Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO0() }, // Space Quest 4 - Spanish DOS Floppy (from jvprat, also includes english language) // Executable scanning reports "1.SQ4.056", VERSION file reports "1.000" @@ -3635,7 +3653,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "6dddfa3a8f3a3a513ec9dfdfae955005", 10528}, {"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Space Quest 6 - English DOS/Win3.11 CD ver 1.11 (from FRG) // SCI interpreter version 2.100.002 (just a guess) @@ -3643,7 +3661,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "e0615d6e4e10e37ae42e6a2a95aaf145", 10528}, {"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Space Quest 6 - French DOS/Win3.11 CD (from French magazine Joystick - September 1997) // Executable scanning reports "2.100.002", VERSION file reports "1.0" @@ -3651,7 +3669,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "3c831625931d5079b73ae8c275f52c95", 10534}, {"resource.000", 0, "4195ca940f759424f62b90e262cc1737", 40932397}, AD_LISTEND}, - Common::FR_FRA, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::FR_FRA, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Space Quest 6 - German DOS (from Tobis87, updated info from markcoolio in bug report #2723884) // SCI interpreter version 2.100.002 (just a guess) @@ -3659,7 +3677,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "664d797415484f85c90b1b45aedc7686", 10534}, {"resource.000", 0, "ba87ba91e5bdabb4169dd0df75777722", 40933685}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::DE_DEU, Common::kPlatformPC, ADGF_CD | ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, // Space Quest 6 - English DOS/Win3.11 Interactive Demo (from FRG) // SCI interpreter version 2.100.002 (just a guess) @@ -3667,7 +3685,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "368f07b07433db3f819fa3fa0e5efee5", 2572}, {"resource.000", 0, "ab12724e078dea34b624e0d2a38dcd7c", 2272050}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, #endif // ENABLE_SCI32 // The Island of Dr. Brain - English DOS CD (from jvprat) @@ -3676,7 +3694,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.map", 0, "2388efef8430b041b0f3b00b9050e4a2", 3281}, {"resource.000", 0, "b3acd9b9dd7fe53c4ee133ac9a1acfab", 2103560}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformPC, 0, GUIO1(GUIO_NONE) }, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO0() }, // The Island of Dr. Brain - English DOS (from Quietust) // Executable scanning reports "1.001.053", VERSION file reports "1.1 2.3.93" @@ -3701,7 +3719,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "9a3e172cde9963d0a969f26469318cec", 3403}, {"ressci.000", 0, "db3e290481c35c3224e9602e71e4a1f1", 5073868}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Torin's Passage - English Windows // SCI interpreter version 2.100.002 (just a guess) @@ -3709,7 +3727,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799}, {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Torin's Passage - Spanish Windows (from jvprat) // Executable scanning reports "2.100.002", VERSION file reports "1.0" @@ -3718,7 +3736,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, // TODO: depend on one of the patches? AD_LISTEND}, - Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Torin's Passage - French Windows // SCI interpreter version 2.100.002 (just a guess) @@ -3726,7 +3744,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799}, {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, AD_LISTEND}, - Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Torin's Passage - German Windows // SCI interpreter version 2.100.002 (just a guess) @@ -3734,7 +3752,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799}, {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, AD_LISTEND}, - Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOSPEECH) }, + Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO2(GUIO_NOSPEECH, GUIO_NOASPECT) }, // Torin's Passage - Italian Windows CD (from glorifindel) // SCI interpreter version 2.100.002 (just a guess) @@ -3742,7 +3760,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799}, {"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887}, AD_LISTEND}, - Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NONE) }, + Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) }, #endif // ENABLE_SCI32 // SCI Fanmade Games diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index a5c1b970f1..b3cfee873c 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -430,19 +430,16 @@ SciVersion GameFeatures::detectMessageFunctionType() { return _messageFunctionType; } - Common::List<ResourceId> *resources = g_sci->getResMan()->listResources(kResourceTypeMessage, -1); - - if (resources->empty()) { - delete resources; + Common::List<ResourceId> resources = g_sci->getResMan()->listResources(kResourceTypeMessage, -1); + if (resources.empty()) { // No messages found, so this doesn't really matter anyway... _messageFunctionType = SCI_VERSION_1_1; return _messageFunctionType; } - Resource *res = g_sci->getResMan()->findResource(*resources->begin(), false); + Resource *res = g_sci->getResMan()->findResource(*resources.begin(), false); assert(res); - delete resources; // Only v2 Message resources use the kGetMessage kernel function. // v3-v5 use the kMessage kernel function. diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 6f783d79e8..c99bc4fe47 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -914,28 +914,32 @@ Common::String Kernel::lookupText(reg_t address, int index) { // TODO: script_adjust_opcode_formats should probably be part of the // constructor (?) of a VirtualMachine or a ScriptManager class. void script_adjust_opcode_formats() { + + g_sci->_opcode_formats = new opcode_format[128][4]; + memcpy(g_sci->_opcode_formats, g_base_opcode_formats, 128*4*sizeof(opcode_format)); + if (g_sci->_features->detectLofsType() != SCI_VERSION_0_EARLY) { - g_opcode_formats[op_lofsa][0] = Script_Offset; - g_opcode_formats[op_lofss][0] = Script_Offset; + g_sci->_opcode_formats[op_lofsa][0] = Script_Offset; + g_sci->_opcode_formats[op_lofss][0] = Script_Offset; } #ifdef ENABLE_SCI32 // In SCI32, some arguments are now words instead of bytes if (getSciVersion() >= SCI_VERSION_2) { - g_opcode_formats[op_calle][2] = Script_Word; - g_opcode_formats[op_callk][1] = Script_Word; - g_opcode_formats[op_super][1] = Script_Word; - g_opcode_formats[op_send][0] = Script_Word; - g_opcode_formats[op_self][0] = Script_Word; - g_opcode_formats[op_call][1] = Script_Word; - g_opcode_formats[op_callb][1] = Script_Word; + g_sci->_opcode_formats[op_calle][2] = Script_Word; + g_sci->_opcode_formats[op_callk][1] = Script_Word; + g_sci->_opcode_formats[op_super][1] = Script_Word; + g_sci->_opcode_formats[op_send][0] = Script_Word; + g_sci->_opcode_formats[op_self][0] = Script_Word; + g_sci->_opcode_formats[op_call][1] = Script_Word; + g_sci->_opcode_formats[op_callb][1] = Script_Word; } if (getSciVersion() >= SCI_VERSION_3) { // TODO: There are also opcodes in // here to get the superclass, and possibly the species too. - g_opcode_formats[0x4d/2][0] = Script_None; - g_opcode_formats[0x4e/2][0] = Script_None; + g_sci->_opcode_formats[0x4d/2][0] = Script_None; + g_sci->_opcode_formats[0x4e/2][0] = Script_None; } #endif } diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index 8cb294e166..e549c1f8ae 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -457,6 +457,7 @@ reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv); reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv); reg_t kInPolygon(EngineState *s, int argc, reg_t *argv); reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv); +reg_t kEditText(EngineState *s, int argc, reg_t *argv); // SCI2.1 Kernel Functions reg_t kText(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index afe6b176e5..622511c906 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -24,7 +24,7 @@ #define SCI_ENGINE_KERNEL_TABLES_H #include "sci/engine/workarounds.h" -#include "sci/engine/vm.h" // for opcode_formats +#include "sci/engine/vm_types.h" // for opcode_formats namespace Sci { @@ -499,6 +499,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(UpdatePlane), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(ObjectIntersect), SIG_EVERYWHERE, "oo", NULL, NULL }, + { MAP_CALL(EditText), SIG_EVERYWHERE, "o", NULL, NULL }, // SCI2 unmapped functions - TODO! @@ -523,13 +524,6 @@ static SciKernelMapEntry s_kernelMap[] = { // TODO: Implement once the original save/load menus are implemented. { MAP_DUMMY(MakeSaveFileName), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - // Used for edit boxes in save/load dialogs. It's a rewritten version of kEditControl, - // but it handles events on its own, using an internal loop, instead of using SCI - // scripts for event management like kEditControl does. Called by script 64914, - // DEdit::hilite(). - // TODO: Implement once the original save/load menus are implemented. - { MAP_DUMMY(EditText), SIG_EVERYWHERE, "o", NULL, NULL }, - // Unused / debug SCI2 unused functions, always mapped to kDummy // AddMagnify/DeleteMagnify are both called by script 64979 (the Magnifier @@ -616,6 +610,12 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_DUMMY(DeletePic), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(GetSierraProfileString), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + // Unused / debug functions in the in-between SCI2.1 interpreters + { MAP_DUMMY(PreloadResource), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(CheckCDisc), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(GetSaveCDisc), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(TestPoly), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + // SCI2.1 unmapped functions - TODO! // MovePlaneItems - used by SQ6 to scroll through the inventory via the up/down buttons @@ -1116,7 +1116,9 @@ static const char *const sci21_default_knames[] = { #endif -opcode_format g_opcode_formats[128][4] = { +// Base set of opcode formats. They're copied and adjusted slightly in +// script_adjust_opcode_format depending on SCI version. +static const opcode_format g_base_opcode_formats[128][4] = { /*00*/ {Script_None}, {Script_None}, {Script_None}, {Script_None}, /*04*/ diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 9e9441847d..312497720a 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -22,7 +22,9 @@ #include "common/archive.h" #include "common/config-manager.h" +#include "common/debug-channels.h" #include "common/file.h" +#include "common/macresman.h" #include "common/str.h" #include "common/savefile.h" #include "common/system.h" @@ -52,9 +54,10 @@ struct SavegameDesc { * arbitrary data files, simply because many of our target platforms do not * support this. The only files one can create are savestates. But SCI has an * opcode to create and write to seemingly 'arbitrary' files. This is mainly - * used in LSL3 for LARRY3.DRV (which is a game data file, not a driver) and - * in LSL5 for MEMORY.DRV (which is again a game data file and contains the - * game's password). + * used in LSL3 for LARRY3.DRV (which is a game data file, not a driver, used + * for persisting the results of the "age quiz" across restarts) and in LSL5 + * for MEMORY.DRV (which is again a game data file and contains the game's + * password, XOR encrypted). * To implement that opcode, we combine the SaveFileManager with regular file * code, similarly to how the SCUMM HE engine does it. * @@ -115,20 +118,6 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u if (!inFile) inFile = SearchMan.createReadStreamForMember(englishName); - // Special case for LSL3: It tries to create a new dummy file, - // LARRY3.DRV. Apparently, if the file doesn't exist here, it should be - // created. The game scripts then go ahead and fill its contents with - // data. It seems to be a similar case as the dummy MEMORY.DRV file in - // LSL5, but LSL5 creates the file if it can't find it with a separate - // call to file_open(). - if (!inFile && englishName == "LARRY3.DRV") { - outFile = saveFileMan->openForSaving(wrappedName); - outFile->finalize(); - delete outFile; - outFile = 0; - inFile = SearchMan.createReadStreamForMember(wrappedName); - } - if (!inFile) debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_OPEN_OR_FAIL): failed to open file '%s'", englishName.c_str()); } else if (mode == _K_FILE_MODE_CREATE) { @@ -835,7 +824,7 @@ reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) { int size = argv[2].toUint16(); char *buf = new char[size]; bool success = false; - s->_segMan->memcpy((byte*)buf, argv[1], size); + s->_segMan->memcpy((byte *)buf, argv[1], size); debugC(kDebugLevelFile, "kFileIO(writeRaw): %d, %d", handle, size); FileHandle *f = getFileFromHandle(s, handle); @@ -1060,6 +1049,18 @@ reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) { exists = !saveFileMan->listSavefiles(wrappedName).empty(); } + // SCI2+ debug mode + if (DebugMan.isDebugChannelEnabled(kDebugLevelDebugMode)) { + if (!exists && name == "1.scr") // PQ4 + exists = true; + if (!exists && name == "18.scr") // QFG4 + exists = true; + if (!exists && name == "99.scr") // GK1, KQ7 + exists = true; + if (!exists && name == "classes") // GK2, SQ6, LSL7 + exists = true; + } + // Special case for non-English versions of LSL5: The English version of // LSL5 calls kFileIO(), case K_FILEIO_OPEN for reading to check if // memory.drv exists (which is where the game's password is stored). If @@ -1080,6 +1081,14 @@ reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) { delete outFile; } + // Special case for KQ6 Mac: The game checks for two video files to see + // if they exist before it plays them. Since we support multiple naming + // schemes for resource fork files, we also need to support that here in + // case someone has a "HalfDome.bin" file, etc. + if (!exists && g_sci->getGameId() == GID_KQ6 && g_sci->getPlatform() == Common::kPlatformMacintosh && + (name == "HalfDome" || name == "Kq6Movie")) + exists = Common::MacResManager::exists(name); + debugC(kDebugLevelFile, "kFileIO(fileExists) %s -> %d", name.c_str(), exists); return make_reg(0, exists); } diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index ea2b4816fc..caae562d67 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -25,6 +25,7 @@ #include "engines/util.h" #include "graphics/cursorman.h" #include "graphics/surface.h" +#include "graphics/palette.h" // temporary, for the fadeIn()/fadeOut() functions below #include "gui/message.h" @@ -39,7 +40,7 @@ #include "sci/graphics/animate.h" #include "sci/graphics/cache.h" #include "sci/graphics/compare.h" -#include "sci/graphics/controls.h" +#include "sci/graphics/controls16.h" #include "sci/graphics/cursor.h" #include "sci/graphics/palette.h" #include "sci/graphics/paint16.h" @@ -49,6 +50,7 @@ #include "sci/graphics/text16.h" #include "sci/graphics/view.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/controls32.h" #include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class #include "sci/graphics/text32.h" #include "sci/graphics/frameout.h" @@ -57,11 +59,13 @@ namespace Sci { static int16 adjustGraphColor(int16 color) { - // WORKAROUND: SCI1 EGA and Amiga games can set invalid colors (above 0 - 15). - // Colors above 15 are all white in SCI1 EGA games, which is why this was never - // observed. We clip them all to (0, 15) instead, as colors above 15 are used - // for the undithering algorithm in EGA games - bug #3048908. - if (getSciVersion() >= SCI_VERSION_1_EARLY && g_sci->getResMan()->getViewType() == kViewEga) + // WORKAROUND: EGA and Amiga games can set invalid colors (above 0 - 15). + // It seems only the lower nibble was used in these games. + // bug #3048908, #3486899. + // Confirmed in EGA games KQ4(late), QFG1(ega), LB1 that + // at least FillBox (only one of the functions using adjustGraphColor) + // behaves like this. + if (g_sci->getResMan()->getViewType() == kViewEga) return color & 0x0F; // 0 - 15 else return color; @@ -810,13 +814,13 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { switch (type) { case SCI_CONTROLS_TYPE_BUTTON: debugC(kDebugLevelGraphics, "drawing button %04x:%04x to %d,%d", PRINT_REG(controlObject), x, y); - g_sci->_gfxControls->kernelDrawButton(rect, controlObject, g_sci->strSplit(text.c_str(), NULL).c_str(), fontId, style, hilite); + g_sci->_gfxControls16->kernelDrawButton(rect, controlObject, g_sci->strSplit(text.c_str(), NULL).c_str(), fontId, style, hilite); return; case SCI_CONTROLS_TYPE_TEXT: alignment = readSelectorValue(s->_segMan, controlObject, SELECTOR(mode)); debugC(kDebugLevelGraphics, "drawing text %04x:%04x ('%s') to %d,%d, mode=%d", PRINT_REG(controlObject), text.c_str(), x, y, alignment); - g_sci->_gfxControls->kernelDrawText(rect, controlObject, g_sci->strSplit(text.c_str()).c_str(), fontId, alignment, style, hilite); + g_sci->_gfxControls16->kernelDrawText(rect, controlObject, g_sci->strSplit(text.c_str()).c_str(), fontId, alignment, style, hilite); s->r_acc = g_sci->_gfxText16->allocAndFillReferenceRectArray(); return; @@ -830,7 +834,7 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { writeSelectorValue(s->_segMan, controlObject, SELECTOR(cursor), cursorPos); } debugC(kDebugLevelGraphics, "drawing edit control %04x:%04x (text %04x:%04x, '%s') to %d,%d", PRINT_REG(controlObject), PRINT_REG(textReference), text.c_str(), x, y); - g_sci->_gfxControls->kernelDrawTextEdit(rect, controlObject, g_sci->strSplit(text.c_str(), NULL).c_str(), fontId, mode, style, cursorPos, maxChars, hilite); + g_sci->_gfxControls16->kernelDrawTextEdit(rect, controlObject, g_sci->strSplit(text.c_str(), NULL).c_str(), fontId, mode, style, cursorPos, maxChars, hilite); return; case SCI_CONTROLS_TYPE_ICON: @@ -847,7 +851,7 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { priority = -1; } debugC(kDebugLevelGraphics, "drawing icon control %04x:%04x to %d,%d", PRINT_REG(controlObject), x, y - 1); - g_sci->_gfxControls->kernelDrawIcon(rect, controlObject, viewId, loopNo, celNo, priority, style, hilite); + g_sci->_gfxControls16->kernelDrawIcon(rect, controlObject, viewId, loopNo, celNo, priority, style, hilite); return; case SCI_CONTROLS_TYPE_LIST: @@ -895,7 +899,7 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { } debugC(kDebugLevelGraphics, "drawing list control %04x:%04x to %d,%d, diff %d", PRINT_REG(controlObject), x, y, SCI_MAX_SAVENAME_LENGTH); - g_sci->_gfxControls->kernelDrawList(rect, controlObject, maxChars, listCount, listEntries, fontId, style, upperPos, cursorPos, isAlias, hilite); + g_sci->_gfxControls16->kernelDrawList(rect, controlObject, maxChars, listCount, listEntries, fontId, style, upperPos, cursorPos, isAlias, hilite); free(listEntries); delete[] listStrings; return; @@ -975,7 +979,10 @@ reg_t kEditControl(EngineState *s, int argc, reg_t *argv) { switch (controlType) { case SCI_CONTROLS_TYPE_TEXTEDIT: // Only process textedit controls in here - g_sci->_gfxControls->kernelTexteditChange(controlObject, eventObject); + g_sci->_gfxControls16->kernelTexteditChange(controlObject, eventObject); + break; + default: + break; } } return s->r_acc; @@ -1208,7 +1215,8 @@ reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) { switch (operation) { case 0: { // Set remapping to base. 0 turns remapping off. int16 base = (argc >= 2) ? argv[1].toSint16() : 0; - warning("kRemapColors: Set remapping to base %d", base); + if (base != 0) // 0 is the default behavior when changing rooms in GK1, thus silencing the warning + warning("kRemapColors: Set remapping to base %d", base); } break; case 1: { // unknown @@ -1436,6 +1444,46 @@ reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } +// Taken from the SCI16 GfxTransitions class +static void fadeOut() { + byte oldPalette[3 * 256], workPalette[3 * 256]; + int16 stepNr, colorNr; + // Sierra did not fade in/out color 255 for sci1.1, but they used it in + // several pictures (e.g. qfg3 demo/intro), so the fading looked weird + int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 255 : 254; + + g_system->getPaletteManager()->grabPalette(oldPalette, 0, 256); + + for (stepNr = 100; stepNr >= 0; stepNr -= 10) { + for (colorNr = 1; colorNr <= tillColorNr; colorNr++) { + if (g_sci->_gfxPalette->colorIsFromMacClut(colorNr)) { + workPalette[colorNr * 3 + 0] = oldPalette[colorNr * 3]; + workPalette[colorNr * 3 + 1] = oldPalette[colorNr * 3 + 1]; + workPalette[colorNr * 3 + 2] = oldPalette[colorNr * 3 + 2]; + } else { + workPalette[colorNr * 3 + 0] = oldPalette[colorNr * 3] * stepNr / 100; + workPalette[colorNr * 3 + 1] = oldPalette[colorNr * 3 + 1] * stepNr / 100; + workPalette[colorNr * 3 + 2] = oldPalette[colorNr * 3 + 2] * stepNr / 100; + } + } + g_system->getPaletteManager()->setPalette(workPalette + 3, 1, tillColorNr); + g_sci->getEngineState()->wait(2); + } +} + +// Taken from the SCI16 GfxTransitions class +static void fadeIn() { + int16 stepNr; + // Sierra did not fade in/out color 255 for sci1.1, but they used it in + // several pictures (e.g. qfg3 demo/intro), so the fading looked weird + int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 255 : 254; + + for (stepNr = 0; stepNr <= 100; stepNr += 10) { + g_sci->_gfxPalette->kernelSetIntensity(1, tillColorNr + 1, stepNr, true); + g_sci->getEngineState()->wait(2); + } +} + /** * Used for scene transitions, replacing (but reusing parts of) the old * transition code. @@ -1446,31 +1494,65 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) { // tables inside graphics/transitions.cpp uint16 showStyle = argv[0].toUint16(); // 0 - 15 reg_t planeObj = argv[1]; // the affected plane - //argv[2] // seconds that the transition lasts - //argv[3] // back color to be used(?) - //int16 priority = argv[4].toSint16(); - //argv[5] // boolean, animate or not while the transition lasts - //argv[6] // refFrame + uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts + uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff + int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out + uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts + uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out + int16 divisions; // If the game has the pFadeArray selector, another parameter is used here, // before the optional last parameter - /*bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0; + bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0; if (hasFadeArray) { // argv[7] - //int16 unk7 = (argc >= 9) ? argv[8].toSint16() : 0; // divisions (transition steps?) + divisions = (argc >= 9) ? argv[8].toSint16() : -1; // divisions (transition steps?) } else { - //int16 unk7 = (argc >= 8) ? argv[7].toSint16() : 0; // divisions (transition steps?) - }*/ + divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?) + } if (showStyle > 15) { warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj)); return s->r_acc; } + // TODO: Proper implementation. This is a very basic version. I'm not even + // sure if the rest of the styles will work with this mechanism. + + // Check if the passed parameters are the ones we expect + if (showStyle == 13 || showStyle == 14) { // fade out / fade in + if (seconds != 1) + warning("kSetShowStyle(fade): seconds isn't 1, it's %d", seconds); + if (backColor != 0 && backColor != 0xFFFF) + warning("kSetShowStyle(fade): backColor isn't 0 or 0xFFFF, it's %d", backColor); + if (priority != 200) + warning("kSetShowStyle(fade): priority isn't 200, it's %d", priority); + if (animate != 0) + warning("kSetShowStyle(fade): animate isn't 0, it's %d", animate); + if (refFrame != 0) + warning("kSetShowStyle(fade): refFrame isn't 0, it's %d", refFrame); + if (divisions >= 0 && divisions != 20) + warning("kSetShowStyle(fade): divisions isn't 20, it's %d", divisions); + } + // TODO: Check if the plane is in the list of planes to draw - // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now - kStub(s, argc, argv); + switch (showStyle) { + //case 0: // no transition, perhaps? (like in the previous SCI versions) + case 13: // fade out + // TODO: Temporary implementation, which ignores all additional parameters + fadeOut(); + break; + case 14: // fade in + // TODO: Temporary implementation, which ignores all additional parameters + g_sci->_gfxFrameout->kernelFrameout(); // draw new scene before fading in + fadeIn(); + break; + default: + // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now + kStub(s, argc, argv); + break; + } return s->r_acc; } @@ -1662,8 +1744,8 @@ reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { memset(memoryPtr + BITMAP_HEADER_SIZE, back, width * height); // Save totalWidth, totalHeight // TODO: Save the whole bitmap header, like SSCI does - WRITE_LE_UINT16((void *)memoryPtr, width); - WRITE_LE_UINT16((void *)(memoryPtr + 2), height); + WRITE_LE_UINT16(memoryPtr, width); + WRITE_LE_UINT16(memoryPtr + 2, height); return memoryId; } break; @@ -1689,8 +1771,8 @@ reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16((void *)memoryPtr); - uint16 totalHeight = READ_LE_UINT16((void *)(memoryPtr + 2)); + uint16 totalWidth = READ_LE_UINT16(memoryPtr); + uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; GfxView *view = g_sci->_gfxCache->getView(viewNum); @@ -1730,8 +1812,8 @@ reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16((void *)memoryPtr); - uint16 totalHeight = READ_LE_UINT16((void *)(memoryPtr + 2)); + uint16 totalWidth = READ_LE_UINT16(memoryPtr); + uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; GfxFont *font = g_sci->_gfxCache->getFont(fontId); @@ -1773,8 +1855,8 @@ reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16((void *)memoryPtr); - uint16 totalHeight = READ_LE_UINT16((void *)(memoryPtr + 2)); + uint16 totalWidth = READ_LE_UINT16(memoryPtr); + uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); uint16 width = MIN<uint16>(totalWidth - x, fillWidth); uint16 height = MIN<uint16>(totalHeight - y, fillHeight); byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; @@ -1795,6 +1877,20 @@ reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } +// Used for edit boxes in save/load dialogs. It's a rewritten version of kEditControl, +// but it handles events on its own, using an internal loop, instead of using SCI +// scripts for event management like kEditControl does. Called by script 64914, +// DEdit::hilite(). +reg_t kEditText(EngineState *s, int argc, reg_t *argv) { + reg_t controlObject = argv[0]; + + if (!controlObject.isNull()) { + g_sci->_gfxControls32->kernelTexteditChange(controlObject); + } + + return s->r_acc; +} + #endif } // End of namespace Sci diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp index 8500f08211..2a33df26bc 100644 --- a/engines/sci/engine/klists.cpp +++ b/engines/sci/engine/klists.cpp @@ -409,7 +409,7 @@ int sort_temp_cmp(const void *p1, const void *p2) { const sort_temp_t *st1 = (const sort_temp_t *)p1; const sort_temp_t *st2 = (const sort_temp_t *)p2; - if (st1->order.segment < st1->order.segment || (st1->order.segment == st1->order.segment && st1->order.offset < st2->order.offset)) + if (st1->order.segment < st2->order.segment || (st1->order.segment == st2->order.segment && st1->order.offset < st2->order.offset)) return -1; if (st1->order.segment > st2->order.segment || (st1->order.segment == st2->order.segment && st1->order.offset > st2->order.offset)) @@ -753,7 +753,6 @@ reg_t kArray(EngineState *s, int argc, reg_t *argv) { reg_t arrayHandle = argv[1]; SciArray<reg_t> *array1 = s->_segMan->lookupArray(argv[1]); - //SciArray<reg_t> *array1 = !argv[1].isNull() ? s->_segMan->lookupArray(argv[1]) : s->_segMan->allocateArray(&arrayHandle); SciArray<reg_t> *array2 = s->_segMan->lookupArray(argv[3]); uint32 index1 = argv[2].toUint16(); uint32 index2 = argv[4].toUint16(); @@ -790,21 +789,8 @@ reg_t kArray(EngineState *s, int argc, reg_t *argv) { #endif return NULL_REG; } - SegmentType sourceType = s->_segMan->getSegmentObj(argv[1].segment)->getType(); - if (sourceType == SEG_TYPE_SCRIPT) { - // A technique used in later SCI2.1 and SCI3 games: the contents of a script - // are loaded in an array (well, actually a string). - Script *scr = s->_segMan->getScript(argv[1].segment); - reg_t stringHandle; - - SciString *dupString = s->_segMan->allocateString(&stringHandle); - dupString->setSize(scr->getBufSize()); - dupString->fromString(Common::String((const char *)scr->getBuf())); - - return stringHandle; - } else if (sourceType != SEG_TYPE_ARRAY && sourceType != SEG_TYPE_SCRIPT) { - error("kArray(Dup): Request to duplicate a segment which isn't an array or a script"); - } + if (s->_segMan->getSegmentObj(argv[1].segment)->getType() != SEG_TYPE_ARRAY) + error("kArray(Dup): Request to duplicate a segment which isn't an array"); reg_t arrayHandle; SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle); diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index 375aeaa06b..089b325a7f 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -1545,7 +1545,6 @@ reg_t kAvoidPath(EngineState *s, int argc, reg_t *argv) { default: warning("Unknown AvoidPath subfunction %d", argc); return NULL_REG; - break; } } diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index 93c1fffe3c..9b0e490d7e 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -74,17 +74,13 @@ reg_t kLock(EngineState *s, int argc, reg_t *argv) { case 0 : if (id.getNumber() == 0xFFFF) { // Unlock all resources of the requested type - Common::List<ResourceId> *resources = g_sci->getResMan()->listResources(type); - Common::List<ResourceId>::iterator itr = resources->begin(); - - while (itr != resources->end()) { + Common::List<ResourceId> resources = g_sci->getResMan()->listResources(type); + Common::List<ResourceId>::iterator itr; + for (itr = resources.begin(); itr != resources.end(); ++itr) { Resource *res = g_sci->getResMan()->testResource(*itr); if (res->isLocked()) g_sci->getResMan()->unlockResource(res); - ++itr; } - - delete resources; } else { which = g_sci->getResMan()->findResource(id, 0); diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index 33bef58e52..c469f775f9 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -195,6 +195,13 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) { return make_reg(0, 1); } else { int16 language = argv[1].toSint16(); + + // athrxx: It seems from disasm that the original KQ5 FM-Towns loads a default language (Japanese) audio map at the beginning + // right after loading the video and audio drivers. The -1 language argument in here simply means that the original will stick + // with Japanese. Instead of doing that we switch to the language selected in the launcher. + if (g_sci->getPlatform() == Common::kPlatformFMTowns && language == -1) + language = (g_sci->getLanguage() == Common::JA_JPN) ? K_LANG_JAPANESE : K_LANG_ENGLISH; + debugC(kDebugLevelSound, "kDoAudio: set language to %d", language); if (language != -1) diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 1a9359bb26..fe8d631497 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -147,7 +147,7 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) { Common::String source_str = s->_segMan->getString(argv[0]); const char *source = source_str.c_str(); - while (isspace((unsigned char)*source)) + while (Common::isSpace(*source)) source++; /* Skip whitespace */ int16 result = 0; @@ -246,14 +246,14 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) { /* int writelength; -- unused atm */ - if (xfer && (isdigit(static_cast<unsigned char>(xfer)) || xfer == '-' || xfer == '=')) { + if (xfer && (Common::isDigit(xfer) || xfer == '-' || xfer == '=')) { char *destp; if (xfer == '0') fillchar = '0'; else if (xfer == '=') align = ALIGN_CENTER; - else if (isdigit(static_cast<unsigned char>(xfer)) || (xfer == '-')) + else if (Common::isDigit(xfer) || (xfer == '-')) source--; // Go to start of length argument strLength = strtol(source, &destp, 10); @@ -697,13 +697,15 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { case 6: { // Cpy const char *string2 = 0; uint32 string2Size = 0; + Common::String string; if (argv[3].segment == s->_segMan->getStringSegmentId()) { - SciString *string = s->_segMan->lookupString(argv[3]); - string2 = string->getRawData(); - string2Size = string->getSize(); + SciString *sstr; + sstr = s->_segMan->lookupString(argv[3]); + string2 = sstr->getRawData(); + string2Size = sstr->getSize(); } else { - Common::String string = s->_segMan->getString(argv[3]); + string = s->_segMan->getString(argv[3]); string2 = string.c_str(); string2Size = string.size() + 1; } @@ -743,28 +745,16 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { return make_reg(0, strcmp(string1.c_str(), string2.c_str())); } case 8: { // Dup - const char *rawString = 0; - uint32 size = 0; reg_t stringHandle; - // We allocate the new string first because if the StringTable needs to - // grow, our rawString pointer will be invalidated + SciString *dupString = s->_segMan->allocateString(&stringHandle); if (argv[1].segment == s->_segMan->getStringSegmentId()) { - SciString *string = s->_segMan->lookupString(argv[1]); - rawString = string->getRawData(); - size = string->getSize(); + *dupString = *s->_segMan->lookupString(argv[1]); } else { - Common::String string = s->_segMan->getString(argv[1]); - rawString = string.c_str(); - size = string.size() + 1; + dupString->fromString(s->_segMan->getString(argv[1])); } - dupString->setSize(size); - - for (uint32 i = 0; i < size; i++) - dupString->setValue(i, rawString[i]); - return stringHandle; } case 9: // Getdata diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp index f30f4e923e..cddd01e10c 100644 --- a/engines/sci/engine/message.cpp +++ b/engines/sci/engine/message.cpp @@ -345,7 +345,7 @@ bool MessageState::stringLit(Common::String &outStr, const Common::String &inStr } bool MessageState::stringStage(Common::String &outstr, const Common::String &inStr, uint &index) { - // Stage directions of the form (n*), where n is anything but a digit or a lowercase character + // Stage directions of the form (n *), where n is anything but a digit or a lowercase character if (inStr[index] != '(') return false; diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 030c0f3f54..404bea799d 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -66,7 +66,7 @@ void syncWithSerializer(Common::Serializer &s, T &obj) { } // By default, sync using syncWithSerializer, which in turn can easily be overloaded. -template <typename T> +template<typename T> struct DefaultSyncer : Common::BinaryFunction<Common::Serializer, T, void> { void operator()(Common::Serializer &s, T &obj) const { //obj.saveLoadWithSerializer(s); @@ -87,7 +87,7 @@ struct DefaultSyncer : Common::BinaryFunction<Common::Serializer, T, void> { * * TODO: Add something like this for lists, queues.... */ -template <typename T, class Syncer = DefaultSyncer<T> > +template<typename T, class Syncer = DefaultSyncer<T> > struct ArraySyncer : Common::BinaryFunction<Common::Serializer, T, void> { void operator()(Common::Serializer &s, Common::Array<T> &arr) const { uint len = arr.size(); @@ -113,13 +113,13 @@ void syncArray(Common::Serializer &s, Common::Array<T> &arr) { } -template <> +template<> void syncWithSerializer(Common::Serializer &s, reg_t &obj) { s.syncAsUint16LE(obj.segment); s.syncAsUint16LE(obj.offset); } -template <> +template<> void syncWithSerializer(Common::Serializer &s, synonym_t &obj) { s.syncAsUint16LE(obj.replaceant); s.syncAsUint16LE(obj.replacement); @@ -203,7 +203,8 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) { // Now, load the script itself scr->load(g_sci->getResMan()); - for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) + ObjMap objects = scr->getObjectMap(); + for (ObjMap::iterator it = objects.begin(); it != objects.end(); ++it) it->_value.syncBaseObject(scr->getBuf(it->_value.getPos().offset)); } @@ -226,9 +227,10 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) { continue; Script *scr = (Script *)_heap[i]; - scr->_localsBlock = (scr->_localsSegment == 0) ? NULL : (LocalVariables *)(_heap[scr->_localsSegment]); + scr->syncLocalsBlock(this); - for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) { + ObjMap objects = scr->getObjectMap(); + for (ObjMap::iterator it = objects.begin(); it != objects.end(); ++it) { reg_t addr = it->_value.getPos(); Object *obj = scr->scriptObjInit(addr, false); @@ -237,7 +239,7 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) { // TODO/FIXME: This should not be happening at all. It might indicate a possible issue // with the garbage collector. It happens for example in LSL5 (German, perhaps English too). warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr)); - scr->_objects.erase(addr.toUint16()); + objects.erase(addr.toUint16()); } } } @@ -245,7 +247,7 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) { } -template <> +template<> void syncWithSerializer(Common::Serializer &s, Class &obj) { s.syncAsSint32LE(obj.script); syncWithSerializer(s, obj.reg); @@ -324,14 +326,14 @@ void Object::saveLoadWithSerializer(Common::Serializer &s) { syncArray<reg_t>(s, _variables); } -template <> +template<> void syncWithSerializer(Common::Serializer &s, SegmentObjTable<Clone>::Entry &obj) { s.syncAsSint32LE(obj.next_free); syncWithSerializer<Object>(s, obj); } -template <> +template<> void syncWithSerializer(Common::Serializer &s, SegmentObjTable<List>::Entry &obj) { s.syncAsSint32LE(obj.next_free); @@ -339,7 +341,7 @@ void syncWithSerializer(Common::Serializer &s, SegmentObjTable<List>::Entry &obj syncWithSerializer(s, obj.last); } -template <> +template<> void syncWithSerializer(Common::Serializer &s, SegmentObjTable<Node>::Entry &obj) { s.syncAsSint32LE(obj.next_free); @@ -350,7 +352,7 @@ void syncWithSerializer(Common::Serializer &s, SegmentObjTable<Node>::Entry &obj } #ifdef ENABLE_SCI32 -template <> +template<> void syncWithSerializer(Common::Serializer &s, SegmentObjTable<SciArray<reg_t> >::Entry &obj) { s.syncAsSint32LE(obj.next_free); @@ -386,7 +388,7 @@ void syncWithSerializer(Common::Serializer &s, SegmentObjTable<SciArray<reg_t> > } } -template <> +template<> void syncWithSerializer(Common::Serializer &s, SegmentObjTable<SciString>::Entry &obj) { s.syncAsSint32LE(obj.next_free); @@ -414,7 +416,7 @@ void syncWithSerializer(Common::Serializer &s, SegmentObjTable<SciString>::Entry } #endif -template <typename T> +template<typename T> void sync_Table(Common::Serializer &s, T &obj) { s.syncAsSint32LE(obj.first_free); s.syncAsSint32LE(obj.entries_used); diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 01e1afe5ea..8b26969f4a 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -492,8 +492,29 @@ SegmentRef Script::dereference(reg_t pointer) { return ret; } +LocalVariables *Script::allocLocalsSegment(SegManager *segMan) { + if (!getLocalsCount()) { // No locals + return NULL; + } else { + LocalVariables *locals; + + if (_localsSegment) { + locals = (LocalVariables *)segMan->getSegment(_localsSegment, SEG_TYPE_LOCALS); + if (!locals || locals->getType() != SEG_TYPE_LOCALS || locals->script_id != getScriptNumber()) + error("Invalid script locals segment while allocating locals"); + } else + locals = (LocalVariables *)segMan->allocSegment(new LocalVariables(), &_localsSegment); + + _localsBlock = locals; + locals->script_id = getScriptNumber(); + locals->_locals.resize(getLocalsCount()); + + return locals; + } +} + void Script::initializeLocals(SegManager *segMan) { - LocalVariables *locals = segMan->allocLocalsSegment(this); + LocalVariables *locals = allocLocalsSegment(segMan); if (locals) { if (getSciVersion() > SCI_VERSION_0_EARLY) { const byte *base = (const byte *)(_buf + getLocalsOffset()); @@ -508,6 +529,10 @@ void Script::initializeLocals(SegManager *segMan) { } } +void Script::syncLocalsBlock(SegManager *segMan) { + _localsBlock = (_localsSegment == 0) ? NULL : (LocalVariables *)(segMan->getSegment(_localsSegment, SEG_TYPE_LOCALS)); +} + void Script::initializeClasses(SegManager *segMan) { const byte *seeker = 0; uint16 mult = 0; diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index ff061e0e36..1ebae3b7a8 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -62,23 +62,18 @@ private: const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */ uint16 _numExports; /**< Number of entries in the exports table */ - const byte *_synonyms; /**< Synonyms block or 0 if not present*/ + const byte *_synonyms; /**< Synonyms block or 0 if not present */ uint16 _numSynonyms; /**< Number of entries in the synonyms block */ int _localsOffset; uint16 _localsCount; bool _markedAsDeleted; - -public: - /** - * Table for objects, contains property variables. - * Indexed by the TODO offset. - */ - ObjMap _objects; SegmentId _localsSegment; /**< The local variable segment */ LocalVariables *_localsBlock; + ObjMap _objects; /**< Table for objects, contains property variables */ + public: int getLocalsOffset() const { return _localsOffset; } uint16 getLocalsCount() const { return _localsCount; } @@ -89,6 +84,11 @@ public: const byte *getBuf(uint offset = 0) const { return _buf + offset; } int getScriptNumber() const { return _nr; } + SegmentId getLocalsSegment() const { return _localsSegment; } + reg_t *getLocalsBegin() { return _localsBlock ? _localsBlock->_locals.begin() : NULL; } + void syncLocalsBlock(SegManager *segMan); + ObjMap &getObjectMap() { return _objects; } + const ObjMap &getObjectMap() const { return _objects; } public: Script(); @@ -295,6 +295,8 @@ private: * @param segmentId The script's segment id */ void initializeObjectsSci3(SegManager *segMan, SegmentId segmentId); + + LocalVariables *allocLocalsSegment(SegManager *segMan); }; } // End of namespace Sci diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 7efcb42f4b..187f1ce021 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -366,7 +366,7 @@ const uint16 freddypharkasPatchLadderEvent[] = { // script, description, magic DWORD, adjust const SciScriptSignature freddypharkasSignatures[] = { { 0, "CD: score early disposal", 1, PATCH_MAGICDWORD(0x39, 0x0d, 0x43, 0x75), -3, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal }, - { 235, "CD: canister pickup hang", 3, PATCH_MAGICDWORD(0x39, 0x07, 0x39, 0x08), -4, freddypharkasSignatureCanisterHang, freddypharkasPatchCanisterHang }, + { 235, "CD: canister pickup hang", 3, PATCH_MAGICDWORD(0x39, 0x07, 0x39, 0x08), -4, freddypharkasSignatureCanisterHang, freddypharkasPatchCanisterHang }, { 320, "ladder event issue", 2, PATCH_MAGICDWORD(0x6d, 0x76, 0x38, 0xf5), -1, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -437,8 +437,68 @@ const uint16 gk1PatchDay5PhoneFreeze[] = { PATCH_END }; +// Floppy version: Interrogation::dispose() compares an object reference +// (stored in the view selector) with a number, leading to a crash (this kind +// of comparison was not used in SCI32). The view selector is used to store +// both a view number (in some cases), and a view reference (in other cases). +// In the floppy version, the checks are in the wrong order, so there is a +// comparison between a number an an object. In the CD version, the checks are +// in the correct order, thus the comparison is correct, thus we use the code +// from the CD version in the floppy one. +const byte gk1SignatureInterrogationBug[] = { + 43, + 0x65, 0x4c, // aTop 4c + 0x67, 0x50, // pTos 50 + 0x34, 0x10, 0x27, // ldi 2710 + 0x1e, // gt? + 0x31, 0x08, // bnt 08 [05a0] + 0x67, 0x50, // pTos 50 + 0x34, 0x10, 0x27, // ldi 2710 + 0x04, // sub + 0x65, 0x50, // aTop 50 + 0x63, 0x50, // pToa 50 + 0x31, 0x15, // bnt 15 [05b9] + 0x39, 0x0e, // pushi 0e + 0x76, // push0 + 0x4a, 0x04, 0x00, // send 0004 + 0xa5, 0x00, // sat 00 + 0x38, 0x93, 0x00, // pushi 0093 + 0x76, // push0 + 0x63, 0x50, // pToa 50 + 0x4a, 0x04, 0x00, // send 0004 + 0x85, 0x00, // lat 00 + 0x65, 0x50, // aTop 50 + 0 +}; + +const uint16 gk1PatchInterrogationBug[] = { + 0x65, 0x4c, // aTop 4c + 0x63, 0x50, // pToa 50 + 0x31, 0x15, // bnt 15 [05b9] + 0x39, 0x0e, // pushi 0e + 0x76, // push0 + 0x4a, 0x04, 0x00, // send 0004 + 0xa5, 0x00, // sat 00 + 0x38, 0x93, 0x00, // pushi 0093 + 0x76, // push0 + 0x63, 0x50, // pToa 50 + 0x4a, 0x04, 0x00, // send 0004 + 0x85, 0x00, // lat 00 + 0x65, 0x50, // aTop 50 + 0x67, 0x50, // pTos 50 + 0x34, 0x10, 0x27, // ldi 2710 + 0x1e, // gt? + 0x31, 0x08, // bnt 08 [05b9] + 0x67, 0x50, // pTos 50 + 0x34, 0x10, 0x27, // ldi 2710 + 0x04, // sub + 0x65, 0x50, // aTop 50 + PATCH_END +}; + // script, description, magic DWORD, adjust const SciScriptSignature gk1Signatures[] = { + { 51, "interrogation bug", 1, PATCH_MAGICDWORD(0x65, 0x4c, 0x67, 0x50), 0, gk1SignatureInterrogationBug, gk1PatchInterrogationBug }, { 212, "day 5 phone freeze", 1, PATCH_MAGICDWORD(0x35, 0x03, 0x65, 0x1a), 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze }, { 230, "day 6 police beignet timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -16, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet }, { 230, "day 6 police sleep timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -5, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep }, diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index ad3f4fb788..ef61b2e28a 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -122,8 +122,8 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode #endif i = 0; - while (g_opcode_formats[opcode][i]) { - switch (g_opcode_formats[opcode][i++]) { + while (g_sci->_opcode_formats[opcode][i]) { + switch (g_sci->_opcode_formats[opcode][i++]) { case Script_Invalid: warning("-Invalid operation-"); break; @@ -296,7 +296,7 @@ bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpTarget) { Script *script_entity = (Script *)mobj; const byte *scr = script_entity->getBuf(); - int scr_size = script_entity->getBufSize(); + int scr_size = script_entity->getScriptSize(); if (pos.offset >= scr_size) return false; @@ -310,7 +310,13 @@ bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpTarget) { case op_bt: case op_bnt: case op_jmp: - jumpTarget = pos + bytecount + opparams[0]; + { + reg_t jmpTarget = pos + bytecount + opparams[0]; + // QFG2 has invalid jumps outside the script buffer in script 260 + if (jmpTarget.offset >= scr_size) + return false; + jumpTarget = jmpTarget; + } return true; default: return false; @@ -721,7 +727,7 @@ void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *ke switch (mobj->getType()) { case SEG_TYPE_HUNK: { - HunkTable *ht = (HunkTable*)mobj; + HunkTable *ht = (HunkTable *)mobj; int index = argv[parmNr].offset; if (ht->isValidEntry(index)) { // NOTE: This ", deleted" isn't as useful as it could diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 1510af8508..cc127c8dbc 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -151,8 +151,8 @@ void SegManager::deallocate(SegmentId seg) { if (mobj->getType() == SEG_TYPE_SCRIPT) { Script *scr = (Script *)mobj; _scriptSegMap.erase(scr->getScriptNumber()); - if (scr->_localsSegment) - deallocate(scr->_localsSegment); + if (scr->getLocalsSegment()) + deallocate(scr->getLocalsSegment()); } delete mobj; @@ -270,12 +270,13 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) { if (mobj->getType() == SEG_TYPE_SCRIPT) { // It's a script, scan all objects in it const Script *scr = (const Script *)mobj; - for (ObjMap::const_iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) { + const ObjMap &objects = scr->getObjectMap(); + for (ObjMap::const_iterator it = objects.begin(); it != objects.end(); ++it) { objpos.offset = it->_value.getPos().offset; if (name == getObjectName(objpos)) result.push_back(objpos); } - } else if (mobj->getType() == SEG_TYPE_CLONES) { + } else if (mobj->getType() == SEG_TYPE_CLONES) { // It's clone table, scan all objects in it const CloneTable *ct = (const CloneTable *)mobj; for (uint idx = 0; idx < ct->_table.size(); ++idx) { @@ -341,29 +342,6 @@ SegmentId SegManager::getScriptSegment(int script_nr, ScriptLoadType load) { return segment; } -LocalVariables *SegManager::allocLocalsSegment(Script *scr) { - if (!scr->getLocalsCount()) { // No locals - scr->_localsSegment = 0; - scr->_localsBlock = NULL; - return NULL; - } else { - LocalVariables *locals; - - if (scr->_localsSegment) { - locals = (LocalVariables *)_heap[scr->_localsSegment]; - if (!locals || locals->getType() != SEG_TYPE_LOCALS || locals->script_id != scr->getScriptNumber()) - error("Invalid script locals segment while allocating locals"); - } else - locals = (LocalVariables *)allocSegment(new LocalVariables(), &scr->_localsSegment); - - scr->_localsBlock = locals; - locals->script_id = scr->getScriptNumber(); - locals->_locals.resize(scr->getLocalsCount()); - - return locals; - } -} - DataStack *SegManager::allocateStack(int size, SegmentId *segid) { SegmentObj *mobj = allocSegment(new DataStack(), segid); DataStack *retval = (DataStack *)mobj; @@ -713,7 +691,7 @@ void SegManager::memcpy(reg_t dest, const byte* src, size_t n) { if (dest_r.isRaw) { // raw -> raw - ::memcpy((char*)dest_r.raw, src, n); + ::memcpy((char *)dest_r.raw, src, n); } else { // raw -> non-raw for (uint i = 0; i < n; i++) diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index ab5aeacabf..62e711e686 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -463,8 +463,10 @@ private: SegmentId _stringSegId; #endif -private: +public: SegmentObj *allocSegment(SegmentObj *mem, SegmentId *segid); + +private: void deallocate(SegmentId seg); void createClassTable(); @@ -477,9 +479,6 @@ private: * 'seg' is a valid segment */ bool check(SegmentId seg); - -public: - LocalVariables *allocLocalsSegment(Script *scr); }; } // End of namespace Sci diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 3f11d6ff49..36b7d92c07 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -143,9 +143,11 @@ SegmentRef LocalVariables::dereference(reg_t pointer) { if (ret.maxSize > 0) { ret.reg = &_locals[pointer.offset / 2]; } else { - if ((g_sci->getEngineState()->currentRoomNumber() == 660 || g_sci->getEngineState()->currentRoomNumber() == 660) + if ((g_sci->getEngineState()->currentRoomNumber() == 160 || + g_sci->getEngineState()->currentRoomNumber() == 220) && g_sci->getGameId() == GID_LAURABOW2) { - // Happens in two places during the intro of LB2CD, both from kMemory(peek): + // WORKAROUND: Happens in two places during the intro of LB2CD, both + // from kMemory(peek): // - room 160: Heap 160 has 83 local variables (0-82), and the game // asks for variables at indices 83 - 90 too. // - room 220: Heap 220 has 114 local variables (0-113), and the @@ -292,18 +294,19 @@ void SciString::fromString(const Common::String &string) { if (_type != 3) error("SciString::fromString(): Array is not a string"); - if (string.size() > _size) - setSize(string.size()); + setSize(string.size() + 1); for (uint32 i = 0; i < string.size(); i++) _data[i] = string[i]; + + _data[string.size()] = 0; } SegmentRef StringTable::dereference(reg_t pointer) { SegmentRef ret; ret.isRaw = true; ret.maxSize = _table[pointer.offset].getSize(); - ret.raw = (byte*)_table[pointer.offset].getRawData(); + ret.raw = (byte *)_table[pointer.offset].getRawData(); return ret; } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 009a2558ce..54cf7b98af 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -370,7 +370,7 @@ public: #ifdef ENABLE_SCI32 -template <typename T> +template<typename T> class SciArray { public: SciArray() : _type(-1), _data(NULL), _size(0), _actualSize(0) { } diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index a9aca9e22f..a8b1cf7ec2 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -178,6 +178,7 @@ void Kernel::mapSelectors() { FIND_SELECTOR(dimmed); FIND_SELECTOR(fore); FIND_SELECTOR(back); + FIND_SELECTOR(skip); FIND_SELECTOR(fixPriority); FIND_SELECTOR(mirrored); FIND_SELECTOR(useInsetRect); diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h index bbd86bb03e..4b913a866a 100644 --- a/engines/sci/engine/selector.h +++ b/engines/sci/engine/selector.h @@ -144,6 +144,7 @@ struct SelectorCache { Selector fore; Selector back; + Selector skip; Selector dimmed; Selector fixPriority; diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index 4ea9f72054..28818cddef 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -145,12 +145,12 @@ void EngineState::wait(int16 ticks) { void EngineState::initGlobals() { Script *script_000 = _segMan->getScript(1); - if (!script_000->_localsBlock) + if (script_000->getLocalsCount() == 0) error("Script 0 has no locals block"); - variablesSegment[VAR_GLOBAL] = script_000->_localsSegment; - variablesBase[VAR_GLOBAL] = variables[VAR_GLOBAL] = script_000->_localsBlock->_locals.begin(); - variablesMax[VAR_GLOBAL] = script_000->_localsBlock->_locals.size(); + variablesSegment[VAR_GLOBAL] = script_000->getLocalsSegment(); + variablesBase[VAR_GLOBAL] = variables[VAR_GLOBAL] = script_000->getLocalsBegin(); + variablesMax[VAR_GLOBAL] = script_000->getLocalsCount(); } uint16 EngineState::currentRoomNumber() const { diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index c94fdac034..162dce9fcc 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -235,6 +235,9 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP if (g_sci->getGameId() == GID_TORIN && script == 64036) { // Script 64036 in Torin's Passage is empty and contains an invalid // (empty) export + } else if (g_sci->getGameId() == GID_RAMA && script == 64908) { + // Script 64908 in the demo of RAMA contains an invalid (empty) + // export } else #endif error("Request for invalid exported function 0x%x of script %d", pubfunct, script); @@ -462,10 +465,10 @@ int readPMachineInstruction(const byte *src, byte &extOpcode, int16 opparams[4]) memset(opparams, 0, 4*sizeof(int16)); - for (int i = 0; g_opcode_formats[opcode][i]; ++i) { + for (int i = 0; g_sci->_opcode_formats[opcode][i]; ++i) { //debugN("Opcode: 0x%x, Opnumber: 0x%x, temp: %d\n", opcode, opcode, temp); assert(i < 3); - switch (g_opcode_formats[opcode][i]) { + switch (g_sci->_opcode_formats[opcode][i]) { case Script_Byte: opparams[i] = src[offset++]; @@ -593,15 +596,9 @@ void run_vm(EngineState *s) { if (!local_script) { error("Could not find local script from segment %x", s->xs->local_segment); } else { - s->variablesSegment[VAR_LOCAL] = local_script->_localsSegment; - if (local_script->_localsBlock) - s->variablesBase[VAR_LOCAL] = s->variables[VAR_LOCAL] = local_script->_localsBlock->_locals.begin(); - else - s->variablesBase[VAR_LOCAL] = s->variables[VAR_LOCAL] = NULL; - if (local_script->_localsBlock) - s->variablesMax[VAR_LOCAL] = local_script->_localsBlock->_locals.size(); - else - s->variablesMax[VAR_LOCAL] = 0; + s->variablesSegment[VAR_LOCAL] = local_script->getLocalsSegment(); + s->variablesBase[VAR_LOCAL] = s->variables[VAR_LOCAL] = local_script->getLocalsBegin(); + s->variablesMax[VAR_LOCAL] = local_script->getLocalsCount(); s->variablesMax[VAR_TEMP] = s->xs->sp - s->xs->fp; s->variablesMax[VAR_PARAM] = s->xs->argc + 1; } @@ -770,16 +767,28 @@ void run_vm(EngineState *s) { // Branch relative if true if (s->r_acc.offset || s->r_acc.segment) s->xs->addr.pc.offset += opparams[0]; + + if (s->xs->addr.pc.offset >= local_script->getScriptSize()) + error("[VM] op_bt: request to jump past the end of script %d (offset %d, script is %d bytes)", + local_script->getScriptNumber(), s->xs->addr.pc.offset, local_script->getScriptSize()); break; case op_bnt: // 0x18 (24) // Branch relative if not true if (!(s->r_acc.offset || s->r_acc.segment)) s->xs->addr.pc.offset += opparams[0]; + + if (s->xs->addr.pc.offset >= local_script->getScriptSize()) + error("[VM] op_bnt: request to jump past the end of script %d (offset %d, script is %d bytes)", + local_script->getScriptNumber(), s->xs->addr.pc.offset, local_script->getScriptSize()); break; case op_jmp: // 0x19 (25) s->xs->addr.pc.offset += opparams[0]; + + if (s->xs->addr.pc.offset >= local_script->getScriptSize()) + error("[VM] op_jmp: request to jump past the end of script %d (offset %d, script is %d bytes)", + local_script->getScriptNumber(), s->xs->addr.pc.offset, local_script->getScriptSize()); break; case op_ldi: // 0x1a (26) diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 36eadfa1c2..334d224baf 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -139,26 +139,6 @@ enum { GC_INTERVAL = 0x8000 }; -// Opcode formats -enum opcode_format { - Script_Invalid = -1, - Script_None = 0, - Script_Byte, - Script_SByte, - Script_Word, - Script_SWord, - Script_Variable, - Script_SVariable, - Script_SRelative, - Script_Property, - Script_Global, - Script_Local, - Script_Temp, - Script_Param, - Script_Offset, - Script_End -}; - enum sci_opcodes { op_bnot = 0x00, // 000 op_add = 0x01, // 001 @@ -290,8 +270,6 @@ enum sci_opcodes { op_minusspi = 0x7f // 127 }; -extern opcode_format g_opcode_formats[128][4]; - void script_adjust_opcode_formats(); /** diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h index dc87cf758a..7b155a4532 100644 --- a/engines/sci/engine/vm_types.h +++ b/engines/sci/engine/vm_types.h @@ -172,6 +172,26 @@ enum { NULL_SELECTOR = -1 }; +// Opcode formats +enum opcode_format { + Script_Invalid = -1, + Script_None = 0, + Script_Byte, + Script_SByte, + Script_Word, + Script_SWord, + Script_Variable, + Script_SVariable, + Script_SRelative, + Script_Property, + Script_Global, + Script_Local, + Script_Temp, + Script_Param, + Script_Offset, + Script_End +}; + } // End of namespace Sci diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index f68b74e1e0..a556134e32 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -353,7 +353,7 @@ const SciWorkaroundEntry kNewWindow_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[] = { - { GID_QFG4, 100, 100, 0, "doMovie", "<noname144>", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #3034506 + { GID_QFG4, 100, 100, 0, "doMovie", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #3034506 SCI_WORKAROUNDENTRY_TERMINATOR }; diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp index c14cfada07..378e88b7df 100644 --- a/engines/sci/event.cpp +++ b/engines/sci/event.cpp @@ -253,14 +253,11 @@ SciEvent EventManager::getScummVMEvent() { if ((modifiers & Common::KBD_ALT) && input.character > 0 && input.character < 27) input.character += 96; // 0x01 -> 'a' - if (getSciVersion() <= SCI_VERSION_1_MIDDLE) { - // TODO: find out if altify is also not needed for sci1late+, couldnt find any game that uses those keys - // Scancodify if appropriate - if (modifiers & Common::KBD_ALT) - input.character = altify(input.character); - else if ((modifiers & Common::KBD_CTRL) && input.character > 0 && input.character < 27) - input.character += 96; // 0x01 -> 'a' - } + // Scancodify if appropriate + if (modifiers & Common::KBD_ALT) + input.character = altify(input.character); + else if ((modifiers & Common::KBD_CTRL) && input.character > 0 && input.character < 27) + input.character += 96; // 0x01 -> 'a' // If no actual key was pressed (e.g. if only a modifier key was pressed), // ignore the event diff --git a/engines/sci/graphics/controls.cpp b/engines/sci/graphics/controls16.cpp index a0750c7d3e..ab54e468d1 100644 --- a/engines/sci/graphics/controls.cpp +++ b/engines/sci/graphics/controls16.cpp @@ -36,26 +36,26 @@ #include "sci/graphics/font.h" #include "sci/graphics/screen.h" #include "sci/graphics/text16.h" -#include "sci/graphics/controls.h" +#include "sci/graphics/controls16.h" namespace Sci { -GfxControls::GfxControls(SegManager *segMan, GfxPorts *ports, GfxPaint16 *paint16, GfxText16 *text16, GfxScreen *screen) +GfxControls16::GfxControls16(SegManager *segMan, GfxPorts *ports, GfxPaint16 *paint16, GfxText16 *text16, GfxScreen *screen) : _segMan(segMan), _ports(ports), _paint16(paint16), _text16(text16), _screen(screen) { init(); } -GfxControls::~GfxControls() { +GfxControls16::~GfxControls16() { } -void GfxControls::init() { +void GfxControls16::init() { _texteditCursorVisible = false; } const char controlListUpArrow[2] = { 0x18, 0 }; const char controlListDownArrow[2] = { 0x19, 0 }; -void GfxControls::drawListControl(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 upperPos, int16 cursorPos, bool isAlias) { +void GfxControls16::drawListControl(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 upperPos, int16 cursorPos, bool isAlias) { Common::Rect workerRect = rect; GuiResourceId oldFontId = _text16->GetFontId(); int16 oldPenColor = _ports->_curPort->penClr; @@ -112,7 +112,7 @@ void GfxControls::drawListControl(Common::Rect rect, reg_t obj, int16 maxChars, _text16->SetFont(oldFontId); } -void GfxControls::texteditCursorDraw(Common::Rect rect, const char *text, uint16 curPos) { +void GfxControls16::texteditCursorDraw(Common::Rect rect, const char *text, uint16 curPos) { int16 textWidth, i; if (!_texteditCursorVisible) { textWidth = 0; @@ -130,7 +130,7 @@ void GfxControls::texteditCursorDraw(Common::Rect rect, const char *text, uint16 } } -void GfxControls::texteditCursorErase() { +void GfxControls16::texteditCursorErase() { if (_texteditCursorVisible) { _paint16->invertRect(_texteditCursorRect); _paint16->bitsShow(_texteditCursorRect); @@ -139,11 +139,11 @@ void GfxControls::texteditCursorErase() { texteditSetBlinkTime(); } -void GfxControls::texteditSetBlinkTime() { +void GfxControls16::texteditSetBlinkTime() { _texteditBlinkTime = g_system->getMillis() + (30 * 1000 / 60); } -void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) { +void GfxControls16::kernelTexteditChange(reg_t controlObject, reg_t eventObject) { uint16 cursorPos = readSelectorValue(_segMan, controlObject, SELECTOR(cursor)); uint16 maxChars = readSelectorValue(_segMan, controlObject, SELECTOR(max)); reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text)); @@ -277,13 +277,13 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) { writeSelectorValue(_segMan, controlObject, SELECTOR(cursor), cursorPos); } -int GfxControls::getPicNotValid() { +int GfxControls16::getPicNotValid() { if (getSciVersion() >= SCI_VERSION_1_1) return _screen->_picNotValidSci11; return _screen->_picNotValid; } -void GfxControls::kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool hilite) { +void GfxControls16::kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool hilite) { int16 sci0EarlyPen = 0, sci0EarlyBack = 0; if (!hilite) { if (getSciVersion() == SCI_VERSION_0_EARLY) { @@ -321,7 +321,7 @@ void GfxControls::kernelDrawButton(Common::Rect rect, reg_t obj, const char *tex } } -void GfxControls::kernelDrawText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, TextAlignment alignment, int16 style, bool hilite) { +void GfxControls16::kernelDrawText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, TextAlignment alignment, int16 style, bool hilite) { if (!hilite) { rect.grow(1); _paint16->eraseRect(rect); @@ -338,7 +338,7 @@ void GfxControls::kernelDrawText(Common::Rect rect, reg_t obj, const char *text, } } -void GfxControls::kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite) { +void GfxControls16::kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite) { Common::Rect textRect = rect; uint16 oldFontId = _text16->GetFontId(); @@ -359,7 +359,7 @@ void GfxControls::kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *t _paint16->bitsShow(rect); } -void GfxControls::kernelDrawIcon(Common::Rect rect, reg_t obj, GuiResourceId viewId, int16 loopNo, int16 celNo, int16 priority, int16 style, bool hilite) { +void GfxControls16::kernelDrawIcon(Common::Rect rect, reg_t obj, GuiResourceId viewId, int16 loopNo, int16 celNo, int16 priority, int16 style, bool hilite) { if (!hilite) { _paint16->drawCelAndShow(viewId, loopNo, celNo, rect.left, rect.top, priority, 0); if (style & 0x20) { @@ -373,7 +373,7 @@ void GfxControls::kernelDrawIcon(Common::Rect rect, reg_t obj, GuiResourceId vie } } -void GfxControls::kernelDrawList(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 style, int16 upperPos, int16 cursorPos, bool isAlias, bool hilite) { +void GfxControls16::kernelDrawList(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 style, int16 upperPos, int16 cursorPos, bool isAlias, bool hilite) { if (!hilite) { drawListControl(rect, obj, maxChars, count, entries, fontId, upperPos, cursorPos, isAlias); rect.grow(1); diff --git a/engines/sci/graphics/controls.h b/engines/sci/graphics/controls16.h index 17e7c39318..90bd7beacb 100644 --- a/engines/sci/graphics/controls.h +++ b/engines/sci/graphics/controls16.h @@ -20,8 +20,8 @@ * */ -#ifndef SCI_GRAPHICS_CONTROLS_H -#define SCI_GRAPHICS_CONTROLS_H +#ifndef SCI_GRAPHICS_CONTROLS16_H +#define SCI_GRAPHICS_CONTROLS16_H namespace Sci { @@ -50,10 +50,10 @@ class GfxScreen; /** * Controls class, handles drawing of controls in SCI16 (SCI0-SCI1.1) games */ -class GfxControls { +class GfxControls16 { public: - GfxControls(SegManager *segMan, GfxPorts *ports, GfxPaint16 *paint16, GfxText16 *text16, GfxScreen *screen); - ~GfxControls(); + GfxControls16(SegManager *segMan, GfxPorts *ports, GfxPaint16 *paint16, GfxText16 *text16, GfxScreen *screen); + ~GfxControls16(); void kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool hilite); void kernelDrawText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 alignment, int16 style, bool hilite); diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp new file mode 100644 index 0000000000..ad1d9e8623 --- /dev/null +++ b/engines/sci/graphics/controls32.cpp @@ -0,0 +1,204 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/system.h" + +#include "sci/sci.h" +#include "sci/event.h" +#include "sci/engine/kernel.h" +#include "sci/engine/seg_manager.h" +#include "sci/graphics/cache.h" +#include "sci/graphics/compare.h" +#include "sci/graphics/controls32.h" +#include "sci/graphics/font.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/text32.h" + +namespace Sci { + +GfxControls32::GfxControls32(SegManager *segMan, GfxCache *cache, GfxScreen *screen, GfxText32 *text) + : _segMan(segMan), _cache(cache), _screen(screen), _text(text) { +} + +GfxControls32::~GfxControls32() { +} + +void GfxControls32::kernelTexteditChange(reg_t controlObject) { + SciEvent curEvent; + uint16 maxChars = 40; //readSelectorValue(_segMan, controlObject, SELECTOR(max)); // TODO + reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text)); + GfxFont *font = _cache->getFont(readSelectorValue(_segMan, controlObject, SELECTOR(font))); + Common::String text; + uint16 textSize; + bool textChanged = false; + bool textAddChar = false; + Common::Rect rect; + + if (textReference.isNull()) + error("kEditControl called on object that doesnt have a text reference"); + text = _segMan->getString(textReference); + + // TODO: Finish this + warning("kEditText ('%s')", text.c_str()); + return; + + uint16 cursorPos = 0; + //uint16 oldCursorPos = cursorPos; + bool captureEvents = true; + EventManager* eventMan = g_sci->getEventManager(); + + while (captureEvents) { + curEvent = g_sci->getEventManager()->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK); + + if (curEvent.type == SCI_EVENT_NONE) { + eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + } else { + textSize = text.size(); + + switch (curEvent.type) { + case SCI_EVENT_MOUSE_PRESS: + // TODO: Implement mouse support for cursor change + break; + case SCI_EVENT_KEYBOARD: + switch (curEvent.data) { + case SCI_KEY_BACKSPACE: + if (cursorPos > 0) { + cursorPos--; text.deleteChar(cursorPos); + textChanged = true; + } + eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + break; + case SCI_KEY_DELETE: + if (cursorPos < textSize) { + text.deleteChar(cursorPos); + textChanged = true; + } + eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + break; + case SCI_KEY_HOME: // HOME + cursorPos = 0; textChanged = true; + eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + break; + case SCI_KEY_END: // END + cursorPos = textSize; textChanged = true; + eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + break; + case SCI_KEY_LEFT: // LEFT + if (cursorPos > 0) { + cursorPos--; textChanged = true; + } + eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + break; + case SCI_KEY_RIGHT: // RIGHT + if (cursorPos + 1 <= textSize) { + cursorPos++; textChanged = true; + } + eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + break; + case 3: // returned in SCI1 late and newer when Control - C is pressed + if (curEvent.modifiers & SCI_KEYMOD_CTRL) { + // Control-C erases the whole line + cursorPos = 0; text.clear(); + textChanged = true; + } + eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + break; + case SCI_KEY_UP: + case SCI_KEY_DOWN: + case SCI_KEY_ENTER: + case SCI_KEY_ESC: + case SCI_KEY_TAB: + case SCI_KEY_SHIFT_TAB: + captureEvents = false; + break; + default: + if ((curEvent.modifiers & SCI_KEYMOD_CTRL) && curEvent.data == 99) { + // Control-C in earlier SCI games (SCI0 - SCI1 middle) + // Control-C erases the whole line + cursorPos = 0; text.clear(); + textChanged = true; + } else if (curEvent.data > 31 && curEvent.data < 256 && textSize < maxChars) { + // insert pressed character + textAddChar = true; + textChanged = true; + } + eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event + break; + } + break; + } + } + + if (textChanged) { + rect = g_sci->_gfxCompare->getNSRect(controlObject); + + if (textAddChar) { + const char *textPtr = text.c_str(); + + // We check if we are really able to add the new char + uint16 textWidth = 0; + while (*textPtr) + textWidth += font->getCharWidth((byte)*textPtr++); + textWidth += font->getCharWidth(curEvent.data); + + // Does it fit? + if (textWidth >= rect.width()) { + return; + } + + text.insertChar(curEvent.data, cursorPos++); + + // Note: the following checkAltInput call might make the text + // too wide to fit, but SSCI fails to check that too. + } + + reg_t hunkId = readSelector(_segMan, controlObject, SELECTOR(bitmap)); + Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(controlObject); + //texteditCursorErase(); // TODO: Cursor + + // Write back string + _segMan->strcpy(textReference, text.c_str()); + // Modify the buffer and show it + _text->createTextBitmap(controlObject, 0, 0, hunkId); + + _text->drawTextBitmap(0, 0, nsRect, controlObject); + //texteditCursorDraw(rect, text.c_str(), cursorPos); // TODO: Cursor + g_system->updateScreen(); + } else { + // TODO: Cursor + /* + if (g_system->getMillis() >= _texteditBlinkTime) { + _paint16->invertRect(_texteditCursorRect); + _paint16->bitsShow(_texteditCursorRect); + _texteditCursorVisible = !_texteditCursorVisible; + texteditSetBlinkTime(); + } + */ + } + + textAddChar = false; + textChanged = false; + g_sci->sleep(10); + } // while +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/controls32.h b/engines/sci/graphics/controls32.h new file mode 100644 index 0000000000..68dca59462 --- /dev/null +++ b/engines/sci/graphics/controls32.h @@ -0,0 +1,51 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SCI_GRAPHICS_CONTROLS32_H +#define SCI_GRAPHICS_CONTROLS32_H + +namespace Sci { + +class GfxCache; +class GfxScreen; +class GfxText32; + +/** + * Controls class, handles drawing of controls in SCI32 (SCI2, SCI2.1, SCI3) games + */ +class GfxControls32 { +public: + GfxControls32(SegManager *segMan, GfxCache *cache, GfxScreen *screen, GfxText32 *text); + ~GfxControls32(); + + void kernelTexteditChange(reg_t controlObject); + +private: + SegManager *_segMan; + GfxCache *_cache; + GfxScreen *_screen; + GfxText32 *_text; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/coordadjuster.cpp b/engines/sci/graphics/coordadjuster.cpp index 2952d4da7b..1446888cf4 100644 --- a/engines/sci/graphics/coordadjuster.cpp +++ b/engines/sci/graphics/coordadjuster.cpp @@ -86,8 +86,8 @@ Common::Rect GfxCoordAdjuster16::pictureGetDisplayArea() { #ifdef ENABLE_SCI32 GfxCoordAdjuster32::GfxCoordAdjuster32(SegManager *segMan) : _segMan(segMan) { - scriptsRunningWidth = 0; - scriptsRunningHeight = 0; + _scriptsRunningWidth = 0; + _scriptsRunningHeight = 0; } GfxCoordAdjuster32::~GfxCoordAdjuster32() { @@ -109,18 +109,18 @@ void GfxCoordAdjuster32::kernelLocalToGlobal(int16 &x, int16 &y, reg_t planeObje } void GfxCoordAdjuster32::setScriptsResolution(uint16 width, uint16 height) { - scriptsRunningWidth = width; - scriptsRunningHeight = height; + _scriptsRunningWidth = width; + _scriptsRunningHeight = height; } void GfxCoordAdjuster32::fromDisplayToScript(int16 &y, int16 &x) { - y = ((y * scriptsRunningHeight) / g_sci->_gfxScreen->getHeight()); - x = ((x * scriptsRunningWidth) / g_sci->_gfxScreen->getWidth()); + y = ((y * _scriptsRunningHeight) / g_sci->_gfxScreen->getHeight()); + x = ((x * _scriptsRunningWidth) / g_sci->_gfxScreen->getWidth()); } void GfxCoordAdjuster32::fromScriptToDisplay(int16 &y, int16 &x) { - y = ((y * g_sci->_gfxScreen->getHeight()) / scriptsRunningHeight); - x = ((x * g_sci->_gfxScreen->getWidth()) / scriptsRunningWidth); + y = ((y * g_sci->_gfxScreen->getHeight()) / _scriptsRunningHeight); + x = ((x * g_sci->_gfxScreen->getWidth()) / _scriptsRunningWidth); } void GfxCoordAdjuster32::pictureSetDisplayArea(Common::Rect displayArea) { diff --git a/engines/sci/graphics/coordadjuster.h b/engines/sci/graphics/coordadjuster.h index 23cf79d209..63f608be6b 100644 --- a/engines/sci/graphics/coordadjuster.h +++ b/engines/sci/graphics/coordadjuster.h @@ -96,8 +96,8 @@ private: Common::Rect _pictureDisplayArea; - uint16 scriptsRunningWidth; - uint16 scriptsRunningHeight; + uint16 _scriptsRunningWidth; + uint16 _scriptsRunningHeight; }; #endif diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp index 50da48aaf3..52a5961070 100644 --- a/engines/sci/graphics/cursor.cpp +++ b/engines/sci/graphics/cursor.cpp @@ -59,10 +59,16 @@ GfxCursor::GfxCursor(ResourceManager *resMan, GfxPalette *palette, GfxScreen *sc _zoomColor = 0; _zoomMultiplier = 0; _cursorSurface = 0; + if (g_sci && g_sci->getGameId() == GID_KQ6 && g_sci->getPlatform() == Common::kPlatformWindows) _useOriginalKQ6WinCursors = ConfMan.getBool("windows_cursors"); else _useOriginalKQ6WinCursors = false; + + if (g_sci && g_sci->getGameId() == GID_SQ4 && getSciVersion() == SCI_VERSION_1_1) + _useSilverSQ4CDCursors = ConfMan.getBool("silver_cursors"); + else + _useSilverSQ4CDCursors = false; } GfxCursor::~GfxCursor() { @@ -125,18 +131,28 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) { error("cursor resource %d has invalid size", resourceId); resourceData = resource->data; - // hotspot is specified for SCI1 cursors - hotspot.x = READ_LE_UINT16(resourceData); - hotspot.y = READ_LE_UINT16(resourceData + 2); - // bit 0 of resourceData[3] is set on <SCI1 games, which means center hotspot - if ((hotspot.x == 0) && (hotspot.y == 256)) - hotspot.x = hotspot.y = SCI_CURSOR_SCI0_HEIGHTWIDTH / 2; + + if (getSciVersion() <= SCI_VERSION_0_LATE) { + // SCI0 cursors contain hotspot flags, not actual hotspot coordinates. + // If bit 0 of resourceData[3] is set, the hotspot should be centered, + // otherwise it's in the top left of the mouse cursor. + hotspot.x = hotspot.y = resourceData[3] ? SCI_CURSOR_SCI0_HEIGHTWIDTH / 2 : 0; + } else { + // Cursors in newer SCI versions contain actual hotspot coordinates. + hotspot.x = READ_LE_UINT16(resourceData); + hotspot.y = READ_LE_UINT16(resourceData + 2); + } // Now find out what colors we are supposed to use colorMapping[0] = 0; // Black is hardcoded colorMapping[1] = _screen->getColorWhite(); // White is also hardcoded colorMapping[2] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR; colorMapping[3] = _palette->matchColor(170, 170, 170); // Grey + // Special case for the magnifier cursor in LB1 (bug #3487092). + // No other SCI0 game has a cursor resource of 1, so this is handled + // specifically for LB1. + if (g_sci->getGameId() == GID_LAURABOW && resourceId == 1) + colorMapping[3] = _screen->getColorWhite(); // Seek to actual data resourceData += 4; @@ -165,6 +181,11 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) { rawBitmap = upscaledBitmap; } + if (hotspot.x >= heightWidth || hotspot.y >= heightWidth) { + error("cursor %d's hotspot (%d, %d) is out of range of the cursor's dimensions (%dx%d)", + resourceId, hotspot.x, hotspot.y, heightWidth, heightWidth); + } + CursorMan.replaceCursor(rawBitmap, heightWidth, heightWidth, hotspot.x, hotspot.y, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR); kernelShow(); @@ -191,6 +212,26 @@ void GfxCursor::kernelSetView(GuiResourceId viewNum, int loopNum, int celNum, Co return; } + // Use the alternate silver cursors in SQ4 CD, if requested + if (_useSilverSQ4CDCursors) { + switch(viewNum) { + case 850: + case 852: + case 854: + case 856: + celNum = 3; + break; + case 851: + case 853: + case 855: + case 999: + celNum = 2; + break; + default: + break; + } + } + if (!_cachedCursors.contains(viewNum)) _cachedCursors[viewNum] = new GfxView(_resMan, _screen, _palette, viewNum); diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h index 25109b3920..ac928f50bb 100644 --- a/engines/sci/graphics/cursor.h +++ b/engines/sci/graphics/cursor.h @@ -113,13 +113,18 @@ private: bool _isVisible; - // KQ6 Windows has different black and white cursors. If this is - // true (set from the sci_originalkq6wincursors ini setting), then - // we use these, and don't scale them by 2x like the rest of the - // graphics, like SSCI did. These look very ugly, which is why - // they aren't enabled by default. + // KQ6 Windows has different black and white cursors. If this is true (set + // from the windows_cursors ini setting), then we use these and don't scale + // them by 2x like the rest of the graphics, like SSCI did. These look very + // ugly, which is why they aren't enabled by default. bool _useOriginalKQ6WinCursors; + // The CD version of SQ4 contains a complete set of silver mouse cursors. + // If this is true (set from the silver_cursors ini setting), then we use + // these instead and replace the game's gold cursors with their silver + // equivalents. + bool _useSilverSQ4CDCursors; + // Mac versions of games use a remap list to remap their cursors Common::Array<uint16> _macCursorRemap; }; diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index a41efd6a9f..b12413ab69 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -56,17 +56,18 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd : _segMan(segMan), _resMan(resMan), _cache(cache), _screen(screen), _palette(palette), _paint32(paint32) { _coordAdjuster = (GfxCoordAdjuster32 *)coordAdjuster; - scriptsRunningWidth = 320; - scriptsRunningHeight = 200; + _scriptsRunningWidth = 320; + _scriptsRunningHeight = 200; } GfxFrameout::~GfxFrameout() { + clear(); } void GfxFrameout::clear() { - _screenItems.clear(); + deletePlaneItems(NULL_REG); _planes.clear(); - _planePictures.clear(); + deletePlanePictures(NULL_REG); } void GfxFrameout::kernelAddPlane(reg_t object) { @@ -80,11 +81,11 @@ void GfxFrameout::kernelAddPlane(reg_t object) { // The above can be 0 in SCI3 (e.g. Phantasmagoria 2) if (tmpRunningWidth > 0 && tmpRunningHeight > 0) { - scriptsRunningWidth = tmpRunningWidth; - scriptsRunningHeight = tmpRunningHeight; + _scriptsRunningWidth = tmpRunningWidth; + _scriptsRunningHeight = tmpRunningHeight; } - _coordAdjuster->setScriptsResolution(scriptsRunningWidth, scriptsRunningHeight); + _coordAdjuster->setScriptsResolution(_scriptsRunningWidth, _scriptsRunningHeight); } newPlane.object = object; @@ -101,7 +102,7 @@ void GfxFrameout::kernelAddPlane(reg_t object) { } void GfxFrameout::kernelUpdatePlane(reg_t object) { - for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) { + for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { if (it->object == object) { // Read some information it->priority = readSelectorValue(_segMan, object, SELECTOR(priority)); @@ -118,14 +119,14 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) { } it->planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top)); it->planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left)); - it->planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)) + 1; - it->planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)) + 1; + it->planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)); + it->planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)); Common::Rect screenRect(_screen->getWidth(), _screen->getHeight()); - it->planeRect.top = (it->planeRect.top * screenRect.height()) / scriptsRunningHeight; - it->planeRect.left = (it->planeRect.left * screenRect.width()) / scriptsRunningWidth; - it->planeRect.bottom = (it->planeRect.bottom * screenRect.height()) / scriptsRunningHeight; - it->planeRect.right = (it->planeRect.right * screenRect.width()) / scriptsRunningWidth; + it->planeRect.top = (it->planeRect.top * screenRect.height()) / _scriptsRunningHeight; + it->planeRect.left = (it->planeRect.left * screenRect.width()) / _scriptsRunningWidth; + it->planeRect.bottom = (it->planeRect.bottom * screenRect.height()) / _scriptsRunningHeight; + it->planeRect.right = (it->planeRect.right * screenRect.width()) / _scriptsRunningWidth; // We get negative left in kq7 in scrolling rooms if (it->planeRect.left < 0) { @@ -178,22 +179,23 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) { } void GfxFrameout::kernelDeletePlane(reg_t object) { + deletePlaneItems(object); deletePlanePictures(object); - for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) { + + for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) { if (it->object == object) { _planes.erase(it); Common::Rect planeRect; planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top)); planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left)); - planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)) + 1; - planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)) + 1; + planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom)); + planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right)); Common::Rect screenRect(_screen->getWidth(), _screen->getHeight()); - planeRect.top = (planeRect.top * screenRect.height()) / scriptsRunningHeight; - planeRect.left = (planeRect.left * screenRect.width()) / scriptsRunningWidth; - planeRect.bottom = (planeRect.bottom * screenRect.height()) / scriptsRunningHeight; - planeRect.right = (planeRect.right * screenRect.width()) / scriptsRunningWidth; - planeRect.clip(screenRect); // we need to do this, at least in gk1 on cemetary we get bottom right -> 201, 321 + planeRect.top = (planeRect.top * screenRect.height()) / _scriptsRunningHeight; + planeRect.left = (planeRect.left * screenRect.width()) / _scriptsRunningWidth; + planeRect.bottom = (planeRect.bottom * screenRect.height()) / _scriptsRunningHeight; + planeRect.right = (planeRect.right * screenRect.width()) / _scriptsRunningWidth; // Blackout removed plane rect _paint32->fillRect(planeRect, 0); return; @@ -213,12 +215,15 @@ void GfxFrameout::addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 } void GfxFrameout::deletePlanePictures(reg_t object) { - for (PlanePictureList::iterator it = _planePictures.begin(); it != _planePictures.end(); it++) { - if (it->object == object) { + PlanePictureList::iterator it = _planePictures.begin(); + + while (it != _planePictures.end()) { + if (it->object == object || object.isNull()) { + delete it->pictureCels; delete it->picture; - _planePictures.erase(it); - deletePlanePictures(object); - return; + it = _planePictures.erase(it); + } else { + ++it; } } } @@ -271,6 +276,29 @@ void GfxFrameout::kernelDeleteScreenItem(reg_t object) { } _screenItems.remove(itemEntry); + delete itemEntry; +} + +void GfxFrameout::deletePlaneItems(reg_t planeObject) { + FrameoutList::iterator listIterator = _screenItems.begin(); + + while (listIterator != _screenItems.end()) { + bool objectMatches = false; + if (!planeObject.isNull()) { + reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); + objectMatches = (planeObject == itemPlane); + } else { + objectMatches = true; + } + + if (objectMatches) { + FrameoutEntry *itemEntry = *listIterator; + listIterator = _screenItems.erase(listIterator); + delete itemEntry; + } else { + ++listIterator; + } + } } FrameoutEntry *GfxFrameout::findScreenItem(reg_t object) { @@ -329,37 +357,149 @@ void GfxFrameout::sortPlanes() { Common::sort(_planes.begin(), _planes.end(), planeSortHelper); } -void GfxFrameout::kernelFrameout() { - if (g_sci->_robotDecoder->isVideoLoaded()) { - bool skipVideo = false; - RobotDecoder *videoDecoder = g_sci->_robotDecoder; - uint16 x = videoDecoder->getPos().x; - uint16 y = videoDecoder->getPos().y; +int16 GfxFrameout::upscaleHorizontalCoordinate(int16 coordinate) { + return ((coordinate * _screen->getWidth()) / _scriptsRunningWidth); +} - if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); +int16 GfxFrameout::upscaleVerticalCoordinate(int16 coordinate) { + return ((coordinate * _screen->getHeight()) / _scriptsRunningHeight); +} - while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { - if (videoDecoder->needsUpdate()) { - const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); - if (frame) { - g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); +Common::Rect GfxFrameout::upscaleRect(Common::Rect &rect) { + rect.top = (rect.top * _scriptsRunningHeight) / _screen->getHeight(); + rect.left = (rect.left * _scriptsRunningWidth) / _screen->getWidth(); + rect.bottom = (rect.bottom * _scriptsRunningHeight) / _screen->getHeight(); + rect.right = (rect.right * _scriptsRunningWidth) / _screen->getWidth(); - if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + return rect; +} - g_system->updateScreen(); - } +void GfxFrameout::showVideo() { + bool skipVideo = false; + RobotDecoder *videoDecoder = g_sci->_robotDecoder; + uint16 x = videoDecoder->getPos().x; + uint16 y = videoDecoder->getPos().y; + + if (videoDecoder->hasDirtyPalette()) + videoDecoder->setSystemPalette(); + + while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { + if (videoDecoder->needsUpdate()) { + const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); + if (frame) { + g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h); + + if (videoDecoder->hasDirtyPalette()) + videoDecoder->setSystemPalette(); + + g_system->updateScreen(); } + } - Common::Event event; - while (g_system->getEventManager()->pollEvent(event)) { - if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) - skipVideo = true; + Common::Event event; + while (g_system->getEventManager()->pollEvent(event)) { + if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) + skipVideo = true; + } + + g_system->delayMillis(10); + } +} + +void GfxFrameout::createPlaneItemList(reg_t planeObject, FrameoutList &itemList) { + // Copy screen items of the current frame to the list of items to be drawn + for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { + reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); + if (planeObject == itemPlane) { + kernelUpdateScreenItem((*listIterator)->object); // TODO: Why is this necessary? + itemList.push_back(*listIterator); + } + } + + for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { + if (pictureIt->object == planeObject) { + GfxPicture *planePicture = pictureIt->picture; + // Allocate memory for picture cels + pictureIt->pictureCels = new FrameoutEntry[planePicture->getSci32celCount()]; + + // Add following cels to the itemlist + FrameoutEntry *picEntry = pictureIt->pictureCels; + int planePictureCels = planePicture->getSci32celCount(); + for (int pictureCelNr = 0; pictureCelNr < planePictureCels; pictureCelNr++) { + picEntry->celNo = pictureCelNr; + picEntry->object = NULL_REG; + picEntry->picture = planePicture; + picEntry->y = planePicture->getSci32celY(pictureCelNr); + picEntry->x = planePicture->getSci32celX(pictureCelNr); + picEntry->picStartX = pictureIt->startX; + picEntry->picStartY = pictureIt->startY; + + picEntry->priority = planePicture->getSci32celPriority(pictureCelNr); + + itemList.push_back(picEntry); + picEntry++; } + } + } + + // Now sort our itemlist + Common::sort(itemList.begin(), itemList.end(), sortHelper); +} - g_system->delayMillis(10); +bool GfxFrameout::isPictureOutOfView(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 planeOffsetX, int16 planeOffsetY) { + // Out of view horizontally (sanity checks) + int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x; + int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo); + int16 planeStartX = planeOffsetX; + int16 planeEndX = planeStartX + planeRect.width(); + if (pictureCelEndX < planeStartX) + return true; + if (pictureCelStartX > planeEndX) + return true; + + // Out of view vertically (sanity checks) + int16 pictureCelStartY = itemEntry->picStartY + itemEntry->y; + int16 pictureCelEndY = pictureCelStartY + itemEntry->picture->getSci32celHeight(itemEntry->celNo); + int16 planeStartY = planeOffsetY; + int16 planeEndY = planeStartY + planeRect.height(); + if (pictureCelEndY < planeStartY) + return true; + if (pictureCelStartY > planeEndY) + return true; + + return false; +} + +void GfxFrameout::drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int16 planeOffsetY, bool planePictureMirrored) { + int16 pictureOffsetX = planeOffsetX; + int16 pictureX = itemEntry->x; + if ((planeOffsetX) || (itemEntry->picStartX)) { + if (planeOffsetX <= itemEntry->picStartX) { + pictureX += itemEntry->picStartX - planeOffsetX; + pictureOffsetX = 0; + } else { + pictureOffsetX = planeOffsetX - itemEntry->picStartX; + } + } + + int16 pictureOffsetY = planeOffsetY; + int16 pictureY = itemEntry->y; + if ((planeOffsetY) || (itemEntry->picStartY)) { + if (planeOffsetY <= itemEntry->picStartY) { + pictureY += itemEntry->picStartY - planeOffsetY; + pictureOffsetY = 0; + } else { + pictureOffsetY = planeOffsetY - itemEntry->picStartY; } + } + + itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, pictureOffsetY, planePictureMirrored); + // warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority); +} + +void GfxFrameout::kernelFrameout() { + if (g_sci->_robotDecoder->isVideoLoaded()) { + showVideo(); return; } @@ -383,7 +523,8 @@ void GfxFrameout::kernelFrameout() { // There is a race condition lurking in SQ6, which causes the game to hang in the intro, when teleporting to Polysorbate LX. // Since I first wrote the patch, the race has stopped occurring for me though. // I'll leave this for investigation later, when someone can reproduce. - if (it->pictureId == 0xffff) + //if (it->pictureId == 0xffff) // FIXME: This is what SSCI does, and fixes the intro of LSL7, but breaks the dialogs in GK1 (adds black boxes) + if (it->planeBack) _paint32->fillRect(it->planeRect, it->planeBack); GuiResourceId planeMainPictureId = it->pictureId; @@ -393,43 +534,7 @@ void GfxFrameout::kernelFrameout() { FrameoutList itemList; - // Copy screen items of the current frame to the list of items to be drawn - for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { - reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane)); - if (planeObject == itemPlane) { - kernelUpdateScreenItem((*listIterator)->object); // TODO: Why is this necessary? - itemList.push_back(*listIterator); - } - } - - for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { - if (pictureIt->object == planeObject) { - GfxPicture *planePicture = pictureIt->picture; - // Allocate memory for picture cels - pictureIt->pictureCels = new FrameoutEntry[planePicture->getSci32celCount()]; - - // Add following cels to the itemlist - FrameoutEntry *picEntry = pictureIt->pictureCels; - int planePictureCels = planePicture->getSci32celCount(); - for (int pictureCelNr = 0; pictureCelNr < planePictureCels; pictureCelNr++) { - picEntry->celNo = pictureCelNr; - picEntry->object = NULL_REG; - picEntry->picture = planePicture; - picEntry->y = planePicture->getSci32celY(pictureCelNr); - picEntry->x = planePicture->getSci32celX(pictureCelNr); - picEntry->picStartX = pictureIt->startX; - picEntry->picStartY = pictureIt->startY; - - picEntry->priority = planePicture->getSci32celPriority(pictureCelNr); - - itemList.push_back(picEntry); - picEntry++; - } - } - } - - // Now sort our itemlist - Common::sort(itemList.begin(), itemList.end(), sortHelper); + createPlaneItemList(planeObject, itemList); // warning("Plane %s", _segMan->getObjectName(planeObject)); @@ -438,69 +543,24 @@ void GfxFrameout::kernelFrameout() { if (itemEntry->object.isNull()) { // Picture cel data - itemEntry->y = ((itemEntry->y * _screen->getHeight()) / scriptsRunningHeight); - itemEntry->x = ((itemEntry->x * _screen->getWidth()) / scriptsRunningWidth); - itemEntry->picStartX = ((itemEntry->picStartX * _screen->getWidth()) / scriptsRunningWidth); - itemEntry->picStartY = ((itemEntry->picStartY * _screen->getHeight()) / scriptsRunningHeight); - - // Out of view horizontally (sanity checks) - int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x; - int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo); - int16 planeStartX = it->planeOffsetX; - int16 planeEndX = planeStartX + it->planeRect.width(); - if (pictureCelEndX < planeStartX) - continue; - if (pictureCelStartX > planeEndX) - continue; - - // Out of view vertically (sanity checks) - int16 pictureCelStartY = itemEntry->picStartY + itemEntry->y; - int16 pictureCelEndY = pictureCelStartY + itemEntry->picture->getSci32celHeight(itemEntry->celNo); - int16 planeStartY = it->planeOffsetY; - int16 planeEndY = planeStartY + it->planeRect.height(); - if (pictureCelEndY < planeStartY) - continue; - if (pictureCelStartY > planeEndY) - continue; + itemEntry->x = upscaleHorizontalCoordinate(itemEntry->x); + itemEntry->y = upscaleVerticalCoordinate(itemEntry->y); + itemEntry->picStartX = upscaleHorizontalCoordinate(itemEntry->picStartX); + itemEntry->picStartY = upscaleVerticalCoordinate(itemEntry->picStartY); - int16 pictureOffsetX = it->planeOffsetX; - int16 pictureX = itemEntry->x; - if ((it->planeOffsetX) || (itemEntry->picStartX)) { - if (it->planeOffsetX <= itemEntry->picStartX) { - pictureX += itemEntry->picStartX - it->planeOffsetX; - pictureOffsetX = 0; - } else { - pictureOffsetX = it->planeOffsetX - itemEntry->picStartX; - } - } - - int16 pictureOffsetY = it->planeOffsetY; - int16 pictureY = itemEntry->y; - if ((it->planeOffsetY) || (itemEntry->picStartY)) { - if (it->planeOffsetY <= itemEntry->picStartY) { - pictureY += itemEntry->picStartY - it->planeOffsetY; - pictureOffsetY = 0; - } else { - pictureOffsetY = it->planeOffsetY - itemEntry->picStartY; - } - } - - itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, pictureOffsetY, it->planePictureMirrored); -// warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority); - - } else if (itemEntry->viewId != 0xFFFF) { - GfxView *view = _cache->getView(itemEntry->viewId); - -// warning("view %s %04x:%04x", _segMan->getObjectName(itemEntry->object), PRINT_REG(itemEntry->object)); - - if (view->isSci2Hires()) { + if (!isPictureOutOfView(itemEntry, it->planeRect, it->planeOffsetX, it->planeOffsetY)) + drawPicture(itemEntry, it->planeOffsetX, it->planeOffsetY, it->planePictureMirrored); + } else { + GfxView *view = (itemEntry->viewId != 0xFFFF) ? _cache->getView(itemEntry->viewId) : NULL; + + if (view && view->isSci2Hires()) { int16 dummyX = 0; view->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x); view->adjustToUpscaledCoordinates(itemEntry->z, dummyX); } else if (getSciVersion() == SCI_VERSION_2_1) { - itemEntry->y = (itemEntry->y * _screen->getHeight()) / scriptsRunningHeight; - itemEntry->x = (itemEntry->x * _screen->getWidth()) / scriptsRunningWidth; - itemEntry->z = (itemEntry->z * _screen->getHeight()) / scriptsRunningHeight; + itemEntry->x = upscaleHorizontalCoordinate(itemEntry->x); + itemEntry->y = upscaleVerticalCoordinate(itemEntry->y); + itemEntry->z = upscaleVerticalCoordinate(itemEntry->z); } // Adjust according to current scroll position @@ -511,33 +571,33 @@ void GfxFrameout::kernelFrameout() { if (useInsetRect) { itemEntry->celRect.top = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inTop)); itemEntry->celRect.left = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inLeft)); - itemEntry->celRect.bottom = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inBottom)) + 1; - itemEntry->celRect.right = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inRight)) + 1; - if (view->isSci2Hires()) { + itemEntry->celRect.bottom = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inBottom)); + itemEntry->celRect.right = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inRight)); + if (view && view->isSci2Hires()) { view->adjustToUpscaledCoordinates(itemEntry->celRect.top, itemEntry->celRect.left); view->adjustToUpscaledCoordinates(itemEntry->celRect.bottom, itemEntry->celRect.right); } itemEntry->celRect.translate(itemEntry->x, itemEntry->y); // TODO: maybe we should clip the cels rect with this, i'm not sure // the only currently known usage is game menu of gk1 - } else { - if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) - view->getCelRect(itemEntry->loopNo, itemEntry->celNo, itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect); - else - view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo, itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX, itemEntry->scaleY, itemEntry->celRect); + } else if (view) { + if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) + view->getCelRect(itemEntry->loopNo, itemEntry->celNo, + itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect); + else + view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo, + itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX, + itemEntry->scaleY, itemEntry->celRect); Common::Rect nsRect = itemEntry->celRect; // Translate back to actual coordinate within scrollable plane nsRect.translate(it->planeOffsetX, it->planeOffsetY); - if (view->isSci2Hires()) { + if (view && view->isSci2Hires()) { view->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left); view->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right); } else if (getSciVersion() == SCI_VERSION_2_1) { - nsRect.top = (nsRect.top * scriptsRunningHeight) / _screen->getHeight(); - nsRect.left = (nsRect.left * scriptsRunningWidth) / _screen->getWidth(); - nsRect.bottom = (nsRect.bottom * scriptsRunningHeight) / _screen->getHeight(); - nsRect.right = (nsRect.right * scriptsRunningWidth) / _screen->getWidth(); + nsRect = upscaleRect(nsRect); } if (g_sci->getGameId() == GID_PHANTASMAGORIA2) { @@ -552,7 +612,7 @@ void GfxFrameout::kernelFrameout() { int16 screenHeight = _screen->getHeight(); int16 screenWidth = _screen->getWidth(); - if (view->isSci2Hires()) { + if (view && view->isSci2Hires()) { screenHeight = _screen->getDisplayHeight(); screenWidth = _screen->getDisplayWidth(); } @@ -565,7 +625,8 @@ void GfxFrameout::kernelFrameout() { Common::Rect clipRect, translatedClipRect; clipRect = itemEntry->celRect; - if (view->isSci2Hires()) { + + if (view && view->isSci2Hires()) { clipRect.clip(it->upscaledPlaneClipRect); translatedClipRect = clipRect; translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top); @@ -575,16 +636,20 @@ void GfxFrameout::kernelFrameout() { translatedClipRect.translate(it->planeRect.left, it->planeRect.top); } - if (!clipRect.isEmpty()) { - if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) - view->draw(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires()); - else - view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY); + if (view) { + if (!clipRect.isEmpty()) { + if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128)) + view->draw(itemEntry->celRect, clipRect, translatedClipRect, + itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires()); + else + view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect, + itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY); + } } - } else { - // Most likely a text entry + + // Draw text, if it exists if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) { - g_sci->_gfxText32->drawTextBitmap(itemEntry->object); + g_sci->_gfxText32->drawTextBitmap(itemEntry->x, itemEntry->y, it->planeRect, itemEntry->object); } } } diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index 160c343b05..8c3cc261d5 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -94,6 +94,7 @@ public: void kernelAddScreenItem(reg_t object); void kernelUpdateScreenItem(reg_t object); void kernelDeleteScreenItem(reg_t object); + void deletePlaneItems(reg_t planeObject); FrameoutEntry *findScreenItem(reg_t object); int16 kernelGetHighPlanePri(); void kernelAddPicAt(reg_t planeObj, GuiResourceId pictureId, int16 pictureX, int16 pictureY); @@ -104,6 +105,14 @@ public: void clear(); private: + void showVideo(); + void createPlaneItemList(reg_t planeObject, FrameoutList &itemList); + bool isPictureOutOfView(FrameoutEntry *itemEntry, Common::Rect planeRect, int16 planeOffsetX, int16 planeOffsetY); + void drawPicture(FrameoutEntry *itemEntry, int16 planeOffsetX, int16 planeOffsetY, bool planePictureMirrored); + int16 upscaleHorizontalCoordinate(int16 coordinate); + int16 upscaleVerticalCoordinate(int16 coordinate); + Common::Rect upscaleRect(Common::Rect &rect); + SegManager *_segMan; ResourceManager *_resMan; GfxCoordAdjuster32 *_coordAdjuster; @@ -118,8 +127,8 @@ private: void sortPlanes(); - uint16 scriptsRunningWidth; - uint16 scriptsRunningHeight; + uint16 _scriptsRunningWidth; + uint16 _scriptsRunningHeight; }; } // End of namespace Sci diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index b52af38675..47d1647c6c 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -709,6 +709,13 @@ bool GfxPalette::palVaryLoadTargetPalette(GuiResourceId resourceId) { } void GfxPalette::palVaryInstallTimer() { + // Remove any possible leftover palVary timer callbacks. + // This happens for example in QFG1VGA, when sleeping at Erana's place + // (bug #3439240) - the nighttime to daytime effect clashes with the + // scene transition effect, as we load scene images too quickly for + // the SCI scripts in that case (also refer to kernelPalVaryInit). + palVaryRemoveTimer(); + int16 ticks = _palVaryTicks > 0 ? _palVaryTicks : 1; // Call signal increase every [ticks] g_sci->getTimerManager()->installTimerProc(&palVaryCallback, 1000000 / 60 * ticks, this, "sciPalette"); @@ -966,7 +973,7 @@ void GfxPalette::loadMacIconBarPalette() { } bool GfxPalette::colorIsFromMacClut(byte index) { - return index != 0 && _macClut && (_macClut[index * 3] != 0 || _macClut[index * 3 + 1] != 0 || _macClut[index * 3 + 1] != 0); + return index != 0 && _macClut && (_macClut[index * 3] != 0 || _macClut[index * 3 + 1] != 0 || _macClut[index * 3 + 2] != 0); } #ifdef ENABLE_SCI32 diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index 6469bc0cb3..4020518b72 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -438,7 +438,7 @@ void GfxScreen::bitsSaveScreen(Common::Rect rect, byte *screen, uint16 screenWid screen += (rect.top * screenWidth) + rect.left; for (y = rect.top; y < rect.bottom; y++) { - memcpy(memoryPtr, (void*)screen, width); memoryPtr += width; + memcpy(memoryPtr, (void *)screen, width); memoryPtr += width; screen += screenWidth; } } @@ -458,7 +458,7 @@ void GfxScreen::bitsSaveDisplayScreen(Common::Rect rect, byte *&memoryPtr) { } for (y = rect.top; y < rect.bottom; y++) { - memcpy(memoryPtr, (void*)screen, width); memoryPtr += width; + memcpy(memoryPtr, (void *)screen, width); memoryPtr += width; screen += _displayWidth; } } @@ -503,7 +503,7 @@ void GfxScreen::bitsRestoreScreen(Common::Rect rect, byte *&memoryPtr, byte *scr screen += (rect.top * screenWidth) + rect.left; for (y = rect.top; y < rect.bottom; y++) { - memcpy((void*) screen, memoryPtr, width); memoryPtr += width; + memcpy((void *) screen, memoryPtr, width); memoryPtr += width; screen += screenWidth; } } @@ -523,7 +523,7 @@ void GfxScreen::bitsRestoreDisplayScreen(Common::Rect rect, byte *&memoryPtr) { } for (y = rect.top; y < rect.bottom; y++) { - memcpy((void*) screen, memoryPtr, width); memoryPtr += width; + memcpy((void *) screen, memoryPtr, width); memoryPtr += width; screen += _displayWidth; } } diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp index 84547d9828..7eaa0168b8 100644 --- a/engines/sci/graphics/text16.cpp +++ b/engines/sci/graphics/text16.cpp @@ -100,7 +100,7 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1 // cX -> sets textColor to _textColors[X-1] curCode = textCode[0]; curCodeParm = textCode[1]; - if (isdigit(static_cast<unsigned char>(curCodeParm))) { + if (Common::isDigit(curCodeParm)) { curCodeParm -= '0'; } else { curCodeParm = -1; diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp index 029030165d..7894c7109c 100644 --- a/engines/sci/graphics/text32.cpp +++ b/engines/sci/graphics/text32.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/sci/graphics/text16.cpp $ - * $Id: text16.cpp 55178 2011-01-08 23:16:44Z thebluegr $ - * */ #include "common/util.h" @@ -41,6 +38,10 @@ namespace Sci { #define BITMAP_HEADER_SIZE 46 +#define SCI_TEXT32_ALIGNMENT_RIGHT -1 +#define SCI_TEXT32_ALIGNMENT_CENTER 1 +#define SCI_TEXT32_ALIGNMENT_LEFT 0 + GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) : _segMan(segMan), _cache(fonts), _screen(screen) { } @@ -48,7 +49,7 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) GfxText32::~GfxText32() { } -reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight) { +reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text)); // The object in the text selector of the item can be either a raw string @@ -58,13 +59,21 @@ reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxH stringObject = readSelector(_segMan, stringObject, SELECTOR(data)); Common::String text = _segMan->getString(stringObject); - GfxFont *font = _cache->getFont(readSelectorValue(_segMan, textObject, SELECTOR(font))); + // HACK: The character offsets of the up and down arrow buttons are off by one + // in GK1, for some unknown reason. Fix them here. + if (text.size() == 1 && (text[0] == 29 || text[0] == 30)) { + text.setChar(text[0] + 1, 0); + } + GuiResourceId fontId = readSelectorValue(_segMan, textObject, SELECTOR(font)); + GfxFont *font = _cache->getFont(fontId); bool dimmed = readSelectorValue(_segMan, textObject, SELECTOR(dimmed)); + int16 alignment = readSelectorValue(_segMan, textObject, SELECTOR(mode)); uint16 foreColor = readSelectorValue(_segMan, textObject, SELECTOR(fore)); + uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back)); - Common::Rect planeRect = getPlaneRect(textObject); - uint16 width = planeRect.width() + 1; - uint16 height = planeRect.height() + 1; + Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(textObject); + uint16 width = nsRect.width() + 1; + uint16 height = nsRect.height() + 1; // Limit rectangle dimensions, if requested if (maxWidth > 0) @@ -79,24 +88,74 @@ reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxH } int entrySize = width * height + BITMAP_HEADER_SIZE; - reg_t memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize); - writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId); + reg_t memoryId = NULL_REG; + if (prevHunk.isNull()) { + memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize); + writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId); + } else { + memoryId = prevHunk; + } byte *memoryPtr = _segMan->getHunkPointer(memoryId); - memset(memoryPtr, 0, entrySize); + + if (prevHunk.isNull()) + memset(memoryPtr, 0, BITMAP_HEADER_SIZE); + byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; + memset(bitmap, backColor, width * height); + + // Save totalWidth, totalHeight + WRITE_LE_UINT16(memoryPtr, width); + WRITE_LE_UINT16(memoryPtr + 2, height); int16 charCount = 0; uint16 curX = 0, curY = 0; const char *txt = text.c_str(); + int16 textWidth, textHeight, totalHeight = 0, offsetX = 0, offsetY = 0; + uint16 start = 0; + + // Calculate total text height + while (*txt) { + charCount = GetLongest(txt, width, font); + if (charCount == 0) + break; + + Width(txt, 0, (int16)strlen(txt), fontId, textWidth, textHeight, true); + + totalHeight += textHeight; + txt += charCount; + while (*txt == ' ') + txt++; // skip over breaking spaces + } + + txt = text.c_str(); + // Draw text in buffer while (*txt) { charCount = GetLongest(txt, width, font); if (charCount == 0) break; + Width(txt, start, charCount, fontId, textWidth, textHeight, true); + + switch (alignment) { + case SCI_TEXT32_ALIGNMENT_RIGHT: + offsetX = width - textWidth; + break; + case SCI_TEXT32_ALIGNMENT_CENTER: + // Center text both horizontally and vertically + offsetX = (width - textWidth) / 2; + offsetY = (height - totalHeight) / 2; + break; + case SCI_TEXT32_ALIGNMENT_LEFT: + offsetX = 0; + break; + + default: + warning("Invalid alignment %d used in TextBox()", alignment); + } for (int i = 0; i < charCount; i++) { unsigned char curChar = txt[i]; - font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, bitmap, width, height); + font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, foreColor, dimmed, bitmap, width, height); curX += font->getCharWidth(curChar); } @@ -114,13 +173,18 @@ void GfxText32::disposeTextBitmap(reg_t hunkId) { _segMan->freeHunkEntry(hunkId); } -void GfxText32::drawTextBitmap(reg_t textObject) { +void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject) { reg_t hunkId = readSelector(_segMan, textObject, SELECTOR(bitmap)); + uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back)); // Sanity check: Check if the hunk is set. If not, either the game scripts // didn't set it, or an old saved game has been loaded, where it wasn't set. if (hunkId.isNull()) return; + // Negative coordinates indicate that text shouldn't be displayed + if (x < 0 || y < 0) + return; + byte *memoryPtr = _segMan->getHunkPointer(hunkId); if (!memoryPtr) @@ -129,46 +193,28 @@ void GfxText32::drawTextBitmap(reg_t textObject) { byte *surface = memoryPtr + BITMAP_HEADER_SIZE; int curByte = 0; - Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(textObject); - Common::Rect planeRect = getPlaneRect(textObject); - uint16 x = readSelectorValue(_segMan, textObject, SELECTOR(x)); - uint16 y = readSelectorValue(_segMan, textObject, SELECTOR(y)); + uint16 skipColor = readSelectorValue(_segMan, textObject, SELECTOR(skip)); uint16 textX = planeRect.left + x; uint16 textY = planeRect.top + y; - uint16 width = nsRect.width() + 1; - uint16 height = nsRect.height() + 1; + // Get totalWidth, totalHeight + uint16 width = READ_LE_UINT16(memoryPtr); + uint16 height = READ_LE_UINT16(memoryPtr + 2); // Upscale the coordinates/width if the fonts are already upscaled if (_screen->fontIsUpscaled()) { textX = textX * _screen->getDisplayWidth() / _screen->getWidth(); textY = textY * _screen->getDisplayHeight() / _screen->getHeight(); - width = width * _screen->getDisplayWidth() / _screen->getWidth(); - height = height * _screen->getDisplayHeight() / _screen->getHeight(); } for (int curY = 0; curY < height; curY++) { for (int curX = 0; curX < width; curX++) { byte pixel = surface[curByte++]; - if (pixel) + if (pixel != skipColor && pixel != backColor) _screen->putFontPixel(textY, curX + textX, curY, pixel); } } } -Common::Rect GfxText32::getPlaneRect(reg_t textObject) { - Common::Rect planeRect(0, 0, _screen->getWidth(), _screen->getHeight()); - - reg_t planeObject = readSelector(_segMan, textObject, SELECTOR(plane)); - if (!planeObject.isNull()) { - planeRect.top = readSelectorValue(_segMan, planeObject, SELECTOR(top)); - planeRect.left = readSelectorValue(_segMan, planeObject, SELECTOR(left)); - planeRect.bottom = readSelectorValue(_segMan, planeObject, SELECTOR(bottom)); - planeRect.right = readSelectorValue(_segMan, planeObject, SELECTOR(right)); - } - - return planeRect; -} - int16 GfxText32::GetLongest(const char *text, int16 maxWidth, GfxFont *font) { uint16 curChar = 0; int16 maxChars = 0, curCharCount = 0; @@ -251,6 +297,10 @@ int16 GfxText32::Size(Common::Rect &rect, const char *text, GuiResourceId fontId int16 maxTextWidth = 0, textWidth; int16 totalHeight = 0, textHeight; + // Adjust maxWidth if we're using an upscaled font + if (_screen->fontIsUpscaled()) + maxWidth = maxWidth * _screen->getDisplayWidth() / _screen->getWidth(); + rect.top = rect.left = 0; GfxFont *font = _cache->getFont(fontId); @@ -277,6 +327,14 @@ int16 GfxText32::Size(Common::Rect &rect, const char *text, GuiResourceId fontId rect.bottom = totalHeight; rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth); } + + // Adjust the width/height if we're using an upscaled font + // for the scripts + if (_screen->fontIsUpscaled()) { + rect.right = rect.right * _screen->getWidth() / _screen->getDisplayWidth(); + rect.bottom = rect.bottom * _screen->getHeight() / _screen->getDisplayHeight(); + } + return rect.right; } diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h index dfcbf63ccf..3505de85eb 100644 --- a/engines/sci/graphics/text32.h +++ b/engines/sci/graphics/text32.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/sci/graphics/text16.h $ - * $Id: text16.h 55178 2011-01-08 23:16:44Z thebluegr $ - * */ #ifndef SCI_GRAPHICS_TEXT32_H @@ -35,9 +32,9 @@ class GfxText32 { public: GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen); ~GfxText32(); - reg_t createTextBitmap(reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0); + reg_t createTextBitmap(reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG); void disposeTextBitmap(reg_t hunkId); - void drawTextBitmap(reg_t textObject); + void drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject); int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font); void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight); @@ -46,7 +43,6 @@ private: int16 Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth); void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont); void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight); - Common::Rect getPlaneRect(reg_t textObject); SegManager *_segMan; GfxCache *_cache; diff --git a/engines/sci/graphics/transitions.cpp b/engines/sci/graphics/transitions.cpp index d047eb10a1..b385c2c1db 100644 --- a/engines/sci/graphics/transitions.cpp +++ b/engines/sci/graphics/transitions.cpp @@ -52,8 +52,8 @@ static const GfxTransitionTranslateEntry oldTransitionIDs[] = { { 3, SCI_TRANSITIONS_STRAIGHT_FROM_LEFT, false }, { 4, SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM, false }, { 5, SCI_TRANSITIONS_STRAIGHT_FROM_TOP, false }, - { 6, SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, false }, - { 7, SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, false }, + { 6, SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, false }, + { 7, SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, false }, { 8, SCI_TRANSITIONS_BLOCKS, false }, { 9, SCI_TRANSITIONS_VERTICALROLL_TOCENTER, false }, { 10, SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER, false }, @@ -295,12 +295,12 @@ void GfxTransitions::fadeOut() { int16 stepNr, colorNr; // Sierra did not fade in/out color 255 for sci1.1, but they used it in // several pictures (e.g. qfg3 demo/intro), so the fading looked weird - int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 256 : 255; + int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 255 : 254; g_system->getPaletteManager()->grabPalette(oldPalette, 0, 256); for (stepNr = 100; stepNr >= 0; stepNr -= 10) { - for (colorNr = 1; colorNr < tillColorNr; colorNr++) { + for (colorNr = 1; colorNr <= tillColorNr; colorNr++) { if (_palette->colorIsFromMacClut(colorNr)) { workPalette[colorNr * 3 + 0] = oldPalette[colorNr * 3]; workPalette[colorNr * 3 + 1] = oldPalette[colorNr * 3 + 1]; @@ -311,7 +311,7 @@ void GfxTransitions::fadeOut() { workPalette[colorNr * 3 + 2] = oldPalette[colorNr * 3 + 2] * stepNr / 100; } } - g_system->getPaletteManager()->setPalette(workPalette + 3, 1, 254); + g_system->getPaletteManager()->setPalette(workPalette + 3, 1, tillColorNr); g_sci->getEngineState()->wait(2); } } @@ -322,10 +322,10 @@ void GfxTransitions::fadeIn() { int16 stepNr; // Sierra did not fade in/out color 255 for sci1.1, but they used it in // several pictures (e.g. qfg3 demo/intro), so the fading looked weird - int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 256 : 255; + int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 255 : 254; for (stepNr = 0; stepNr <= 100; stepNr += 10) { - _palette->kernelSetIntensity(1, tillColorNr, stepNr, true); + _palette->kernelSetIntensity(1, tillColorNr + 1, stepNr, true); g_sci->getEngineState()->wait(2); } } diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index e095cde697..a77bcccc52 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -432,10 +432,11 @@ void unpackCelData(byte *inBuffer, byte *celBitmap, byte clearColor, int pixelCo // Skip the next YYYYY pixels (i.e. transparency) if (literalPos && isMacSci11ViewData) { - // KQ6/Freddy Pharkas use byte lengths, all others use uint16 + // KQ6/Freddy Pharkas/Slater use byte lengths, all others use uint16 // The SCI devs must have realized that a max of 255 pixels wide // was not very good for 320 or 640 width games. - bool hasByteLengths = (g_sci->getGameId() == GID_KQ6 || g_sci->getGameId() == GID_FREDDYPHARKAS); + bool hasByteLengths = (g_sci->getGameId() == GID_KQ6 || g_sci->getGameId() == GID_FREDDYPHARKAS + || g_sci->getGameId() == GID_SLATER); // compression for SCI1.1+ Mac while (pixelNr < pixelCount) { diff --git a/engines/sci/module.mk b/engines/sci/module.mk index c129ae5439..90a0f33f06 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -43,7 +43,7 @@ MODULE_OBJS := \ graphics/animate.o \ graphics/cache.o \ graphics/compare.o \ - graphics/controls.o \ + graphics/controls16.o \ graphics/coordadjuster.o \ graphics/cursor.o \ graphics/font.o \ @@ -71,6 +71,7 @@ MODULE_OBJS := \ sound/drivers/amigamac.o \ sound/drivers/cms.o \ sound/drivers/fb01.o \ + sound/drivers/fmtowns.o \ sound/drivers/midi.o \ sound/drivers/pcjr.o \ video/seq_decoder.o @@ -78,6 +79,7 @@ MODULE_OBJS := \ ifdef ENABLE_SCI32 MODULE_OBJS += \ + graphics/controls32.o \ graphics/frameout.o \ graphics/paint32.o \ graphics/text32.o \ diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp index d44109faec..eff4a29f49 100644 --- a/engines/sci/parser/said.cpp +++ b/engines/sci/parser/said.cpp @@ -743,7 +743,7 @@ static void node_print_desc(ParseTreeNode* node) { } } #else -static void node_print_desc(ParseTreeNode*) { } +static void node_print_desc(ParseTreeNode *) { } #endif diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp index a5c4686b3b..e56158ecc1 100644 --- a/engines/sci/parser/vocabulary.cpp +++ b/engines/sci/parser/vocabulary.cpp @@ -534,7 +534,7 @@ bool Vocabulary::tokenizeString(ResultWordListList &retval, const char *sentence do { c = sentence[pos_in_sentence++]; - if (isalnum(c) || (c == '-' && wordLen) || (c >= 0x80)) { + if (Common::isAlnum(c) || (c == '-' && wordLen) || (c >= 0x80)) { currentWord[wordLen] = lowerCaseMap[c]; ++wordLen; } diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index c50d1b8d8a..77a6a40a92 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -169,8 +169,11 @@ ResourceType ResourceManager::convertResType(byte type) { if (type < ARRAYSIZE(s_resTypeMapSci21)) { // LSL6 hires doesn't have the chunk resource type, to match // the resource types of the lowres version, thus we use the - // older resource types here - if (g_sci && g_sci->getGameId() == GID_LSL6HIRES) + // older resource types here. + // PQ4 CD and QFG4 CD are SCI2.1, but use the resource types of the + // corresponding SCI2 floppy disk versions. + if (g_sci && (g_sci->getGameId() == GID_LSL6HIRES || + g_sci->getGameId() == GID_QFG4 || g_sci->getGameId() == GID_PQ4)) return s_resTypeMapSci0[type]; else return s_resTypeMapSci21[type]; @@ -606,7 +609,7 @@ int ResourceManager::addAppropriateSources() { if (Common::File::exists("alt.map") && Common::File::exists("resource.alt")) addSource(new VolumeResourceSource("resource.alt", addExternalMap("alt.map", 10), 10)); #endif - } else if (Common::File::exists("Data1")) { + } else if (Common::MacResManager::exists("Data1")) { // Mac SCI1.1+ file naming scheme SearchMan.listMatchingMembers(files, "Data?*"); @@ -750,12 +753,10 @@ void ResourceManager::addScriptChunkSources() { // to try to get to any scripts in there. The Lighthouse SCI2.1 demo // does exactly this. - Common::List<ResourceId> *resources = listResources(kResourceTypeScript); + Common::List<ResourceId> resources = listResources(kResourceTypeScript); - if (resources->empty() && testResource(ResourceId(kResourceTypeChunk, 0))) + if (resources.empty() && testResource(ResourceId(kResourceTypeChunk, 0))) addResourcesFromChunk(0); - - delete resources; } #endif } @@ -1042,13 +1043,13 @@ void ResourceManager::freeOldResources() { } } -Common::List<ResourceId> *ResourceManager::listResources(ResourceType type, int mapNumber) { - Common::List<ResourceId> *resources = new Common::List<ResourceId>; +Common::List<ResourceId> ResourceManager::listResources(ResourceType type, int mapNumber) { + Common::List<ResourceId> resources; ResourceMap::iterator itr = _resMap.begin(); while (itr != _resMap.end()) { if ((itr->_value->getType() == type) && ((mapNumber == -1) || (itr->_value->getNumber() == mapNumber))) - resources->push_back(itr->_value->_id); + resources.push_back(itr->_value->_id); ++itr; } @@ -1557,7 +1558,7 @@ void ResourceManager::readResourcePatches() { name = (*x)->getName(); // SCI1 scheme - if (isdigit(static_cast<unsigned char>(name[0]))) { + if (Common::isDigit(name[0])) { char *end = 0; resourceNr = strtol(name.c_str(), &end, 10); bAdd = (*end == '.'); // Ensure the next character is the period @@ -1565,7 +1566,7 @@ void ResourceManager::readResourcePatches() { // SCI0 scheme int resname_len = strlen(szResType); if (scumm_strnicmp(name.c_str(), szResType, resname_len) == 0 - && !isalpha(static_cast<unsigned char>(name[resname_len + 1]))) { + && !Common::isAlpha(name[resname_len + 1])) { resourceNr = atoi(name.c_str() + resname_len + 1); bAdd = true; } @@ -2196,14 +2197,16 @@ void ResourceManager::detectSciVersion() { // Handle SCI32 versions here if (_volVersion >= kResVersionSci2) { - Common::List<ResourceId> *heaps = listResources(kResourceTypeHeap); + Common::List<ResourceId> heaps = listResources(kResourceTypeHeap); + bool hasHeapResources = !heaps.empty(); + // SCI2.1/3 and SCI1 Late resource maps are the same, except that // SCI1 Late resource maps have the resource types or'd with // 0x80. We differentiate between SCI2 and SCI2.1/3 based on that. if (_mapVersion == kResVersionSci1Late) { s_sciVersion = SCI_VERSION_2; return; - } else if (!heaps->empty()) { + } else if (hasHeapResources) { s_sciVersion = SCI_VERSION_2_1; return; } else { diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 47602de017..294a4672e2 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -322,7 +322,7 @@ public: * @param mapNumber For audio36 and sync36, limit search to this map * @return The resource list */ - Common::List<ResourceId> *listResources(ResourceType type, int mapNumber = -1); + Common::List<ResourceId> listResources(ResourceType type, int mapNumber = -1); void setAudioLanguage(int language); int getAudioLanguage() const; diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index f3a3c8dd5b..684e1a1d0d 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -185,6 +185,7 @@ void ResourceManager::processWavePatch(ResourceId resourceId, Common::String nam file.open(name); updateResource(resourceId, resSrc, file.size()); + _sources.push_back(resSrc); debugC(1, kDebugLevelResMan, "Patching %s - OK", name.c_str()); } @@ -197,7 +198,7 @@ void ResourceManager::readWaveAudioPatches() { for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) { Common::String name = (*x)->getName(); - if (isdigit(static_cast<unsigned char>(name[0]))) + if (Common::isDigit(name[0])) processWavePatch(ResourceId(kResourceTypeAudio, atoi(name.c_str())), name); } } @@ -538,11 +539,10 @@ bool ResourceManager::isGMTrackIncluded() { // Read the first song and check if it has a GM track bool result = false; - Common::List<ResourceId> *resources = listResources(kResourceTypeSound, -1); - Common::sort(resources->begin(), resources->end()); - Common::List<ResourceId>::iterator itr = resources->begin(); + Common::List<ResourceId> resources = listResources(kResourceTypeSound, -1); + Common::sort(resources.begin(), resources.end()); + Common::List<ResourceId>::iterator itr = resources.begin(); int firstSongId = itr->getNumber(); - delete resources; SoundResource *song1 = new SoundResource(firstSongId, this, soundVersion); if (!song1) { @@ -892,10 +892,10 @@ void AudioVolumeResourceSource::loadResource(ResourceManager *resMan, Resource * } bool ResourceManager::addAudioSources() { - Common::List<ResourceId> *resources = listResources(kResourceTypeMap); - Common::List<ResourceId>::iterator itr = resources->begin(); + Common::List<ResourceId> resources = listResources(kResourceTypeMap); + Common::List<ResourceId>::iterator itr; - while (itr != resources->end()) { + for (itr = resources.begin(); itr != resources.end(); ++itr) { ResourceSource *src = addSource(new IntMapResourceSource("MAP", itr->getNumber())); if ((itr->getNumber() == 65535) && Common::File::exists("RESOURCE.SFX")) @@ -904,29 +904,30 @@ bool ResourceManager::addAudioSources() { addSource(new AudioVolumeResourceSource(this, "RESOURCE.AUD", src, 0)); else return false; - - ++itr; } - delete resources; - return true; } void ResourceManager::changeAudioDirectory(Common::String path) { // Remove all of the audio map resource sources, as well as the audio resource sources - for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) { + for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end();) { ResourceSource *source = *it; ResSourceType sourceType = source->getSourceType(); // Remove the resource source, if it's an audio map or an audio file if (sourceType == kSourceIntMap || sourceType == kSourceAudioVolume) { // Don't remove 65535.map (the SFX map) or resource.sfx - if (source->_volumeNumber == 65535 || source->getLocationName() == "RESOURCE.SFX") + if (source->_volumeNumber == 65535 || source->getLocationName() == "RESOURCE.SFX") { + ++it; continue; + } + // erase() will move the iterator to the next element it = _sources.erase(it); delete source; + } else { + ++it; } } @@ -938,8 +939,9 @@ void ResourceManager::changeAudioDirectory(Common::String path) { audioResourceName = Common::String::format("%s/RESOURCE.AUD", path.c_str()); } - Common::List<ResourceId> *resources = listResources(kResourceTypeMap); - for (Common::List<ResourceId>::iterator it = resources->begin(); it != resources->end(); ++it) { + Common::List<ResourceId> resources = listResources(kResourceTypeMap); + Common::List<ResourceId>::iterator it; + for (it = resources.begin(); it != resources.end(); ++it) { // Don't readd 65535.map or resource.sfx if ((it->getNumber() == 65535)) continue; @@ -948,8 +950,6 @@ void ResourceManager::changeAudioDirectory(Common::String path) { addSource(new AudioVolumeResourceSource(this, audioResourceName, src, 0)); } - delete resources; - // Rescan the newly added resources scanNewSources(); } diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 1d0d63870d..4ae55cbcba 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -46,7 +46,8 @@ #include "sci/graphics/animate.h" #include "sci/graphics/cache.h" #include "sci/graphics/compare.h" -#include "sci/graphics/controls.h" +#include "sci/graphics/controls16.h" +#include "sci/graphics/controls32.h" #include "sci/graphics/coordadjuster.h" #include "sci/graphics/cursor.h" #include "sci/graphics/maciconbar.h" @@ -90,6 +91,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam _vocabularyLanguage = 1; // we load english vocabulary on startup _eventMan = 0; _console = 0; + _opcode_formats = 0; // Set up the engine specific debug levels DebugMan.addDebugChannel(kDebugLevelError, "Error", "Script error debugging"); @@ -113,6 +115,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam DebugMan.addDebugChannel(kDebugLevelGC, "GC", "Garbage Collector debugging"); DebugMan.addDebugChannel(kDebugLevelResMan, "ResMan", "Resource manager debugging"); DebugMan.addDebugChannel(kDebugLevelOnStartup, "OnStartup", "Enter debugger at start of game"); + DebugMan.addDebugChannel(kDebugLevelDebugMode, "DebugMode", "Enable game debug mode at start of game"); const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -147,12 +150,13 @@ SciEngine::~SciEngine() { DebugMan.clearAllDebugChannels(); #ifdef ENABLE_SCI32 + delete _gfxControls32; delete _gfxText32; delete _robotDecoder; delete _gfxFrameout; #endif delete _gfxMenu; - delete _gfxControls; + delete _gfxControls16; delete _gfxText16; delete _gfxAnimate; delete _gfxPaint; @@ -176,6 +180,9 @@ SciEngine::~SciEngine() { delete _eventMan; delete _gamestate->_segMan; delete _gamestate; + + delete[] _opcode_formats; + delete _resMan; // should be deleted last g_sci = 0; } @@ -187,6 +194,7 @@ Common::Error SciEngine::run() { ConfMan.registerDefault("sci_originalsaveload", "false"); ConfMan.registerDefault("native_fb01", "false"); ConfMan.registerDefault("windows_cursors", "false"); // Windows cursors for KQ6 Windows + ConfMan.registerDefault("silver_cursors", "false"); // Silver cursors for SQ4 CD _resMan = new ResourceManager(); assert(_resMan); @@ -588,7 +596,7 @@ void SciEngine::initGraphics() { _gfxAnimate = 0; _gfxCache = 0; _gfxCompare = 0; - _gfxControls = 0; + _gfxControls16 = 0; _gfxCoordAdjuster = 0; _gfxCursor = 0; _gfxMacIconBar = 0; @@ -600,6 +608,7 @@ void SciEngine::initGraphics() { _gfxText16 = 0; _gfxTransitions = 0; #ifdef ENABLE_SCI32 + _gfxControls32 = 0; _gfxText32 = 0; _robotDecoder = 0; _gfxFrameout = 0; @@ -622,6 +631,7 @@ void SciEngine::initGraphics() { _gfxPaint32 = new GfxPaint32(_resMan, _gamestate->_segMan, _kernel, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette); _gfxPaint = _gfxPaint32; _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen); + _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxText32); _robotDecoder = new RobotDecoder(g_system->getMixer(), getPlatform() == Common::kPlatformMacintosh); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette, _gfxPaint32); } else { @@ -636,7 +646,7 @@ void SciEngine::initGraphics() { _gfxPaint = _gfxPaint16; _gfxAnimate = new GfxAnimate(_gamestate, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette, _gfxCursor, _gfxTransitions); _gfxText16 = new GfxText16(_resMan, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen); - _gfxControls = new GfxControls(_gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen); + _gfxControls16 = new GfxControls16(_gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen); _gfxMenu = new GfxMenu(_eventMan, _gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen, _gfxCursor); _gfxMenu->reset(); diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 81bbdc51de..9f18219cb7 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -59,7 +59,8 @@ class SegManager; class GfxAnimate; class GfxCache; class GfxCompare; -class GfxControls; +class GfxControls16; +class GfxControls32; class GfxCoordAdjuster; class GfxCursor; class GfxMacIconBar; @@ -101,7 +102,8 @@ enum kDebugLevels { kDebugLevelScripts = 1 << 17, kDebugLevelGC = 1 << 18, kDebugLevelResMan = 1 << 19, - kDebugLevelOnStartup = 1 << 20 + kDebugLevelOnStartup = 1 << 20, + kDebugLevelDebugMode = 1 << 21 }; enum SciGameId { @@ -303,7 +305,8 @@ public: GfxAnimate *_gfxAnimate; // Animate for 16-bit gfx GfxCache *_gfxCache; GfxCompare *_gfxCompare; - GfxControls *_gfxControls; // Controls for 16-bit gfx + GfxControls16 *_gfxControls16; // Controls for 16-bit gfx + GfxControls32 *_gfxControls32; // Controls for 32-bit gfx GfxCoordAdjuster *_gfxCoordAdjuster; GfxCursor *_gfxCursor; GfxMenu *_gfxMenu; // Menu for 16-bit gfx @@ -327,6 +330,8 @@ public: SoundCommandParser *_soundCmd; GameFeatures *_features; + opcode_format (*_opcode_formats)[4]; + DebugState _debugState; Common::MacResManager *getMacExecutable() { return &_macExecutable; } diff --git a/engines/sci/sound/drivers/adlib.cpp b/engines/sci/sound/drivers/adlib.cpp index add3d8851f..db9317e071 100644 --- a/engines/sci/sound/drivers/adlib.cpp +++ b/engines/sci/sound/drivers/adlib.cpp @@ -613,8 +613,6 @@ void MidiDriver_AdLib::setNote(int voice, int note, bool key) { _voices[voice].note = note; - delta = 0; - n = note % 12; if (bend < 8192) diff --git a/engines/sci/sound/drivers/amigamac.cpp b/engines/sci/sound/drivers/amigamac.cpp index 3c750401b9..131a85f371 100644 --- a/engines/sci/sound/drivers/amigamac.cpp +++ b/engines/sci/sound/drivers/amigamac.cpp @@ -130,7 +130,7 @@ private: }; bool _isSci1; - bool _isSci1Early; // KQ1 Amiga, patch 5 + bool _isSci1Early; // KQ1/MUMG Amiga, patch 5 bool _playSwitch; int _masterVolume; int _frequency; @@ -524,7 +524,7 @@ MidiDriver_AmigaMac::InstrumentSample *MidiDriver_AmigaMac::readInstrumentSCI0(C instrument->size = seg_size[0]; instrument->loop_size = seg_size[1]; - instrument->loop = (int8*)malloc(instrument->loop_size + 1); + instrument->loop = (int8 *)malloc(instrument->loop_size + 1); memcpy(instrument->loop, instrument->samples + loop_offset, instrument->loop_size); instrument->samples[instrument->size] = instrument->loop[0]; @@ -586,12 +586,12 @@ int MidiDriver_AmigaMac::open() { } else { ResourceManager *resMan = g_sci->getResMan(); - Resource *resource = resMan->findResource(ResourceId(kResourceTypePatch, 7), false); // Mac + Resource *resource = resMan->findResource(ResourceId(kResourceTypePatch, 7), false); // Mac if (!resource) - resource = resMan->findResource(ResourceId(kResourceTypePatch, 9), false); // Amiga + resource = resMan->findResource(ResourceId(kResourceTypePatch, 9), false); // Amiga if (!resource) { - resource = resMan->findResource(ResourceId(kResourceTypePatch, 5), false); // KQ1 Amiga + resource = resMan->findResource(ResourceId(kResourceTypePatch, 5), false); // KQ1/MUMG Amiga if (resource) _isSci1Early = true; } @@ -708,7 +708,7 @@ void MidiDriver_AmigaMac::generateSamples(int16 *data, int len) { if (len == 0) return; - int16 *buffers = (int16*)malloc(len * 2 * kChannels); + int16 *buffers = (int16 *)malloc(len * 2 * kChannels); memset(buffers, 0, len * 2 * kChannels); @@ -869,7 +869,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0Mac(Common::SeekableReadStream &fil instrument->size = seg_size[0]; instrument->loop_size = seg_size[1] - seg_size[0]; - instrument->loop = (int8*)malloc(instrument->loop_size + 1); + instrument->loop = (int8 *)malloc(instrument->loop_size + 1); memcpy(instrument->loop, instrument->samples + loop_offset, instrument->loop_size); instrument->samples[instrument->size] = instrument->loop[0]; @@ -892,7 +892,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI1(Common::SeekableReadStream &file) _bank.size = 128; if (_isSci1Early) - file.skip(4); // TODO: What is this offset for? + file.readUint32BE(); // Skip size of bank Common::Array<uint32> instrumentOffsets; instrumentOffsets.resize(_bank.size); @@ -911,12 +911,6 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI1(Common::SeekableReadStream &file) // Read in the instrument name file.read(_bank.instruments[i].name, 10); // last two bytes are always 0 - // TODO: Finish off support of SCI1 early patches (patch.005 - KQ1 Amiga) - if (_isSci1Early) { - warning("Music patch 5 isn't supported yet - ignoring instrument %d", i); - continue; - } - for (uint32 j = 0; ; j++) { InstrumentSample *sample = new InstrumentSample; memset(sample, 0, sizeof(InstrumentSample)); @@ -943,16 +937,30 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI1(Common::SeekableReadStream &file) int16 loop = file.readSint16BE(); uint32 nextSamplePos = file.pos(); - file.seek(samplePtr); + file.seek(samplePtr + (_isSci1Early ? 4 : 0)); file.read(sample->name, 8); - sample->isUnsigned = file.readUint16BE() == 0; - uint16 phase1Offset = file.readUint16BE(); - uint16 phase1End = file.readUint16BE(); - uint16 phase2Offset = file.readUint16BE(); - uint16 phase2End = file.readUint16BE(); - sample->baseNote = file.readUint16BE(); - uint32 periodTableOffset = file.readUint32BE(); + uint16 phase1Offset, phase1End; + uint16 phase2Offset, phase2End; + + if (_isSci1Early) { + sample->isUnsigned = false; + file.readUint32BE(); // skip total sample size + phase2Offset = file.readUint16BE(); + phase2End = file.readUint16BE(); + sample->baseNote = file.readUint16BE(); + phase1Offset = file.readUint16BE(); + phase1End = file.readUint16BE(); + } else { + sample->isUnsigned = file.readUint16BE() == 0; + phase1Offset = file.readUint16BE(); + phase1End = file.readUint16BE(); + phase2Offset = file.readUint16BE(); + phase2End = file.readUint16BE(); + sample->baseNote = file.readUint16BE(); + } + + uint32 periodTableOffset = _isSci1Early ? 0 : file.readUint32BE(); uint32 sampleDataPos = file.pos(); sample->size = phase1End - phase1Offset + 1; @@ -974,8 +982,13 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI1(Common::SeekableReadStream &file) _bank.instruments[i].push_back(sample); - file.seek(periodTableOffset + 0xe0); - sample->baseFreq = file.readUint16BE(); + if (_isSci1Early) { + // There's no frequency specified by the sample and is hardcoded like in SCI0 + sample->baseFreq = 11000; + } else { + file.seek(periodTableOffset + 0xe0); + sample->baseFreq = file.readUint16BE(); + } file.seek(nextSamplePos); } diff --git a/engines/sci/sound/drivers/fmtowns.cpp b/engines/sci/sound/drivers/fmtowns.cpp new file mode 100644 index 0000000000..6d8bb2e525 --- /dev/null +++ b/engines/sci/sound/drivers/fmtowns.cpp @@ -0,0 +1,652 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "sci/sci.h" + +#include "common/file.h" +#include "common/system.h" +#include "common/textconsole.h" + +#include "audio/softsynth/fmtowns_pc98/towns_audio.h" + +#include "sci/resource.h" +#include "sci/sound/drivers/mididriver.h" + +namespace Sci { + +class MidiDriver_FMTowns; + +class TownsChannel { +public: + TownsChannel(MidiDriver_FMTowns *driver, uint8 id); + ~TownsChannel() {} + + void noteOff(); + void noteOn(uint8 note, uint8 velo); + void pitchBend(int16 val); + void updateVolume(); + void updateDuration(); + + uint8 _assign; + uint8 _note; + uint8 _sustain; + uint16 _duration; + +private: + uint8 _id; + uint8 _velo; + uint8 _program; + + MidiDriver_FMTowns *_drv; +}; + +class TownsMidiPart { +friend class MidiDriver_FMTowns; +public: + TownsMidiPart(MidiDriver_FMTowns *driver, uint8 id); + ~TownsMidiPart() {} + + void noteOff(uint8 note); + void noteOn(uint8 note, uint8 velo); + void controlChangeVolume(uint8 vol); + void controlChangeSustain(uint8 sus); + void controlChangePolyphony(uint8 numChan); + void controlChangeAllNotesOff(); + void programChange(uint8 prg); + void pitchBend(int16 val); + + void addChannels(int num); + void dropChannels(int num); + + uint8 currentProgram() const; + +private: + int allocateChannel(); + + uint8 _id; + uint8 _program; + uint8 _volume; + uint8 _sustain; + uint8 _chanMissing; + int16 _pitchBend; + uint8 _outChan; + + MidiDriver_FMTowns *_drv; +}; + +class MidiDriver_FMTowns : public MidiDriver, public TownsAudioInterfacePluginDriver { +friend class TownsChannel; +friend class TownsMidiPart; +public: + MidiDriver_FMTowns(Audio::Mixer *mixer, SciVersion version); + ~MidiDriver_FMTowns(); + + int open(); + void loadInstruments(const uint8 *data); + bool isOpen() const { return _isOpen; } + void close(); + + void send(uint32 b); + + uint32 property(int prop, uint32 param); + void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc); + + void setSoundOn(bool toggle); + + uint32 getBaseTempo(); + MidiChannel *allocateChannel() { return 0; } + MidiChannel *getPercussionChannel() { return 0; } + + uint8 currentProgram(); + + void timerCallback(int timerId); + +private: + int getChannelVolume(uint8 midiPart); + void addMissingChannels(); + + void updateParser(); + void updateChannels(); + + Common::TimerManager::TimerProc _timerProc; + void *_timerProcPara; + + TownsMidiPart **_parts; + TownsChannel **_out; + + uint8 _masterVolume; + + bool _soundOn; + + bool _isOpen; + bool _ready; + + const uint16 _baseTempo; + SciVersion _version; + + TownsAudioInterface *_intf; +}; + +class MidiPlayer_FMTowns : public MidiPlayer { +public: + MidiPlayer_FMTowns(SciVersion version); + ~MidiPlayer_FMTowns(); + + int open(ResourceManager *resMan); + + bool hasRhythmChannel() const; + byte getPlayId() const; + int getPolyphony() const; + void playSwitch(bool play); + +private: + MidiDriver_FMTowns *_townsDriver; +}; + +TownsChannel::TownsChannel(MidiDriver_FMTowns *driver, uint8 id) : _drv(driver), _id(id), _assign(0xff), _note(0xff), _velo(0), _sustain(0), _duration(0), _program(0xff) { +} + +void TownsChannel::noteOn(uint8 note, uint8 velo) { + _duration = 0; + + if (_drv->_version != SCI_VERSION_1_EARLY) { + if (_program != _drv->_parts[_assign]->currentProgram() && _drv->_soundOn) { + _program = _drv->_parts[_assign]->currentProgram(); + _drv->_intf->callback(4, _id, _program); + } + } + + _note = note; + _velo = velo; + _drv->_intf->callback(1, _id, _note, _velo); +} + +void TownsChannel::noteOff() { + if (_sustain) + return; + + _drv->_intf->callback(2, _id); + _note = 0xff; + _duration = 0; +} + +void TownsChannel::pitchBend(int16 val) { + _drv->_intf->callback(7, _id, val); +} + +void TownsChannel::updateVolume() { + if (_assign > 15 && _drv->_version != SCI_VERSION_1_EARLY) + return; + _drv->_intf->callback(8, _id, _drv->getChannelVolume((_drv->_version == SCI_VERSION_1_EARLY) ? 0 : _assign)); +} + +void TownsChannel::updateDuration() { + if (_note != 0xff) + _duration++; +} + +TownsMidiPart::TownsMidiPart(MidiDriver_FMTowns *driver, uint8 id) : _drv(driver), _id(id), _program(0), _volume(0x3f), _sustain(0), _chanMissing(0), _pitchBend(0x2000), _outChan(0) { +} + +void TownsMidiPart::noteOff(uint8 note) { + for (int i = 0; i < 6; i++) { + if ((_drv->_out[i]->_assign != _id && _drv->_version != SCI_VERSION_1_EARLY) || _drv->_out[i]->_note != note) + continue; + if (_sustain) + _drv->_out[i]->_sustain = 1; + else + _drv->_out[i]->noteOff(); + return; + } +} + +void TownsMidiPart::noteOn(uint8 note, uint8 velo) { + if (note < 12 || note > 107) + return; + + if (velo == 0) { + noteOff(note); + return; + } + + if (_drv->_version != SCI_VERSION_1_EARLY) + velo >>= 1; + + for (int i = 0; i < 6; i++) { + if ((_drv->_out[i]->_assign != _id && _drv->_version != SCI_VERSION_1_EARLY) || _drv->_out[i]->_note != note) + continue; + _drv->_out[i]->_sustain = 0; + _drv->_out[i]->noteOff(); + _drv->_out[i]->noteOn(note, velo); + return; + } + + int chan = allocateChannel(); + if (chan != -1) + _drv->_out[chan]->noteOn(note, velo); +} + +void TownsMidiPart::controlChangeVolume(uint8 vol) { + if (_drv->_version == SCI_VERSION_1_EARLY) + return; + + _volume = vol >> 1; + for (int i = 0; i < 6; i++) { + if (_drv->_out[i]->_assign == _id) + _drv->_out[i]->updateVolume(); + } +} + +void TownsMidiPart::controlChangeSustain(uint8 sus) { + if (_drv->_version == SCI_VERSION_1_EARLY) + return; + + _sustain = sus; + if (_sustain) + return; + + for (int i = 0; i < 6; i++) { + if (_drv->_out[i]->_assign == _id && _drv->_out[i]->_sustain) { + _drv->_out[i]->_sustain = 0; + _drv->_out[i]->noteOff(); + } + } +} + +void TownsMidiPart::controlChangePolyphony(uint8 numChan) { + if (_drv->_version == SCI_VERSION_1_EARLY) + return; + + uint8 numAssigned = 0; + for (int i = 0; i < 6; i++) { + if (_drv->_out[i]->_assign == _id) + numAssigned++; + } + + numAssigned += _chanMissing; + if (numAssigned < numChan) { + addChannels(numChan - numAssigned); + } else if (numAssigned > numChan) { + dropChannels(numAssigned - numChan); + _drv->addMissingChannels(); + } +} + +void TownsMidiPart::controlChangeAllNotesOff() { + for (int i = 0; i < 6; i++) { + if ((_drv->_out[i]->_assign == _id || _drv->_version == SCI_VERSION_1_EARLY) && _drv->_out[i]->_note != 0xff) + _drv->_out[i]->noteOff(); + } +} + +void TownsMidiPart::programChange(uint8 prg) { + _program = prg; +} + +void TownsMidiPart::pitchBend(int16 val) { + _pitchBend = val; + val -= 0x2000; + for (int i = 0; i < 6; i++) { + // Strangely, the early version driver applies the setting to channel 0 only. + if (_drv->_out[i]->_assign == _id || (_drv->_version == SCI_VERSION_1_EARLY && i == 0)) + _drv->_out[i]->pitchBend(val); + } +} + +void TownsMidiPart::addChannels(int num) { + for (int i = 0; i < 6; i++) { + if (_drv->_out[i]->_assign != 0xff) + continue; + + _drv->_out[i]->_assign = _id; + _drv->_out[i]->updateVolume(); + + if (_drv->_out[i]->_note != 0xff) + _drv->_out[i]->noteOff(); + + if (!--num) + break; + } + + _chanMissing += num; + programChange(_program); +} + +void TownsMidiPart::dropChannels(int num) { + if (_chanMissing == num) { + _chanMissing = 0; + return; + } else if (_chanMissing > num) { + _chanMissing -= num; + return; + } + + num -= _chanMissing; + _chanMissing = 0; + + for (int i = 0; i < 6; i++) { + if (_drv->_out[i]->_assign != _id || _drv->_out[i]->_note != 0xff) + continue; + _drv->_out[i]->_assign = 0xff; + if (!--num) + return; + } + + for (int i = 0; i < 6; i++) { + if (_drv->_out[i]->_assign != _id) + continue; + _drv->_out[i]->_sustain = 0; + _drv->_out[i]->noteOff(); + _drv->_out[i]->_assign = 0xff; + if (!--num) + return; + } +} + +uint8 TownsMidiPart::currentProgram() const { + return _program; +} + +int TownsMidiPart::allocateChannel() { + int chan = _outChan; + int ovrChan = 0; + int ld = 0; + bool found = false; + + for (bool loop = true; loop; ) { + if (++chan == 6) + chan = 0; + + if (chan == _outChan) + loop = false; + + if (_id == _drv->_out[chan]->_assign || _drv->_version == SCI_VERSION_1_EARLY) { + if (_drv->_out[chan]->_note == 0xff) { + found = true; + break; + } + + if (_drv->_out[chan]->_duration >= ld) { + ld = _drv->_out[chan]->_duration; + ovrChan = chan; + } + } + } + + if (!found) { + if (!ld) + return -1; + chan = ovrChan; + _drv->_out[chan]->_sustain = 0; + _drv->_out[chan]->noteOff(); + } + + _outChan = chan; + return chan; +} + +MidiDriver_FMTowns::MidiDriver_FMTowns(Audio::Mixer *mixer, SciVersion version) : _version(version), _timerProc(0), _timerProcPara(0), _baseTempo(10080), _ready(false), _isOpen(false), _masterVolume(0x0f), _soundOn(true) { + _intf = new TownsAudioInterface(mixer, this, true); + _out = new TownsChannel*[6]; + for (int i = 0; i < 6; i++) + _out[i] = new TownsChannel(this, i); + _parts = new TownsMidiPart*[16]; + for (int i = 0; i < 16; i++) + _parts[i] = new TownsMidiPart(this, i); +} + +MidiDriver_FMTowns::~MidiDriver_FMTowns() { + delete _intf; + + if (_parts) { + for (int i = 0; i < 16; i++) { + delete _parts[i]; + _parts[i] = 0; + } + delete[] _parts; + _parts = 0; + } + + if (_out) { + for (int i = 0; i < 6; i++) { + delete _out[i]; + _out[i] = 0; + } + delete[] _out; + _out = 0; + } +} + +int MidiDriver_FMTowns::open() { + if (_isOpen) + return MERR_ALREADY_OPEN; + + if (!_ready) { + if (!_intf->init()) + return MERR_CANNOT_CONNECT; + + _intf->callback(0); + + _intf->callback(21, 255, 1); + _intf->callback(21, 0, 1); + _intf->callback(22, 255, 221); + + _intf->callback(33, 8); + _intf->setSoundEffectChanMask(~0x3f); + + _ready = true; + } + + _isOpen = true; + + return 0; +} + +void MidiDriver_FMTowns::loadInstruments(const uint8 *data) { + if (data) { + data += 6; + for (int i = 0; i < 128; i++) { + _intf->callback(5, 0, i, data); + data += 48; + } + } + _intf->callback(70, 3); + property(MIDI_PROP_MASTER_VOLUME, _masterVolume); +} + +void MidiDriver_FMTowns::close() { + _isOpen = false; +} + +void MidiDriver_FMTowns::send(uint32 b) { + if (!_isOpen) + return; + + byte para2 = (b >> 16) & 0xFF; + byte para1 = (b >> 8) & 0xFF; + byte cmd = b & 0xF0; + + TownsMidiPart *chan = _parts[b & 0x0F]; + + switch (cmd) { + case 0x80: + chan->noteOff(para1); + break; + case 0x90: + chan->noteOn(para1, para2); + break; + case 0xb0: + switch (para1) { + case 7: + chan->controlChangeVolume(para2); + break; + case 64: + chan->controlChangeSustain(para2); + break; + case SCI_MIDI_SET_POLYPHONY: + chan->controlChangePolyphony(para2); + break; + case SCI_MIDI_CHANNEL_NOTES_OFF: + chan->controlChangeAllNotesOff(); + break; + default: + break; + } + break; + case 0xc0: + chan->programChange(para1); + break; + case 0xe0: + chan->pitchBend(para1 | (para2 << 7)); + break; + default: + break; + } +} + +uint32 MidiDriver_FMTowns::property(int prop, uint32 param) { + switch(prop) { + case MIDI_PROP_MASTER_VOLUME: + if (param != 0xffff) { + _masterVolume = param; + for (int i = 0; i < 6; i++) + _out[i]->updateVolume(); + } + return _masterVolume; + default: + break; + } + return 0; +} + +void MidiDriver_FMTowns::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { + _timerProc = timer_proc; + _timerProcPara = timer_param; +} + +void MidiDriver_FMTowns::setSoundOn(bool toggle) { + _soundOn = toggle; +} + +uint32 MidiDriver_FMTowns::getBaseTempo() { + return _baseTempo; +} + +void MidiDriver_FMTowns::timerCallback(int timerId) { + if (!_isOpen) + return; + + switch (timerId) { + case 1: + updateParser(); + updateChannels(); + break; + default: + break; + } +} + +int MidiDriver_FMTowns::getChannelVolume(uint8 midiPart) { + static const uint8 volumeTable[] = { 0x00, 0x0D, 0x1B, 0x28, 0x36, 0x43, 0x51, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73, 0x77, 0x7B, 0x7F }; + int tableIndex = (_version == SCI_VERSION_1_EARLY) ? _masterVolume : (_parts[midiPart]->_volume * (_masterVolume + 1)) >> 6; + assert(tableIndex < 16); + return volumeTable[tableIndex]; +} + +void MidiDriver_FMTowns::addMissingChannels() { + uint8 avlChan = 0; + for (int i = 0; i < 6; i++) { + if (_out[i]->_assign == 0xff) + avlChan++; + } + + if (!avlChan) + return; + + for (int i = 0; i < 16; i++) { + if (!_parts[i]->_chanMissing) + continue; + + if (_parts[i]->_chanMissing < avlChan) { + avlChan -= _parts[i]->_chanMissing; + uint8 m = _parts[i]->_chanMissing; + _parts[i]->_chanMissing = 0; + _parts[i]->addChannels(m); + } else { + _parts[i]->_chanMissing -= avlChan; + _parts[i]->addChannels(avlChan); + return; + } + } +} + +void MidiDriver_FMTowns::updateParser() { + if (_timerProc) + _timerProc(_timerProcPara); +} + +void MidiDriver_FMTowns::updateChannels() { + for (int i = 0; i < 6; i++) + _out[i]->updateDuration(); +} + +MidiPlayer_FMTowns::MidiPlayer_FMTowns(SciVersion version) : MidiPlayer(version) { + _driver = _townsDriver = new MidiDriver_FMTowns(g_system->getMixer(), version); +} + +MidiPlayer_FMTowns::~MidiPlayer_FMTowns() { + delete _driver; +} + +int MidiPlayer_FMTowns::open(ResourceManager *resMan) { + int result = MidiDriver::MERR_DEVICE_NOT_AVAILABLE; + if (_townsDriver) { + result = _townsDriver->open(); + if (!result && _version == SCI_VERSION_1_LATE) + _townsDriver->loadInstruments((resMan->findResource(ResourceId(kResourceTypePatch, 8), true))->data); + } + return result; +} + +bool MidiPlayer_FMTowns::hasRhythmChannel() const { + return false; +} + +byte MidiPlayer_FMTowns::getPlayId() const { + return (_version == SCI_VERSION_1_EARLY) ? 0x00 : 0x16; +} + +int MidiPlayer_FMTowns::getPolyphony() const { + return (_version == SCI_VERSION_1_EARLY) ? 1 : 6; +} + +void MidiPlayer_FMTowns::playSwitch(bool play) { + if (_townsDriver) + _townsDriver->setSoundOn(play); +} + +MidiPlayer *MidiPlayer_FMTowns_create(SciVersion _soundVersion) { + return new MidiPlayer_FMTowns(_soundVersion); +} + +} // End of namespace Sci + diff --git a/engines/sci/sound/drivers/mididriver.h b/engines/sci/sound/drivers/mididriver.h index ec66984bd4..8938eef62f 100644 --- a/engines/sci/sound/drivers/mididriver.h +++ b/engines/sci/sound/drivers/mididriver.h @@ -130,6 +130,7 @@ extern MidiPlayer *MidiPlayer_PCSpeaker_create(SciVersion version); extern MidiPlayer *MidiPlayer_CMS_create(SciVersion version); extern MidiPlayer *MidiPlayer_Midi_create(SciVersion version); extern MidiPlayer *MidiPlayer_Fb01_create(SciVersion version); +extern MidiPlayer *MidiPlayer_FMTowns_create(SciVersion version); } // End of namespace Sci diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index ad7ba7ca36..422948f975 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -355,17 +355,14 @@ void MidiParser_SCI::sendInitCommands() { } } - // Send a velocity off signal to all channels - for (int i = 0; i < 15; ++i) { - if (_channelUsed[i]) - sendToDriver(0xB0 | i, 0x4E, 0); // Reset velocity - } - - // Center the pitch wheels and hold pedal in preparation for the next piece of music + // Reset all the parameters of the channels used by this song for (int i = 0; i < 16; ++i) { if (_channelUsed[i]) { - sendToDriver(0xE0 | i, 0, 0x40); // Reset pitch wheel - sendToDriver(0xB0 | i, 0x40, 0); // Reset hold pedal + sendToDriver(0xB0 | i, 0x07, 127); // Reset volume to maximum + sendToDriver(0xB0 | i, 0x0A, 64); // Reset panning to center + sendToDriver(0xB0 | i, 0x40, 0); // Reset hold pedal to none + sendToDriver(0xB0 | i, 0x4E, 0); // Reset velocity to none + sendToDriver(0xE0 | i, 0, 64); // Reset pitch wheel to center } } } diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 9610b6f847..09cab75c39 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -37,15 +37,17 @@ namespace Sci { -SciMusic::SciMusic(SciVersion soundVersion) - : _soundVersion(soundVersion), _soundOn(true), _masterVolume(0), _globalReverb(0) { +SciMusic::SciMusic(SciVersion soundVersion, bool useDigitalSFX) + : _soundVersion(soundVersion), _soundOn(true), _masterVolume(0), _globalReverb(0), _useDigitalSFX(useDigitalSFX) { // Reserve some space in the playlist, to avoid expensive insertion // operations _playList.reserve(10); - for (int i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) { _usedChannel[i] = 0; + _channelRemap[i] = -1; + } _queuedCommands.reserve(1000); } @@ -76,6 +78,13 @@ void SciMusic::init() { if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY && getSciVersion() <= SCI_VERSION_1_1) deviceFlags |= MDT_CMS; + if (g_sci->getPlatform() == Common::kPlatformFMTowns) { + if (getSciVersion() > SCI_VERSION_1_EARLY) + deviceFlags = MDT_TOWNS; + else + deviceFlags |= MDT_TOWNS; + } + uint32 dev = MidiDriver::detectDevice(deviceFlags); _musicType = MidiDriver::getMusicType(dev); @@ -96,6 +105,9 @@ void SciMusic::init() { case MT_CMS: _pMidiDrv = MidiPlayer_CMS_create(_soundVersion); break; + case MT_TOWNS: + _pMidiDrv = MidiPlayer_FMTowns_create(_soundVersion); + break; default: if (ConfMan.getBool("native_fb01")) _pMidiDrv = MidiPlayer_Fb01_create(_soundVersion); @@ -110,8 +122,6 @@ void SciMusic::init() { error("Failed to initialize sound driver"); } - _bMultiMidi = ConfMan.getBool("multi_midi"); - // Find out what the first possible channel is (used, when doing channel // remapping). _driverFirstChannel = _pMidiDrv->getFirstChannel(); @@ -273,10 +283,10 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId()); // If MIDI device is selected but there is no digital track in sound - // resource try to use adlib's digital sample if possible. Also, if the + // resource try to use Adlib's digital sample if possible. Also, if the // track couldn't be found, load the digital track, as some games depend on // this (e.g. the Longbow demo). - if (!track || (_bMultiMidi && track->digitalChannelNr == -1)) { + if (!track || (_useDigitalSFX && track->digitalChannelNr == -1)) { SoundResource::Track *digital = pSnd->soundRes->getDigitalTrack(); if (digital) track = digital; @@ -349,6 +359,7 @@ int16 SciMusic::tryToOwnChannel(MusicEntry *caller, int16 bestChannel) { if (!_usedChannel[bestChannel]) { // currently unused, so give it to caller directly _usedChannel[bestChannel] = caller; + _channelRemap[bestChannel] = bestChannel; return bestChannel; } // otherwise look for unused channel @@ -357,6 +368,7 @@ int16 SciMusic::tryToOwnChannel(MusicEntry *caller, int16 bestChannel) { continue; if (!_usedChannel[channelNr]) { _usedChannel[channelNr] = caller; + _channelRemap[bestChannel] = channelNr; return channelNr; } } @@ -369,8 +381,24 @@ int16 SciMusic::tryToOwnChannel(MusicEntry *caller, int16 bestChannel) { void SciMusic::freeChannels(MusicEntry *caller) { // Remove used channels for (int i = 0; i < 15; i++) { - if (_usedChannel[i] == caller) + if (_usedChannel[i] == caller) { + if (_channelRemap[i] != -1) { + // athrxx: The original handles this differently. It seems to be checking for (and effecting) necessary + // remaps / resets etc. more or less all the time. There are several more tables to keep track of everything. + // I don't know whether all of that is needed and to which SCI versions it applies, though. + // At least it is necessary to release the allocated channels inside the driver. Otherwise these channels + // won't be available any more (e.g. after half of the KQ5 FM-Towns intro there will be no more music + // since the driver can't pick up any more channels). The channels also have to be reset to + // default values, since the original does the same (although in a different manny) and the music will be wrong + // otherwise (at least KQ5 FM-Towns). + + sendMidiCommand(0x4000e0 | _channelRemap[i]); // Reset pitch wheel + sendMidiCommand(0x0040b0 | _channelRemap[i]); // Release pedal + sendMidiCommand(0x004bb0 | _channelRemap[i]); // Release assigned driver channels + } _usedChannel[i] = 0; + _channelRemap[i] = -1; + } } // Also tell midiparser, that he lost ownership caller->pMidiParser->lostChannels(); @@ -446,9 +474,9 @@ void SciMusic::soundPlay(MusicEntry *pSnd) { // volume of the sound channels that the faded song occupies.. // Fixes bug #3266480 and partially fixes bug #3041738. for (uint i = 0; i < playListCount; i++) { - // Is another MIDI song being faded? If yes, stop it + // Is another MIDI song being faded down? If yes, stop it // immediately instead - if (_playList[i]->fadeStep && _playList[i]->pMidiParser) { + if (_playList[i]->fadeStep < 0 && _playList[i]->pMidiParser) { _playList[i]->status = kSoundStopped; if (_soundVersion <= SCI_VERSION_0_LATE) _playList[i]->isQueued = false; diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 8577ed7313..1f798c90d7 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -120,7 +120,7 @@ typedef Common::Array<uint32> MidiCommandQueue; class SciMusic : public Common::Serializable { public: - SciMusic(SciVersion soundVersion); + SciMusic(SciVersion soundVersion, bool useDigitalSFX); ~SciMusic(); void init(); @@ -210,15 +210,15 @@ protected: MidiPlayer *_pMidiDrv; uint32 _dwTempo; - // Mixed AdLib/MIDI mode: when enabled from the ScummVM sound options screen, - // and a sound has a digital track, the sound from the AdLib track is played - bool _bMultiMidi; + // If true and a sound has a digital track, the sound from the AdLib track is played + bool _useDigitalSFX; private: MusicList _playList; bool _soundOn; byte _masterVolume; MusicEntry *_usedChannel[16]; + int8 _channelRemap[16]; int8 _globalReverb; MidiCommandQueue _queuedCommands; diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 274c532779..b8be898abc 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -32,20 +32,30 @@ namespace Sci { +//#define ENABLE_SFX_TYPE_SELECTION + SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segMan, Kernel *kernel, AudioPlayer *audio, SciVersion soundVersion) : _resMan(resMan), _segMan(segMan), _kernel(kernel), _audio(audio), _soundVersion(soundVersion) { - _music = new SciMusic(_soundVersion); - _music->init(); +#ifdef ENABLE_SFX_TYPE_SELECTION // Check if the user wants synthesized or digital sound effects in SCI1.1 - // or later games - _bMultiMidi = ConfMan.getBool("multi_midi"); + // games based on the multi_midi config setting + // In SCI2 and later games, this check should always be true - there was // always only one version of each sound effect or digital music track // (e.g. the menu music in GK1 - there is a sound effect with the same // resource number, but it's totally unrelated to the menu music). - if (getSciVersion() >= SCI_VERSION_2) - _bMultiMidi = true; + // The GK1 demo (very late SCI1.1) does the same thing + // TODO: Check the QFG4 demo + + _useDigitalSFX = (getSciVersion() >= SCI_VERSION_2 || g_sci->getGameId() == GID_GK1 || ConfMan.getBool("multi_midi")); +#else + // Always prefer digital sound effects + _useDigitalSFX = true; +#endif + + _music = new SciMusic(_soundVersion, _useDigitalSFX); + _music->init(); } SoundCommandParser::~SoundCommandParser() { @@ -84,16 +94,14 @@ void SoundCommandParser::initSoundResource(MusicEntry *newSound) { // effects map) bool checkAudioResource = getSciVersion() >= SCI_VERSION_1_1; // Hoyle 4 has garbled audio resources in place of the sound resources. - // The demo of GK1 has no alternate sound effects. - if ((g_sci->getGameId() == GID_HOYLE4) || - (g_sci->getGameId() == GID_GK1 && g_sci->isDemo())) + if (g_sci->getGameId() == GID_HOYLE4) checkAudioResource = false; if (checkAudioResource && _resMan->testResource(ResourceId(kResourceTypeAudio, newSound->resourceId))) { // Found a relevant audio resource, create an audio stream if there is // no associated sound resource, or if both resources exist and the // user wants the digital version. - if (_bMultiMidi || !newSound->soundRes) { + if (_useDigitalSFX || !newSound->soundRes) { int sampleLen; newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen); newSound->soundType = Audio::Mixer::kSpeechSoundType; @@ -485,7 +493,7 @@ void SoundCommandParser::processUpdateCues(reg_t obj) { } else { // Slot actually has no data (which would mean that a sound-resource w/ // unsupported data is used. - // (example lsl5 - sound resource 744 - it's roland exclusive + // (example lsl5 - sound resource 744 - it's Roland exclusive writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET); // If we don't set signal here, at least the switch to the mud wrestling // room in lsl5 will not work. diff --git a/engines/sci/sound/soundcmd.h b/engines/sci/sound/soundcmd.h index c1dce014d2..d76f969c7d 100644 --- a/engines/sci/sound/soundcmd.h +++ b/engines/sci/sound/soundcmd.h @@ -111,7 +111,9 @@ private: SciMusic *_music; AudioPlayer *_audio; SciVersion _soundVersion; - bool _bMultiMidi; + // If true and an alternative digital sound effect exists, the digital + // sound effect is preferred instead + bool _useDigitalSFX; void processInitSound(reg_t obj); void processDisposeSound(reg_t obj); |