// ************************************************************************
void CObjectRefIdClient::getNameInParent(std::string &name, sint32 &indexInArray) const
{
	//H_AUTO(R2_CObjectRefIdClient_getNameInParent)
	if (_IndexInParent != -1 && _ParentInstance)
	{
		CObjectTable *parentInstanceTable = _ParentInstance->getObjectTable();
		// check that index is still valid (true most of the case unless instance has been moved)
		if (_IndexInParent <= (sint32) parentInstanceTable->getSize())
		{
			if (_IndexInParentArray == -1)
			{
				if (parentInstanceTable->getValue(_IndexInParent) == static_cast<const CObject *>(this))
				{
					name =  parentInstanceTable->getKey(_IndexInParent);
					indexInArray = -1;
					return;
				}
			}
			else
			{
				CObject *subObject = parentInstanceTable->getValue(_IndexInParent);
				if (subObject->isTable())
				{
					CObjectTable *subTable = (CObjectTable *) subObject;
					if (_IndexInParentArray < (sint32) subTable->getSize())
					{
						if (subTable->getValue(_IndexInParentArray) == static_cast<const CObject *>(this))
						{
							name =  parentInstanceTable->getKey(_IndexInParent);
							indexInArray = _IndexInParentArray;
						}
					}
				}
			}
		}
	}
	// must search name in parent (on init or when object is moved)
	updateParentInstancePtr();
	if (!_ParentInstance)
	{
		_IndexInParent = -1;
		_IndexInParentArray = -1;
		name.clear();
		indexInArray = -1;
		return;
	}
	CObjectTable *parentInstanceTable = _ParentInstance->getObjectTable();
	const CObject *ptrInParent = (parentInstanceTable == this->getParent()) ? static_cast<const CObject *>(this) : this->getParent();
	// if instance is the direct parent (e.g object is not in an array of the parent)
	for (uint k = 0; k < parentInstanceTable->getSize(); ++k)
	{
		if (parentInstanceTable->getValue(k) == ptrInParent)
		{
			_IndexInParent = k;
			if (ptrInParent == this)
			{
				_IndexInParentArray = -1;
				indexInArray = -1;
				name = parentInstanceTable->getKey(_IndexInParent);
				return;
			}
			else
			{
				// I'm in an array in my parent, retrieve the index
				for (uint l = 0; l < getParent()->getSize(); ++l)
				{
					if (getParent()->getValue(l) == static_cast<const CObject *>(this))
					{
						name = parentInstanceTable->getKey(_IndexInParent);
						_IndexInParentArray = l;
						return;
					}
				}
			}
		}
	}
	// TMP TMP
	nlwarning("=========================================");
	CLuaIHMRyzom::dumpCallStack();
	nlwarning("=========================================");
	nlwarning("ObservedObject = %s", getValue().c_str());
	CInstance *obsInstance = getEditor().getInstanceFromId(getValue().c_str());
	nlwarning("ObservedObject instance ptr = %p", obsInstance);
	nlwarning("=========================================");
	if (obsInstance)
	{
		obsInstance->getLuaProjection().dump();
		CInstance *parent = obsInstance->getParent();
		nlwarning("ObservedObject parent instance ptr = %p", parent);
		parent->getLuaProjection().dump();
	}
	nlassert(0); // not found in parent
}
Beispiel #2
0
//***************************************************************
std::string CToolCreateEntity::cloneEntityIntoScenario(CEntityCL *clonee,
												const NLMISC::CVector &createPosition,
												float createAngle,
												bool  newAction,
												bool  createGhost
											   )
{
	//H_AUTO(R2_CToolCreateEntity_cloneEntityIntoScenario)
	if (!clonee) return "";
	std::string instanceId;
	bool isBotObject = isBotObjectSheet(clonee->sheetId());

	if (!getEditor().verifyRoomLeft(isBotObject ? 0 : 1, isBotObject ? 1 : 0)) { return ""; }

	std::string className;
	// if class is given in the palette node, then use it. Default to 'Npc' else
	CObject *paletteNode = getDMC().getPaletteElement(_PaletteId);
	if (paletteNode && paletteNode->findIndex("Class") != -1)
	{
		className = getString(paletteNode, "Class");
	}
	if (className.empty())
	{
		className = "Npc";
	}

	ucstring readableName;
	// retrieve name from the palette id
	CLuaState &ls = getEditor().getLua();
	getEditor().getEnv()["PaletteIdToTranslation"][_PaletteId].push();
	if (ls.isString(-1))
	{
		readableName.fromUtf8(ls.toString(-1));
	}
	if (readableName.empty())
	{
		// if no name found then give a default one
		readableName = CI18N::get(isBotObject ? "uiR2EDNameBotObject" : "uiR2EDNameNPC");
	}

	// except for creatures, posfix the name with a number
	std::string creaturePaletteRoot = "palette.entities.creatures";
	if (_PaletteId.substr(0, creaturePaletteRoot.size()) != creaturePaletteRoot)
	{
		readableName = getEditor().genInstanceName(readableName);
	}
	else
	{
		className = "NpcCreature";

		// is Plant
		std::string sheetClient = getString(paletteNode, "SheetClient");
		getEditor().getLua().push(sheetClient);
		if (getEditor().getEnv().callMethodByNameNoThrow("isNPCPlant", 1, 1))
		{
			CLuaObject result(getEditor().getLua());
			bool isPlant = result.toBoolean();
			if (isPlant)
				className = "NpcPlant";
		}
	}

	if (newAction)
	{
		getDMC().newAction(NLMISC::CI18N::get("uiR2EDCreateAction") + readableName);
	}
	// send network commands to create entity on server
	std::auto_ptr<CObject> desc(getDMC().newComponent(className));

	if (desc.get())
	{
		// TMP FIX : if the created entity is a custom npc, then retrieve look from the clonee visual properties
		if (className == "NpcCustom")
		{
			SPropVisualA vA;
			SPropVisualB vB;
			SPropVisualC vC;
			const string propNameA = toString("SERVER:Entities:E%d:P%d", clonee->slot(), CLFECOMMON::PROPERTY_VPA);
			const string propNameB = toString("SERVER:Entities:E%d:P%d", clonee->slot(), CLFECOMMON::PROPERTY_VPB);
			const string propNameC = toString("SERVER:Entities:E%d:P%d", clonee->slot(), CLFECOMMON::PROPERTY_VPC);
			CCDBNodeLeaf *leafA = CInterfaceManager::getInstance()->getDbProp(propNameA);
			CCDBNodeLeaf *leafB = CInterfaceManager::getInstance()->getDbProp(propNameB);
			CCDBNodeLeaf *leafC = CInterfaceManager::getInstance()->getDbProp(propNameC);
			if (!leafA)
			{
				nlwarning("Can't find DB leaf %s", propNameA.c_str());
				return "";
			}
			if (!leafB)
			{
				nlwarning("Can't find DB leaf %s", propNameB.c_str());
				return "";
			}
			if (!leafC)
			{
				nlwarning("Can't find DB leaf %s", propNameC.c_str());
				return "";
			}

			vA.PropertyA = leafA->getValue64();
			vB.PropertyB = leafB->getValue64();
			vC.PropertyC = leafC->getValue64();
			nlassert(desc->isTable());
			CObjectTable *props = (CObjectTable *) desc.get();

			props->set("GabaritHeight",     (double)vC.PropertySubData.CharacterHeight);
			props->set("GabaritTorsoWidth", (double)vC.PropertySubData.TorsoWidth);
			props->set("GabaritArmsWidth",  (double)vC.PropertySubData.ArmsWidth);
			props->set("GabaritLegsWidth",  (double)vC.PropertySubData.LegsWidth);
			props->set("GabaritBreastSize", (double)vC.PropertySubData.BreastSize);

			props->set("HairColor", (double)vA.PropertySubData.HatColor);
			props->set("Tattoo",    (double)vC.PropertySubData.Tattoo);
			props->set("EyesColor", (double)vC.PropertySubData.EyesColor);

			props->set("MorphTarget1", (double)vC.PropertySubData.MorphTarget1);
			props->set("MorphTarget2", (double)vC.PropertySubData.MorphTarget2);
			props->set("MorphTarget3", (double)vC.PropertySubData.MorphTarget3);
			props->set("MorphTarget4", (double)vC.PropertySubData.MorphTarget4);
			props->set("MorphTarget5", (double)vC.PropertySubData.MorphTarget5);
			props->set("MorphTarget6", (double)vC.PropertySubData.MorphTarget6);
			props->set("MorphTarget7", (double)vC.PropertySubData.MorphTarget7);
			props->set("MorphTarget8", (double)vC.PropertySubData.MorphTarget8);

			props->set("Sex", (double)vA.PropertySubData.Sex);

			CVisualSlotManager * vsManager = CVisualSlotManager::getInstance();
			NLMISC::CSheetId * sheetId = NULL;

			if(vA.PropertySubData.HatModel == 0)
			{
				props->set("HatModel", 0);
			}
			else
			{
				sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.HatModel, SLOTTYPE::HEAD_SLOT);
				if (sheetId)
				{
					props->set("HairType",  (double)sheetId->asInt());
				}
			}

			if(vA.PropertySubData.JacketModel == 0)
			{
				props->set("JacketModel", 0);
			}
			else
			{
				sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.JacketModel, SLOTTYPE::CHEST_SLOT);
				if (sheetId)
				{
					props->set("JacketModel",  (double)sheetId->asInt());
				}
			}

			if(vA.PropertySubData.TrouserModel == 0)
			{
				props->set("TrouserModel", 0);
			}
			else
			{
				sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.TrouserModel, SLOTTYPE::LEGS_SLOT);
				if (sheetId)
				{
					props->set("TrouserModel",  (double)sheetId->asInt());
				}
			}

			if(vB.PropertySubData.FeetModel == 0)
			{
				props->set("FeetModel", 0);
			}
			else
			{
				sheetId = vsManager->index2Sheet((uint32)vB.PropertySubData.FeetModel, SLOTTYPE::FEET_SLOT);
				if (sheetId)
				{
					props->set("FeetModel",  (double)sheetId->asInt());
				}
			}

			if(vB.PropertySubData.HandsModel == 0)
			{
				props->set("HandsModel", 0);
			}
			else
			{
				sheetId = vsManager->index2Sheet((uint32)vB.PropertySubData.HandsModel, SLOTTYPE::HANDS_SLOT);
				if (sheetId)
				{
					props->set("HandsModel",  (double)sheetId->asInt());
				}
			}

			if(vA.PropertySubData.ArmModel == 0)
			{
				props->set("ArmModel", 0);
			}
			else
			{
				sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.ArmModel, SLOTTYPE::ARMS_SLOT);
				if (sheetId)
				{
					props->set("ArmModel",  (double)sheetId->asInt());
				}
			}

			double weaponRH=0, weaponLH=0;
			if(vA.PropertySubData.WeaponRightHand == 0)
			{
				props->set("WeaponRightHand", 0);
			}
			else
			{
				sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.WeaponRightHand, SLOTTYPE::RIGHT_HAND_SLOT);
				if (sheetId)
				{
					weaponRH = (double)sheetId->asInt();
				}
				props->set("WeaponRightHand",  weaponRH);
			}

			if(vA.PropertySubData.WeaponLeftHand == 0)
			{
				props->set("WeaponLeftHand", 0);
			}
			else
			{
				sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.WeaponLeftHand, SLOTTYPE::LEFT_HAND_SLOT);
				if (sheetId)
				{
					weaponLH = (double)sheetId->asInt();
				}
				props->set("WeaponLeftHand",  weaponLH);
			}

			props->set("JacketColor", (double)vA.PropertySubData.JacketColor);
			props->set("TrouserColor", (double)vA.PropertySubData.TrouserColor);
			props->set("FeetColor", (double)vB.PropertySubData.FeetColor);
			props->set("HandsColor", (double)vB.PropertySubData.HandsColor);
			props->set("ArmColor", (double)vA.PropertySubData.ArmColor);

			CPlayerR2CL * player = (CPlayerR2CL*)dynamic_cast<CPlayerR2CL*>(clonee);
			if(player != NULL)
			{
				std::string race, gender, sheetClient;
				switch(player->people())
				{
				case EGSPD::CPeople::Fyros:
					sheetClient = "basic_fyros_";
					race = "Fyros";
					break;

				case EGSPD::CPeople::Matis:
					sheetClient = "basic_matis_";
					race = "Matis";
					break;

				case EGSPD::CPeople::Tryker:
					sheetClient = "basic_tryker_";
					race = "Tryker";
					break;

				case EGSPD::CPeople::Zorai:
					sheetClient = "basic_zorai_";
					race = "Zorai";
					break;

				default:
					nlwarning("CToolCreateEntity::commit unknown people");
				}
				switch(player->getGender())
				{
				case GSGENDER::female:
					sheetClient = sheetClient+"female.creature";
					gender = "female";
					break;

				case GSGENDER::male:
					sheetClient = sheetClient+"male.creature";
					gender = "male";
					break;

				default:
					nlwarning("CToolCreateEntity::commit unknown gender");
				}

				props->set("SheetClient", sheetClient);

				// random name
				getEditor().getLua().push(race);
				getEditor().getLua().push(gender);
				if (getEditor().getEnv().callMethodByNameNoThrow("randomNPCName", 2, 1))
				{
					CLuaObject result(getEditor().getLua());
					std::string name = result.toString();
					props->set("Name", name);
				}
			}

			getEditor().getLua().push(getString(paletteNode, "Equipment"));
			getEditor().getLua().push(weaponRH);
			getEditor().getLua().push(weaponLH);
			getEditor().getLua().push(getString(paletteNode, "Sheet"));
			getEditor().getLua().push(getString(paletteNode, "SheetModel"));
			if (getEditor().getEnv().callMethodByNameNoThrow("searchSheet", 5, 1))
			{
				CLuaObject result(getEditor().getLua());
				std::string sheet = result.toString();
				props->set("Sheet", sheet);
			}
			else
			{
				nlwarning("SearchSheet failed : Palette Id = %s", _PaletteId.c_str());
				return "";
			}
		}
		else
		{
			desc->set("Name", readableName.toUtf8());
		}

		desc->set("Base", _PaletteId);
		desc->setObject("Position", buildVector(CVectorD(createPosition)));
		desc->set("Angle", createAngle);
		//desc->set("Name", readableName.toUtf8());

		instanceId = getString(desc.get(), "InstanceId");
		if (!instanceId.empty())
		{
			if (!createGhost)
			{
				// selection asked when instance is created
				getEditor().setCookie(instanceId, "Select", true);
			}
			else
			{
				getEditor().setCookie(instanceId, "GhostDuplicate", true);
			}
		}

		// send creation command
		// tmp : static npc counter
		// add in component list of default feature
		if (getEditor().getDefaultFeature())
		{
			std::string targetInstanceId;
			// if object is a bot object, it is considered to be permanent content
			// and should be created in the base act
			CInstance *targetAct =  isBotObject ? getEditor().getBaseAct() : getEditor().getCurrentAct();
			if (!targetAct)
			{
				nlwarning("Can't find act when creating an entity");
			}
			else
			{
				if (_AutoGroup.getGroupingCandidate())
				{
					nlassert(!createGhost); // either autogroup or arraymode, both at the same time not supported
					_AutoGroup.group(desc.get(), createPosition);
				}
				else
				{
					// create standalone
					desc->setGhost(createGhost);
					getDMC().requestInsertNode(getEditor().getDefaultFeature(targetAct)->getId(),
											   "Components",
											   -1,
											   "",
											   desc.get());
				}
			}
		}
	}
	return instanceId;
}
//*********************************************************************************************************
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);
	}
}
Beispiel #4
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;
}
//*********************************************************************************************************
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);
	}
}