Add infos into target window
[ryzomcore.git] / ryzom / client / src / r2 / tool_create_entity.cpp
blobeef82ef87231554d9220de58b4abd8f31a70b272
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdpch.h"
22 #include "editor.h"
23 #include "tool_create_entity.h"
25 #include "nel/misc/vectord.h"
26 #include "nel/misc/i18n.h"
28 #include "../client_sheets/character_sheet.h"
30 #include "../entity_cl.h"
31 #include "../player_r2_cl.h"
32 #include "../sheet_manager.h"
33 #include "nel/gui/lua_ihm.h"
34 #include "nel/misc/cdb_leaf.h"
35 #include "../interface_v3/interface_manager.h"
36 #include "dmc/palette.h"
37 #include "displayer_visual.h"
38 #include "r2_config.h"
39 #include "verbose_clock.h"
40 #include "entity_sorter.h"
42 #include "nel/gui/ctrl_base_button.h"
44 #include "game_share/player_visual_properties.h"
45 #include "game_share/visual_slot_manager.h"
47 #ifdef DEBUG_NEW
48 #define new DEBUG_NEW
49 #endif
51 using namespace NLPACS;
52 using namespace NLMISC;
53 using namespace std;
55 namespace R2
58 // ***************************************************************
59 CToolCreateEntity::~CToolCreateEntity()
61 clearArray();
64 // ***************************************************************
65 void CToolCreateEntity::cancel()
67 CToolChoosePos::cancel();
68 clearArray();
71 // ***************************************************************
72 CToolCreateEntity::CToolCreateEntity(uint ghostSlot, const std::string &paletteId, bool arrayMode) : CToolChoosePos(ghostSlot)
74 _PaletteId = paletteId;
75 if (!arrayMode)
77 enableMultiPos();
79 _CreateState = CreateSingle;
80 _ArrayOrigin.set(0.f, 0.f, 0.f);
81 _ArrayEnd.set(0.f, 0.f, 0.f);
82 _ArrayDefaultAngle = 0.f;
83 if (arrayMode)
85 CObject *paletteNode = getEditor().getDMC().getPaletteElement(paletteId);
86 if (paletteNode)
88 std::string sheetClient = getString(paletteNode, "SheetClient");
89 if (isBotObjectSheet(CSheetId(sheetClient)))
91 _CreateState = ChooseArrayOrigin;
95 _ArrayWantedAction = ArrayActionNone;
98 // ***************************************************************
99 void CToolCreateEntity::updateInvalidCursorOnUI()
101 //H_AUTO(R2_CToolCreateEntity_updateInvalidCursorOnUI)
102 // set the default cursor unless the mouse is on the palette
103 const std::vector<CInterfaceGroup *> &groups = CWidgetManager::getInstance()->getGroupsUnderPointer();
104 for(uint k = 0; k < groups.size(); ++k)
106 if (groups[k]->getId() == "ui:interface:r2ed_palette") // hardcoded for now ...
108 setMouseCursor(_CursValid);
109 return;
112 setMouseCursor(DEFAULT_CURSOR);
115 // ***************************************************************
116 void CToolCreateEntity::commit(const NLMISC::CVector &createPosition, float createAngle)
118 //H_AUTO(R2_CToolCreateEntity_commit)
119 if (_CreateState == ChooseArrayOrigin)
121 if (!getEditor().verifyRoomLeft(0, 1))
124 CLuaManager::getInstance().executeLuaScript("r2:checkStaticQuota(1)");
125 return;
127 setContextHelp(CI18N::get("uiR2EDDrawArrayContextHelp"));
128 _CreateState = DrawArray;
129 _ArrayDefaultAngle = createAngle;
130 _ArrayOrigin = createPosition;
131 _ArrayEnd = createPosition;
132 updateArray(getGhost());
133 removeGhostSlot();
134 return;
137 CEntityCL *ghost = getGhost();
138 if (!ghost) return;
140 cloneEntityIntoScenario(ghost,
141 createPosition,
142 createAngle,
143 true, /* new action */
144 false /* create ghost */);
146 if (isMultiPos() && isShiftDown())
148 // prevent newly created ghost to be removed twice ...
149 removeGhostSlot();
150 // re set this tool to generate a new entity look
151 CAHManager::getInstance()->runActionHandler("r2ed_create_entity", NULL, "PaletteId=" + _PaletteId);
155 // ***************************************************************
156 bool CToolCreateEntity::isBotObjectSheet(const NLMISC::CSheetId &sheetId) const
158 //H_AUTO(R2_CToolCreateEntity_isBotObjectSheet)
159 const CCharacterSheet *charSheet = dynamic_cast<const CCharacterSheet *>(SheetMngr.get(sheetId));
160 if (charSheet)
162 std::string botobjectsPaletteRoot = "palette.entities.botobjects";
163 return (_PaletteId.substr(0, botobjectsPaletteRoot.size()) == botobjectsPaletteRoot);
165 return false;
169 // ***************************************************************
170 std::string CToolCreateEntity::cloneEntityIntoScenario(CEntityCL *clonee,
171 const NLMISC::CVector &createPosition,
172 float createAngle,
173 bool newAction,
174 bool createGhost
177 //H_AUTO(R2_CToolCreateEntity_cloneEntityIntoScenario)
178 if (!clonee) return "";
179 std::string instanceId;
180 bool isBotObject = isBotObjectSheet(clonee->sheetId());
182 if (!getEditor().verifyRoomLeft(isBotObject ? 0 : 1, isBotObject ? 1 : 0)) { return ""; }
184 std::string className;
185 // if class is given in the palette node, then use it. Default to 'Npc' else
186 CObject *paletteNode = getDMC().getPaletteElement(_PaletteId);
187 if (paletteNode && paletteNode->findIndex("Class") != -1)
189 className = getString(paletteNode, "Class");
191 if (className.empty())
193 className = "Npc";
196 ucstring readableName;
197 // retrieve name from the palette id
198 CLuaState &ls = getEditor().getLua();
199 getEditor().getEnv()["PaletteIdToTranslation"][_PaletteId].push();
200 if (ls.isString(-1))
202 readableName.fromUtf8(ls.toString(-1));
204 if (readableName.empty())
206 // if no name found then give a default one
207 readableName = CI18N::get(isBotObject ? "uiR2EDNameBotObject" : "uiR2EDNameNPC");
210 // except for creatures, posfix the name with a number
211 std::string creaturePaletteRoot = "palette.entities.creatures";
212 if (_PaletteId.substr(0, creaturePaletteRoot.size()) != creaturePaletteRoot)
214 readableName = getEditor().genInstanceName(readableName);
216 else
218 className = "NpcCreature";
220 // is Plant
221 std::string sheetClient = getString(paletteNode, "SheetClient");
222 getEditor().getLua().push(sheetClient);
223 if (getEditor().getEnv().callMethodByNameNoThrow("isNPCPlant", 1, 1))
225 CLuaObject result(getEditor().getLua());
226 bool isPlant = result.toBoolean();
227 if (isPlant)
228 className = "NpcPlant";
232 if (newAction)
234 getDMC().newAction(NLMISC::CI18N::get("uiR2EDCreateAction") + readableName);
236 // send network commands to create entity on server
237 CUniquePtr<CObject> desc(getDMC().newComponent(className));
239 if (desc.get())
241 // TMP FIX : if the created entity is a custom npc, then retrieve look from the clonee visual properties
242 if (className == "NpcCustom")
244 SPropVisualA vA;
245 SPropVisualB vB;
246 SPropVisualC vC;
247 const string propNameA = toString("SERVER:Entities:E%d:P%d", clonee->slot(), CLFECOMMON::PROPERTY_VPA);
248 const string propNameB = toString("SERVER:Entities:E%d:P%d", clonee->slot(), CLFECOMMON::PROPERTY_VPB);
249 const string propNameC = toString("SERVER:Entities:E%d:P%d", clonee->slot(), CLFECOMMON::PROPERTY_VPC);
250 CCDBNodeLeaf *leafA = NLGUI::CDBManager::getInstance()->getDbProp(propNameA);
251 CCDBNodeLeaf *leafB = NLGUI::CDBManager::getInstance()->getDbProp(propNameB);
252 CCDBNodeLeaf *leafC = NLGUI::CDBManager::getInstance()->getDbProp(propNameC);
253 if (!leafA)
255 nlwarning("Can't find DB leaf %s", propNameA.c_str());
256 return "";
258 if (!leafB)
260 nlwarning("Can't find DB leaf %s", propNameB.c_str());
261 return "";
263 if (!leafC)
265 nlwarning("Can't find DB leaf %s", propNameC.c_str());
266 return "";
269 vA.PropertyA = leafA->getValue64();
270 vB.PropertyB = leafB->getValue64();
271 vC.PropertyC = leafC->getValue64();
272 nlassert(desc->isTable());
273 CObjectTable *props = (CObjectTable *) desc.get();
275 props->set("GabaritHeight", (double)vC.PropertySubData.CharacterHeight);
276 props->set("GabaritTorsoWidth", (double)vC.PropertySubData.TorsoWidth);
277 props->set("GabaritArmsWidth", (double)vC.PropertySubData.ArmsWidth);
278 props->set("GabaritLegsWidth", (double)vC.PropertySubData.LegsWidth);
279 props->set("GabaritBreastSize", (double)vC.PropertySubData.BreastSize);
281 props->set("HairColor", (double)vA.PropertySubData.HatColor);
282 props->set("Tattoo", (double)vC.PropertySubData.Tattoo);
283 props->set("EyesColor", (double)vC.PropertySubData.EyesColor);
285 props->set("MorphTarget1", (double)vC.PropertySubData.MorphTarget1);
286 props->set("MorphTarget2", (double)vC.PropertySubData.MorphTarget2);
287 props->set("MorphTarget3", (double)vC.PropertySubData.MorphTarget3);
288 props->set("MorphTarget4", (double)vC.PropertySubData.MorphTarget4);
289 props->set("MorphTarget5", (double)vC.PropertySubData.MorphTarget5);
290 props->set("MorphTarget6", (double)vC.PropertySubData.MorphTarget6);
291 props->set("MorphTarget7", (double)vC.PropertySubData.MorphTarget7);
292 props->set("MorphTarget8", (double)vC.PropertySubData.MorphTarget8);
294 props->set("Sex", (double)vA.PropertySubData.Sex);
296 CVisualSlotManager * vsManager = CVisualSlotManager::getInstance();
297 NLMISC::CSheetId * sheetId = NULL;
299 if(vA.PropertySubData.HatModel == 0)
301 props->set("HatModel", 0);
303 else
305 sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.HatModel, SLOTTYPE::HEAD_SLOT);
306 if (sheetId)
308 props->set("HairType", (double)sheetId->asInt());
312 if(vA.PropertySubData.JacketModel == 0)
314 props->set("JacketModel", 0);
316 else
318 sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.JacketModel, SLOTTYPE::CHEST_SLOT);
319 if (sheetId)
321 props->set("JacketModel", (double)sheetId->asInt());
325 if(vA.PropertySubData.TrouserModel == 0)
327 props->set("TrouserModel", 0);
329 else
331 sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.TrouserModel, SLOTTYPE::LEGS_SLOT);
332 if (sheetId)
334 props->set("TrouserModel", (double)sheetId->asInt());
338 if(vB.PropertySubData.FeetModel == 0)
340 props->set("FeetModel", 0);
342 else
344 sheetId = vsManager->index2Sheet((uint32)vB.PropertySubData.FeetModel, SLOTTYPE::FEET_SLOT);
345 if (sheetId)
347 props->set("FeetModel", (double)sheetId->asInt());
351 if(vB.PropertySubData.HandsModel == 0)
353 props->set("HandsModel", 0);
355 else
357 sheetId = vsManager->index2Sheet((uint32)vB.PropertySubData.HandsModel, SLOTTYPE::HANDS_SLOT);
358 if (sheetId)
360 props->set("HandsModel", (double)sheetId->asInt());
364 if(vA.PropertySubData.ArmModel == 0)
366 props->set("ArmModel", 0);
368 else
370 sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.ArmModel, SLOTTYPE::ARMS_SLOT);
371 if (sheetId)
373 props->set("ArmModel", (double)sheetId->asInt());
377 double weaponRH=0, weaponLH=0;
378 if(vA.PropertySubData.WeaponRightHand == 0)
380 props->set("WeaponRightHand", 0);
382 else
384 sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.WeaponRightHand, SLOTTYPE::RIGHT_HAND_SLOT);
385 if (sheetId)
387 weaponRH = (double)sheetId->asInt();
389 props->set("WeaponRightHand", weaponRH);
392 if(vA.PropertySubData.WeaponLeftHand == 0)
394 props->set("WeaponLeftHand", 0);
396 else
398 sheetId = vsManager->index2Sheet((uint32)vA.PropertySubData.WeaponLeftHand, SLOTTYPE::LEFT_HAND_SLOT);
399 if (sheetId)
401 weaponLH = (double)sheetId->asInt();
403 props->set("WeaponLeftHand", weaponLH);
406 props->set("JacketColor", (double)vA.PropertySubData.JacketColor);
407 props->set("TrouserColor", (double)vA.PropertySubData.TrouserColor);
408 props->set("FeetColor", (double)vB.PropertySubData.FeetColor);
409 props->set("HandsColor", (double)vB.PropertySubData.HandsColor);
410 props->set("ArmColor", (double)vA.PropertySubData.ArmColor);
412 CPlayerR2CL * player = (CPlayerR2CL*)dynamic_cast<CPlayerR2CL*>(clonee);
413 if(player != NULL)
415 std::string race, gender, sheetClient;
416 switch(player->people())
418 case EGSPD::CPeople::Fyros:
419 sheetClient = "basic_fyros_";
420 race = "Fyros";
421 break;
423 case EGSPD::CPeople::Matis:
424 sheetClient = "basic_matis_";
425 race = "Matis";
426 break;
428 case EGSPD::CPeople::Tryker:
429 sheetClient = "basic_tryker_";
430 race = "Tryker";
431 break;
433 case EGSPD::CPeople::Zorai:
434 sheetClient = "basic_zorai_";
435 race = "Zorai";
436 break;
438 default:
439 nlwarning("CToolCreateEntity::commit unknown people");
441 switch(player->getGender())
443 case GSGENDER::female:
444 sheetClient = sheetClient+"female.creature";
445 gender = "female";
446 break;
448 case GSGENDER::male:
449 sheetClient = sheetClient+"male.creature";
450 gender = "male";
451 break;
453 default:
454 nlwarning("CToolCreateEntity::commit unknown gender");
457 props->set("SheetClient", sheetClient);
459 // random name
460 getEditor().getLua().push(race);
461 getEditor().getLua().push(gender);
462 if (getEditor().getEnv().callMethodByNameNoThrow("randomNPCName", 2, 1))
464 CLuaObject result(getEditor().getLua());
465 std::string name = result.toString();
466 props->set("Name", name);
470 getEditor().getLua().push(getString(paletteNode, "Equipment"));
471 getEditor().getLua().push(weaponRH);
472 getEditor().getLua().push(weaponLH);
473 getEditor().getLua().push(getString(paletteNode, "Sheet"));
474 getEditor().getLua().push(getString(paletteNode, "SheetModel"));
475 if (getEditor().getEnv().callMethodByNameNoThrow("searchSheet", 5, 1))
477 CLuaObject result(getEditor().getLua());
478 std::string sheet = result.toString();
479 props->set("Sheet", sheet);
481 else
483 nlwarning("SearchSheet failed : Palette Id = %s", _PaletteId.c_str());
484 return "";
487 else
489 desc->set("Name", readableName.toUtf8());
492 desc->set("Base", _PaletteId);
493 desc->setObject("Position", buildVector(CVectorD(createPosition)));
494 desc->set("Angle", createAngle);
495 //desc->set("Name", readableName.toUtf8());
497 instanceId = getString(desc.get(), "InstanceId");
498 if (!instanceId.empty())
500 if (!createGhost)
502 // selection asked when instance is created
503 getEditor().setCookie(instanceId, "Select", true);
505 else
507 getEditor().setCookie(instanceId, "GhostDuplicate", true);
511 // send creation command
512 // tmp : static npc counter
513 // add in component list of default feature
514 if (getEditor().getDefaultFeature())
516 std::string targetInstanceId;
517 // if object is a bot object, it is considered to be permanent content
518 // and should be created in the base act
519 CInstance *targetAct = isBotObject ? getEditor().getBaseAct() : getEditor().getCurrentAct();
520 if (!targetAct)
522 nlwarning("Can't find act when creating an entity");
524 else
526 if (_AutoGroup.getGroupingCandidate())
528 nlassert(!createGhost); // either autogroup or arraymode, both at the same time not supported
529 _AutoGroup.group(desc.get(), createPosition);
531 else
533 // create standalone
534 desc->setGhost(createGhost);
535 getDMC().requestInsertNode(getEditor().getDefaultFeature(targetAct)->getId(),
536 "Components",
539 desc.get());
544 return instanceId;
547 // ***************************************************************
548 void CToolCreateEntity::onActivate()
550 //H_AUTO(R2_CToolCreateEntity_onActivate)
551 setContextHelp(CI18N::get("uiR2EDToolCreateEntity"));
554 // ***************************************************************
555 void CToolCreateEntity::updateBeforeRender()
557 //H_AUTO(R2_CToolCreateEntity_updateBeforeRender)
558 if (_CreateState != DrawArray)
560 CToolChoosePos::updateBeforeRender();
561 _AutoGroup.update(_CreatePosition, _PaletteId, _Valid && !isCtrlDown());
562 setContextHelp(CI18N::get(_AutoGroup.getGroupingCandidate() ? "uiR2EDToolCreateEntityAutoGroup" : "uiR2EDToolCreateEntity"));
563 return;
565 setContextHelp(CI18N::get("uiR2EDDrawArrayContextHelp"));
566 // update for array mode
567 bool valid = true;
568 sint32 mouseX, mouseY;
569 getMousePos(mouseX, mouseY);
570 if (!isInScreen(mouseX, mouseY) || (isMouseOnUI() && !isMouseOnWorldMap()))
572 valid = false;
573 _ArrayEnd = _ArrayOrigin;
576 CTool::CWorldViewRay worldViewRay;
577 computeWorldViewRay(mouseX, mouseY, worldViewRay);
579 CVector entityPos; // the pos where the ghost will be shown
580 CVector inter; // intersection of view ray with landscape
581 _ValidArray = true;
582 TRayIntersectionType rayIntersectionType = computeLandscapeRayIntersection(worldViewRay, inter);
583 switch(rayIntersectionType)
585 case NoIntersection:
586 _ValidArray = false;
587 _ArrayEnd = _ArrayOrigin;
588 break;
589 case ValidPacsPos:
590 case InvalidPacsPos:
591 _ArrayEnd = inter;
592 break;
594 for (uint k = 0; valid && k < _ArrayElements.size(); ++k)
596 if (_ArrayElements[k])
598 if (_ArrayElements[k]->getDisplayFlag(CDisplayerVisual::FlagBadPos))
600 _ValidArray = false;
604 CGroupMap *worldMap = getWorldMap();
605 if (worldMap) worldMap->setSelectionAxis(_ValidArray);
606 setMouseCursor(_ValidArray ? _CursValid : _CursInvalid);
609 // ***************************************************************
610 void CToolCreateEntity::updateAfterRender()
612 //H_AUTO(R2_CToolCreateEntity_updateAfterRender)
613 if (_CreateState != DrawArray)
615 CToolChoosePos::updateAfterRender();
616 return;
618 switch(_ArrayWantedAction)
620 case ArrayActionNone:
621 break;
622 case ArrayActionValidate:
624 commitArray();
625 CTool::TSmartPtr hold(this);
626 CAHManager::getInstance()->runActionHandler("r2ed_create_entity", NULL, "PaletteId="+_PaletteId);
627 return;
629 break;
630 case ArrayActionCancel:
632 CTool::TSmartPtr hold(this);
633 cancel();
634 getEditor().setCurrentTool(NULL);
635 return;
637 break;
639 updateArray(NULL);
643 // ***************************************************************
644 bool CToolCreateEntity::onMouseLeftButtonClicked()
646 //H_AUTO(R2_CToolCreateEntity_onMouseLeftButtonClicked)
647 if (_CreateState != DrawArray)
649 return CToolChoosePos::onMouseLeftButtonClicked();
651 if (_ValidArray)
653 _ArrayWantedAction = ArrayActionValidate;
655 return true;
658 // ***************************************************************
659 bool CToolCreateEntity::onMouseRightButtonClicked()
661 //H_AUTO(R2_CToolCreateEntity_onMouseRightButtonClicked)
662 if (_CreateState != DrawArray)
664 return CToolChoosePos::onMouseRightButtonClicked();
666 _ArrayWantedAction = ArrayActionCancel;
667 return true;
670 // ***************************************************************
671 void CToolCreateEntity::clearArray()
673 //H_AUTO(R2_CToolCreateEntity_clearArray)
674 for (uint k = 0; k < _ArrayElements.size(); ++k)
676 if (_ArrayElements[k])
678 getEditor().getDMC().requestEraseNode(_ArrayElements[k]->getDisplayedInstance()->getId(), "", -1);
683 // ***************************************************************
684 void CToolCreateEntity::updateArray(CEntityCL *clonee)
686 //H_AUTO(R2_CToolCreateEntity_updateArray)
687 if (!clonee)
689 nlassert(!_ArrayElements.empty());
690 nlassert(_ArrayElements[0] != NULL);
691 clonee = _ArrayElements[0]->getEntity();
692 if (!clonee)
694 return;
698 CVector extent = _ArrayEnd - _ArrayOrigin;
699 uint arraySize = 1;
700 float arrayStepLength = 1.f;
701 if (!_ArrayElements.empty() && _ArrayElements[0])
703 arrayStepLength = 2.f * _ArrayElements[0]->getSelectionDecalRadius();
704 arraySize = (uint) floorf(extent.norm() / arrayStepLength) + 1;
705 arraySize = std::min(arraySize, (uint) 16);
707 while (!getEditor().verifyRoomLeft(0, arraySize))
709 -- arraySize;
710 if (arraySize == 0)
712 TSmartPtr hold(this);
713 cancel();
714 return;
717 _ArrayElements.resize(std::max(arraySize, uint(_ArrayElements.size())));
718 CVector delta = arrayStepLength * extent.normed();
719 float angle = _ArrayDefaultAngle;
720 if (arraySize > 1)
722 angle = - (float) atan2(extent.x, extent.y);
724 bool newEntityCreated = false;
725 uint numCreatedEntity = 0;
726 for (uint k = 0; k < _ArrayElements.size(); ++k)
728 CVector pos = _ArrayOrigin + (float) k * delta;
729 if (!_ArrayElements[k])
731 if (k < arraySize)
733 nlwarning("NEW ENTITY");
734 // create new element
735 std::string instanceId = cloneEntityIntoScenario(clonee,
736 pos,
737 angle,
738 false, /*new action*/
739 true /*create ghost*/);
740 CInstance *inst = getEditor().getInstanceFromId(instanceId);
741 if (inst)
743 _ArrayElements[k] = dynamic_cast<CDisplayerVisualEntity *>(inst->getDisplayerVisual());
744 if (_ArrayElements[k])
746 _ArrayElements[k]->setDisplayMode(CDisplayerVisual::DisplayModeArray);
749 newEntityCreated = true;
750 ++ numCreatedEntity;
754 if (_ArrayElements[k])
756 bool active = k < arraySize;
757 // do a kind of 'reserve' on the list of entities : don't delete entities in excess, but hide them instead
758 if (active != _ArrayElements[k]->getActive())
760 _ArrayElements[k]->setActive(active);
761 if (active)
763 newEntityCreated = true;
764 _ArrayElements[k]->setDisplayMode(CDisplayerVisual::DisplayModeArray);
767 if (active)
769 // update pos & angle
770 TInstanceId instanceId = _ArrayElements[k]->getDisplayedInstance()->getId();
771 CVector worldPos = _ArrayElements[k]->getWorldPos();
772 if (pos != worldPos)
774 CObject *newPos = buildVector(pos, _ArrayElements[k]->getDisplayedInstance()->getPosInstanceId());
775 getEditor().getDMC().requestSetNode(instanceId, "Position", newPos);
776 delete newPos;
778 if (angle != _ArrayElements[k]->getAngle())
780 CObjectNumber *angleObject = new CObjectNumber(angle);
781 getEditor().getDMC().requestSetNode(instanceId, "Angle", angleObject);
782 delete angleObject;
787 if (newEntityCreated)
789 nlwarning("Num created entity = %d", numCreatedEntity);
790 getEditor().getEntitySorter()->clipEntitiesByDist();
794 // ***************************************************************
795 void CToolCreateEntity::commitArray()
797 //H_AUTO(R2_CToolCreateEntity_commitArray)
798 for (uint k = 0; k < _ArrayElements.size(); ++k)
800 if (_ArrayElements[k])
802 cloneEntityIntoScenario(_ArrayElements[k]->getEntity(),
803 _ArrayElements[k]->getWorldPos(),
804 _ArrayElements[k]->getAngle(),
805 k == 0, /*new action*/
806 false /*create ghost*/);
809 clearArray();
810 getEditor().getDMC().flushActions();
813 // ***************************************************************
814 bool CToolCreateEntity::stopAfterCommit() const
816 //H_AUTO(R2_CToolCreateEntity_stopAfterCommit)
817 return _CreateState == CreateSingle;
822 // ***************************************************************
823 class CAHR2EDToggleDrawArray : public IActionHandler
825 virtual void execute(CCtrlBase *pCaller, const std::string &/* sParams */)
827 CInterfaceManager *im = CInterfaceManager::getInstance();
828 CCtrlBaseButton *but = dynamic_cast<CCtrlBaseButton *>(pCaller);
829 if (but)
831 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:R2_DRAW_ARRAY")->setValueBool(but->getPushed());
832 CToolCreateEntity *tce = dynamic_cast<CToolCreateEntity *>(getEditor().getCurrentTool());
833 if (tce)
835 CAHManager::getInstance()->runActionHandler("r2ed_create_entity", NULL, "PaletteId=" + tce->getPaletteId());
840 REGISTER_ACTION_HANDLER(CAHR2EDToggleDrawArray, "r2ed_toggle_draw_array");
845 } // R2