virtual void visit(CInstance &inst) { if (inst.getDisplayerVisual()) { inst.getDisplayerVisual()->updateWorldPos(); } }
//*************************************************************** 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; } } } }
//*************************************************************** 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; }
// *************************************************************** 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; }
// *************************************************************** void CToolSelectRotate::setRotateInProgress(bool rotateInProgress, CInstance &instance) { //H_AUTO(R2_CToolSelectRotate_setRotateInProgress) CDisplayerVisual *dv = instance.getDisplayerVisual(); if (dv) dv->setRotateInProgress(rotateInProgress); }
//*************************************************************** 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(); } }
//*************************************************************** 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 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); } }