diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sci/engine/object.cpp | 273 | ||||
-rw-r--r-- | engines/sci/engine/object.h | 250 | ||||
-rw-r--r-- | engines/sci/engine/segment.cpp | 246 | ||||
-rw-r--r-- | engines/sci/engine/segment.h | 209 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 1 | ||||
-rw-r--r-- | engines/sci/engine/workarounds.cpp | 1 | ||||
-rw-r--r-- | engines/sci/module.mk | 1 | ||||
-rw-r--r-- | engines/sci/sci.cpp | 1 | ||||
-rw-r--r-- | engines/sci/sound/soundcmd.cpp | 1 |
9 files changed, 531 insertions, 452 deletions
diff --git a/engines/sci/engine/object.cpp b/engines/sci/engine/object.cpp new file mode 100644 index 0000000000..e0d366797e --- /dev/null +++ b/engines/sci/engine/object.cpp @@ -0,0 +1,273 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + + +#include "sci/engine/kernel.h" +#include "sci/engine/object.h" +#include "sci/engine/seg_manager.h" + +namespace Sci { + +// This helper function is used by Script::relocateLocal and Object::relocate +// Duplicate in segment.cpp and script.cpp +static bool relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location, size_t scriptSize) { + int rel = location - block_location; + + if (rel < 0) + return false; + + uint idx = rel >> 1; + + if (idx >= block.size()) + return false; + + if (rel & 1) { + error("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location); + return false; + } + block[idx].segment = segment; // Perform relocation + if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) + block[idx].offset += scriptSize; + + return true; +} + +void Object::init(byte *buf, reg_t obj_pos, bool initVariables) { + byte *data = buf + obj_pos.offset; + _baseObj = data; + _pos = obj_pos; + + if (getSciVersion() <= SCI_VERSION_1_LATE) { + _variables.resize(READ_LE_UINT16(data + kOffsetSelectorCounter)); + _baseVars = (const uint16 *)(_baseObj + _variables.size() * 2); + _baseMethod = (const uint16 *)(data + READ_LE_UINT16(data + kOffsetFunctionArea)); + _methodCount = READ_LE_UINT16(_baseMethod - 1); + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2)); + _baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4)); + _baseMethod = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6)); + _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod); + } else if (getSciVersion() == SCI_VERSION_3) { + initSelectorsSci3(buf); + } + + if (initVariables) { + if (getSciVersion() <= SCI_VERSION_2_1) { + for (uint i = 0; i < _variables.size(); i++) + _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2))); + } else { + _infoSelectorSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 10)); + } + } +} + +const Object *Object::getClass(SegManager *segMan) const { + return isClass() ? this : segMan->getObject(getSuperClassSelector()); +} + +int Object::locateVarSelector(SegManager *segMan, Selector slc) const { + const byte *buf = 0; + uint varnum = 0; + + if (getSciVersion() <= SCI_VERSION_1_LATE) { + varnum = getVarCount(); + int selector_name_offset = varnum * 2 + kOffsetSelectorSegment; + buf = _baseObj + selector_name_offset; + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + const Object *obj = getClass(segMan); + varnum = obj->getVariable(1).toUint16(); + buf = (const byte *)obj->_baseVars; + } else if (getSciVersion() == SCI_VERSION_3) { + varnum = _variables.size(); + buf = (const byte *)_baseVars; + } + + for (uint i = 0; i < varnum; i++) + if (READ_SCI11ENDIAN_UINT16(buf + (i << 1)) == slc) // Found it? + return i; // report success + + return -1; // Failed +} + +bool Object::relocateSci0Sci21(SegmentId segment, int location, size_t scriptSize) { + return relocateBlock(_variables, getPos().offset, segment, location, scriptSize); +} + +bool Object::relocateSci3(SegmentId segment, int location, int offset, size_t scriptSize) { + assert(_propertyOffsetsSci3); + + for (uint i = 0; i < _variables.size(); ++i) { + if (location == _propertyOffsetsSci3[i]) { + _variables[i].segment = segment; + _variables[i].offset += offset; + return true; + } + } + + return false; +} + +int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const { + int selectors = getVarCount(); + + if (propertyOffset < 0 || (propertyOffset >> 1) >= selectors) { + error("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d])", + propertyOffset, propertyOffset >> 1, selectors - 1); + return -1; + } + + if (getSciVersion() < SCI_VERSION_1_1) { + const byte *selectoroffset = ((const byte *)(_baseObj)) + kOffsetSelectorSegment + selectors * 2; + return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset); + } else { + const Object *obj = this; + if (!isClass()) + obj = segMan->getObject(getSuperClassSelector()); + + return READ_SCI11ENDIAN_UINT16((const byte *)obj->_baseVars + propertyOffset); + } +} + +void Object::initSpecies(SegManager *segMan, reg_t addr) { + uint16 speciesOffset = getSpeciesSelector().offset; + + if (speciesOffset == 0xffff) // -1 + setSpeciesSelector(NULL_REG); // no species + else + setSpeciesSelector(segMan->getClassAddress(speciesOffset, SCRIPT_GET_LOCK, addr)); +} + +void Object::initSuperClass(SegManager *segMan, reg_t addr) { + uint16 superClassOffset = getSuperClassSelector().offset; + + if (superClassOffset == 0xffff) // -1 + setSuperClassSelector(NULL_REG); // no superclass + else + setSuperClassSelector(segMan->getClassAddress(superClassOffset, SCRIPT_GET_LOCK, addr)); +} + +bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass) { + const Object *baseObj = segMan->getObject(getSpeciesSelector()); + + if (baseObj) { + _variables.resize(baseObj->getVarCount()); + // Copy base from species class, as we need its selector IDs + _baseObj = baseObj->_baseObj; + if (doInitSuperClass) + initSuperClass(segMan, addr); + return true; + } + + return false; +} + +const int EXTRA_GROUPS = 3; + +void Object::initSelectorsSci3(const byte *buf) { + const byte *groupInfo = _baseObj + 16; + const byte *selectorBase = groupInfo + EXTRA_GROUPS * 32 * 2; + int groups = g_sci->getKernel()->getSelectorNamesSize()/32; + int methods, properties; + + if (g_sci->getKernel()->getSelectorNamesSize() % 32) + ++groups; + + methods = properties = 0; + + // Selectors are divided into groups of 32, of which the first + // two selectors are always reserved (because their storage + // space is used by the typeMask). + // We don't know beforehand how many methods and properties + // there are, so we count them first. + for (int groupNr = 0; groupNr < groups; ++groupNr) { + byte groupLocation = groupInfo[groupNr]; + const byte *seeker = selectorBase + groupLocation * 32 * 2; + + if (groupLocation != 0) { + // This object actually has selectors belonging to this group + int typeMask = READ_SCI11ENDIAN_UINT32(seeker); + + for (int bit = 2; bit < 32; ++bit) { + int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2); + if (typeMask & (1 << bit)) { // Property + ++properties; + } else if (value != 0xffff) { // Method + ++methods; + } else { + // Undefined selector + } + + } + } + } + + _variables.resize(properties); + uint16 *methodIds = (uint16*) malloc(sizeof(uint16)*2*methods); + uint16 *propertyIds = (uint16*) malloc(sizeof(uint16)*properties); + uint16 *methodOffsets = (uint16*) malloc(sizeof(uint16)*2*methods); + uint16 *propertyOffsets = (uint16*) malloc(sizeof(uint16)*properties); + int propertyCounter = 0; + int methodCounter = 0; + + // Go through the whole thing again to get the property values + // and method pointers + for (int groupNr = 0; groupNr < groups; ++groupNr) { + byte groupLocation = groupInfo[groupNr]; + const byte *seeker = selectorBase + groupLocation * 32 * 2; + + if (groupLocation != 0) { + // This object actually has selectors belonging to this group + int typeMask = READ_SCI11ENDIAN_UINT32(seeker); + int groupBaseId = groupNr * 32; + + for (int bit = 2; bit < 32; ++bit) { + int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2); + if (typeMask & (1 << bit)) { // Property + propertyIds[propertyCounter] = groupBaseId + bit; + _variables[propertyCounter] = make_reg(0, value); + propertyOffsets[propertyCounter] = (seeker + bit * 2) - buf; + ++propertyCounter; + } else if (value != 0xffff) { // Method + methodIds[methodCounter * 2] = groupBaseId + bit; + methodIds[methodCounter * 2 + 1] = value + READ_SCI11ENDIAN_UINT32(buf); + methodOffsets[methodCounter] = (seeker + bit * 2) - buf; + ++methodCounter; + } else /* Undefined selector */ {}; + + } + } + } + + _speciesSelectorSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 4)); + _superClassPosSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 8)); + + _baseVars = propertyIds; + _baseMethod = methodIds; + _methodCount = methods; + _propertyOffsetsSci3 = propertyOffsets; + //_methodOffsetsSci3 = methodOffsets; +} + +} // End of namespace Sci diff --git a/engines/sci/engine/object.h b/engines/sci/engine/object.h new file mode 100644 index 0000000000..19ae5fea60 --- /dev/null +++ b/engines/sci/engine/object.h @@ -0,0 +1,250 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SCI_ENGINE_OBJECT_H +#define SCI_ENGINE_OBJECT_H + +#include "common/array.h" +#include "common/serializer.h" + +#include "sci/sci.h" // for the SCI versions +#include "sci/engine/vm_types.h" // for reg_t +#include "sci/util.h" + +namespace Sci { + +class SegManager; + +/** Clone has been marked as 'freed' */ +enum { + OBJECT_FLAG_FREED = (1 << 0) +}; + +enum infoSelectorFlags { + kInfoFlagClone = 0x0001, + kInfoFlagClass = 0x8000 +}; + +enum ObjectOffsets { + kOffsetLocalVariables = -6, + kOffsetFunctionArea = -4, + kOffsetSelectorCounter = -2, + kOffsetSelectorSegment = 0, + kOffsetInfoSelectorSci0 = 4, + kOffsetNamePointerSci0 = 6, + kOffsetInfoSelectorSci11 = 14, + kOffsetNamePointerSci11 = 16 +}; + +class Object { +public: + Object() { + _offset = getSciVersion() < SCI_VERSION_1_1 ? 0 : 5; + _flags = 0; + _baseObj = 0; + _baseVars = 0; + _baseMethod = 0; + _methodCount = 0; + _propertyOffsetsSci3 = 0; + } + + ~Object() { } + + reg_t getSpeciesSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[_offset]; + else // SCI3 + return _speciesSelectorSci3; + } + + void setSpeciesSelector(reg_t value) { + if (getSciVersion() <= SCI_VERSION_2_1) + _variables[_offset] = value; + else // SCI3 + _speciesSelectorSci3 = value; + } + + reg_t getSuperClassSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[_offset + 1]; + else // SCI3 + return _superClassPosSci3; + } + + void setSuperClassSelector(reg_t value) { + if (getSciVersion() <= SCI_VERSION_2_1) + _variables[_offset + 1] = value; + else // SCI3 + _superClassPosSci3 = value; + } + + reg_t getInfoSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[_offset + 2]; + else // SCI3 + return _infoSelectorSci3; + } + + void setInfoSelector(reg_t info) { + if (getSciVersion() <= SCI_VERSION_2_1) + _variables[_offset + 2] = info; + else // SCI3 + _infoSelectorSci3 = info; + } + + // No setter for the -info- selector + + reg_t getNameSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _offset + 3 < (uint16)_variables.size() ? _variables[_offset + 3] : NULL_REG; + else // SCI3 + return _variables.size() ? _variables[0] : NULL_REG; + } + + // No setter for the name selector + + reg_t getPropDictSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[2]; + else + // This should never occur, this is called from a SCI1.1 - SCI2.1 only function + error("getPropDictSelector called for SCI3"); + } + + void setPropDictSelector(reg_t value) { + if (getSciVersion() <= SCI_VERSION_2_1) + _variables[2] = value; + else + // This should never occur, this is called from a SCI1.1 - SCI2.1 only function + error("setPropDictSelector called for SCI3"); + } + + reg_t getClassScriptSelector() const { + if (getSciVersion() <= SCI_VERSION_2_1) + return _variables[4]; + else // SCI3 + return make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 6)); + } + + void setClassScriptSelector(reg_t value) { + if (getSciVersion() <= SCI_VERSION_2_1) + _variables[4] = value; + else // SCI3 + // This should never occur, this is called from a SCI1.1 - SCI2.1 only function + error("setClassScriptSelector called for SCI3"); + } + + Selector getVarSelector(uint16 i) const { return READ_SCI11ENDIAN_UINT16(_baseVars + i); } + + reg_t getFunction(uint16 i) const { + uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? _methodCount + 1 + i : i * 2 + 2; + if (getSciVersion() == SCI_VERSION_3) + offset--; + return make_reg(_pos.segment, READ_SCI11ENDIAN_UINT16(_baseMethod + offset)); + } + + Selector getFuncSelector(uint16 i) const { + uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? i : i * 2 + 1; + if (getSciVersion() == SCI_VERSION_3) + offset--; + return READ_SCI11ENDIAN_UINT16(_baseMethod + offset); + } + + /** + * Determines if this object is a class and explicitly defines the + * selector as a funcselector. Does NOT say anything about the object's + * superclasses, i.e. failure may be returned even if one of the + * superclasses defines the funcselector + */ + int funcSelectorPosition(Selector sel) const { + for (uint i = 0; i < _methodCount; i++) + if (getFuncSelector(i) == sel) + return i; + + return -1; + } + + /** + * Determines if the object explicitly defines slc as a varselector. + * Returns -1 if not found. + */ + int locateVarSelector(SegManager *segMan, Selector slc) const; + + bool isClass() const { return (getInfoSelector().offset & kInfoFlagClass); } + const Object *getClass(SegManager *segMan) const; + + void markAsFreed() { _flags |= OBJECT_FLAG_FREED; } + bool isFreed() const { return _flags & OBJECT_FLAG_FREED; } + + uint getVarCount() const { return _variables.size(); } + + void init(byte *buf, reg_t obj_pos, bool initVariables = true); + + reg_t getVariable(uint var) const { return _variables[var]; } + reg_t &getVariableRef(uint var) { return _variables[var]; } + + uint16 getMethodCount() const { return _methodCount; } + reg_t getPos() const { return _pos; } + + void saveLoadWithSerializer(Common::Serializer &ser); + + void cloneFromObject(const Object *obj) { + _baseObj = obj ? obj->_baseObj : NULL; + _baseMethod = obj ? obj->_baseMethod : NULL; + _baseVars = obj ? obj->_baseVars : NULL; + } + + bool relocateSci0Sci21(SegmentId segment, int location, size_t scriptSize); + bool relocateSci3(SegmentId segment, int location, int offset, size_t scriptSize); + + int propertyOffsetToId(SegManager *segMan, int propertyOffset) const; + + void initSpecies(SegManager *segMan, reg_t addr); + void initSuperClass(SegManager *segMan, reg_t addr); + bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true); + void syncBaseObject(const byte *ptr) { _baseObj = ptr; } + +private: + void initSelectorsSci3(const byte *buf); + + const byte *_baseObj; /**< base + object offset within base */ + const uint16 *_baseVars; /**< Pointer to the varselector area for this object */ + const uint16 *_baseMethod; /**< Pointer to the method selector area for this object */ + const uint16 *_propertyOffsetsSci3; + + Common::Array<reg_t> _variables; + uint16 _methodCount; + int _flags; + uint16 _offset; + reg_t _pos; /**< Object offset within its script; for clones, this is their base */ + reg_t _superClassPosSci3; /**< reg_t pointing to superclass for SCI3 */ + reg_t _speciesSelectorSci3; /**< reg_t containing species "selector" for SCI3 */ + reg_t _infoSelectorSci3; /**< reg_t containing info "selector" for SCI3 */ +}; + + +} // End of namespace Sci + +#endif // SCI_ENGINE_SEGMENT_H diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 69b9153621..e40777755f 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -28,6 +28,7 @@ #include "sci/sci.h" #include "sci/engine/kernel.h" #include "sci/engine/features.h" +#include "sci/engine/object.h" #include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS #include "sci/engine/segment.h" #include "sci/engine/seg_manager.h" @@ -131,30 +132,6 @@ const char *SegmentObj::getSegmentTypeName(SegmentType type) { return NULL; } -// This helper function is used by Script::relocateLocal and Object::relocate -// Duplicate in segment.cpp and script.cpp -static bool relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location, size_t scriptSize) { - int rel = location - block_location; - - if (rel < 0) - return false; - - uint idx = rel >> 1; - - if (idx >= block.size()) - return false; - - if (rel & 1) { - error("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location); - return false; - } - block[idx].segment = segment; // Perform relocation - if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) - block[idx].offset += scriptSize; - - return true; -} - SegmentRef SegmentObj::dereference(reg_t pointer) { error("Error: Trying to dereference pointer %04x:%04x to inappropriate segment", PRINT_REG(pointer)); @@ -370,227 +347,6 @@ Common::Array<reg_t> NodeTable::listAllOutgoingReferences(reg_t addr) const { return tmp; } - -//-------------------- hunk -------------------- - -//-------------------- object ---------------------------- - -void Object::init(byte *buf, reg_t obj_pos, bool initVariables) { - byte *data = buf + obj_pos.offset; - _baseObj = data; - _pos = obj_pos; - - if (getSciVersion() <= SCI_VERSION_1_LATE) { - _variables.resize(READ_LE_UINT16(data + kOffsetSelectorCounter)); - _baseVars = (const uint16 *)(_baseObj + _variables.size() * 2); - _baseMethod = (const uint16 *)(data + READ_LE_UINT16(data + kOffsetFunctionArea)); - _methodCount = READ_LE_UINT16(_baseMethod - 1); - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { - _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2)); - _baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4)); - _baseMethod = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6)); - _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod); - } else if (getSciVersion() == SCI_VERSION_3) { - initSelectorsSci3(buf); - } - - if (initVariables) { - if (getSciVersion() <= SCI_VERSION_2_1) { - for (uint i = 0; i < _variables.size(); i++) - _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2))); - } else { - _infoSelectorSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 10)); - } - } -} - -const Object *Object::getClass(SegManager *segMan) const { - return isClass() ? this : segMan->getObject(getSuperClassSelector()); -} - -int Object::locateVarSelector(SegManager *segMan, Selector slc) const { - const byte *buf = 0; - uint varnum = 0; - - if (getSciVersion() <= SCI_VERSION_1_LATE) { - varnum = getVarCount(); - int selector_name_offset = varnum * 2 + kOffsetSelectorSegment; - buf = _baseObj + selector_name_offset; - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { - const Object *obj = getClass(segMan); - varnum = obj->getVariable(1).toUint16(); - buf = (const byte *)obj->_baseVars; - } else if (getSciVersion() == SCI_VERSION_3) { - varnum = _variables.size(); - buf = (const byte *)_baseVars; - } - - for (uint i = 0; i < varnum; i++) - if (READ_SCI11ENDIAN_UINT16(buf + (i << 1)) == slc) // Found it? - return i; // report success - - return -1; // Failed -} - -bool Object::relocateSci0Sci21(SegmentId segment, int location, size_t scriptSize) { - return relocateBlock(_variables, getPos().offset, segment, location, scriptSize); -} - -bool Object::relocateSci3(SegmentId segment, int location, int offset, size_t scriptSize) { - assert(_propertyOffsetsSci3); - - for (uint i = 0; i < _variables.size(); ++i) { - if (location == _propertyOffsetsSci3[i]) { - _variables[i].segment = segment; - _variables[i].offset += offset; - return true; - } - } - - return false; -} - -int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const { - int selectors = getVarCount(); - - if (propertyOffset < 0 || (propertyOffset >> 1) >= selectors) { - error("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d])", - propertyOffset, propertyOffset >> 1, selectors - 1); - return -1; - } - - if (getSciVersion() < SCI_VERSION_1_1) { - const byte *selectoroffset = ((const byte *)(_baseObj)) + kOffsetSelectorSegment + selectors * 2; - return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset); - } else { - const Object *obj = this; - if (!isClass()) - obj = segMan->getObject(getSuperClassSelector()); - - return READ_SCI11ENDIAN_UINT16((const byte *)obj->_baseVars + propertyOffset); - } -} - -void Object::initSpecies(SegManager *segMan, reg_t addr) { - uint16 speciesOffset = getSpeciesSelector().offset; - - if (speciesOffset == 0xffff) // -1 - setSpeciesSelector(NULL_REG); // no species - else - setSpeciesSelector(segMan->getClassAddress(speciesOffset, SCRIPT_GET_LOCK, addr)); -} - -void Object::initSuperClass(SegManager *segMan, reg_t addr) { - uint16 superClassOffset = getSuperClassSelector().offset; - - if (superClassOffset == 0xffff) // -1 - setSuperClassSelector(NULL_REG); // no superclass - else - setSuperClassSelector(segMan->getClassAddress(superClassOffset, SCRIPT_GET_LOCK, addr)); -} - -bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass) { - const Object *baseObj = segMan->getObject(getSpeciesSelector()); - - if (baseObj) { - _variables.resize(baseObj->getVarCount()); - // Copy base from species class, as we need its selector IDs - _baseObj = baseObj->_baseObj; - if (doInitSuperClass) - initSuperClass(segMan, addr); - return true; - } - - return false; -} - -const int EXTRA_GROUPS = 3; - -void Object::initSelectorsSci3(const byte *buf) { - const byte *groupInfo = _baseObj + 16; - const byte *selectorBase = groupInfo + EXTRA_GROUPS * 32 * 2; - int groups = g_sci->getKernel()->getSelectorNamesSize()/32; - int methods, properties; - - if (g_sci->getKernel()->getSelectorNamesSize() % 32) - ++groups; - - methods = properties = 0; - - // Selectors are divided into groups of 32, of which the first - // two selectors are always reserved (because their storage - // space is used by the typeMask). - // We don't know beforehand how many methods and properties - // there are, so we count them first. - for (int groupNr = 0; groupNr < groups; ++groupNr) { - byte groupLocation = groupInfo[groupNr]; - const byte *seeker = selectorBase + groupLocation * 32 * 2; - - if (groupLocation != 0) { - // This object actually has selectors belonging to this group - int typeMask = READ_SCI11ENDIAN_UINT32(seeker); - - for (int bit = 2; bit < 32; ++bit) { - int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2); - if (typeMask & (1 << bit)) { // Property - ++properties; - } else if (value != 0xffff) { // Method - ++methods; - } else { - // Undefined selector - } - - } - } - } - - _variables.resize(properties); - uint16 *methodIds = (uint16*) malloc(sizeof(uint16)*2*methods); - uint16 *propertyIds = (uint16*) malloc(sizeof(uint16)*properties); - uint16 *methodOffsets = (uint16*) malloc(sizeof(uint16)*2*methods); - uint16 *propertyOffsets = (uint16*) malloc(sizeof(uint16)*properties); - int propertyCounter = 0; - int methodCounter = 0; - - // Go through the whole thing again to get the property values - // and method pointers - for (int groupNr = 0; groupNr < groups; ++groupNr) { - byte groupLocation = groupInfo[groupNr]; - const byte *seeker = selectorBase + groupLocation * 32 * 2; - - if (groupLocation != 0) { - // This object actually has selectors belonging to this group - int typeMask = READ_SCI11ENDIAN_UINT32(seeker); - int groupBaseId = groupNr * 32; - - for (int bit = 2; bit < 32; ++bit) { - int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2); - if (typeMask & (1 << bit)) { // Property - propertyIds[propertyCounter] = groupBaseId + bit; - _variables[propertyCounter] = make_reg(0, value); - propertyOffsets[propertyCounter] = (seeker + bit * 2) - buf; - ++propertyCounter; - } else if (value != 0xffff) { // Method - methodIds[methodCounter * 2] = groupBaseId + bit; - methodIds[methodCounter * 2 + 1] = value + READ_SCI11ENDIAN_UINT32(buf); - methodOffsets[methodCounter] = (seeker + bit * 2) - buf; - ++methodCounter; - } else /* Undefined selector */ {}; - - } - } - } - - _speciesSelectorSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 4)); - _superClassPosSci3 = make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 8)); - - _baseVars = propertyIds; - _baseMethod = methodIds; - _methodCount = methods; - _propertyOffsetsSci3 = propertyOffsets; - //_methodOffsetsSci3 = methodOffsets; -} - //-------------------- dynamic memory -------------------- reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) const { diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 8cebfbcb7d..aae4c9650c 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -27,6 +27,8 @@ #define SCI_ENGINE_SEGMENT_H #include "common/serializer.h" + +#include "sci/engine/object.h" #include "sci/engine/vm.h" #include "sci/engine/vm_types.h" // for reg_t #include "sci/util.h" @@ -203,213 +205,6 @@ public: virtual void saveLoadWithSerializer(Common::Serializer &ser); }; -/** Clone has been marked as 'freed' */ -enum { - OBJECT_FLAG_FREED = (1 << 0) -}; - -enum infoSelectorFlags { - kInfoFlagClone = 0x0001, - kInfoFlagClass = 0x8000 -}; - -enum ObjectOffsets { - kOffsetLocalVariables = -6, - kOffsetFunctionArea = -4, - kOffsetSelectorCounter = -2, - kOffsetSelectorSegment = 0, - kOffsetInfoSelectorSci0 = 4, - kOffsetNamePointerSci0 = 6, - kOffsetInfoSelectorSci11 = 14, - kOffsetNamePointerSci11 = 16 -}; - -class Object { -public: - Object() { - _offset = getSciVersion() < SCI_VERSION_1_1 ? 0 : 5; - _flags = 0; - _baseObj = 0; - _baseVars = 0; - _baseMethod = 0; - _methodCount = 0; - _propertyOffsetsSci3 = 0; - } - - ~Object() { } - - reg_t getSpeciesSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) - return _variables[_offset]; - else // SCI3 - return _speciesSelectorSci3; - } - - void setSpeciesSelector(reg_t value) { - if (getSciVersion() <= SCI_VERSION_2_1) - _variables[_offset] = value; - else // SCI3 - _speciesSelectorSci3 = value; - } - - reg_t getSuperClassSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) - return _variables[_offset + 1]; - else // SCI3 - return _superClassPosSci3; - } - - void setSuperClassSelector(reg_t value) { - if (getSciVersion() <= SCI_VERSION_2_1) - _variables[_offset + 1] = value; - else // SCI3 - _superClassPosSci3 = value; - } - - reg_t getInfoSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) - return _variables[_offset + 2]; - else // SCI3 - return _infoSelectorSci3; - } - - void setInfoSelector(reg_t info) { - if (getSciVersion() <= SCI_VERSION_2_1) - _variables[_offset + 2] = info; - else // SCI3 - _infoSelectorSci3 = info; - } - - // No setter for the -info- selector - - reg_t getNameSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) - return _offset + 3 < (uint16)_variables.size() ? _variables[_offset + 3] : NULL_REG; - else // SCI3 - return _variables.size() ? _variables[0] : NULL_REG; - } - - // No setter for the name selector - - reg_t getPropDictSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) - return _variables[2]; - else - // This should never occur, this is called from a SCI1.1 - SCI2.1 only function - error("getPropDictSelector called for SCI3"); - } - - void setPropDictSelector(reg_t value) { - if (getSciVersion() <= SCI_VERSION_2_1) - _variables[2] = value; - else - // This should never occur, this is called from a SCI1.1 - SCI2.1 only function - error("setPropDictSelector called for SCI3"); - } - - reg_t getClassScriptSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) - return _variables[4]; - else // SCI3 - return make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 6)); - } - - void setClassScriptSelector(reg_t value) { - if (getSciVersion() <= SCI_VERSION_2_1) - _variables[4] = value; - else // SCI3 - // This should never occur, this is called from a SCI1.1 - SCI2.1 only function - error("setClassScriptSelector called for SCI3"); - } - - Selector getVarSelector(uint16 i) const { return READ_SCI11ENDIAN_UINT16(_baseVars + i); } - - reg_t getFunction(uint16 i) const { - uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? _methodCount + 1 + i : i * 2 + 2; - if (getSciVersion() == SCI_VERSION_3) - offset--; - return make_reg(_pos.segment, READ_SCI11ENDIAN_UINT16(_baseMethod + offset)); - } - - Selector getFuncSelector(uint16 i) const { - uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? i : i * 2 + 1; - if (getSciVersion() == SCI_VERSION_3) - offset--; - return READ_SCI11ENDIAN_UINT16(_baseMethod + offset); - } - - /** - * Determines if this object is a class and explicitly defines the - * selector as a funcselector. Does NOT say anything about the object's - * superclasses, i.e. failure may be returned even if one of the - * superclasses defines the funcselector - */ - int funcSelectorPosition(Selector sel) const { - for (uint i = 0; i < _methodCount; i++) - if (getFuncSelector(i) == sel) - return i; - - return -1; - } - - /** - * Determines if the object explicitly defines slc as a varselector. - * Returns -1 if not found. - */ - int locateVarSelector(SegManager *segMan, Selector slc) const; - - bool isClass() const { return (getInfoSelector().offset & kInfoFlagClass); } - const Object *getClass(SegManager *segMan) const; - - void markAsFreed() { _flags |= OBJECT_FLAG_FREED; } - bool isFreed() const { return _flags & OBJECT_FLAG_FREED; } - - uint getVarCount() const { return _variables.size(); } - - void init(byte *buf, reg_t obj_pos, bool initVariables = true); - - reg_t getVariable(uint var) const { return _variables[var]; } - reg_t &getVariableRef(uint var) { return _variables[var]; } - - uint16 getMethodCount() const { return _methodCount; } - reg_t getPos() const { return _pos; } - - void saveLoadWithSerializer(Common::Serializer &ser); - - void cloneFromObject(const Object *obj) { - _baseObj = obj ? obj->_baseObj : NULL; - _baseMethod = obj ? obj->_baseMethod : NULL; - _baseVars = obj ? obj->_baseVars : NULL; - } - - bool relocateSci0Sci21(SegmentId segment, int location, size_t scriptSize); - bool relocateSci3(SegmentId segment, int location, int offset, size_t scriptSize); - - int propertyOffsetToId(SegManager *segMan, int propertyOffset) const; - - void initSpecies(SegManager *segMan, reg_t addr); - void initSuperClass(SegManager *segMan, reg_t addr); - bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true); - void syncBaseObject(const byte *ptr) { _baseObj = ptr; } - -private: - void initSelectorsSci3(const byte *buf); - - const byte *_baseObj; /**< base + object offset within base */ - const uint16 *_baseVars; /**< Pointer to the varselector area for this object */ - const uint16 *_baseMethod; /**< Pointer to the method selector area for this object */ - const uint16 *_propertyOffsetsSci3; - - Common::Array<reg_t> _variables; - uint16 _methodCount; - int _flags; - uint16 _offset; - reg_t _pos; /**< Object offset within its script; for clones, this is their base */ - reg_t _superClassPosSci3; /**< reg_t pointing to superclass for SCI3 */ - reg_t _speciesSelectorSci3; /**< reg_t containing species "selector" for SCI3 */ - reg_t _infoSelectorSci3; /**< reg_t containing info "selector" for SCI3 */ -}; - /** Data stack */ struct DataStack : SegmentObj { int _capacity; /**< Number of stack entries */ diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index d2db895e33..94fa016790 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -34,6 +34,7 @@ #include "sci/engine/features.h" #include "sci/engine/state.h" #include "sci/engine/kernel.h" +#include "sci/engine/object.h" #include "sci/engine/script.h" #include "sci/engine/seg_manager.h" #include "sci/engine/selector.h" // for SELECTOR diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index bed057979e..4c4cf5f74a 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -24,6 +24,7 @@ */ #include "sci/engine/kernel.h" +#include "sci/engine/object.h" #include "sci/engine/state.h" #include "sci/engine/vm.h" #include "sci/engine/workarounds.h" diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 344eef76d4..ad133e8a82 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -27,6 +27,7 @@ MODULE_OBJS := \ engine/kstring.o \ engine/kvideo.o \ engine/message.o \ + engine/object.o \ engine/savegame.o \ engine/script.o \ engine/scriptdebug.o \ diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 3ffb33f934..940c473947 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -39,6 +39,7 @@ #include "sci/engine/features.h" #include "sci/engine/message.h" +#include "sci/engine/object.h" #include "sci/engine/state.h" #include "sci/engine/kernel.h" #include "sci/engine/script.h" // for script_adjust_opcode_formats diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 790164cf41..d8cfa672ce 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -29,6 +29,7 @@ #include "sci/sound/soundcmd.h" #include "sci/engine/kernel.h" +#include "sci/engine/object.h" #include "sci/engine/selector.h" namespace Sci { |