diff options
author | Neeraj Kumar | 2010-06-08 17:24:29 +0000 |
---|---|---|
committer | Neeraj Kumar | 2010-06-08 17:24:29 +0000 |
commit | 207a5e0779de9f0002b0b1984bde90ce6597e1f2 (patch) | |
tree | 98883ef89261afd4288f6dadbffe436d5d966dfc /engines/sci/engine/script.cpp | |
parent | e00e94ae18aeb1ed460476f822e20b5bdfe171a4 (diff) | |
parent | 356728dab7f2c4cedf73684d7fe3b968be7396fd (diff) | |
download | scummvm-rg350-207a5e0779de9f0002b0b1984bde90ce6597e1f2.tar.gz scummvm-rg350-207a5e0779de9f0002b0b1984bde90ce6597e1f2.tar.bz2 scummvm-rg350-207a5e0779de9f0002b0b1984bde90ce6597e1f2.zip |
updated my outdate copy of trunk, added couple of more tests in gfxtests
svn-id: r49510
Diffstat (limited to 'engines/sci/engine/script.cpp')
-rw-r--r-- | engines/sci/engine/script.cpp | 277 |
1 files changed, 78 insertions, 199 deletions
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index e9b1ce3f28..1f32e50b67 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -123,13 +123,13 @@ void SegManager::createClassTable() { error("SegManager: failed to open vocab 996"); int totalClasses = vocab996->size >> 2; - _classtable.resize(totalClasses); + _classTable.resize(totalClasses); for (uint16 classNr = 0; classNr < totalClasses; classNr++) { uint16 scriptNr = READ_SCI11ENDIAN_UINT16(vocab996->data + classNr * 4 + 2); - _classtable[classNr].reg = NULL_REG; - _classtable[classNr].script = scriptNr; + _classTable[classNr].reg = NULL_REG; + _classTable[classNr].script = scriptNr; } _resMan->unlockResource(vocab996); @@ -139,11 +139,11 @@ reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, reg_t caller if (classnr == 0xffff) return NULL_REG; - if (classnr < 0 || (int)_classtable.size() <= classnr || _classtable[classnr].script < 0) { - error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classtable.size()); + if (classnr < 0 || (int)_classTable.size() <= classnr || _classTable[classnr].script < 0) { + error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classTable.size()); return NULL_REG; } else { - Class *the_class = &_classtable[classnr]; + Class *the_class = &_classTable[classnr]; if (!the_class->reg.segment) { getScriptSegment(the_class->script, lock); @@ -175,7 +175,7 @@ void SegManager::scriptInitialiseLocals(reg_t location) { Script *scr = getScript(location.segment); unsigned int count; - VERIFY(location.offset + 1 < (uint16)scr->_bufSize, "Locals beyond end of script\n"); + VERIFY(location.offset + 1 < (uint16)scr->getBufSize(), "Locals beyond end of script\n"); if (getSciVersion() >= SCI_VERSION_1_1) count = READ_SCI11ENDIAN_UINT16(scr->_buf + location.offset - 2); @@ -185,55 +185,38 @@ void SegManager::scriptInitialiseLocals(reg_t location) { scr->_localsOffset = location.offset; - if (!(location.offset + count * 2 + 1 < scr->_bufSize)) { - warning("Locals extend beyond end of script: offset %04x, count %x vs size %x", location.offset, count, (uint)scr->_bufSize); - count = (scr->_bufSize - location.offset) >> 1; + if (!(location.offset + count * 2 + 1 < scr->getBufSize())) { + warning("Locals extend beyond end of script: offset %04x, count %x vs size %x", location.offset, count, (uint)scr->getBufSize()); + count = (scr->getBufSize() - location.offset) >> 1; } LocalVariables *locals = allocLocalsSegment(scr, count); if (locals) { uint i; - byte *base = (byte *)(scr->_buf + location.offset); + const byte *base = (const byte *)(scr->_buf + location.offset); for (i = 0; i < count; i++) locals->_locals[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(base + i * 2)); } } -void SegManager::scriptRelocateExportsSci11(SegmentId seg) { - Script *scr = getScript(seg); - for (int i = 0; i < scr->_numExports; i++) { - /* We are forced to use an ugly heuristic here to distinguish function - exports from object/class exports. The former kind points into the - script resource, the latter into the heap resource. */ - uint16 location = READ_SCI11ENDIAN_UINT16((byte *)(scr->_exportTable + i)); - - if ((location < scr->_heapSize - 1) && (READ_SCI11ENDIAN_UINT16(scr->_heapStart + location) == SCRIPT_OBJECT_MAGIC_NUMBER)) { - WRITE_SCI11ENDIAN_UINT16((byte *)(scr->_exportTable + i), location + scr->_heapStart - scr->_buf); - } else { - // Otherwise it's probably a function export, - // and we don't need to do anything. - } - } -} - void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { Script *scr = getScript(seg); - byte *seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2; + const byte *seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2; while (READ_SCI11ENDIAN_UINT16(seeker) == SCRIPT_OBJECT_MAGIC_NUMBER) { - if (READ_SCI11ENDIAN_UINT16(seeker + 14) & SCRIPT_INFO_CLASS) { + if (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass) { // -info- selector int classpos = seeker - scr->_buf; int species = READ_SCI11ENDIAN_UINT16(seeker + 10); - if (species < 0 || species >= (int)_classtable.size()) { + if (species < 0 || species >= (int)_classTable.size()) { error("Invalid species %d(0x%x) not in interval [0,%d) while instantiating script %d", - species, species, _classtable.size(), scr->_nr); + species, species, _classTable.size(), scr->_nr); return; } - _classtable[species].reg.segment = seg; - _classtable[species].reg.offset = classpos; + _classTable[species].reg.segment = seg; + _classTable[species].reg.offset = classpos; } seeker += READ_SCI11ENDIAN_UINT16(seeker + 2) * 2; } @@ -243,19 +226,20 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { reg_t reg = make_reg(seg, seeker - scr->_buf); Object *obj = scr->scriptObjInit(reg); -#if 0 - if (obj->_variables[5].offset != 0xffff) { - obj->_variables[5] = INST_LOOKUP_CLASS(obj->_variables[5].offset); - baseObj = getObject(obj->_variables[5]); - obj->variable_names_nr = baseObj->variables_nr; - obj->_baseObj = baseObj->_baseObj; - } -#endif - // Copy base from species class, as we need its selector IDs obj->setSuperClassSelector( getClassAddress(obj->getSuperClassSelector().offset, SCRIPT_GET_LOCK, NULL_REG)); + // If object is instance, get -propDict- from class and set it for this object + // This is needed for ::isMemberOf() to work. + // Example testcase - room 381 of sq4cd - if isMemberOf() doesn't work, talk-clicks on the robot will act like + // clicking on ego + if (!obj->isClass()) { + reg_t classObject = obj->getSuperClassSelector(); + Object *classObj = getObject(classObject); + obj->setPropDictSelector(classObj->getPropDictSelector()); + } + // Set the -classScript- selector to the script number. // FIXME: As this selector is filled in at run-time, it is likely // that it is supposed to hold a pointer. The Obj::isKindOf method @@ -268,86 +252,24 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { } } - - -int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, Resource **script, Resource **heap, int *was_new) { - *was_new = 1; - - *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0); - if (getSciVersion() >= SCI_VERSION_1_1) - *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0); - - if (!*script || (getSciVersion() >= SCI_VERSION_1_1 && !heap)) { - warning("Script 0x%x requested but not found", script_nr); - if (getSciVersion() >= SCI_VERSION_1_1) { - if (*heap) - warning("Inconsistency: heap resource WAS found"); - else if (*script) - warning("Inconsistency: script resource WAS found"); - } - return 0; - } - - SegmentId seg_id = segMan->getScriptSegment(script_nr); - Script *scr = segMan->getScriptIfLoaded(seg_id); - if (scr) { - if (!scr->isMarkedAsDeleted()) { - scr->incrementLockers(); - return seg_id; - } else { - scr->freeScript(); - } - } else { - scr = segMan->allocateScript(script_nr, &seg_id); - if (!scr) { // ALL YOUR SCRIPT BASE ARE BELONG TO US - error("Not enough heap space for script size 0x%x of script 0x%x (Should this happen?)", (*script)->size, script_nr); - return 0; - } - } - - scr->init(script_nr, resMan); - - // Set heap position (beyond the size word) - scr->setLockers(1); - scr->setExportTableOffset(0); - scr->setSynonymsOffset(0); - scr->setSynonymsNr(0); - - *was_new = 0; - - return seg_id; -} - -#define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : segMan->getClassAddress(id, SCRIPT_GET_LOCK, addr)) - -int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int script_nr) { +void script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) { int objType; uint32 objLength = 0; - int relocation = -1; - Resource *script; - int was_new; bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); - const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, NULL, &was_new); uint16 curOffset = oldScriptHeader ? 2 : 0; - if (was_new) - return seg_id; - - Script *scr = segMan->getScript(seg_id); - scr->mcpyInOut(0, script->data, script->size); - if (oldScriptHeader) { // Old script block // There won't be a localvar block in this case // Instead, the script starts with a 16 bit int specifying the // number of locals we need; these are then allocated and zeroed. - int locals_nr = READ_LE_UINT16(script->data); - if (locals_nr) - segMan->scriptInitialiseLocalsZero(seg_id, locals_nr); + int localsCount = READ_LE_UINT16(scr->_buf); + if (localsCount) + segMan->scriptInitialiseLocalsZero(segmentId, localsCount); } // Now do a first pass through the script objects to find the - // export table and local variable block + // local variable blocks do { objType = scr->getHeap(curOffset); @@ -355,48 +277,30 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr break; objLength = scr->getHeap(curOffset + 2); - - // This happens in some demos (e.g. the EcoQuest 1 demo). Not sure what is the - // actual cause of it, but the scripts of these demos can't be loaded properly - // and we're stuck forever in this loop, as objLength never changes - if (!objLength) { - warning("script_instantiate_sci0: objLength is 0, unable to parse script"); - return 0; - } - curOffset += 4; // skip header switch (objType) { - case SCI_OBJ_EXPORTS: - scr->setExportTableOffset(curOffset); - break; - case SCI_OBJ_SYNONYMS: - scr->setSynonymsOffset(curOffset); - scr->setSynonymsNr((objLength) / 4); - break; case SCI_OBJ_LOCALVARS: - segMan->scriptInitialiseLocals(make_reg(seg_id, curOffset)); + segMan->scriptInitialiseLocals(make_reg(segmentId, curOffset)); break; - case SCI_OBJ_CLASS: { int classpos = curOffset - SCRIPT_OBJECT_MAGIC_OFFSET; int species = scr->getHeap(curOffset - SCRIPT_OBJECT_MAGIC_OFFSET + SCRIPT_SPECIES_OFFSET); - if (species < 0 || species >= (int)segMan->_classtable.size()) { - if (species == (int)segMan->_classtable.size()) { + if (species < 0 || species >= (int)segMan->classTableSize()) { + if (species == (int)segMan->classTableSize()) { // Happens in the LSL2 demo warning("Applying workaround for an off-by-one invalid species access"); - segMan->_classtable.resize(segMan->_classtable.size() + 1); + segMan->resizeClassTable(segMan->classTableSize() + 1); } else { - warning("Invalid species %d(0x%x) not in interval " - "[0,%d) while instantiating script %d\n", - species, species, segMan->_classtable.size(), - script_nr); - return 0; + error("Invalid species %d(0x%x) not in interval " + "[0,%d) while instantiating script at segment %d\n", + species, species, segMan->classTableSize(), + segmentId); + return; } } - segMan->_classtable[species].reg.segment = seg_id; - segMan->_classtable[species].reg.offset = classpos; + segMan->setClassOffset(species, make_reg(segmentId, classpos)); // Set technical class position-- into the block allocated for it } break; @@ -406,7 +310,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr } curOffset += objLength - 4; - } while (objType != 0 && curOffset < script->size - 2); + } while (objType != 0 && curOffset < scr->getScriptSize() - 2); // And now a second pass to adjust objects and class pointers, and the general pointers objLength = 0; @@ -420,7 +324,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr objLength = scr->getHeap(curOffset + 2); curOffset += 4; // skip header - reg_t addr = make_reg(seg_id, curOffset); + reg_t addr = make_reg(segmentId, curOffset); switch (objType) { case SCI_OBJ_CODE: @@ -429,77 +333,52 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr case SCI_OBJ_OBJECT: case SCI_OBJ_CLASS: { // object or class? Object *obj = scr->scriptObjInit(addr); + obj->initSpecies(segMan, addr); - // Instantiate the superclass, if neccessary - obj->setSpeciesSelector(INST_LOOKUP_CLASS(obj->getSpeciesSelector().offset)); - - Object *baseObj = segMan->getObject(obj->getSpeciesSelector()); - - if (baseObj) { - obj->setVarCount(baseObj->getVarCount()); - // Copy base from species class, as we need its selector IDs - obj->_baseObj = baseObj->_baseObj; - - obj->setSuperClassSelector(INST_LOOKUP_CLASS(obj->getSuperClassSelector().offset)); - } else { + if (!obj->initBaseObject(segMan, addr)) { warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr)); - scr->scriptObjRemove(addr); } } // if object or class break; - case SCI_OBJ_POINTERS: // A relocation table - relocation = addr.offset; - break; - default: break; } curOffset += objLength - 4; - } while (objType != 0 && curOffset < script->size - 2); - - if (relocation >= 0) - scr->scriptRelocate(make_reg(seg_id, relocation)); - - return seg_id; // instantiation successful + } while (objType != 0 && curOffset < scr->getScriptSize() - 2); } -int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int script_nr) { - Resource *script, *heap; - int was_new; - const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, &heap, &was_new); - - if (was_new) - return seg_id; - - Script *scr = segMan->getScript(seg_id); - int _heapStart = script->size; - - if (script->size & 2) - _heapStart++; - - scr->mcpyInOut(0, script->data, script->size); - scr->mcpyInOut(_heapStart, heap->data, heap->size); - - if (READ_SCI11ENDIAN_UINT16(script->data + 6) > 0) - scr->setExportTableOffset(6); - - segMan->scriptInitialiseLocals(make_reg(seg_id, _heapStart + 4)); - - segMan->scriptRelocateExportsSci11(seg_id); - segMan->scriptInitialiseObjectsSci11(seg_id); +int script_instantiate(ResourceManager *resMan, SegManager *segMan, int scriptNum) { + SegmentId segmentId = segMan->getScriptSegment(scriptNum); + Script *scr = segMan->getScriptIfLoaded(segmentId); + if (scr) { + if (!scr->isMarkedAsDeleted()) { + scr->incrementLockers(); + return segmentId; + } else { + scr->freeScript(); + } + } else { + scr = segMan->allocateScript(scriptNum, &segmentId); + } - scr->heapRelocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(heap->data))); + scr->init(scriptNum, resMan); + scr->load(resMan); - return seg_id; -} + if (getSciVersion() >= SCI_VERSION_1_1) { + int heapStart = scr->getScriptSize(); + segMan->scriptInitialiseLocals(make_reg(segmentId, heapStart + 4)); + segMan->scriptInitialiseObjectsSci11(segmentId); + scr->relocate(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); + } else { + script_instantiate_sci0(scr, segmentId, segMan); + byte *relocationBlock = scr->findBlock(SCI_OBJ_POINTERS); + if (relocationBlock) + scr->relocate(make_reg(segmentId, relocationBlock - scr->_buf + 4)); + } -int script_instantiate(ResourceManager *resMan, SegManager *segMan, int script_nr) { - if (getSciVersion() >= SCI_VERSION_1_1) - return script_instantiate_sci11(resMan, segMan, script_nr); - else - return script_instantiate_sci0(resMan, segMan, script_nr); + return segmentId; } void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg) { @@ -528,7 +407,7 @@ void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg) superclass = scr->getHeap(reg.offset + SCRIPT_SUPERCLASS_OFFSET); // Get superclass... if (superclass >= 0) { - int superclass_script = segMan->_classtable[superclass].script; + int superclass_script = segMan->getClass(superclass).script; if (superclass_script == script_nr) { if (scr->getLockers()) @@ -562,9 +441,9 @@ void script_uninstantiate(SegManager *segMan, int script_nr) { return; // Free all classtable references to this script - for (uint i = 0; i < segMan->_classtable.size(); i++) - if (segMan->_classtable[i].reg.segment == segment) - segMan->_classtable[i].reg = NULL_REG; + for (uint i = 0; i < segMan->classTableSize(); i++) + if (segMan->getClass(i).reg.segment == segment) + segMan->setClassOffset(i, NULL_REG); if (getSciVersion() < SCI_VERSION_1_1) script_uninstantiate_sci0(segMan, script_nr, segment); |