diff options
Diffstat (limited to 'engines/sci/engine/script.cpp')
-rw-r--r-- | engines/sci/engine/script.cpp | 61 |
1 files changed, 49 insertions, 12 deletions
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 26a7ff5718..8a973bd217 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -72,6 +72,11 @@ void Script::freeScript() { _offsetLookupSaidCount = 0; } +enum { + kSci11NumExportsOffset = 6, + kSci11ExportTableOffset = 8 +}; + void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptPatcher) { freeScript(); @@ -172,10 +177,11 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP _localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1; // half block size } } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { - if (READ_LE_UINT16(_buf + 1 + 5) > 0) { // does the script have an export table? - _exportTable = (const uint16 *)(_buf + 1 + 5 + 2); - _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1); + _numExports = READ_SCI11ENDIAN_UINT16(_buf + kSci11NumExportsOffset); + if (_numExports) { + _exportTable = (const uint16 *)(_buf + kSci11ExportTableOffset); } + _localsOffset = _scriptSize + 4; _localsCount = READ_SCI11ENDIAN_UINT16(_buf + _localsOffset - 2); } else if (getSciVersion() == SCI_VERSION_3) { @@ -234,6 +240,7 @@ void Script::identifyOffsets() { _offsetLookupObjectCount = 0; _offsetLookupStringCount = 0; _offsetLookupSaidCount = 0; + _codeOffset = 0; if (getSciVersion() < SCI_VERSION_1_1) { // SCI0 + SCI1 @@ -392,6 +399,16 @@ void Script::identifyOffsets() { scriptDataPtr = _heapStart; scriptDataLeft = _heapSize; + enum { + kExportSize = 2, + kPropertySize = 2, + kNumMethodsSize = 2, + kPropDictEntrySize = 2, + kMethDictEntrySize = 4 + }; + + const byte *hunkPtr = _buf + kSci11ExportTableOffset + _numExports * kExportSize; + if (scriptDataLeft < 4) error("Script::identifyOffsets(): unexpected end of script in script %d", _nr); @@ -431,11 +448,22 @@ void Script::identifyOffsets() { if (scriptDataLeft < 2) error("Script::identifyOffsets(): unexpected end of script in script %d", _nr); - blockSize = READ_SCI11ENDIAN_UINT16(scriptDataPtr) * 2; + const uint16 numProperties = READ_SCI11ENDIAN_UINT16(scriptDataPtr); + blockSize = numProperties * kPropertySize; if (blockSize < 4) error("Script::identifyOffsets(): invalid block size in script %d", _nr); scriptDataPtr += 2; scriptDataLeft -= 2; + + const uint16 scriptNum = READ_SCI11ENDIAN_UINT16(scriptDataPtr + 6); + + if (scriptNum != 0xFFFF) { + hunkPtr += numProperties * kPropDictEntrySize; + } + + const uint16 numMethods = READ_SCI11ENDIAN_UINT16(hunkPtr); + hunkPtr += kNumMethodsSize + numMethods * kMethDictEntrySize; + blockSize -= 4; // blocksize contains UINT16 type and UINT16 size if (scriptDataLeft < blockSize) error("Script::identifyOffsets(): invalid block size in script %d", _nr); @@ -444,6 +472,8 @@ void Script::identifyOffsets() { scriptDataLeft -= blockSize; } while (1); + _codeOffset = hunkPtr - _buf; + // now scriptDataPtr points to right at the start of the strings if (scriptDataPtr > endOfStringPtr) error("Script::identifyOffsets(): string block / end-of-string block mismatch in script %d", _nr); @@ -674,7 +704,7 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme return true; } -int Script::relocateOffsetSci3(uint32 offset) { +int Script::relocateOffsetSci3(uint32 offset) const { int relocStart = READ_LE_UINT32(_buf + 8); int relocCount = READ_LE_UINT16(_buf + 18); const byte *seeker = _buf + relocStart; @@ -820,9 +850,10 @@ uint32 Script::validateExportFunc(int pubfunct, bool relocSci3) { } } - // Note that it's perfectly normal to return a zero offset, especially in - // SCI1.1 and newer games. Examples include script 64036 in Torin's Passage, - // script 64908 in the demo of RAMA and script 1013 in KQ6 floppy. + // TODO: Check if this should be done for SCI1.1 games as well + if (getSciVersion() >= SCI_VERSION_2 && offset == 0) { + offset = _codeOffset; + } if (offset >= _bufSize) error("Invalid export function pointer"); @@ -1058,11 +1089,17 @@ void Script::initializeObjectsSci11(SegManager *segMan, SegmentId segmentId) { obj->setSuperClassSelector( segMan->getClassAddress(obj->getSuperClassSelector().getOffset(), SCRIPT_GET_LOCK, 0)); - // If object is instance, get -propDict- from class and set it for this - // object. This is needed for ::isMemberOf() to work. + // -propDict- is used by Obj::isMemberOf to determine if an object + // is an instance of a class. For classes, we therefore relocate + // -propDict- to the script's segment. For instances, we copy + // -propDict- from its class. // Example test case - room 381 of sq4cd - if isMemberOf() doesn't work, - // talk-clicks on the robot will act like clicking on ego - if (!obj->isClass()) { + // talk-clicks on the robot will act like clicking on ego. + if (obj->isClass()) { + reg_t propDict = obj->getPropDictSelector(); + propDict.setSegment(segmentId); + obj->setPropDictSelector(propDict); + } else { reg_t classObject = obj->getSuperClassSelector(); const Object *classObj = segMan->getObject(classObject); obj->setPropDictSelector(classObj->getPropDictSelector()); |