// 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 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; } }