// SCI1 Early: // KQ5 - no fastcast, LSL1 (demo) - no fastcast, Mixed Up Fairy Tales - *has fastcast*, XMas Card 1990 - no fastcast, // SQ4Floppy - no fastcast, Mixed Up Mother Goose - no fastcast // // SCI1 Middle: // LSL5 demo - no fastfast, Conquest of the Longbow demo - no fastcast, LSL1 - no fastcast, // Astro Chicken II - no fastcast // // SCI1 Late: // Castle of Dr. Brain demo - has fastcast, Castle of Dr. Brain - has fastcast, // Conquests of the Longbow - has fastcast, Space Quest 1 EGA - has fastcast, // King's Quest 5 multilingual - *NO* fastcast, Police Quest 3 demo - *NO* fastcast, // LSL5 multilingual - has fastcast, Police Quest 3 - has fastcast, // EcoQuest 1 - has fastcast, Mixed Up Fairy Tales demo - has fastcast, // Space Quest 4 multilingual - *NO* fastcast // // SCI1.1 // Quest for Glory 3 demo - has fastcast, Police Quest 1 - hast fastcast, Quest for Glory 1 - has fastcast // Laura Bow 2 Floppy - has fastcast, Mixed Up Mother Goose - has fastcast, Quest for Glory 3 - has fastcast // Island of Dr. Brain - has fastcast, King's Quest 6 - has fastcast, Space Quest 5 - has fastcast // Hoyle 4 - has fastcast, Laura Bow 2 CD - has fastcast, Freddy Pharkas CD - has fastcast bool GfxAnimate::detectFastCast() { SegManager *segMan = _s->_segMan; const reg_t gameVMObject = g_sci->getGameObject(); reg_t gameSuperVMObject = segMan->getObject(gameVMObject)->getSuperClassSelector(); uint32 magicDWord = 0; // platform-specific BE/LE for performance int magicDWordOffset = 0; if (gameSuperVMObject.isNull()) { gameSuperVMObject = gameVMObject; // Just in case. According to sci.cpp this may happen in KQ5CD, when loading saved games before r54510 } Script *objectScript = segMan->getScript(gameSuperVMObject.getSegment()); byte *scriptData = const_cast<byte *>(objectScript->getBuf(0)); uint32 scriptSize = objectScript->getBufSize(); _scriptPatcher->calculateMagicDWordAndVerify("fast cast detection", fastCastSignature, true, magicDWord, magicDWordOffset); // Signature is found for multilingual King's Quest 5 too, but it looks as if the fast cast global is never set // within that game. Which means even though we detect it as having the capability, it's never actually used. // The original multilingual KQ5 interpreter did have this feature disabled. // Sierra probably used latest system scripts and that's why we detect it. if (_scriptPatcher->findSignature(magicDWord, magicDWordOffset, fastCastSignature, "fast cast detection", scriptData, scriptSize) >= 0) { // Signature found, game seems to use fast cast for kAnimate return true; } return false; }
void SciEngine::patchGameSaveRestore() { SegManager *segMan = _gamestate->_segMan; const Object *gameObject = segMan->getObject(_gameObjectAddress); const Object *gameSuperObject = segMan->getObject(gameObject->getSuperClassSelector()); if (!gameSuperObject) gameSuperObject = gameObject; // happens in KQ5CD, when loading saved games before r54510 byte kernelIdRestore = 0; byte kernelIdSave = 0; switch (_gameId) { case GID_HOYLE1: // gets confused, although the game doesn't support saving/restoring at all case GID_HOYLE2: // gets confused, see hoyle1 case GID_JONES: // gets confused, when we patch us in, the game is only able to save to 1 slot, so hooking is not required case GID_KQ7: // has custom save/load code case GID_MOTHERGOOSE: // mother goose EGA saves/restores directly and has no save/restore dialogs case GID_MOTHERGOOSE256: // mother goose saves/restores directly and has no save/restore dialogs case GID_MOTHERGOOSEHIRES: // has custom save/load code case GID_PHANTASMAGORIA: // has custom save/load code case GID_PQSWAT: // has custom save/load code case GID_SHIVERS: // has custom save/load code return; default: break; } if (ConfMan.getBool("originalsaveload")) return; uint16 kernelNamesSize = _kernel->getKernelNamesSize(); for (uint16 kernelNr = 0; kernelNr < kernelNamesSize; kernelNr++) { Common::String kernelName = _kernel->getKernelName(kernelNr); if (kernelName == "RestoreGame") kernelIdRestore = kernelNr; if (kernelName == "SaveGame") kernelIdSave = kernelNr; if (kernelName == "Save") kernelIdSave = kernelIdRestore = kernelNr; } // Search for gameobject superclass ::restore uint16 gameSuperObjectMethodCount = gameSuperObject->getMethodCount(); for (uint16 methodNr = 0; methodNr < gameSuperObjectMethodCount; methodNr++) { uint16 selectorId = gameSuperObject->getFuncSelector(methodNr); Common::String methodName = _kernel->getSelectorName(selectorId); if (methodName == "restore") { #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { patchGameSaveRestoreCodeSci2(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore, true); } else #endif patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore); } else if (methodName == "save") { if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { patchGameSaveRestoreCodeSci2(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave, false); } else #endif patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave); } } } const Object *patchObjectSave = nullptr; if (getSciVersion() < SCI_VERSION_2) { // Patch gameobject ::save for now for SCI0 - SCI1.1 // TODO: It seems this was never adjusted to superclass, but adjusting it now may cause // issues with some game. Needs to get checked and then possibly changed. patchObjectSave = gameObject; } else { // Patch superclass ::save for SCI32 patchObjectSave = gameSuperObject; } // Search for gameobject ::save, if there is one patch that one too uint16 patchObjectMethodCount = patchObjectSave->getMethodCount(); for (uint16 methodNr = 0; methodNr < patchObjectMethodCount; methodNr++) { uint16 selectorId = patchObjectSave->getFuncSelector(methodNr); Common::String methodName = _kernel->getSelectorName(selectorId); if (methodName == "save") { if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { patchGameSaveRestoreCodeSci2(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave, false); } else #endif patchGameSaveRestoreCode(segMan, patchObjectSave->getFunction(methodNr), kernelIdSave); } break; } } }
Common::Error SciEngine::run() { _resMan = new ResourceManager(); assert(_resMan); _resMan->addAppropriateSources(); _resMan->init(); // TODO: Add error handling. Check return values of addAppropriateSources // and init. We first have to *add* sensible return values, though ;). /* if (!_resMan) { warning("No resources found, aborting"); return Common::kNoGameDataFoundError; } */ // Reset, so that error()s before SoundCommandParser is initialized wont cause a crash _soundCmd = NULL; // Add the after market GM patches for the specified game, if they exist _resMan->addNewGMPatch(_gameId); _gameObjectAddress = _resMan->findGameObject(); _scriptPatcher = new ScriptPatcher(); SegManager *segMan = new SegManager(_resMan, _scriptPatcher); // Read user option for forcing hires graphics // Only show/selectable for: // - King's Quest 6 CD // - King's Quest 6 CD demo // - Gabriel Knight 1 CD // - Police Quest 4 CD // TODO: Check, if Gabriel Knight 1 floppy supports high resolution // // Gabriel Knight 1 on Mac is hi-res only, so it should NOT get this option. // Confirmed by [md5] and originally by clone2727. if (Common::checkGameGUIOption(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, ConfMan.get("guioptions"))) { // GAMEOPTION_HIGH_RESOLUTION_GRAPHICS is available for the currently detected game, // so read the user option now. // We need to do this, because the option's default is "true", but we don't want "true" // for any game that does not have this option. _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics"); } if (getSciVersion() < SCI_VERSION_2) { // Initialize the game screen _gfxScreen = new GfxScreen(_resMan); _gfxScreen->enableUndithering(ConfMan.getBool("disable_dithering")); } else { _gfxScreen = nullptr; } _kernel = new Kernel(_resMan, segMan); _kernel->init(); _features = new GameFeatures(segMan, _kernel); // Only SCI0, SCI01 and SCI1 EGA games used a parser _vocabulary = (getSciVersion() <= SCI_VERSION_1_EGA_ONLY) ? new Vocabulary(_resMan, false) : NULL; // Also, XMAS1990 apparently had a parser too. Refer to http://forums.scummvm.org/viewtopic.php?t=9135 if (getGameId() == GID_CHRISTMAS1990) _vocabulary = new Vocabulary(_resMan, false); _gamestate = new EngineState(segMan); _eventMan = new EventManager(_resMan->detectFontExtended()); #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { _audio32 = new Audio32(_resMan); } else #endif _audio = new AudioPlayer(_resMan); #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { _video32 = new Video32(segMan, _eventMan); } #endif _sync = new Sync(_resMan, segMan); // Create debugger console. It requires GFX and _gamestate to be initialized _console = new Console(this); // The game needs to be initialized before the graphics system is initialized, as // the graphics code checks parts of the seg manager upon initialization (e.g. for // the presence of the fastCast object) if (!initGame()) { /* Initialize */ warning("Game initialization failed: Aborting..."); // TODO: Add an "init failed" error? return Common::kUnknownError; } // we try to find the super class address of the game object, we can't do that earlier const Object *gameObject = segMan->getObject(_gameObjectAddress); if (!gameObject) { warning("Could not get game object, aborting..."); return Common::kUnknownError; } script_adjust_opcode_formats(); // Must be called after game_init(), as they use _features _kernel->loadKernelNames(_features); // Load our Mac executable here for icon bar palettes and high-res fonts loadMacExecutable(); // Initialize all graphics related subsystems initGraphics(); // Sound must be initialized after graphics because SysEx transfers at the // start of the game must pump the event loop to avoid making the OS think // that ScummVM is hanged, and pumping the event loop requires GfxCursor to // be initialized _soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, _features->detectDoSoundType()); syncSoundSettings(); syncIngameAudioOptions(); // Patch in our save/restore code, so that dialogs are replaced patchGameSaveRestore(); setLauncherLanguage(); // Check whether loading a savestate was requested int directSaveSlotLoading = ConfMan.getInt("save_slot"); if (directSaveSlotLoading >= 0) { _gamestate->_delayedRestoreGame = true; _gamestate->_delayedRestoreGameId = directSaveSlotLoading; _gamestate->_delayedRestoreFromLauncher = true; // Jones only initializes its menus when restarting/restoring, thus set // the gameIsRestarting flag here before initializing. Fixes bug #6536. if (g_sci->getGameId() == GID_JONES) _gamestate->gameIsRestarting = GAMEISRESTARTING_RESTORE; } // Show any special warnings for buggy scripts with severe game bugs, // which have been patched by Sierra if (getGameId() == GID_LONGBOW) { // Longbow 1.0 has a buggy script which prevents the game // from progressing during the Green Man riddle sequence. // A patch for this buggy script has been released by Sierra, // and is necessary to complete the game without issues. // The patched script is included in Longbow 1.1. // Refer to bug #3036609. Resource *buggyScript = _resMan->findResource(ResourceId(kResourceTypeScript, 180), 0); if (buggyScript && (buggyScript->size == 12354 || buggyScript->size == 12362)) { showScummVMDialog("A known buggy game script has been detected, which could " "prevent you from progressing later on in the game, during " "the sequence with the Green Man's riddles. Please, apply " "the latest patch for this game by Sierra to avoid possible " "problems"); } } if (getGameId() == GID_KQ7 && ConfMan.getBool("subtitles")) { showScummVMDialog("Subtitles are enabled, but subtitling in King's" " Quest 7 was unfinished and disabled in the release" " version of the game. ScummVM allows the subtitles" " to be re-enabled, but because they were removed from" " the original game, they do not always render" " properly or reflect the actual game speech." " This is not a ScummVM bug -- it is a problem with" " the game's assets."); } // Show a warning if the user has selected a General MIDI device, no GM patch exists // (i.e. patch 4) and the game is one of the known 8 SCI1 games that Sierra has provided // after market patches for in their "General MIDI Utility". if (_soundCmd->getMusicType() == MT_GM && !ConfMan.getBool("native_mt32")) { if (!_resMan->findResource(ResourceId(kResourceTypePatch, 4), 0)) { switch (getGameId()) { case GID_ECOQUEST: case GID_HOYLE3: case GID_LSL1: case GID_LSL5: case GID_LONGBOW: case GID_SQ1: case GID_SQ4: case GID_FAIRYTALES: showScummVMDialog("You have selected General MIDI as a sound device. Sierra " "has provided after-market support for General MIDI for this " "game in their \"General MIDI Utility\". Please, apply this " "patch in order to enjoy MIDI music with this game. Once you " "have obtained it, you can unpack all of the included *.PAT " "files in your ScummVM extras folder and ScummVM will add the " "appropriate patch automatically. Alternatively, you can follow " "the instructions in the READ.ME file included in the patch and " "rename the associated *.PAT file to 4.PAT and place it in the " "game folder. Without this patch, General MIDI music for this " "game will sound badly distorted."); break; default: break; } } } if (gameHasFanMadePatch()) { showScummVMDialog("Your game is patched with a fan made script patch. Such patches have " "been reported to cause issues, as they modify game scripts extensively. " "The issues that these patches fix do not occur in ScummVM, so you are " "advised to remove this patch from your game folder in order to avoid " "having unexpected errors and/or issues later on."); } runGame(); ConfMan.flushToDisk(); return Common::kNoError; }
void SciEngine::patchGameSaveRestore() { SegManager *segMan = _gamestate->_segMan; const Object *gameObject = segMan->getObject(_gameObjectAddress); const uint16 gameMethodCount = gameObject->getMethodCount(); const Object *gameSuperObject = segMan->getObject(_gameSuperClassAddress); if (!gameSuperObject) gameSuperObject = gameObject; // happens in KQ5CD, when loading saved games before r54510 const uint16 gameSuperMethodCount = gameSuperObject->getMethodCount(); reg_t methodAddress; const uint16 kernelCount = _kernel->getKernelNamesSize(); const byte *scriptRestorePtr = NULL; byte kernelIdRestore = 0; const byte *scriptSavePtr = NULL; byte kernelIdSave = 0; // this feature is currently not supported on SCI32 if (getSciVersion() >= SCI_VERSION_2) return; switch (_gameId) { case GID_MOTHERGOOSE256: // mother goose saves/restores directly and has no save/restore dialogs case GID_JONES: // gets confused, when we patch us in, the game is only able to save to 1 slot, so hooking is not required case GID_HOYLE1: // gets confused, although the game doesnt support saving/restoring at all case GID_HOYLE2: // gets confused, see hoyle1 return; default: break; } if (ConfMan.getBool("sci_originalsaveload")) return; for (uint16 kernelNr = 0; kernelNr < kernelCount; kernelNr++) { Common::String kernelName = _kernel->getKernelName(kernelNr); if (kernelName == "RestoreGame") kernelIdRestore = kernelNr; if (kernelName == "SaveGame") kernelIdSave = kernelNr; } // Search for gameobject-superclass ::restore for (uint16 methodNr = 0; methodNr < gameSuperMethodCount; methodNr++) { uint16 selectorId = gameSuperObject->getFuncSelector(methodNr); Common::String methodName = _kernel->getSelectorName(selectorId); if (methodName == "restore") { methodAddress = gameSuperObject->getFunction(methodNr); Script *script = segMan->getScript(methodAddress.segment); scriptRestorePtr = script->getBuf(methodAddress.offset); } if (methodName == "save") { methodAddress = gameSuperObject->getFunction(methodNr); Script *script = segMan->getScript(methodAddress.segment); scriptSavePtr = script->getBuf(methodAddress.offset); } } // Search for gameobject ::save, if there is one patch that one instead for (uint16 methodNr = 0; methodNr < gameMethodCount; methodNr++) { uint16 selectorId = gameObject->getFuncSelector(methodNr); Common::String methodName = _kernel->getSelectorName(selectorId); if (methodName == "save") { methodAddress = gameObject->getFunction(methodNr); Script *script = segMan->getScript(methodAddress.segment); scriptSavePtr = script->getBuf(methodAddress.offset); break; } } switch (_gameId) { case GID_FAIRYTALES: // fairy tales automatically saves w/o dialog scriptSavePtr = NULL; default: break; } if (scriptRestorePtr) { // Now patch in our code byte *patchPtr = const_cast<byte *>(scriptRestorePtr); memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave)); patchPtr[8] = kernelIdRestore; } if (scriptSavePtr) { // Now patch in our code byte *patchPtr = const_cast<byte *>(scriptSavePtr); memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave)); patchPtr[8] = kernelIdSave; } }
Common::Error SciEngine::run() { g_eventRec.registerRandomSource(_rng, "sci"); // Assign default values to the config manager, in case settings are missing ConfMan.registerDefault("sci_originalsaveload", "false"); ConfMan.registerDefault("native_fb01", "false"); ConfMan.registerDefault("windows_cursors", "false"); // Windows cursors for KQ6 Windows _resMan = new ResourceManager(); assert(_resMan); _resMan->addAppropriateSources(); _resMan->init(); // TODO: Add error handling. Check return values of addAppropriateSources // and init. We first have to *add* sensible return values, though ;). /* if (!_resMan) { warning("No resources found, aborting"); return Common::kNoGameDataFoundError; } */ // Reset, so that error()s before SoundCommandParser is initialized wont cause a crash _soundCmd = NULL; // Add the after market GM patches for the specified game, if they exist _resMan->addNewGMPatch(_gameId); _gameObjectAddress = _resMan->findGameObject(); _gameSuperClassAddress = NULL_REG; SegManager *segMan = new SegManager(_resMan); // Initialize the game screen _gfxScreen = new GfxScreen(_resMan); _gfxScreen->debugUnditherSetState(ConfMan.getBool("disable_dithering")); // Create debugger console. It requires GFX to be initialized _console = new Console(this); _kernel = new Kernel(_resMan, segMan); _features = new GameFeatures(segMan, _kernel); // Only SCI0, SCI01 and SCI1 EGA games used a parser _vocabulary = (getSciVersion() <= SCI_VERSION_1_EGA) ? new Vocabulary(_resMan, false) : NULL; // Also, XMAS1990 apparently had a parser too. Refer to http://forums.scummvm.org/viewtopic.php?t=9135 if (getGameId() == GID_CHRISTMAS1990) _vocabulary = new Vocabulary(_resMan, false); _audio = new AudioPlayer(_resMan); _gamestate = new EngineState(segMan); _eventMan = new EventManager(_resMan->detectFontExtended()); // The game needs to be initialized before the graphics system is initialized, as // the graphics code checks parts of the seg manager upon initialization (e.g. for // the presence of the fastCast object) if (!initGame()) { /* Initialize */ warning("Game initialization failed: Aborting..."); // TODO: Add an "init failed" error? return Common::kUnknownError; } // we try to find the super class address of the game object, we can't do that earlier const Object *gameObject = segMan->getObject(_gameObjectAddress); if (!gameObject) { warning("Could not get game object, aborting..."); return Common::kUnknownError; } _gameSuperClassAddress = gameObject->getSuperClassSelector(); script_adjust_opcode_formats(); // Must be called after game_init(), as they use _features _kernel->loadKernelNames(_features); _soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, _features->detectDoSoundType()); syncSoundSettings(); syncIngameAudioOptions(); // Initialize all graphics related subsystems initGraphics(); debug("Emulating SCI version %s\n", getSciVersionDesc(getSciVersion())); // Patch in our save/restore code, so that dialogs are replaced patchGameSaveRestore(); setLauncherLanguage(); // Check whether loading a savestate was requested int directSaveSlotLoading = ConfMan.getInt("save_slot"); if (directSaveSlotLoading >= 0) { // call GameObject::play (like normally) initStackBaseWithSelector(SELECTOR(play)); // We set this, so that the game automatically quit right after init _gamestate->variables[VAR_GLOBAL][4] = TRUE_REG; _gamestate->_executionStackPosChanged = false; run_vm(_gamestate); // As soon as we get control again, actually restore the game reg_t restoreArgv[2] = { NULL_REG, make_reg(0, directSaveSlotLoading) }; // special call (argv[0] is NULL) kRestoreGame(_gamestate, 2, restoreArgv); // this indirectly calls GameObject::init, which will setup menu, text font/color codes etc. // without this games would be pretty badly broken } // Show any special warnings for buggy scripts with severe game bugs, // which have been patched by Sierra if (getGameId() == GID_LONGBOW) { // Longbow 1.0 has a buggy script which prevents the game // from progressing during the Green Man riddle sequence. // A patch for this buggy script has been released by Sierra, // and is necessary to complete the game without issues. // The patched script is included in Longbow 1.1. // Refer to bug #3036609. Resource *buggyScript = _resMan->findResource(ResourceId(kResourceTypeScript, 180), 0); if (buggyScript && (buggyScript->size == 12354 || buggyScript->size == 12362)) { showScummVMDialog("A known buggy game script has been detected, which could " "prevent you from progressing later on in the game, during " "the sequence with the Green Man's riddles. Please, apply " "the latest patch for this game by Sierra to avoid possible " "problems"); } } // Show a warning if the user has selected a General MIDI device, no GM patch exists // (i.e. patch 4) and the game is one of the known 8 SCI1 games that Sierra has provided // after market patches for in their "General MIDI Utility". if (_soundCmd->getMusicType() == MT_GM && !ConfMan.getBool("native_mt32")) { if (!_resMan->findResource(ResourceId(kResourceTypePatch, 4), 0)) { switch (getGameId()) { case GID_ECOQUEST: case GID_HOYLE3: case GID_LSL1: case GID_LSL5: case GID_LONGBOW: case GID_SQ1: case GID_SQ4: case GID_FAIRYTALES: showScummVMDialog("You have selected General MIDI as a sound device. Sierra " "has provided after-market support for General MIDI for this " "game in their \"General MIDI Utility\". Please, apply this " "patch in order to enjoy MIDI music with this game. Once you " "have obtained it, you can unpack all of the included *.PAT " "files in your ScummVM extras folder and ScummVM will add the " "appropriate patch automatically. Alternatively, you can follow " "the instructions in the READ.ME file included in the patch and " "rename the associated *.PAT file to 4.PAT and place it in the " "game folder. Without this patch, General MIDI music for this " "game will sound badly distorted."); break; default: break; } } } if (gameHasFanMadePatch()) { showScummVMDialog("Your game is patched with a fan made script patch. Such patches have " "been reported to cause issues, as they modify game scripts extensively. " "The issues that these patches fix do not occur in ScummVM, so you are " "advised to remove this patch from your game folder in order to avoid " "having unexpected errors and/or issues later on."); } runGame(); ConfMan.flushToDisk(); return Common::kNoError; }
void SciEngine::patchGameSaveRestore() { SegManager *segMan = _gamestate->_segMan; const Object *gameObject = segMan->getObject(_gameObjectAddress); const Object *gameSuperObject = segMan->getObject(gameObject->getSuperClassSelector()); if (!gameSuperObject) gameSuperObject = gameObject; // happens in KQ5CD, when loading saved games before r54510 byte kernelIdRestore = 0; byte kernelIdSave = 0; switch (_gameId) { case GID_HOYLE1: // gets confused, although the game doesnt support saving/restoring at all case GID_HOYLE2: // gets confused, see hoyle1 case GID_JONES: // gets confused, when we patch us in, the game is only able to save to 1 slot, so hooking is not required case GID_MOTHERGOOSE256: // mother goose saves/restores directly and has no save/restore dialogs case GID_PHANTASMAGORIA: // has custom save/load code case GID_SHIVERS: // has custom save/load code return; default: break; } if (ConfMan.getBool("originalsaveload")) return; uint16 kernelNamesSize = _kernel->getKernelNamesSize(); for (uint16 kernelNr = 0; kernelNr < kernelNamesSize; kernelNr++) { Common::String kernelName = _kernel->getKernelName(kernelNr); if (kernelName == "RestoreGame") kernelIdRestore = kernelNr; if (kernelName == "SaveGame") kernelIdSave = kernelNr; if (kernelName == "Save") kernelIdSave = kernelIdRestore = kernelNr; } // Search for gameobject superclass ::restore uint16 gameSuperObjectMethodCount = gameSuperObject->getMethodCount(); for (uint16 methodNr = 0; methodNr < gameSuperObjectMethodCount; methodNr++) { uint16 selectorId = gameSuperObject->getFuncSelector(methodNr); Common::String methodName = _kernel->getSelectorName(selectorId); if (methodName == "restore") { if (kernelIdSave != kernelIdRestore) patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore); else patchGameSaveRestoreCodeSci21(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore, true); } else if (methodName == "save") { if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog if (kernelIdSave != kernelIdRestore) patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave); else patchGameSaveRestoreCodeSci21(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave, false); } } } // Search for gameobject ::save, if there is one patch that one too uint16 gameObjectMethodCount = gameObject->getMethodCount(); for (uint16 methodNr = 0; methodNr < gameObjectMethodCount; methodNr++) { uint16 selectorId = gameObject->getFuncSelector(methodNr); Common::String methodName = _kernel->getSelectorName(selectorId); if (methodName == "save") { if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog if (kernelIdSave != kernelIdRestore) patchGameSaveRestoreCode(segMan, gameObject->getFunction(methodNr), kernelIdSave); else patchGameSaveRestoreCodeSci21(segMan, gameObject->getFunction(methodNr), kernelIdSave, false); } break; } } }