Beispiel #1
0
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;
}