From d2f5023ee9ec5534a9f7a4754c4f1e805c0fb605 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 8 Jun 2019 13:57:00 +0300 Subject: SCI: Do not apply script patches when checking for static selectors Fixes bug #10969 --- engines/sci/engine/kernel.cpp | 5 ----- engines/sci/engine/kernel.h | 2 -- engines/sci/engine/script.cpp | 19 ++++++++++--------- engines/sci/engine/script.h | 18 ++++++++++-------- engines/sci/engine/script_patches.cpp | 4 ---- engines/sci/engine/seg_manager.cpp | 14 +++++++------- engines/sci/engine/seg_manager.h | 16 +++++++++------- engines/sci/engine/static_selectors.cpp | 11 +++++++---- 8 files changed, 43 insertions(+), 46 deletions(-) (limited to 'engines/sci/engine') diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 17f799a77f..d75c910d30 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -112,11 +112,6 @@ int Kernel::findSelector(const char *selectorName) const { return -1; } -// used by Script patcher to figure out, if it's okay to initialize signature/patch-table -bool Kernel::selectorNamesAvailable() { - return !_selectorNames.empty(); -} - void Kernel::loadSelectorNames() { Resource *r = _resMan->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SELECTORS), 0); bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index 558224fdec..a27df1ad08 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -168,8 +168,6 @@ public: */ int findSelector(const char *selectorName) const; - bool selectorNamesAvailable(); - // Script dissection/dumping functions void dissectScript(int scriptNumber, Vocabulary *vocab); void dumpScriptObject(const SciSpan &script, SciSpan object); diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 0dea69214a..25d12833c3 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -80,7 +80,7 @@ enum { kSci11ExportTableOffset = 8 }; -void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher) { +void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher, bool applyScriptPatches) { freeScript(); Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), false); @@ -147,7 +147,8 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP } // Check scripts (+ possibly SCI 1.1 heap) for matching signatures and patch those, if found - scriptPatcher->processScript(_nr, outBuffer); + if (applyScriptPatches) + scriptPatcher->processScript(_nr, outBuffer); if (getSciVersion() <= SCI_VERSION_1_LATE) { // Some buggy game scripts contain two export tables (e.g. script 912 @@ -1119,7 +1120,7 @@ void Script::initializeObjectsSci0(SegManager *segMan, SegmentId segmentId) { relocateSci0Sci21(segmentId); } -void Script::initializeObjectsSci11(SegManager *segMan, SegmentId segmentId) { +void Script::initializeObjectsSci11(SegManager *segMan, SegmentId segmentId, bool applyScriptPatches) { SciSpan seeker = _heap.subspan(4 + _heap.getUint16SEAt(2) * 2); Common::Array mismatchedVarCountObjects; @@ -1129,7 +1130,7 @@ void Script::initializeObjectsSci11(SegManager *segMan, SegmentId segmentId) { // Copy base from species class, as we need its selector IDs obj->setSuperClassSelector( - segMan->getClassAddress(obj->getSuperClassSelector().getOffset(), SCRIPT_GET_LOCK, 0)); + segMan->getClassAddress(obj->getSuperClassSelector().getOffset(), SCRIPT_GET_LOCK, 0, applyScriptPatches)); // -propDict- is used by Obj::isMemberOf to determine if an object // is an instance of a class. For classes, we therefore relocate @@ -1187,12 +1188,12 @@ void Script::initializeObjectsSci11(SegManager *segMan, SegmentId segmentId) { } #ifdef ENABLE_SCI32 -void Script::initializeObjectsSci3(SegManager *segMan, SegmentId segmentId) { +void Script::initializeObjectsSci3(SegManager *segMan, SegmentId segmentId, bool applyScriptPatches) { SciSpan seeker = getSci3ObjectsPointer(); while (seeker.getUint16SEAt(0) == SCRIPT_OBJECT_MAGIC_NUMBER) { Object *obj = scriptObjInit(make_reg32(segmentId, seeker - *_buf)); - obj->setSuperClassSelector(segMan->getClassAddress(obj->getSuperClassSelector().getOffset(), SCRIPT_GET_LOCK, 0)); + obj->setSuperClassSelector(segMan->getClassAddress(obj->getSuperClassSelector().getOffset(), SCRIPT_GET_LOCK, 0, applyScriptPatches)); seeker += seeker.getUint16SEAt(2); } @@ -1200,14 +1201,14 @@ void Script::initializeObjectsSci3(SegManager *segMan, SegmentId segmentId) { } #endif -void Script::initializeObjects(SegManager *segMan, SegmentId segmentId) { +void Script::initializeObjects(SegManager *segMan, SegmentId segmentId, bool applyScriptPatches) { if (getSciVersion() <= SCI_VERSION_1_LATE) initializeObjectsSci0(segMan, segmentId); else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) - initializeObjectsSci11(segMan, segmentId); + initializeObjectsSci11(segMan, segmentId, applyScriptPatches); #ifdef ENABLE_SCI32 else if (getSciVersion() == SCI_VERSION_3) - initializeObjectsSci3(segMan, segmentId); + initializeObjectsSci3(segMan, segmentId, applyScriptPatches); #endif } diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index f4afca7681..e1a4b9613b 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -133,7 +133,7 @@ public: ~Script(); void freeScript(const bool keepLocalsSegment = false); - void load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher); + void load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher, bool applyScriptPatches = true); virtual bool isValidOffset(uint32 offset) const; virtual SegmentRef dereference(reg_t pointer); @@ -180,10 +180,11 @@ public: /** * Initializes the script's objects (SCI0) - * @param segMan A reference to the segment manager - * @param segmentId The script's segment id + * @param segMan A reference to the segment manager + * @param segmentId The script's segment id + * @param applyScriptPatches Apply patches for the script, if available */ - void initializeObjects(SegManager *segMan, SegmentId segmentId); + void initializeObjects(SegManager *segMan, SegmentId segmentId, bool applyScriptPatches); // script lock operations @@ -336,10 +337,11 @@ private: /** * Initializes the script's objects (SCI1.1 - SCI2.1) - * @param segMan A reference to the segment manager - * @param segmentId The script's segment id + * @param segMan A reference to the segment manager + * @param segmentId The script's segment id + * @applyScriptPatches Apply patches for the script, if available */ - void initializeObjectsSci11(SegManager *segMan, SegmentId segmentId); + void initializeObjectsSci11(SegManager *segMan, SegmentId segmentId, bool applyScriptPatches); #ifdef ENABLE_SCI32 /** @@ -347,7 +349,7 @@ private: * @param segMan A reference to the segment manager * @param segmentId The script's segment id */ - void initializeObjectsSci3(SegManager *segMan, SegmentId segmentId); + void initializeObjectsSci3(SegManager *segMan, SegmentId segmentId, bool applyScriptPatches); #endif LocalVariables *allocLocalsSegment(SegManager *segMan); diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 806fb36913..4412ffb533 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -14067,10 +14067,6 @@ void ScriptPatcher::processScript(uint16 scriptNr, SciSpan scriptData) { _isMacSci11 = (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1); if (!_runtimeTable) { - // Abort, in case selectors are not yet initialized (happens for games w/o selector-dictionary) - if (!g_sci->getKernel()->selectorNamesAvailable()) - return; - // signature table needs to get initialized (Magic DWORD set, selector table set) initSignature(signatureTable); diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 45666336e9..fd6b86e405 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -347,11 +347,11 @@ SegmentId SegManager::getScriptSegment(int script_id) const { return _scriptSegMap.getVal(script_id, 0); } -SegmentId SegManager::getScriptSegment(int script_nr, ScriptLoadType load) { +SegmentId SegManager::getScriptSegment(int script_nr, ScriptLoadType load, bool applyScriptPatches) { SegmentId segment; if ((load & SCRIPT_GET_LOAD) == SCRIPT_GET_LOAD) - instantiateScript(script_nr); + instantiateScript(script_nr, applyScriptPatches); segment = getScriptSegment(script_nr); @@ -1003,7 +1003,7 @@ void SegManager::createClassTable() { } } -reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, uint16 callerSegment) { +reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, uint16 callerSegment, bool applyScriptPatches) { if (classnr == 0xffff) return NULL_REG; @@ -1012,7 +1012,7 @@ reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, uint16 calle } else { Class *the_class = &_classTable[classnr]; if (!the_class->reg.getSegment()) { - getScriptSegment(the_class->script, lock); + getScriptSegment(the_class->script, lock, applyScriptPatches); if (!the_class->reg.getSegment()) { if (lock == SCRIPT_GET_DONT_LOAD) @@ -1028,7 +1028,7 @@ reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, uint16 calle } } -int SegManager::instantiateScript(int scriptNum) { +int SegManager::instantiateScript(int scriptNum, bool applyScriptPatches) { SegmentId segmentId = getScriptSegment(scriptNum); Script *scr = getScriptIfLoaded(segmentId); if (scr) { @@ -1042,10 +1042,10 @@ int SegManager::instantiateScript(int scriptNum) { scr = allocateScript(scriptNum, &segmentId); } - scr->load(scriptNum, _resMan, _scriptPatcher); + scr->load(scriptNum, _resMan, _scriptPatcher, applyScriptPatches); scr->initializeLocals(this); scr->initializeClasses(this); - scr->initializeObjects(this, segmentId); + scr->initializeObjects(this, segmentId, applyScriptPatches); #ifdef ENABLE_SCI32 g_sci->_guestAdditions->instantiateScriptHook(*scr); #endif diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index d13edf0ef2..fdef0b6463 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -98,10 +98,11 @@ public: * Determines the segment occupied by a certain script. Optionally * load it, or load & lock it. * @param[in] script_nr Number of the script to look up - * @param[in] load flag determining whether to load/lock the script - * @return The script's segment ID, or 0 on failure + * @param[in] load Flag determining whether to load/lock the script + * @param[in] applyScriptPatches Apply patches for the script, if available + * @return The script's segment ID, or 0 on failure */ - SegmentId getScriptSegment(int script_nr, ScriptLoadType load); + SegmentId getScriptSegment(int script_nr, ScriptLoadType load, bool applyScriptPatches = true); /** * Makes sure that a script and its superclasses get loaded to the heap. @@ -109,10 +110,11 @@ public: * increased. All scripts containing superclasses of this script are loaded * recursively as well, unless 'recursive' is set to zero. The * complementary function is "uninstantiateScript()" below. - * @param[in] script_nr The script number to load - * @return The script's segment ID or 0 if out of heap + * @param[in] script_nr The script number to load + * @param[in] applyScriptPatches Apply patches for the script, if available + * @return The script's segment ID or 0 if out of heap */ - int instantiateScript(int script_nr); + int instantiateScript(int script_nr, bool applyScriptPatches = true); /** * Decreases the numer of lockers of a script and unloads it if that number @@ -128,7 +130,7 @@ private: public: // TODO: document this - reg_t getClassAddress(int classnr, ScriptLoadType lock, uint16 callerSegment); + reg_t getClassAddress(int classnr, ScriptLoadType lock, uint16 callerSegment, bool applyScriptPatches = true); /** * Return a pointer to the specified script. diff --git a/engines/sci/engine/static_selectors.cpp b/engines/sci/engine/static_selectors.cpp index 08c6f5d75a..ae6c7afc84 100644 --- a/engines/sci/engine/static_selectors.cpp +++ b/engines/sci/engine/static_selectors.cpp @@ -224,11 +224,14 @@ Common::StringArray Kernel::checkStaticSelectorNames() { void Kernel::findSpecificSelectors(Common::StringArray &selectorNames) { // Now, we need to find out selectors which keep changing place... // We do that by dissecting game objects, and looking for selectors at - // specified locations. + // specified locations. We need to load some game scripts here to + // find these selectors, but all of the loaded scripts will be + // purged at the end of this function, as the segment manager will be + // reset. // We need to initialize script 0 here, to make sure that it's always // located at segment 1. - _segMan->instantiateScript(0); + _segMan->instantiateScript(0, false); // The Actor class contains the init, xLast and yLast selectors, which // we reference directly. It's always in script 998, so we need to @@ -242,7 +245,7 @@ void Kernel::findSpecificSelectors(Common::StringArray &selectorNames) { #endif if (_resMan->testResource(ResourceId(kResourceTypeScript, actorScript))) { - _segMan->instantiateScript(actorScript); + _segMan->instantiateScript(actorScript, false); const Object *actorClass = _segMan->getObject(_segMan->findObjectByName("Actor")); @@ -284,7 +287,7 @@ void Kernel::findSpecificSelectors(Common::StringArray &selectorNames) { if (!_resMan->testResource(ResourceId(kResourceTypeScript, classReferences[i].script))) continue; - _segMan->instantiateScript(classReferences[i].script); + _segMan->instantiateScript(classReferences[i].script, false); const Object *targetClass = _segMan->getObject(_segMan->findObjectByName(classReferences[i].className)); int targetSelectorPos = 0; -- cgit v1.2.3