Example #1
0
		virtual void visit(CInstance &inst)
		{
			if (inst.getDisplayerVisual())
			{
				inst.getDisplayerVisual()->updateWorldPos();
			}
		}
Example #2
0
//***************************************************************
CInstance *CToolSelectMove::createGhost(CInstance &instance)
{
	//H_AUTO(R2_CToolSelectMove_createGhost)
	CLuaState &ls = getEditor().getLua();
	// copy then do a local paste
	CLuaStackRestorer lsr(&ls, 0);
	//
	CLuaObject &luaProj = instance.getLuaProjection();
	CLuaObject &classDef = instance.getClass();
	if (luaProj.callMethodByNameNoThrow("copy", 0, 1))
	{
		// now we got a table that is an exact (canonical) copy of the original object, with the
		// same instance ids..
		// prepare for new insertion by renaming these instance id's (which 'newCopy' does)
		if (classDef["newCopy"].callNoThrow(1, 1))
		{
			// now, insert the new copy as a ghost in the new scene
			if (classDef["pasteGhost"].callNoThrow(1, 1))
			{

				CLuaObject ghost(ls); // pop the ghost from stack
				CInstance *newInst = getEditor().getInstanceFromId(ghost["InstanceId"].toString());
				if (newInst)
				{
					if (!newInst->getGhost())
					{
						nlwarning("When duplicating an object using the 'select/move' tool, temporary duplicate should be inserted \
								   as a ghost in the scene, removing object...");
						getEditor().getDMC().requestEraseNode(newInst->getId(), "", -1);
					}
					// set the flag so that the cost of this object isn't taken in account in the displayed quotas
					newInst->getLuaProjection()["User"].setValue("GhostDuplicate", true);
					getEditor().setSelectedInstance(newInst);
					newInst->getDisplayerVisual()->setDisplayFlag(CDisplayerVisual::FlagHideActivities, true);
					nlwarning("CToolSelectMove: beginning duplicate with instance with id %s", newInst->getId().c_str());
					// show in "frozen" state
					{
						/*CObjectNumber *numberValue = new CObjectNumber(2); // 2 = frozen state
						getEditor().getDMC().requestSetNode(newInst->getId(), "DisplayMode", numberValue);
						delete numberValue;
						*/
						newInst->getDisplayerVisual()->setDisplayMode(CDisplayerVisual::DisplayModeFrozen);
						getEditor().getEntitySorter()->clipEntitiesByDist();
						return newInst;
					}
				}
			}
		}
Example #3
0
//***************************************************************
void CAutoGroup::update(const CVector &testPos, const std::string &paletteEntry, bool valid)
{
	//H_AUTO(R2_CAutoGroup_update)
	_TestPos = testPos;
	_PaletteEntry = paletteEntry;
	_AutoGroupEnabled = valid;
	CInstance *candidate = getGroupingCandidate();
	if (!candidate && _AutoGroup.isAddedToWorldMap())
	{
		clear();
	}
	else if (candidate)
	{
		// update the display
		if (!_AutoGroup.isAddedToWorldMap())
		{
			CGroupMap *gm = CTool::getWorldMap();
			if (gm)
			{
				gm->addDeco(&_AutoGroup);
			}
		}
		CDisplayerVisual *dv = candidate->getDisplayerVisual();
		nlassert(dv); // should not be null because getGrou^pingCandidate succeeded
		_PrimRenderVertices.resize(2);
		CVector pos = dv->isCompound() ? dv->getSon(0)->getWorldPos() : dv->getWorldPos();
		_PrimRenderVertices[0] = pos;
		_PrimRenderVertices[1] = _TestPos;
		_AutoGroup.setVertices(_PrimRenderVertices);
		_AutoGroup.addDecalsToRenderList();
	}
}
//*********************************************************************************************************
CDisplayerVisual *CDisplayerVisualActivitySequence::getPossibleGroupDV(CDisplayerVisual *entityDV)
{
	//H_AUTO(R2_CDisplayerVisualActivitySequence_getPossibleGroupDV)
	if (!entityDV) return NULL;
	CInstance *parentGroup = entityDV->getDisplayedInstance()->getParent();
	while (parentGroup)
	{
		if (dynamic_cast<CDisplayerVisualGroup *>(parentGroup->getDisplayerVisual()))
		{
			return parentGroup->getDisplayerVisual();
			break;
		}
		parentGroup = parentGroup->getParent();
	}
	return entityDV;
}
//*********************************************************************************************************
CDisplayerVisual *CDisplayerVisualActivitySequence::getParentDV() const
{
	//H_AUTO(R2_CDisplayerVisualActivitySequence_getParentDV)
	CInstance *currParent = getDisplayedInstance()->getParent();
	CDisplayerVisual *prevDV = NULL;
	while (currParent)
	{
		prevDV = currParent->getDisplayerVisual();
		if (prevDV) break;
		currParent = currParent->getParent();
	}
	return prevDV;
}
Example #6
0
// ***************************************************************
CDisplayerVisual *CDisplayerVisual::getParent()
{
	if (_LastParentOk) return _LastParent;
	CDisplayerVisual *result = NULL;
	//H_AUTO(R2_CDisplayerVisual_getParent)
	CInstance *inst = getDisplayedInstance();
	nlassert(inst);
	CInstance *parentInstance = inst->getParent();
	if (parentInstance)
	{
		result = parentInstance->getDisplayerVisual();
	}
	_LastParent = result;
	_LastParentOk = true;
	return result;
}
Example #7
0
// ***************************************************************
void CToolSelectRotate::setRotateInProgress(bool rotateInProgress, CInstance &instance)
{
	//H_AUTO(R2_CToolSelectRotate_setRotateInProgress)
	CDisplayerVisual *dv = instance.getDisplayerVisual();
	if (dv) dv->setRotateInProgress(rotateInProgress);
}
Example #8
0
//***************************************************************
void CToolCreateEntity::updateArray(CEntityCL *clonee)
{
	//H_AUTO(R2_CToolCreateEntity_updateArray)
	if (!clonee)
	{
		nlassert(!_ArrayElements.empty());
		nlassert(_ArrayElements[0] != NULL);
		clonee = _ArrayElements[0]->getEntity();
		if (!clonee)
		{
			return;
		}
	}

	CVector extent = _ArrayEnd - _ArrayOrigin;
	uint arraySize = 1;
	float arrayStepLength = 1.f;
	if (!_ArrayElements.empty() && _ArrayElements[0])
	{
		arrayStepLength = 2.f * _ArrayElements[0]->getSelectionDecalRadius();
		arraySize = (uint) floorf(extent.norm() / arrayStepLength) + 1;
		arraySize = std::min(arraySize, (uint) 16);
	}
	while (!getEditor().verifyRoomLeft(0, arraySize))
	{
		-- arraySize;
		if (arraySize == 0)
		{
			TSmartPtr hold(this);
			cancel();
			return;
		}
	}
	_ArrayElements.resize(std::max(arraySize, uint(_ArrayElements.size())));
	CVector delta = arrayStepLength * extent.normed();
	float angle = _ArrayDefaultAngle;
	if (arraySize > 1)
	{
		angle = - (float) atan2(extent.x, extent.y);
	}
	bool newEntityCreated = false;
	uint numCreatedEntity = 0;
	for (uint k = 0; k < _ArrayElements.size(); ++k)
	{
		CVector pos = _ArrayOrigin + (float) k * delta;
		if (!_ArrayElements[k])
		{
			if (k < arraySize)
			{
				nlwarning("NEW ENTITY");
				// create new element
				std::string instanceId = cloneEntityIntoScenario(clonee,
																 pos,
																 angle,
																 false, /*new action*/
																 true /*create ghost*/);
				CInstance *inst = getEditor().getInstanceFromId(instanceId);
				if (inst)
				{
					_ArrayElements[k] = dynamic_cast<CDisplayerVisualEntity *>(inst->getDisplayerVisual());
					if (_ArrayElements[k])
					{
						_ArrayElements[k]->setDisplayMode(CDisplayerVisual::DisplayModeArray);
					}
				}
				newEntityCreated = true;
				++ numCreatedEntity;
			}
		}

		if (_ArrayElements[k])
		{
			bool active = k < arraySize;
			// do a kind of 'reserve' on the list of entities : don't delete entities in excess, but hide them instead
			if (active != _ArrayElements[k]->getActive())
			{
				_ArrayElements[k]->setActive(active);
				if (active)
				{
					newEntityCreated = true;
					_ArrayElements[k]->setDisplayMode(CDisplayerVisual::DisplayModeArray);
				}
			}
			if (active)
			{
				// update pos & angle
				TInstanceId	instanceId = _ArrayElements[k]->getDisplayedInstance()->getId();
				CVector worldPos = _ArrayElements[k]->getWorldPos();
				if (pos != worldPos)
				{
					CObject *newPos = buildVector(pos, _ArrayElements[k]->getDisplayedInstance()->getPosInstanceId());
					getEditor().getDMC().requestSetNode(instanceId, "Position", newPos);
					delete newPos;
				}
				if (angle != _ArrayElements[k]->getAngle())
				{
					CObjectNumber *angleObject = new CObjectNumber(angle);
					getEditor().getDMC().requestSetNode(instanceId, "Angle", angleObject);
					delete angleObject;
				}
			}
		}
	}
	if (newEntityCreated)
	{
		nlwarning("Num created entity = %d", numCreatedEntity);
		getEditor().getEntitySorter()->clipEntitiesByDist();
	}
}
Example #9
0
//***************************************************************
CInstance *CAutoGroup::getGroupingCandidate()
{
	//H_AUTO(R2_CAutoGroup_getGroupingCandidate)
	if (!_AutoGroupEnabled) return NULL;
	// if I'm a bot object, don't auto-group
	CObject *palEntry = getEditor().getDMC().getPaletteElement(_PaletteEntry);
	if (!palEntry || !palEntry->isTable()) return NULL;
	if (getNumber(palEntry, "IsBotObject") == 1) return NULL;
	// auto-group feature
	// look in default feature and sort objects by distance
	CInstance *defaultFeatInst = getEditor().getDefaultFeature(getEditor().getCurrentAct());
	CInstance *baseDefaultFeatInst = getEditor().getDefaultFeature(getEditor().getBaseAct());
	if (!defaultFeatInst || !baseDefaultFeatInst)
	{
		nlwarning("Can't access to Default Features"); // syntax error in lua was making the client crash
		return NULL; //In this case there is no default features
	}
	CObjectTable *defaultFeat = defaultFeatInst->getObjectTable();
	CObjectTable *baseDefaultFeat = baseDefaultFeatInst->getObjectTable();
	CObject *components = defaultFeat->getAttr("Components");
	CObject *baseComponents = baseDefaultFeat->getAttr("Components");
	if (!components || !baseComponents || !palEntry->isTable()) return NULL;
	_SortedComponents.clear();
	for (uint k = 0; k < (components->getSize()+baseComponents->getSize()); ++k)
	{
		CObject *obj = NULL;
		if(k<components->getSize())
			obj = components->getValue(k);
		else
			obj = baseComponents->getValue(k - components->getSize());
		CInstance *inst = getEditor().getInstanceFromObject(obj);
		if (!inst)
		{
			nlwarning("Error: can not find create Instance of an object.");
			continue;
		}
		CDisplayerVisual *dv = inst->getDisplayerVisual();
		if (!dv) continue;
		CComponentSort cs;
		cs.Dist = (_TestPos - dv->getWorldPos()).norm();
		if (cs.Dist > CV_AutoGroupMaxDist.get()) continue;
		cs.Instance = inst;
		_SortedComponents.push_back(cs);
	}
	// iterate through other features
	CObjectTable *act = getEditor().getCurrentAct()->getObjectTable();
	CObjectTable *baseAct = getEditor().getBaseAct()->getObjectTable();
	if (!act || !baseAct) return NULL;
	CObject *features = act->getAttr("Features");
	CObject *baseFeatures = baseAct->getAttr("Features");
	if (!features || !baseFeatures) return NULL;
	for (uint k = 0; k < (features->getSize()+baseFeatures->getSize()); ++k)
	{
		CObject *obj = NULL;
		if(k<features->getSize())
			obj = features->getValue(k);
		else
			obj = baseFeatures->getValue(k - features->getSize());
		CInstance *inst = getEditor().getInstanceFromObject(obj);
		CDisplayerVisual *dv = inst->getDisplayerVisual();
		if (!dv) continue;
		if (inst->isKindOf("NpcGrpFeature"))
		{
			if (dv->getNumSons() == 0) continue;
			CComponentSort cs;
			cs.Dist = (_TestPos - dv->getSon(0)->getWorldPos()).norm();
			if (cs.Dist > CV_AutoGroupMaxDist.get()) continue;
			cs.Instance = inst;
			_SortedComponents.push_back(cs);
		}
	}


	std::sort(_SortedComponents.begin(), _SortedComponents.end());
	CLuaState &ls = getEditor().getLua();
	const CObject *categoryObj = getObject(palEntry, "Category");
	if (!categoryObj)
	{
		nlwarning("No 'Category' field in palEntry '%s'", _PaletteEntry.c_str());
		return NULL;
	}
	if (!categoryObj->isString()) return NULL;
	std::string category = categoryObj->toString();
	//
	const CObject *subCategoryObj = getObject(palEntry, "SubCategory");
	std::string subCategory;
	if (subCategoryObj && subCategoryObj->isString())
	{
		subCategory = subCategoryObj->toString();
	}
	else
	{
		//nlwarning("No 'SubCategory' field in palEntry '%s'", paletteEntry.c_str());
	}

	//
	if (category.empty()) return NULL;
	for(uint k = 0; k < _SortedComponents.size(); ++k)
	{
		CLuaStackRestorer lsr(&ls, 0);
		if (_SortedComponents[k].Instance->isKindOf("Npc"))
		{
			_SortedComponents[k].Instance->getLuaProjection().callMethodByNameNoThrow("isPlant", 0, 1);
			if (ls.toBoolean(-1) == true) continue;
			_SortedComponents[k].Instance->getLuaProjection().callMethodByNameNoThrow("isBotObject", 0, 1);
			if (ls.toBoolean(-1) == true) continue;
		}
		else if (!_SortedComponents[k].Instance->isKindOf("NpcGrpFeature"))
		{
			continue;
		}
		std::string destCategory;
		if (_SortedComponents[k].Instance->getLuaProjection().callMethodByNameNoThrow("getCategory", 0, 1))
		{
			destCategory = ls.toString(-1);
			ls.pop();
		}
		if (destCategory != category) continue;
		//
		std::string destSubCategory;
		if (_SortedComponents[k].Instance->getLuaProjection().callMethodByNameNoThrow("getSubCategory", 0, 1))
		{
			if (ls.isString(-1))
			{
				destSubCategory = ls.toString(-1);
			}
			ls.pop();
		}
		if (destSubCategory != subCategory) continue;
		// good candidate
		return _SortedComponents[k].Instance;
	}
	return NULL;
}
Example #10
0
//***************************************************************
void CAutoGroup::group(CObject *newEntityDesc, const NLMISC::CVectorD &createPosition)
{
	//H_AUTO(R2_CAutoGroup_group)
	CInstance *destGroup = getGroupingCandidate();
	if (!destGroup || !_AutoGroupEnabled) return;
	_AutoGroupEnabled = false; // force user to call 'update' again
	clear();
	// remove any activity, dialog, or event in the copy
	CObject *behav = newEntityDesc->findAttr("Behavior");
	if (behav)
	{
		behav->setObject("Actions", new CObjectTable());
		behav->setObject("Activities", new CObjectTable());
		behav->setObject("ChatSequences", new CObjectTable());
		newEntityDesc->setObject("ActivitiesId", new CObjectTable());
	}
	nlassert(newEntityDesc);
	nlassert(destGroup);
	std::string targetGroupId;
	if (destGroup->isKindOf("NpcGrpFeature"))
	{
		// make relative to newgroup and insert
		CVectorD relPos = createPosition;
		CDisplayerVisual *vd = destGroup->getDisplayerVisual();
		if (vd)
		{
			relPos = relPos - vd->getWorldPos();
		}
		newEntityDesc->setObject("Position", buildVector(relPos));
		targetGroupId = destGroup->getId();
	}
	else
	{
		// other is a standalone entity -> create a new group
		std::auto_ptr<CObject> newGroup(getEditor().getDMC().newComponent("NpcGrpFeature"));
		if (!newGroup.get())
		{
			nlwarning("Syntax error in r2_features_npc_group.lua.");
			getEditor().getDMC().getActionHistoric().endAction();
			getEditor().getDMC().flushActions();
			return;
		}
		ucstring readableName;
		CLuaState &ls = getEditor().getLua();
		R2::getEditor().getEnv()["PaletteIdToGroupTranslation"][newEntityDesc->getAttr("Base")->toString()].push();
		if (ls.isString(-1))
			readableName.fromUtf8(ls.toString(-1));
		ucstring ucGroupName = ucstring(readableName + " " + CI18N::get("uiR2EDNameGroup").toUtf8());

		newGroup->set("Name", getEditor().genInstanceName(ucGroupName).toUtf8());
		getEditor().getDMC().requestInsertNode(destGroup->getParentAct()->getId(),
							   "Features",
							   -1,
							   "",
							   newGroup.get());
		targetGroupId = getString(newGroup.get(), "InstanceId");
		// move target instance in that group (becomes the leader)
		getEditor().getDMC().requestMoveNode(destGroup->getId(), "", -1, targetGroupId, "Components", -1);
	}
	// move newly created entity into target group
	getEditor().getDMC().requestInsertNode(targetGroupId,
							   "Components",
							   -1,
							   "",
							   newEntityDesc);
	getEditor().getDMC().getActionHistoric().endAction();
	getEditor().getDMC().flushActions();
}
//*********************************************************************************************************
void CDisplayerVisualActivitySequence::update()
{
	//H_AUTO(R2_CDisplayerVisualActivitySequence_update)
	if (!_Active) return;
	if (!_Touched) return;
	_Touched = false;
	CObjectTable *activities = getProps().toTable("Components");
	if (!activities)
	{
		clear();
		return;
	}
	// get first world object parent to get start position
	nlassert(getDisplayedInstance());
	CInstance *prevZone = NULL;
	CDisplayerVisual *prevDV = getParentDV();
	if (!prevDV)
	{
		clear();
		return;
	}
	//
	clear(false);
	//
	for(uint k = 0; k < activities->getSize(); ++k)
	{
		// search next zone of activity
		CObjectTable *activity = activities->getValue(k)->toTable();
		if (!activity) continue;
		std::string activityStr = getString(activity, "Activity");
		if (activityStr == "Stand Still" || activityStr == "Inactive") continue;
		//
		CInstance *nextZone = NULL;
		std::string zoneId = getString(activity, "ActivityZoneId");
		//
		if (!zoneId.empty())
		{
			_ObserverHandles.push_back(getEditor().addInstanceObserver(zoneId, this));
			nextZone = getEditor().getInstanceFromId(zoneId);
		}

		if (!nextZone) break;
		CDisplayerVisual *nextDV = nextZone->getDisplayerVisual();
		if (!nextDV) break;

		_TraversedPrimInfos.push_back(CTraversedPrimInfo());
		_TraversedPrimInfos.back().PrimDisplay = nextDV;
		_TraversedPrimInfos.back().Visible = nextDV->getActualDisplayMode() != DisplayModeHidden;


		CWorldPosCache wpc;
		wpc.DV = nextDV;
		wpc.WorldPos2f = nextDV->getWorldPos2f();
		_WPCache.push_back(wpc);

		if (nextDV->getActualDisplayMode() != DisplayModeHidden
			&& prevDV->getActualDisplayMode() != DisplayModeHidden)
		{
			// special case for regions
			if (nextZone->isKindOf("Region"))
			{
				// first case : previous zone is not a region
				if (!prevZone || !prevZone->isKindOf("Region"))
				{
					// search shortest distance bewteen last pos and the region
					CVector entryPos;
					if (nextDV->evalEnterPoint(prevDV->evalExitPoint(), entryPos))
					{
						addFootSteps(CLine(prevDV->evalExitPoint(), entryPos));
					}
					else
					{
						addWanderSteps(prevDV->evalExitPoint());
					}
				}
				else
				{
					// region-region footsteps
					// just use the couple of vertices for which the distance is the smallest
					static std::vector<CVector2f> r0;
					static std::vector<CVector2f> r1;
					prevDV->getSonsWorldPos2f(r0);
					nextDV->getSonsWorldPos2f(r1);
					if (!r0.empty() && !r1.empty())
					{
						CVector2f p0, p1;
						float bestDist = FLT_MAX;
						for(uint k = 0; k < r0.size(); ++k)
						{
							for(uint l = 0; l < r0.size(); ++l)
							{
								float dist = (r0[k] - r1[l]).norm();
								if (dist <bestDist)
								{
									bestDist = dist;
									p0 = r0[k];
									p1 = r1[l];
								}
							}
						}
						nlassert(bestDist != FLT_MAX);
						addFootSteps(CLine(p0.asVector(), p1.asVector()));
					}
				}
			}
			else
			{
				// special case if prev zone is a region
				if (prevZone && prevZone->isKindOf("Region"))
				{
					// search shortest distance bewteen last pos and the region
					CVector entryPos;
					if (prevDV->evalEnterPoint(nextDV->evalLinkPoint(), entryPos))
					{
						addFootSteps(CLine(entryPos, nextDV->evalLinkPoint()));
					}
					else
					{
						addWanderSteps(nextDV->evalLinkPoint());
					}
				}
				else
				{
					// simple footsteps between last & new pos
					addFootSteps(CLine(prevDV->evalExitPoint(), nextDV->evalLinkPoint()));
				}
			}
		}
		prevDV   = nextDV;
		prevZone = nextZone;
	}
	//
	CGroupMap *gm = CTool::getWorldMap();
	if (!_AddedToWorldMap && gm)
	{
		gm->addDeco(this);
	}
	if (_AddedToWorldMap)
	{
		setWorldMapNumEdges((uint)_FootSteps.size());
		nlassert(gm);
		onUpdate(*gm);
	}
}
//*********************************************************************************************************
void CDisplayerVisualActivitySequence::onPostRender()
{
	//H_AUTO(R2_CDisplayerVisualActivitySequence_onPostRender)
	CDisplayerVisual *entityDV = getParentDV();
	CDisplayerVisual *groupDV = getPossibleGroupDV(entityDV);
	if (!isVisible(groupDV, entityDV))
	{
		removeFromWorldMap();
		return;
	}
	//
	TSequenceState state = Hidden;
	// if this activity sequence is not the selected one in its parent then it is hidden
	updateState(state, groupDV);
	// if current selection is a son of the group...
	static std::vector<CDisplayerVisual *> groupSons;
	groupDV->getSons(groupSons);
	for(uint k = 0; k < groupSons.size(); ++k)
	{
		nlassert(groupSons[k]);
		updateState(state, groupSons[k]);
	}
	// if one of the route is selected or highlighted
	CObjectTable *activities = getProps().toTable("Components");
	if (!activities)
	{
		removeFromWorldMap();
		return;
	}
	// get first world object parent to get start position
	for(uint k = 0; k < activities->getSize(); ++k)
	{
		// search next zone of activity
		CObjectTable *activity = activities->getValue(k)->toTable();
		if (!activity) continue;
		std::string zoneId = getString(activity, "ActivityZoneId");
		if (zoneId.empty()) continue;
		std::string activityStr = getString(activity, "Activity");
		if (activityStr == "Stand Still" || activityStr == "Inactive") continue;
		CInstance *zone = getEditor().getInstanceFromId(zoneId);
		if (!zone) continue;
		CDisplayerVisual *dv = zone->getDisplayerVisual();
		if (!dv) continue;
		updateState(state, dv);
		static std::vector<CDisplayerVisual *> vertices;
		dv->getSons(vertices);
		for (uint l = 0; l < vertices.size(); ++l)
		{
			nlassert(vertices[l]);
			updateState(state, vertices[l]);
		}
	}
	//
	if (state != Hidden && entityDV)
	{
		// see if this sequence is the selected one
		sint index = entityDV->getDisplayedInstance()->getSelectedSequence();
		CObject *sequences = getProps().getParent(); // see what is my index in the sequences list of my parent
		if (sequences)
		{
			clamp(index, (sint) 0, (sint) sequences->getSize() - 1);
			if (index != sequences->findIndex(&getProps()))
			{
				state = Hidden; // not the current selected sequence
			}
		}
	}
	//
	_DecalColor = CV_FootStepDecalSelectedColor.get();
	CRGBA mapColor = CV_FootStepMapSelectedColor.get();
	switch(state)
	{
		case Hidden:
			_DecalColor = CV_FootStepDecalHiddenColor.get();
			mapColor = CV_FootStepMapHiddenColor.get();
		break;
		case HasFocus:
			_DecalColor = CV_FootStepDecalFocusedColor.get();
			mapColor = CV_FootStepMapFocusedColor.get();
		break;
	}
	for(uint k = 0; k < _WPCache.size(); ++k)
	{
		if (_WPCache[k].DV)
		{
			if (_WPCache[k].DV->getWorldPos2f() != _WPCache[k].WorldPos2f)
			{
				touch();
				break;
			}
		}
	}
	update();
	if (_AddedToWorldMap)
	{
		setWorldMapColor(mapColor);
	}
}