From 3485d433c5c158ceb1ea74d985fa9c1274185e9c Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 27 Nov 2010 18:08:47 +0000 Subject: [PATCH] SCI: Fixed bug #3034713 - "ICEMAN Demo: Fails to find base object" This could happen because objects in scripts can be in the wrong order. Same thing happens in the French and German version of KQ5 (bug #3035396). Removed the scriptObjRemove() method, which is in fact a hack. svn-id: r54510 --- engines/sci/engine/savegame.cpp | 18 ++++++---- engines/sci/engine/script.cpp | 63 +++++++++++++++------------------ engines/sci/engine/script.h | 6 ---- 3 files changed, 40 insertions(+), 47 deletions(-) diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 8d941d38b90..f0df3ff627f 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -194,17 +194,23 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) { for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) { reg_t addr = it->_value.getPos(); - Object *obj = scr->scriptObjInit(addr, false); + scr->scriptObjInit(addr, false); + } - if (getSciVersion() < SCI_VERSION_1_1) { + // In SCI0-SCI1, we need to make two passes, as the objects in the + // script might be in the wrong order (e.g. in the demo of Iceman). + // Refer to bug #3034713 + if (getSciVersion() < SCI_VERSION_1_1) { + for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) { + reg_t addr = it->_value.getPos(); + Object *obj = scr->scriptObjInit(addr, false); if (!obj->initBaseObject(this, addr, false)) { - // TODO/FIXME: This should not be happening at all. It might indicate a possible issue - // with the garbage collector. It happens for example in LSL5 (German, perhaps English too). - warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr)); - scr->scriptObjRemove(addr); + error("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr)); + //scr->scriptObjRemove(addr); } } } + } } diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index ec64e1bfa14..789df63e870 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -255,13 +255,6 @@ Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) { return obj; } -void Script::scriptObjRemove(reg_t obj_pos) { - if (getSciVersion() < SCI_VERSION_1_1) - obj_pos.offset += 8; - - _objects.erase(obj_pos.toUint16()); -} - // This helper function is used by Script::relocateLocal and Object::relocate // Duplicate in segment.cpp and script.cpp static bool relocateBlock(Common::Array &block, int block_location, SegmentId segment, int location, size_t scriptSize) { @@ -580,41 +573,41 @@ void Script::initialiseClasses(SegManager *segMan) { void Script::initialiseObjectsSci0(SegManager *segMan, SegmentId segmentId) { bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); - const byte *seeker = _buf + (oldScriptHeader ? 2 : 0); - do { - uint16 objType = READ_SCI11ENDIAN_UINT16(seeker); - if (!objType) - break; + // We need to make two passes, as the objects in the script might be in the + // wrong order (e.g. in the demo of Iceman) - refer to bug #3034713 + for (int pass = 1; pass <= 2; pass++) { + const byte *seeker = _buf + (oldScriptHeader ? 2 : 0); - switch (objType) { - case SCI_OBJ_OBJECT: - case SCI_OBJ_CLASS: - { - reg_t addr = make_reg(segmentId, seeker - _buf + 4); - Object *obj = scriptObjInit(addr); - obj->initSpecies(segMan, addr); + do { + uint16 objType = READ_SCI11ENDIAN_UINT16(seeker); + if (!objType) + break; - if (!obj->initBaseObject(segMan, addr)) { - if ((_nr == 202 || _nr == 764) && g_sci->getGameId() == GID_KQ5) { - // WORKAROUND: Script 202 of KQ5 French and German - // (perhaps Spanish too?) has an invalid object. - // This is non-fatal. Refer to bug #3035396. - // Same happens with script 764, it seems to contain junk towards its end - } else { - error("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr)); + switch (objType) { + case SCI_OBJ_OBJECT: + case SCI_OBJ_CLASS: + { + reg_t addr = make_reg(segmentId, seeker - _buf + 4); + Object *obj = scriptObjInit(addr); + obj->initSpecies(segMan, addr); + + if (pass == 2) { + if (!obj->initBaseObject(segMan, addr)) { + error("Failed to locate base object for object at %04X:%04X", PRINT_REG(addr)); + //scriptObjRemove(addr); + } } - scriptObjRemove(addr); } + break; + + default: + break; } - break; - default: - break; - } - - seeker += READ_SCI11ENDIAN_UINT16(seeker + 2); - } while ((uint32)(seeker - _buf) < getScriptSize() - 2); + seeker += READ_SCI11ENDIAN_UINT16(seeker + 2); + } while ((uint32)(seeker - _buf) < getScriptSize() - 2); + } byte *relocationBlock = findBlockSCI0(SCI_OBJ_POINTERS); if (relocationBlock) diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index 03c470b4e0f..18d71577472 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -136,12 +136,6 @@ public: */ Object *scriptObjInit(reg_t obj_pos, bool fullObjectInit = true); - /** - * Removes a script object - * @param obj_pos Location (segment, offset) of the object. - */ - void scriptObjRemove(reg_t obj_pos); - /** * Initializes the script's local variables * @param segMan A reference to the segment manager