1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef SCI_ENGINE_OBJECT_H 24 #define SCI_ENGINE_OBJECT_H 25 26 #include "common/array.h" 27 #include "common/serializer.h" 28 #include "common/textconsole.h" 29 30 #include "sci/sci.h" // for the SCI versions 31 #include "sci/engine/vm_types.h" // for reg_t 32 #include "sci/util.h" 33 34 namespace Sci { 35 36 class SegManager; 37 class Script; 38 39 enum infoSelectorFlags { 40 kInfoFlagClone = 0x0001, 41 #ifdef ENABLE_SCI32 42 /** 43 * When set, indicates to game scripts that a screen 44 * item can be updated. 45 */ 46 kInfoFlagViewVisible = 0x0008, 47 48 /** 49 * When set, the VM object has an associated ScreenItem in 50 * the rendering tree. 51 */ 52 kInfoFlagViewInserted = 0x0010, 53 #endif 54 kInfoFlagClass = 0x8000 55 }; 56 57 enum ObjectOffsets { 58 kOffsetHeaderSize = 6, 59 kOffsetHeaderLocalVariables = 0, 60 kOffsetHeaderFunctionArea = 2, 61 kOffsetHeaderSelectorCounter = 4, 62 63 kOffsetSelectorSegment = 0, 64 kOffsetInfoSelectorSci0 = 4, 65 kOffsetNamePointerSci0 = 6, 66 kOffsetInfoSelectorSci11 = 14, 67 kOffsetNamePointerSci11 = 16 68 }; 69 70 class Object : public Common::Serializable { 71 public: Object()72 Object() : 73 _name(NULL_REG), 74 _offset(getSciVersion() < SCI_VERSION_1_1 ? 0 : 5), 75 _isFreed(false), 76 _baseObj(), 77 _baseVars(), 78 _methodCount(0) 79 #ifdef ENABLE_SCI32 80 , 81 _propertyOffsetsSci3() 82 #endif 83 {} 84 85 Object &operator=(const Object &other) { 86 _name = other._name; 87 _baseObj = other._baseObj; 88 _baseMethod = other._baseMethod; 89 _variables = other._variables; 90 _methodCount = other._methodCount; 91 _isFreed = other._isFreed; 92 _offset = other._offset; 93 _pos = other._pos; 94 _baseVars = other._baseVars; 95 96 #ifdef ENABLE_SCI32 97 if (getSciVersion() == SCI_VERSION_3) { 98 _propertyOffsetsSci3 = other._propertyOffsetsSci3; 99 _superClassPosSci3 = other._superClassPosSci3; 100 _speciesSelectorSci3 = other._speciesSelectorSci3; 101 _infoSelectorSci3 = other._infoSelectorSci3; 102 _mustSetViewVisible = other._mustSetViewVisible; 103 } 104 #endif 105 106 return *this; 107 } 108 getSpeciesSelector()109 reg_t getSpeciesSelector() const { 110 #ifdef ENABLE_SCI32 111 if (getSciVersion() == SCI_VERSION_3) 112 return _speciesSelectorSci3; 113 else 114 #endif 115 return _variables[_offset]; 116 } 117 setSpeciesSelector(reg_t value)118 void setSpeciesSelector(reg_t value) { 119 #ifdef ENABLE_SCI32 120 if (getSciVersion() == SCI_VERSION_3) 121 _speciesSelectorSci3 = value; 122 else 123 #endif 124 _variables[_offset] = value; 125 } 126 getSuperClassSelector()127 reg_t getSuperClassSelector() const { 128 #ifdef ENABLE_SCI32 129 if (getSciVersion() == SCI_VERSION_3) 130 return _superClassPosSci3; 131 else 132 #endif 133 return _variables[_offset + 1]; 134 } 135 setSuperClassSelector(reg_t value)136 void setSuperClassSelector(reg_t value) { 137 #ifdef ENABLE_SCI32 138 if (getSciVersion() == SCI_VERSION_3) 139 _superClassPosSci3 = value; 140 else 141 #endif 142 _variables[_offset + 1] = value; 143 } 144 getInfoSelector()145 reg_t getInfoSelector() const { 146 #ifdef ENABLE_SCI32 147 if (getSciVersion() == SCI_VERSION_3) 148 return _infoSelectorSci3; 149 else 150 #endif 151 return _variables[_offset + 2]; 152 } 153 setInfoSelector(reg_t info)154 void setInfoSelector(reg_t info) { 155 #ifdef ENABLE_SCI32 156 if (getSciVersion() == SCI_VERSION_3) 157 _infoSelectorSci3 = info; 158 else 159 #endif 160 _variables[_offset + 2] = info; 161 } 162 163 #ifdef ENABLE_SCI32 setInfoSelectorFlag(infoSelectorFlags flag)164 void setInfoSelectorFlag(infoSelectorFlags flag) { 165 if (getSciVersion() == SCI_VERSION_3) { 166 _infoSelectorSci3 |= flag; 167 } else { 168 _variables[_offset + 2] |= flag; 169 } 170 } 171 clearInfoSelectorFlag(infoSelectorFlags flag)172 void clearInfoSelectorFlag(infoSelectorFlags flag) { 173 if (getSciVersion() == SCI_VERSION_3) { 174 _infoSelectorSci3 &= ~flag; 175 } else { 176 _variables[_offset + 2] &= ~flag; 177 } 178 } 179 isInserted()180 bool isInserted() const { 181 return getInfoSelector().toUint16() & kInfoFlagViewInserted; 182 } 183 #endif 184 getNameSelector()185 reg_t getNameSelector() const { 186 return _name; 187 } 188 189 // No setter for the name selector 190 getPropDictSelector()191 reg_t getPropDictSelector() const { 192 #ifdef ENABLE_SCI32 193 if (getSciVersion() == SCI_VERSION_3) 194 // This should never occur, this is called from a SCI1.1 - SCI2.1 only function 195 error("getPropDictSelector called for SCI3"); 196 else 197 #endif 198 return _variables[2]; 199 } 200 setPropDictSelector(reg_t value)201 void setPropDictSelector(reg_t value) { 202 #ifdef ENABLE_SCI32 203 if (getSciVersion() == SCI_VERSION_3) 204 // This should never occur, this is called from a SCI1.1 - SCI2.1 only function 205 error("setPropDictSelector called for SCI3"); 206 else 207 #endif 208 _variables[2] = value; 209 } 210 getClassScriptSelector()211 reg_t getClassScriptSelector() const { 212 #ifdef ENABLE_SCI32 213 if (getSciVersion() == SCI_VERSION_3) 214 return make_reg(0, _baseObj.getUint16SEAt(6)); 215 else 216 #endif 217 return _variables[4]; 218 } 219 setClassScriptSelector(reg_t value)220 void setClassScriptSelector(reg_t value) { 221 #ifdef ENABLE_SCI32 222 if (getSciVersion() == SCI_VERSION_3) 223 // This should never occur, this is called from a SCI1.1 - SCI2.1 only function 224 error("setClassScriptSelector called for SCI3"); 225 else 226 #endif 227 _variables[4] = value; 228 } 229 getVarSelector(uint16 i)230 Selector getVarSelector(uint16 i) const { return _baseVars[i]; } 231 232 /** 233 * @returns A pointer to the code for the method at the given index. 234 */ getFunction(const uint16 index)235 reg_t getFunction(const uint16 index) const { 236 return make_reg32(_pos.getSegment(), _baseMethod[index * 2 + 1]); 237 } 238 239 /** 240 * @returns The selector for the method at the given index. 241 */ getFuncSelector(const uint16 index)242 Selector getFuncSelector(const uint16 index) const { 243 return _baseMethod[index * 2]; 244 } 245 246 /** 247 * Determines if this object is a class and explicitly defines the 248 * selector as a funcselector. Does NOT say anything about the object's 249 * superclasses, i.e. failure may be returned even if one of the 250 * superclasses defines the funcselector 251 */ funcSelectorPosition(Selector sel)252 int funcSelectorPosition(Selector sel) const { 253 for (uint i = 0; i < _methodCount; i++) 254 if (getFuncSelector(i) == sel) 255 return i; 256 257 return -1; 258 } 259 260 /** 261 * Determines if the object explicitly defines slc as a varselector. 262 * Returns -1 if not found. 263 */ 264 int locateVarSelector(SegManager *segMan, Selector slc) const; 265 isClass()266 bool isClass() const { return (getInfoSelector().getOffset() & kInfoFlagClass); } 267 const Object *getClass(SegManager *segMan) const; 268 markAsFreed()269 void markAsFreed() { _isFreed = true; } isFreed()270 bool isFreed() const { return _isFreed; } 271 getVarCount()272 uint getVarCount() const { return _variables.size(); } 273 274 void init(const Script &owner, reg_t obj_pos, bool initVariables = true); 275 getVariable(uint var)276 reg_t getVariable(uint var) const { return _variables[var]; } getVariableRef(uint var)277 reg_t &getVariableRef(uint var) { return _variables[var]; } 278 getMethodCount()279 uint16 getMethodCount() const { return _methodCount; } getPos()280 reg_t getPos() const { return _pos; } 281 282 void saveLoadWithSerializer(Common::Serializer &ser); 283 cloneFromObject(const Object * obj)284 void cloneFromObject(const Object *obj) { 285 _name = obj ? obj->_name : NULL_REG; 286 _baseObj = obj ? obj->_baseObj : SciSpan<const byte>(); 287 _baseMethod = obj ? obj->_baseMethod : Common::Array<uint32>(); 288 _baseVars = obj ? obj->_baseVars : Common::Array<uint16>(); 289 #ifdef ENABLE_SCI32 290 if (getSciVersion() == SCI_VERSION_3) { 291 _mustSetViewVisible = obj ? obj->_mustSetViewVisible : Common::Array<bool>(); 292 } 293 #endif 294 } 295 296 bool relocateSci0Sci21(SegmentId segment, int location, uint32 heapOffset); 297 #ifdef ENABLE_SCI32 298 bool relocateSci3(SegmentId segment, uint32 location, int offset, uint32 scriptSize); 299 #endif 300 301 int propertyOffsetToId(SegManager *segMan, int propertyOffset) const; 302 303 void initSpecies(SegManager *segMan, reg_t addr, bool applyScriptPatches); 304 void initSuperClass(SegManager *segMan, reg_t addr, bool applyScriptPatches); 305 bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true, bool applyScriptPatches = true); 306 307 #ifdef ENABLE_SCI32 308 bool mustSetViewVisible(const int index, const bool fromPropertyOp) const; 309 #endif 310 311 private: 312 #ifdef ENABLE_SCI32 313 void initSelectorsSci3(const SciSpan<const byte> &buf, const bool initVariables); 314 #endif 315 316 /** 317 * The name of the object. 318 */ 319 reg_t _name; 320 321 /** 322 * A pointer to the raw object data within the object's owner script. 323 */ 324 SciSpan<const byte> _baseObj; 325 326 /** 327 * A lookup table from a property index to its corresponding selector 328 * number. 329 */ 330 Common::Array<uint16> _baseVars; 331 332 /** 333 * A lookup table from a method index to its corresponding selector number 334 * or offset to code. The table contains selector + offset in pairs. 335 */ 336 Common::Array<uint32> _baseMethod; 337 338 /** 339 * A lookup table from a property index to the property's current value. 340 */ 341 Common::Array<reg_t> _variables; 342 343 #ifdef ENABLE_SCI32 344 /** 345 * A lookup table from a property index to the property's original absolute 346 * offset within the raw script data. This absolute offset is coded into the 347 * script's relocation table, and is used to look up 32-bit values for 348 * properties in the relocation table (which is used to break the 16-bit 349 * barrier, since the script format still only holds 16-bit values inline). 350 */ 351 Common::Array<uint32> _propertyOffsetsSci3; 352 #endif 353 354 /** 355 * The number of methods on the object. 356 */ 357 uint16 _methodCount; 358 359 /** 360 * Whether or not a clone object has been marked as 'freed'. 361 */ 362 bool _isFreed; 363 364 /** 365 * For SCI0 through SCI2.1, an extra index offset used when looking up 366 * special object properties -species-, -super-, -info-, and name. 367 */ 368 uint16 _offset; 369 370 reg_t _pos; /**< Object offset within its script; for clones, this is their base */ 371 #ifdef ENABLE_SCI32 372 reg_t _superClassPosSci3; /**< reg_t pointing to superclass for SCI3 */ 373 reg_t _speciesSelectorSci3; /**< reg_t containing species "selector" for SCI3 */ 374 reg_t _infoSelectorSci3; /**< reg_t containing info "selector" for SCI3 */ 375 Common::Array<bool> _mustSetViewVisible; /** cached bit of info to make lookup fast, SCI3 only */ 376 #endif 377 }; 378 379 380 } // End of namespace Sci 381 382 #endif // SCI_ENGINE_OBJECT_H 383