reg_t kClone(EngineState *s, int argc, reg_t *argv) { reg_t parentAddr = argv[0]; const Object *parentObj = s->_segMan->getObject(parentAddr); reg_t cloneAddr; Clone *cloneObj; // same as Object* if (!parentObj) { error("Attempt to clone non-object/class at %04x:%04x failed", PRINT_REG(parentAddr)); return NULL_REG; } debugC(kDebugLevelMemory, "Attempting to clone from %04x:%04x", PRINT_REG(parentAddr)); uint16 infoSelector = parentObj->getInfoSelector().toUint16(); cloneObj = s->_segMan->allocateClone(&cloneAddr); if (!cloneObj) { error("Cloning %04x:%04x failed-- internal error", PRINT_REG(parentAddr)); return NULL_REG; } // In case the parent object is a clone itself we need to refresh our // pointer to it here. This is because calling allocateClone might // invalidate all pointers, references and iterators to data in the clones // segment. // // The reason why it might invalidate those is, that the segment code // (Table) uses Common::Array for internal storage. Common::Array now // might invalidate references to its contained data, when it has to // extend the internal storage size. if (infoSelector & kInfoFlagClone) parentObj = s->_segMan->getObject(parentAddr); *cloneObj = *parentObj; // Mark as clone infoSelector &= ~kInfoFlagClass; // remove class bit cloneObj->setInfoSelector(make_reg(0, infoSelector | kInfoFlagClone)); cloneObj->setSpeciesSelector(cloneObj->getPos()); if (parentObj->isClass()) cloneObj->setSuperClassSelector(parentObj->getPos()); s->_segMan->getScript(parentObj->getPos().getSegment())->incrementLockers(); s->_segMan->getScript(cloneObj->getPos().getSegment())->incrementLockers(); return cloneAddr; }