aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/script.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/script.cpp')
-rw-r--r--engines/sci/engine/script.cpp61
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());