Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / ai_service / ai_spire.cpp
blob180e75f1337d9adefa2ea36019e43a256b1b49a4
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdpch.h"
18 #include "ai_spire.h"
20 #include "ai_instance.h"
21 #include "ais_actions.h"
23 using namespace AITYPES;
24 using namespace std;
25 using namespace CAISActionEnums;
28 extern CAIInstance* currentInstance;
30 DEFINE_ACTION(ContextGlobal, SPIREMGR)
32 nlassertex(currentInstance != NULL, ("No AIInstance created !"));
33 CAIInstance* aiInstance = currentInstance ;
34 CWorkPtr::aiInstance(aiInstance); // set the current AIInstance.
36 // get hold of the manager's slot id - note that managers are identified by slot and not by alias!
37 uint32 alias;
38 string spireName;
39 string mapName;
40 string filename;
41 if (!getArgs(args, name(), alias, spireName, mapName, filename))
42 return;
44 string mgrName = "spire_manager_"+spireName;
46 // see whether the manager is already loaded
47 CManager* mgr = aiInstance->managers().getChildByName(mgrName);
49 // not found so look for a free slot
50 if (!mgr)
51 aiInstance->newMgr(MgrTypeNpc, 0, mgrName, mapName, filename);
52 else
53 mgr->registerForFile(filename);
55 mgr = aiInstance->managers().getChildByName(mgrName);
56 CMgrNpc* mgrNpc = dynamic_cast<CMgrNpc*>(mgr);
57 if (!mgrNpc)
58 return;
60 // setup the working manager pointer and exit
61 CWorkPtr::mgr(mgrNpc);
62 CWorkPtr::eventReactionContainer(mgrNpc->getStateMachine());
64 // set workptr state to this state
65 CContextStack::setContext(ContextNpcMgr);
68 DEFINE_ACTION(ContextEventContainer, SPIRSTAT) // spire state
70 CStateMachine* container = CWorkPtr::eventReactionContainer();
71 if (!container)
72 return;
74 uint32 alias;
75 string spireName;
76 if (!getArgs(args, name(), alias, spireName))
77 return;
79 string stateName = "spire_state_"+spireName;
81 CAIStatePositional* state = new CAIStatePositional(container, alias, stateName);
82 container->states().addAliasChild(state);
83 // set workptr::state to this state
84 CWorkPtr::stateState(container->states()[0]);
85 if (!CWorkPtr::stateState())
87 nlwarning("Failed to select state %s", LigoConfig.aliasToString(alias).c_str());
88 return;
91 // set workptr state to this state
92 CContextStack::setContext(ContextPositionalState);
95 DEFINE_ACTION(ContextNpcMgr, SPIREGRP)
97 CMgrNpc* mgr = CWorkPtr::mgrNpc();
98 if (!mgr)
99 return;
101 uint32 alias;
102 string spireName;
103 if (!getArgs(args, name(), alias, spireName))
104 return;
106 string grpName = "spire_group_"+spireName;
108 CGroupNpc* grp = new CGroupNpc(mgr, alias, grpName, RYAI_MAP_CRUNCH::Nothing);
109 grp->setAutoSpawn(false);
110 mgr->groups().addChild(grp);
111 CWorkPtr::grp(grp);
112 if (!CWorkPtr::grpNpc())
114 nlwarning("Failed to select spire group %s as not found in manager: %s",
115 grpName.c_str(),
116 CWorkPtr::mgrNpc()->getName().c_str());
117 return;
119 CStateMachine* stateMachine = CWorkPtr::eventReactionContainer();
120 if (stateMachine)
121 grp->setStartState(stateMachine->cstStates()[0]);
123 CContextStack::setContext(ContextNpcGrp);
126 DEFINE_ACTION(ContextNpcGrp, SPIREBOT)
128 CGroupNpc* grp = CWorkPtr::grpNpc();
129 if (!grp)
130 return;
132 uint32 alias;
133 string spireName;
134 if (!getArgs(args, name(), alias, spireName))
135 return;
137 string botName = "spire_bot_"+spireName;
139 CBotNpc* bot = new CBotNpc(grp, alias, botName);
140 grp->bots().addChild(bot);
141 CWorkPtr::bot(bot);
142 if (!CWorkPtr::botNpc())
144 nlwarning("Failed to select spire bot %s as not found in group: %s",
145 botName.c_str(),
146 CWorkPtr::grpNpc()->getName().c_str());
147 return;
150 if (bot->getChat().isNull())
151 bot->newChat();
152 bot->getChat()->add(bot->getAIInstance(), "op:spire");
154 bot->setStuck(true);
156 // set workptr state to this state
157 CContextStack::setContext(ContextNpcBot);
160 DEFINE_ACTION(ContextNpcBot, SPIRSHTS)
162 CGroupNpc* grp = CWorkPtr::grpNpc();
163 if (!grp)
164 return;
166 CBotNpc* bot = CWorkPtr::botNpc();
167 if (!bot)
168 return;
170 FOREACHC(itArg, std::vector<CAIActions::CArg>, args)
172 string str, name, sheet;
173 itArg->get(str);
174 AI_SHARE::stringToKeywordAndTail(str, name, sheet);
175 grp->setStrLogicVar(NLMISC::CStringMapper::map("$sheet_spire_"+name), sheet);
183 #if 0
184 #include "continent.h"
185 #include "ai_grp_npc.h"
186 #include "game_share/people.h"
187 #include "ai_profile_npc.h"
189 #include "continent_inline.h"
190 #include "dyn_grp_inline.h"
192 using namespace std;
193 using namespace NLMISC;
197 CFileDisplayer SpireDisplayer("spires.log");
198 CLog SpireDbgLog(CLog::LOG_DEBUG), SpireInfLog(CLog::LOG_INFO), SpireWrnLog(CLog::LOG_WARNING), SpireErrLog(CLog::LOG_ERROR);
201 namespace SPIREHELPERS {
203 static std::map<uint32, uint32> spireFactions;
205 bool isAttackingFaction(uint32 factionIndex, CAIEntityPhysical const* player)
207 std::map<uint32, uint32>::const_iterator it = spireFactions.find(player->spireAlias());
208 return it!=spireFactions.end() && it->second==factionIndex;
213 //////////////////////////////////////////////////////////////////////////////
214 // CSpire //
215 //////////////////////////////////////////////////////////////////////////////
217 //std::set<CContinent*> ChangedSpires;
218 //CSpire::TSpireIndex CSpire::_Spires;
220 CSpire::CSpire(CContinent* owner, uint32 alias, std::string const& name, std::string const& filename)
221 : CAliasChild<CContinent>(owner, alias, name)
222 , CAliasTreeRoot(filename)
223 , _OwnerAllianceId(InvalidAllianceId)
224 , _AttackerAllianceId(InvalidAllianceId)
225 , _State(SPIREENUMS::UnknownSpireState)
228 static bool logInitDone = false;
229 if ( ! logInitDone )
231 SpireDbgLog.addDisplayer( &SpireDisplayer );
232 SpireInfLog.addDisplayer( &SpireDisplayer );
233 SpireWrnLog.addDisplayer( &SpireDisplayer );
234 logInitDone = true;
237 SPIRE_DBG("Creating spire %s' (%s)", name.c_str(), getAliasFullName().c_str());
238 if (LogSpireDebug)
239 SPIRE_DBG("Creating spire '%s'", getAliasFullName().c_str());
241 _SpireName = getName();
242 CSpireManager* manager = NULL;
243 // Create default squad manager
244 manager = new CSpireSquadManager(this, 0, "default_squad_manager", filename);
245 if (manager)
247 _Managers.addChild(manager);
248 manager->init();
250 // Create default building manager
251 manager = new CSpireManager(this, 0, "default_building_manager", filename);
252 if (manager)
254 _Managers.addChild(manager);
255 manager->init();
256 CGroupNpc* group = new CGroupNpc(manager, NULL, /*AStarFlag*/RYAI_MAP_CRUNCH::Nothing);
257 if (group)
259 manager->groups().addAliasChild(group);
260 group->setAutoSpawn(false);
261 group->setName("default_building_group");
262 group->clearParameters();
263 group->setPlayerAttackable(false);
264 group->setBotAttackable(false);
265 group->setBotsAreNamedFlag();
270 CSpire::~CSpire()
272 if (LogSpireDebug)
273 SPIRE_DBG("Deleting spire '%s'", getAliasFullName().c_str());
275 _SpawnZones.clear();
278 std::string CSpire::getOneLineInfoString() const
280 return std::string("Spire '") + getName() + "' " + getAliasString() + ", State=" + SPIREENUMS::toString(_State);
283 std::string CSpire::getFullName() const
285 return std::string(getOwner()->getFullName() +":"+ getName());
288 std::string CSpire::getIndexString() const
290 return getOwner()->getIndexString()+NLMISC::toString(":o%u", getChildIndex());
293 std::string CSpire::getPlaceOwnerFullName() const
295 return getFullName();
298 std::string CSpire::getPlaceOwnerIndexString() const
300 return getIndexString();
303 CAIInstance* CSpire::getAIInstance() const
305 return getOwner()->getAIInstance();
308 std::string CSpire::getManagerIndexString(CManager const* manager) const
310 return getIndexString()+NLMISC::toString(":m%u", manager->getChildIndex());
313 IAliasCont* CSpire::getAliasCont(TAIType type)
315 switch (type)
317 case AITypeSpireSquadFamily:
318 SPIRE_WRN( "Obsolete squad family node under spire %s", getName().c_str() );
319 return NULL;
320 case AITypeSpireSpawnZone:
321 return &_SpawnZones;
322 case AITypeManager:
323 return &_Managers;
324 case AITypeSpireManager:
325 return &_Managers;
326 case AITypeSpireBuilding:
327 return getBuildingGroup()->getAliasCont(AITypeBot);
328 default:
329 return NULL;
334 CAliasTreeOwner* CSpire::createChild(IAliasCont* cont, CAIAliasDescriptionNode* aliasTree)
336 if (!cont)
337 return NULL;
339 CAliasTreeOwner* child = NULL;
341 switch(aliasTree->getType())
343 // create the child and adds it to the corresponding position.
344 case AITypeSpireSpawnZone:
345 child = new CSpireSpawnZone(this, aliasTree);
346 break;
347 case AITypeManager:
348 child = new CSpireSquadManager(this, aliasTree->getAlias(), aliasTree->getName());
349 break;
350 case AITypeSpireManager:
351 child = new CSpireSquadManager(this, aliasTree->getAlias(), aliasTree->getName());
352 break;
353 case AITypeSpireBuilding:
354 return getBuildingGroup()->createChild(cont, aliasTree);
357 if (child)
358 cont->addAliasChild(child);
359 return child;
362 CGroup* CSpire::getBuildingGroup()
364 CSpireManager* manager = _Managers.getChildByName("default_building_manager");
365 return manager->groups().getChildByName("default_building_group");
368 void CSpire::setTribe(const std::string &tribeName)
370 // The tribe is only populated by the NPCs of the squads
371 _Tribe = tribeName;
372 if (LogSpireDebug)
373 SPIRE_DBG("setting tribe '%s' in '%s' as owner for spire '%s'",
374 tribeName.c_str(),
375 getOwner()->getName().c_str(),
376 getAliasFullName().c_str());
379 void CSpire::setOwnerAlliance( TAllianceId ownerAllianceId )
381 if (_OwnerAllianceId!=ownerAllianceId)
383 // if the old owner was a tribe
384 if (_OwnerAllianceId==InvalidAllianceId)
386 triggerSpecialEvent(SPIREENUMS::TribeOwnershipEnd);
387 SPIREHELPERS::spireFactions.erase(getAlias());
389 else
390 triggerSpecialEvent(SPIREENUMS::GuildOwnershipEnd);
392 std::swap(_OwnerAllianceId, ownerAllianceId); // 'ownerAllianceId' contains old owner alliance id
393 if (_OwnerAllianceId!=ownerAllianceId)
395 triggerSpecialEvent(SPIREENUMS::OwnerChanged);
396 // if the new owner is a tribe
397 if (_OwnerAllianceId==InvalidAllianceId)
399 SPIREHELPERS::spireFactions.insert(make_pair(getAlias(), CStaticFames::getInstance().getFactionIndex(_Tribe)));
400 triggerSpecialEvent(SPIREENUMS::TribeOwnershipBegin);
402 else
403 triggerSpecialEvent(SPIREENUMS::GuildOwnershipBegin);
407 void CSpire::setAttackerAlliance( TAllianceId attackerAllianceId )
409 std::swap(_AttackerAllianceId, attackerAllianceId); // 'attackerAllianceId' contains old attacker alliance id
410 if (_AttackerAllianceId!=attackerAllianceId)
412 triggerSpecialEvent(SPIREENUMS::AttackerChanged);
415 // Update the enemies of the current squads of the spire
416 FOREACH( im, CAliasCont<CSpireManager>, _Managers )
417 im->setEnemies( _AttackerAllianceId );
420 void CSpire::setState( SPIREENUMS::TSpireState state )
422 if (_State!=state)
424 if (_State==SPIREENUMS::Peace)
425 triggerSpecialEvent(SPIREENUMS::PeaceStateEnd);
427 std::swap(_State, state); // 'state' contains old _State
428 if (_State!=state)
430 triggerSpecialEvent(SPIREENUMS::StateChanged);
431 if (_State==SPIREENUMS::Peace)
432 triggerSpecialEvent(SPIREENUMS::PeaceStateBegin);
436 void CSpire::update()
438 // FOREACH(it, CAliasCont<CSpireSquadFamily>, _SquadFamilies) it->update();
439 // FOREACH(it, CAliasCont<CSpireSpawnZone>, _SpawnZones) it->update();
440 FOREACH(it, CAliasCont<CSpireManager>, _Managers) it->update();
443 void CSpire::addZone(CSpireSpawnZone* zone)
445 #if !FINAL_VERSION
446 if (_ZoneList.find(NLMISC::CStringMapper::map(zone->getName()))!=_ZoneList.end())
447 SPIRE_WRN("this SpireSpawnZone have the same name than another: %s", zone->getName().c_str());
448 #endif
449 _ZoneList[NLMISC::CStringMapper::map(zone->getName())] = zone;
452 void CSpire::removeZone(CSpireSpawnZone* zone)
454 _ZoneList.erase(NLMISC::CStringMapper::map(zone->getName()));
457 CSpireSpawnZone* CSpire::getZone(NLMISC::TStringId zoneName)
459 return _ZoneList[zoneName];
462 void CSpire::serviceEvent(CServiceEvent const& info)
464 if (info.getServiceName()=="EGS" && info.getEventType()==CServiceEvent::SERVICE_DOWN)
466 // Delete all the squad groups
467 CSpireManager* manager = _Managers.getChildByName("default_squad_manager");
468 if (manager)
469 manager->groups().clear();
471 FOREACH(itManager, CAliasCont<CSpireManager>, _Managers)
473 CSpireManager* manager = *itManager;
474 manager->serviceEvent(info);
478 bool CSpire::spawn()
480 // Spawn spire managers
481 CCont<CSpireManager>::iterator itManager, itManagerEnd(_Managers.end());
482 for (itManager=_Managers.begin(); itManager!=itManagerEnd; ++itManager)
484 CSpireManager* manager = *itManager;
485 manager->spawn();
487 // We should check individual errors, but fake success here :)
488 return true;
491 bool CSpire::despawn()
493 // Despawn instance managers
494 CCont<CSpireManager>::iterator itManager, itManagerEnd(_Managers.end());
495 for (itManager=_Managers.begin(); itManager!=itManagerEnd; ++itManager)
497 CSpireManager* manager = *itManager;
498 manager->despawnMgr();
500 // We should check individual errors, but fake success here :)
501 return true;
504 //-----------------------------------------------------------------------------
505 std::string CSpire::getStateName() const
507 return SPIREENUMS::toString(_State);
510 //////////////////////////////////////////////////////////////////////////////
511 // CSpireSquadFamily //
512 //////////////////////////////////////////////////////////////////////////////
514 IAliasCont* CSpireSquadFamily::getAliasCont(TAIType type)
516 switch (type)
518 case AITypeGroupTemplate:
519 case AITypeGroupTemplateMultiLevel:
520 return &_GroupDescs;
521 default:
522 return NULL;
527 CAliasTreeOwner* CSpireSquadFamily::createChild(IAliasCont* cont, CAIAliasDescriptionNode* aliasTree)
529 if (!cont)
530 return NULL;
532 CAliasTreeOwner* child = NULL;
534 switch (aliasTree->getType())
536 case AITypeSquadTemplateVariant:
537 child = new CGroupDesc<CSpireSquadFamily>(this, aliasTree->getAlias(), aliasTree->getParent()->getName()+":"+aliasTree->getName());
538 break;
539 case AITypeGroupTemplate:
540 case AITypeGroupTemplateMultiLevel:
541 child = new CGroupDesc<CSpireSquadFamily>(this, aliasTree->getAlias(), aliasTree->getName());
542 break;
545 if (child)
546 cont->addAliasChild(child);
547 return child;
550 std::string CSpireSquadFamily::getFullName() const
552 // return std::string(getOwner()->getFullName() +":"+ getName());
553 return getName();
556 std::string CSpireSquadFamily::getIndexString() const
558 return getOwner()->getIndexString()+NLMISC::toString(":sf%u", getChildIndex());
561 //////////////////////////////////////////////////////////////////////////////
562 // CGroupDesc //
563 //////////////////////////////////////////////////////////////////////////////
565 template <> size_t const CGroupDesc<CSpireSquadFamily>::_MultiLevelSheetCount = 20;
567 //////////////////////////////////////////////////////////////////////////////
568 // CBotDesc //
569 //////////////////////////////////////////////////////////////////////////////
571 template <> size_t const CBotDesc<CSpireSquadFamily>::_MultiLevelSheetCount = 20;
573 //////////////////////////////////////////////////////////////////////////////
574 // CSpireSpawnZone //
575 //////////////////////////////////////////////////////////////////////////////
577 CSpireSpawnZone::CSpireSpawnZone(CSpire* owner, CAIAliasDescriptionNode* adn)
578 : CAIPlaceXYR(owner, adn)
580 owner->addZone(this);
583 CSpireSpawnZone::~CSpireSpawnZone()
585 static_cast<CSpire*>(getOwner())->removeZone(this);
588 std::string CSpireSpawnZone::getFullName() const
590 return std::string(getOwner()->getFullName() +":"+ getName());
593 std::string CSpireSpawnZone::getIndexString() const
595 return getOwner()->getIndexString()+NLMISC::toString(":%u", getChildIndex());
598 //////////////////////////////////////////////////////////////////////////////
599 // CSpireManager //
600 //////////////////////////////////////////////////////////////////////////////
602 CSpireManager::CSpireManager(CSpire* parent, uint32 alias, std::string const& name, std::string const& filename)
603 : CMgrNpc(parent, alias, name, filename)
604 , _AutoSpawn(false)
606 registerEvents();
609 CSpireManager::~CSpireManager()
611 unregisterEvents(); // need be called otherwise the state manager will be unhappy when the CAIEvent objects are destroyed
614 std::string CSpireManager::getOneLineInfoString() const
616 return std::string("Spire manager '") + getName() + "'";
619 void CSpireManager::update()
621 CMgrNpc::update();
624 IAliasCont* CSpireManager::getAliasCont(TAIType type)
626 // IAliasCont* cont = NULL;
627 // switch (type)
628 // {
629 // default:
630 // break;
631 // }
632 // if (cont)
633 // return cont;
634 // else
635 return CMgrNpc::getAliasCont(type);
638 CAliasTreeOwner* CSpireManager::createChild(IAliasCont* cont, CAIAliasDescriptionNode* aliasTree)
640 // CAliasTreeOwner* child = NULL;
641 // switch (aliasTree->getType())
642 // {
643 // default:
644 // break;
645 // }
646 // if (child)
647 // cont->addAliasChild(child);
648 // if (child)
649 // return child;
650 // else
651 return CMgrNpc::createChild(cont, aliasTree);
654 void CSpireManager::registerEvents()
656 _StateMachine.addEvent( "spire_peace_state_begin", EventSpirePeaceStateBegin );
657 _StateMachine.addEvent( "spire_peace_state_end", EventSpirePeaceStateEnd );
658 _StateMachine.addEvent( "spire_tribe_ownership_begin", EventSpireTribeOwnershipBegin );
659 _StateMachine.addEvent( "spire_tribe_ownership_end", EventSpireTribeOwnershipEnd );
660 _StateMachine.addEvent( "spire_guild_ownership_begin", EventSpireGuildOwnershipBegin );
661 _StateMachine.addEvent( "spire_guild_ownership_end", EventSpireGuildOwnershipEnd );
662 _StateMachine.addEvent( "spire_owner_changed", EventSpireOwnerChanged );
663 _StateMachine.addEvent( "spire_attacker_changed", EventSpireAttackerChanged );
664 _StateMachine.addEvent( "spire_state_changed", EventSpireStateChanged );
667 void CSpireManager::unregisterEvents()
669 _StateMachine.delEvent( "spire_peace_state_begin" );
670 _StateMachine.delEvent( "spire_peace_state_end" );
671 _StateMachine.delEvent( "spire_tribe_ownership_begin" );
672 _StateMachine.delEvent( "spire_tribe_ownership_end" );
673 _StateMachine.delEvent( "spire_guild_ownership_begin" );
674 _StateMachine.delEvent( "spire_guild_ownership_end" );
675 _StateMachine.delEvent( "spire_owner_changed" );
676 _StateMachine.delEvent( "spire_attacker_changed" );
677 _StateMachine.delEvent( "spire_state_changed" );
680 void CSpireManager::autoSpawnBegin()
682 if (!_AutoSpawn)
683 return;
684 FOREACH(itGroup, CCont<CGroup>, groups())
686 CGroupNpc* group = static_cast<CGroupNpc*>(*itGroup);
687 if (group)
689 CSpawnGroupNpc* spawn = group->getSpawnObj();
690 if (spawn)
691 spawn->spawnBots();
696 void CSpireManager::autoSpawnEnd()
698 if (!_AutoSpawn)
699 return;
700 FOREACH(itGroup, CCont<CGroup>, groups())
702 CGroupNpc* group = static_cast<CGroupNpc*>(*itGroup);
703 if (group)
705 CSpawnGroupNpc* spawn = group->getSpawnObj();
706 if (spawn)
707 spawn->despawnBots(1);
712 void CSpireManager::setEnemies( TAllianceId attackerAllianceId )
714 FOREACH( ig, CAliasCont<CGroup>, _Groups )
716 // Attack only the declared ennemies of the spire
717 CGroupNpc *grp = static_cast<CGroupNpc*>(*ig);
718 grp->ennemyFaction().clearExtra();
719 grp->ennemyFaction().addExtraProperty(attackerAllianceId);
723 //////////////////////////////////////////////////////////////////////////////
724 // CSpireSquadManager //
725 //////////////////////////////////////////////////////////////////////////////
727 CSpireSquadManager::CSpireSquadManager(CSpire* parent, uint32 alias, std::string const& name, std::string const& filename)
728 : CSpireManager(parent, alias, name, filename)
730 // Create init state
731 CAIState* state = new CAIStatePositional(getStateMachine(), 0, "spire_squad_init");
732 IAIProfileFactory* aiProfile = lookupAIGrpProfile("squad");
733 state->setActivityProfile(aiProfile);
734 getStateMachine()->states().addChild(state);
736 CAIEventDescription eventDescription;
737 CAIEventActionNode::TSmartPtr eventAction;
738 CAIEventReaction* event;
740 // Create event handler for start of state
741 eventDescription.EventType = "start_of_state";
742 // eventDescription.StateKeywords.push_back("");
743 // eventDescription.NamedStates.push_back("");
744 // eventDescription.GroupKeywords.push_back("");
745 // eventDescription.NamedGroups.push_back("");
747 // Create event action
748 eventAction = new CAIEventActionNode;
749 eventAction->Action = "code";
750 eventAction->Weight = 1;
751 eventAction->Args.push_back("print(\"CREATING A SQUAD\");");
752 // eventAction->Args.push_back("()setFactionProp(\"faction\", \"foo\");");
753 // eventAction->Args.push_back("()setFactionProp(\"ennemyFaction\", \"bar\");");
754 // eventAction->Args.push_back("()setFactionProp(\"friendFaction\", \"baf\");");
755 eventAction->Args.push_back("()setHealer(1);");
757 // Register event action
758 eventDescription.Action = eventAction;
759 eventAction = NULL;
761 // Register event handler
762 // FIXME: 0 == CAIAliasDescriptionNode instance
763 event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType);
764 event->processEventDescription(&eventDescription, getStateMachine());
765 getStateMachine()->eventReactions().addChild(event);
766 event = NULL;
768 // Create event handler for group death
769 eventDescription.EventType = "group_eliminated";
770 // eventDescription.StateKeywords.push_back("");
771 // eventDescription.NamedStates.push_back("");
772 // eventDescription.GroupKeywords.push_back("");
773 // eventDescription.NamedGroups.push_back("");
775 // Create event action
776 eventAction = new CAIEventActionNode;
777 eventAction->Action = "spire_report_squad_death";
778 eventAction->Weight = 1;
779 // eventAction->Args.push_back("");
781 // Register event action
782 eventDescription.Action = eventAction;
783 eventAction = NULL;
785 // Register event handler
786 // FIXME: 0 == CAIAliasDescriptionNode instance
787 event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType);
788 event->processEventDescription(&eventDescription, getStateMachine());
789 getStateMachine()->eventReactions().addChild(event);
790 event = NULL;
792 // Create event handler for bot death
793 eventDescription.EventType = "bot_killed";
794 // eventDescription.StateKeywords.push_back("");
795 // eventDescription.NamedStates.push_back("");
796 // eventDescription.GroupKeywords.push_back("");
797 // eventDescription.NamedGroups.push_back("");
799 // Create event action
800 eventAction = new CAIEventActionNode;
801 eventAction->Action = "spire_send_squad_status";
802 eventAction->Weight = 1;
803 // eventAction->Args.push_back("");
805 // Register event action
806 eventDescription.Action = eventAction;
807 eventAction = NULL;
809 // Register event handler
810 // FIXME: 0 == CAIAliasDescriptionNode instance
811 event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType);
812 event->processEventDescription(&eventDescription, getStateMachine());
813 getStateMachine()->eventReactions().addChild(event);
814 event = NULL;
816 // Create event handler for bot death
817 eventDescription.EventType = "squad_leader_killed";
818 // eventDescription.StateKeywords.push_back("");
819 // eventDescription.NamedStates.push_back("");
820 // eventDescription.GroupKeywords.push_back("");
821 // eventDescription.NamedGroups.push_back("");
823 // Create event action
824 eventAction = new CAIEventActionNode;
825 eventAction->Action = "multi_actions";
826 eventAction->Weight = 1;
827 eventAction->Children.resize(2);
828 eventAction->Children[0] = new CAIEventActionNode;
829 eventAction->Children[0]->Action = "spire_report_squad_leader_death";
830 eventAction->Children[0]->Weight = 1;
831 // eventAction->Children[0]->Args.push_back("");
832 eventAction->Children[1] = new CAIEventActionNode;
833 eventAction->Children[1]->Action = "code";
834 eventAction->Children[1]->Weight = 1;
835 eventAction->Children[1]->Args.push_back("()setAutoSpawn(0);");
836 #ifdef NL_DEBUG
837 eventAction->Children[1]->Args.push_back("print(\"INFINITE RESPAWN TIME FOR SQUAD\");");
838 #endif
840 // Register event action
841 eventDescription.Action = eventAction;
842 eventAction = NULL;
844 // Register event handler
845 // FIXME: 0 == CAIAliasDescriptionNode instance
846 event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType);
847 event->processEventDescription(&eventDescription, getStateMachine());
848 getStateMachine()->eventReactions().addChild(event);
849 event = NULL;
852 //////////////////////////////////////////////////////////////////////////////
853 //////////////////////////////////////////////////////////////////////////////
854 //////////////////////////////////////////////////////////////////////////////
856 void CSpire::createSquad(string const& dynGroupName, string const& stateMachineName, string const& initialStateName, string const& zoneName, uint32 spawnOrder, uint32 respawTimeGC, SPIREENUMS::TPVPSide side)
858 IManagerParent* const managerParent = getOwner()->getOwner();
859 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
860 if (!aiInstance)
861 return;
863 CSpireSpawnZone const* spawnZone = getZone(CStringMapper::map(zoneName));
864 if (!spawnZone)
866 SPIRE_WRN("newNpcChildGroup failed : spawnZone Not Found ! for StateMachine : %s", stateMachineName.c_str());
867 return;
870 CGroupDesc<CSpireSquadFamily> const* groupDesc = NULL;
872 FOREACH(itGroupDesc, CSquadLinks, _SquadLinks)
874 if ((*itGroupDesc).second->getName()==dynGroupName)
876 groupDesc = (*itGroupDesc).second;
877 goto groupFound;
880 groupFound:
881 if (!groupDesc)
883 SPIRE_WRN("createSquad failed: No Group Found");
884 return;
887 // Find the state machine as a manager
888 CManager* manager = NULL;
889 FOREACH(itCont, CCont<CManager>, aiInstance->managers())
891 if (itCont->getName()==stateMachineName)
893 manager = *itCont;
894 break;
897 if (!manager)
899 FOREACH(itCont, CCont<CSpireManager>, managers())
901 if (itCont->getName()==stateMachineName)
903 manager = *itCont;
904 break;
908 if (!manager)
910 SPIRE_WRN("createSquad failed : Unknown stateMachine %s", stateMachineName.c_str());
911 return;
913 // Find the state machine as a npc manager
914 CSpireSquadManager* spireManager = dynamic_cast<CSpireSquadManager*>(manager);
915 if (!spireManager)
917 SPIRE_WRN("createSquad failed : Not an spire state machine !: ", stateMachineName.c_str());
918 return;
920 createSquad(groupDesc, spireManager, initialStateName, spawnZone, spawnOrder, respawTimeGC, side);
923 void CSpire::createSquad(uint32 dynGroupAlias, uint32 zoneAlias, uint32 spawnOrder, uint32 respawTimeGC, SPIREENUMS::TPVPSide side)
925 IManagerParent* const managerParent = getOwner()->getOwner();
926 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
927 if (!aiInstance)
928 return;
930 CSpireSpawnZone const* spawnZone = spawnZones().getChildByAlias(zoneAlias);
931 if (!spawnZone)
933 SPIRE_WRN("createSquad failed: spawn zone %s not found", LigoConfig.aliasToString(zoneAlias).c_str());
934 return;
937 CGroupDesc<CSpireSquadFamily> const* groupDesc = NULL;
939 // Find the group template.
940 // :TODO: Replace it with a faster map access.
941 groupDesc = getSquad( dynGroupAlias );
942 if (!groupDesc)
944 SPIRE_WRN("createSquad failed: group %s not found", LigoConfig.aliasToString(dynGroupAlias).c_str());
945 return;
948 // Find the state machine as a manager
949 CSpireSquadManager* manager = dynamic_cast<CSpireSquadManager*>(managers().getChildByName("default_squad_manager"));
950 if (!manager)
952 SPIRE_WRN("createSquad failed: default state machine not found! (<- this is a code bug)");
953 return;
955 createSquad(groupDesc, manager, "", spawnZone, spawnOrder, respawTimeGC, side);
958 void CSpire::createSquad(CGroupDesc<CSpireSquadFamily> const* groupDesc, CSpireSquadManager* manager, string const& initialStateName, CSpireSpawnZone const* spawnZone, uint32 createOrder, uint32 respawTimeGC, SPIREENUMS::TPVPSide side)
960 SPIRE_DBG("Creating a squad");
961 CAIVector const& spawnPosition = spawnZone->midPos();
962 sint32 baseLevel = -1;
963 double dispersionRadius = spawnZone->getRadius();
964 // Save the creator state
965 bool const savePlayerAttackable = groupDesc->getGDPlayerAttackable();
966 bool const saveBotAttackable = groupDesc->getGDBotAttackable();
967 // PlayerAttackable must be false as it it sent to the EGS in BotDescriptionMessage to set the
968 // property 'Attackable'. Squads are not attackable unless a player is in war with the owner of
969 // the spire (using botchatprogram instead of the property 'Attackable').
970 // BotAttackable must be true, otherwise the EGS sets it as invulnerable (not attackable).
971 groupDesc->setGDPlayerAttackable(false);
972 groupDesc->setGDBotAttackable(true);
973 // Create the group
974 CGroupNpc* const grp = groupDesc->createNpcGroup(manager, spawnPosition, dispersionRadius, baseLevel, false);
975 // Restore the creator state
976 groupDesc->setGDPlayerAttackable(savePlayerAttackable);
977 groupDesc->setGDBotAttackable(saveBotAttackable);
978 // Verify that the group was created
979 if (!grp)
981 SPIRE_WRN("createSquad failed: group %s cannot spawn", LigoConfig.aliasToString(groupDesc->getAlias()).c_str());
982 return;
984 // Set the new group parameters
985 // Let the EGS destroys squads explicitely because when a group is destroyed in the AIS its groupId can be reused
986 // and 2 squads would have the same groupId in the EGS (it asserts)
987 grp->autoDestroy(false);
988 grp->setAutoSpawn(true);
989 // grp->getPersistentStateInstance()->setParentStateInstance(entity->getPersistentStateInstance());
990 grp->initDynGrp(groupDesc, NULL);
991 // Set color
992 uint8 color = (uint8)(grp->getChildIndex() % 8);
993 grp->setColour(color);
994 // Get the state machine
995 CStateMachine const* stateMachine = manager->getStateMachine();
996 #if !FINAL_VERSION
997 // Verify that we have a state in the state machine
998 if (stateMachine->cstStates().size()==0)
999 nlerror("no state defined for StateMachine in Manager %s", manager->getFullName().c_str());
1000 #endif
1001 // Set the group in that state
1002 CAIState* initialState = NULL;
1003 if (!initialStateName.empty())
1005 // FOREACH(itState, CCont<CAIState>, stateMachine->states())
1006 for (size_t i=0; i<stateMachine->cstStates().size(); ++i)
1008 CAIState* state = stateMachine->cstStates()[i];
1009 if (state->getName()==initialStateName)
1010 initialState = state;
1013 if (initialState==NULL)
1014 initialState = stateMachine->cstStates()[0]; // sets the first state (must exist!).
1015 grp->setStartState(initialState);
1017 // Do not assist friends because it would lead to exploits
1018 /*if ( _OwnerGuild != InvalidGuildId )
1020 //grp->faction().addExtraProperty(_OwnerGuild); // TODO: set the GuildId for the squad npcs?
1021 //grp->friendFaction().addExtraProperty(_OwnerGuild); // will be defended by the squad
1023 else
1025 // A tribe owns the spire and all players are ennemies
1026 // CPropertyId tribeFaction(CGrpProfileFaction::fameFactionToScriptFaction(_OwnerTribe));
1027 //grp->faction().addProperty(tribeFaction);
1028 //grp->friendFaction().addProperty(tribeFaction); // will be defended by the squad
1029 //grp->ennemyFaction().addProperty(CPropertyId("Player"));
1032 // Set guild id of members of the squad (for the tribe case, these *are* the tribe as well)
1033 // This was removed because CBotNpc::spawn() now uses getOwner()->getOwner()->getOwner() to access the outpsot
1034 /*FOREACH(ib, CAliasCont<CBot>, grp->bots())
1036 CBotNpc *bot = static_cast<CBotNpc*>(*ib);
1037 bot->setOwnerSpire(this);
1040 grp->setSpireSide(side);
1041 // Attack only the declared ennemies of the spire
1042 if (side==SPIREENUMS::SpireOwner)
1044 // grp->faction ().addProperty(NLMISC::toString("spire:%s:defender", getAliasString().c_str()));
1045 // grp->friendFaction().addProperty(NLMISC::toString("spire:%s:defender", getAliasString().c_str()));
1046 grp->ennemyFaction().addProperty(NLMISC::toString("spire:%s:attacker", getAliasString().c_str()));
1048 if (side==SPIREENUMS::SpireAttacker)
1050 // grp->faction ().addProperty(NLMISC::toString("spire:%s:attacker", getAliasString().c_str()));
1051 // grp->friendFaction().addProperty(NLMISC::toString("spire:%s:attacker", getAliasString().c_str()));
1052 grp->ennemyFaction().addProperty(NLMISC::toString("spire:%s:defender", getAliasString().c_str()));
1054 grp->_AggroRange = 25;
1055 grp->_UpdateNbTicks = 10;
1056 grp->respawnTime() = respawTimeGC;
1058 grp->updateStateInstance(); // Directly call his first state (to retrieve associated params).
1060 if (createOrder!=0)
1062 CSpireSquadCreatedMsg params;
1063 params.Spire = this->getAlias();
1064 params.CreateOrder = createOrder;
1065 params.GroupId = reinterpret_cast<uint32>(grp);
1066 sendSpireMessage("SPIRE_SQUAD_CREATED", params);
1069 SPIRE_DBG( "Spire %s: squad created defending 0x%x against 0x%x, respawnTime=%u gc", getName().c_str(), _OwnerAllianceId, _AttackerAllianceId, respawTimeGC );
1072 void CSpire::spawnSquad(uint32 groupId)
1074 SPIRE_DBG( "Spire %s: Spawning squad 0x%08x", getName().c_str(), groupId );
1075 FOREACH(itManager, CAliasCont<CSpireManager>, _Managers)
1077 CSpireManager* manager = *itManager;
1078 FOREACH(itGroup, CAliasCont<CGroup>, manager->groups())
1080 CGroup* group = *itGroup;
1081 CGroupNpc* groupNpc = static_cast<CGroupNpc*>(group);
1082 uint32 thisGroupId = reinterpret_cast<uint32>(groupNpc);
1083 if (groupId==thisGroupId)
1085 group->getSpawnObj()->spawnBots();
1086 CSpireSquadSpawnedMsg params;
1087 params.Spire = this->getAlias();
1088 params.GroupId = groupId;
1089 sendSpireMessage("SPIRE_SQUAD_SPAWNED", params);
1090 SPIRE_DBG( "\t\tSpawned" );
1091 return;
1095 SPIRE_WRN("No squad to spawn with group id 0x%08x. Valid group ids are:", groupId);
1096 FOREACH(itManager, CAliasCont<CSpireManager>, _Managers)
1098 CSpireManager* manager = *itManager;
1099 FOREACH(itGroup, CAliasCont<CGroup>, manager->groups())
1101 CGroup* group = *itGroup;
1102 CGroupNpc* groupNpc = static_cast<CGroupNpc*>(group);
1103 uint32 thisGroupId = reinterpret_cast<uint32>(groupNpc);
1104 SPIRE_WRN("- 0x%08x", thisGroupId);
1109 void CSpire::despawnSquad(uint32 groupId)
1111 SPIRE_DBG( "Spire %s: Despawning squad 0x%08x", getName().c_str(), groupId );
1112 FOREACH(itManager, CAliasCont<CSpireManager>, _Managers)
1114 CSpireManager* manager = *itManager;
1115 FOREACH(itGroup, CAliasCont<CGroup>, manager->groups())
1117 CGroup* group = *itGroup;
1118 CGroupNpc* groupNpc = static_cast<CGroupNpc*>(group);
1119 uint32 thisGroupId = reinterpret_cast<uint32>(groupNpc);
1120 if (groupId==thisGroupId)
1122 group->despawnBots();
1123 CSpireSquadDespawnedMsg params;
1124 params.Spire = this->getAlias();
1125 params.GroupId = groupId;
1126 sendSpireMessage("SPIRE_SQUAD_DESPAWNED", params);
1127 return;
1131 SPIRE_WRN("No squad to despawn");
1134 void CSpire::deleteSquad(uint32 groupId)
1136 SPIRE_DBG( "Spire %s: deleting squad 0x%08x", getName().c_str(), groupId );
1137 FOREACH(itManager, CAliasCont<CSpireManager>, _Managers)
1139 CSpireManager* manager = *itManager;
1140 FOREACH(itGroup, CAliasCont<CGroup>, manager->groups())
1142 CGroup* group = *itGroup;
1143 CGroupNpc* groupNpc = static_cast<CGroupNpc*>(group);
1144 uint32 thisGroupId = reinterpret_cast<uint32>(groupNpc);
1145 if (groupId==thisGroupId)
1147 manager->groups().removeChildByIndex(group->getChildIndex());
1148 // No message here since this is called by squad destructor in EGS
1149 return;
1153 SPIRE_WRN("No squad to delete");
1156 void CSpire::sendSpireSquadStatus(CGroupNpc* group)
1158 uint32 alias = this->getAlias();
1159 uint32 groupId = reinterpret_cast<uint32>(group);
1160 bool groupAlive = false;
1161 bool leaderAlive = group->getSquadLeader()!=NULL;
1162 uint32 botCount = 0;
1163 // Persistent status
1164 // Spawn dependent status
1165 CSpawnGroup* spawnGroup = group->getSpawnObj();
1166 if (spawnGroup)
1168 groupAlive = spawnGroup->isGroupAlive();
1170 NLNET::CMessage msgout("SPIRE_SQUAD_STATUS");
1171 msgout.serial(alias);
1172 msgout.serial(groupId);
1173 msgout.serial(groupAlive);
1174 msgout.serial(leaderAlive);
1175 msgout.serial(botCount);
1176 sendMessageViaMirror("EGS", msgout);
1179 void CSpire::squadLeaderDied(CGroupNpc* group)
1181 uint32 alias = this->getAlias();
1182 uint32 groupId = reinterpret_cast<uint32>(group);
1183 NLNET::CMessage msgout("SPIRE_SQUAD_LEADER_DIED");
1184 msgout.serial(alias);
1185 msgout.serial(groupId);
1186 sendMessageViaMirror("EGS", msgout);
1189 void CSpire::squadDied(CGroupNpc* group)
1191 uint32 alias = this->getAlias();
1192 uint32 groupId = reinterpret_cast<uint32>(group);
1193 NLNET::CMessage msgout("SPIRE_SQUAD_DIED");
1194 msgout.serial(alias);
1195 msgout.serial(groupId);
1196 sendMessageViaMirror("EGS", msgout);
1199 void CSpire::triggerSpecialEvent(SPIREENUMS::TSpecialSpireEvent eventId)
1201 // Managers handlers
1202 FOREACH(itManager, CCont<CSpireManager>, _Managers)
1204 CSpireManager* manager = *itManager;
1205 if (manager)
1207 CAIEvent* event = NULL;
1208 switch (eventId)
1210 case SPIREENUMS::PeaceStateBegin: event = &manager->EventSpirePeaceStateBegin; break;
1211 case SPIREENUMS::PeaceStateEnd: event = &manager->EventSpirePeaceStateEnd; break;
1212 case SPIREENUMS::TribeOwnershipBegin: event = &manager->EventSpireTribeOwnershipBegin; break;
1213 case SPIREENUMS::TribeOwnershipEnd: event = &manager->EventSpireTribeOwnershipEnd; break;
1214 case SPIREENUMS::GuildOwnershipBegin: event = &manager->EventSpireGuildOwnershipBegin; break;
1215 case SPIREENUMS::GuildOwnershipEnd: event = &manager->EventSpireGuildOwnershipEnd; break;
1216 case SPIREENUMS::OwnerChanged: event = &manager->EventSpireOwnerChanged; break;
1217 case SPIREENUMS::AttackerChanged: event = &manager->EventSpireAttackerChanged; break;
1218 case SPIREENUMS::StateChanged: event = &manager->EventSpireStateChanged; break;
1220 if (event)
1222 FOREACH(itGroup, CCont<CGroup>, manager->groups())
1224 CGroupNpc* group = static_cast<CGroupNpc*>(*itGroup);
1225 if (group)
1226 group->processStateEvent(*event);
1231 // Special handlers
1232 switch (eventId)
1234 case SPIREENUMS::TribeOwnershipBegin:
1236 FOREACH(itManager, CCont<CSpireManager>, _Managers)
1238 CSpireManager* manager = *itManager;
1239 if (manager)
1240 manager->autoSpawnBegin();
1242 break;
1244 case SPIREENUMS::TribeOwnershipEnd:
1246 FOREACH(itManager, CCont<CSpireManager>, _Managers)
1248 CSpireManager* manager = *itManager;
1249 if (manager)
1250 manager->autoSpawnEnd();
1252 break;
1257 void CSpire::setBuildingBotSheet(uint32 buildingAlias, NLMISC::CSheetId sheetId, bool autoSpawnDespawn, const std::string & customName)
1259 CBot * bot = getBuildingBotByAlias(buildingAlias);
1260 if (bot == NULL)
1262 SPIRE_WRN( "cannot find building bot %s", LigoConfig.aliasToString( buildingAlias ).c_str() );
1263 return;
1266 AISHEETS::ICreatureCPtr const sheet = AISHEETS::CSheets::getInstance()->lookup(sheetId);
1267 if (sheetId!=NLMISC::CSheetId::Unknown && !sheet.isNull())
1269 bot->setCustomName(customName);
1270 bot->triggerSetSheet(sheet);
1271 if (autoSpawnDespawn && !bot->isSpawned())
1272 bot->spawn();
1274 else
1276 if (autoSpawnDespawn && bot->isSpawned())
1277 bot->despawnBot();
1281 void CSpire::despawnAllSquads()
1283 FOREACH(itManager, CAliasCont<CSpireManager>, _Managers)
1285 CSpireManager* manager = *itManager;
1286 CSpireSquadManager* sqManager = dynamic_cast<CSpireSquadManager*>(manager);
1287 if (sqManager)
1289 FOREACH(itGroup, CAliasCont<CGroup>, sqManager->groups())
1291 CGroup* group = *itGroup;
1292 group->despawnBots();
1298 template <class T>
1299 void CSpire::sendSpireMessage(std::string const& msgName, T& paramStruct)
1301 NLNET::CMessage msgout(msgName);
1302 msgout.serial(paramStruct);
1303 sendMessageViaMirror(std::string("EGS"), msgout);
1306 //////////////////////////////////////////////////////////////////////////////
1307 // Commands //
1308 //////////////////////////////////////////////////////////////////////////////
1310 NLMISC_COMMAND(displaySpires, "list the available spire", "")
1312 if (args.size() > 0)
1313 return false;
1315 uint32 instanceNumber = std::numeric_limits<uint32>::max();
1316 for (uint i=0; i<CAIS::instance().AIList().size(); ++i)
1318 CAIInstance *const aii = CAIS::instance().AIList()[i];
1319 if (!aii)
1321 log.displayNL("No current ai instance, can't look for spire");
1322 return true;
1325 string continentName;
1326 if (!args.empty())
1327 continentName = args[0];
1329 // retreive the oupost
1330 for (uint i=0; i<aii->continents().size(); ++i)
1332 CContinent *const continent = aii->continents()[i];
1333 if ( !continent
1334 || ( !continentName.empty()
1335 && continentName!=continent->getName()))
1336 continue;
1338 log.displayNL("Spires in continent '%s':", continent->getName().c_str());
1339 for (uint j=0; j<continent->spires().size(); ++j)
1341 CSpire const* spire = continent->spires()[j];
1342 if (!spire)
1343 continue;
1345 log.displayNL(" %s", spire->getOneLineInfoString().c_str());
1346 log.displayNL(" - %d group descs", spire->squadLinks().size());
1347 for (CSpire::CSquadLinks::const_iterator isl=spire->squadLinks().begin(); isl!=spire->squadLinks().end(); ++isl )
1349 CGroupDesc<CSpireSquadFamily> const* gd = (*isl).second;
1350 if (!gd)
1351 continue;
1353 log.displayNL(" Group desc '%s' %s", gd->getName().c_str(), gd->getAliasString().c_str());
1356 log.displayNL(" - %d spawn zones", spire->spawnZones().size());
1357 for (uint j=0; j<spire->spawnZones().size(); ++j)
1359 CSpireSpawnZone const* sz = spire->spawnZones()[j];
1360 if (!sz)
1361 continue;
1363 log.displayNL(" SpawnZone '%s' %s (%s)", sz->getName().c_str(), sz->getAliasString().c_str(), sz->midPos().toString().c_str());
1365 log.displayNL(" - %d state machines", spire->managers().size());
1366 for (uint j=0; j<spire->managers().size(); ++j)
1368 CSpireManager* manager = spire->managers()[j];
1369 if (!manager)
1370 continue;
1372 log.displayNL(" State machine '%s' %s", manager->getName().c_str(), manager->getAliasString().c_str());
1373 log.displayNL(" - %d states", manager->getStateMachine()->states().size());
1374 for (uint j=0; j<manager->getStateMachine()->states().size(); ++j)
1376 CAIState const* state = manager->getStateMachine()->states()[j];
1377 if (!state)
1378 continue;
1380 log.displayNL(" State '%s' %s", state->getName().c_str(), state->getAliasString().c_str());
1382 log.displayNL(" - %d groups", manager->groups().size());
1383 for (uint j=0; j<manager->groups().size(); ++j)
1385 CGroup const* group = manager->groups()[j];
1386 if (group)
1388 log.displayNL(" Group '%s' %s", group->getName().c_str(), group->getAliasString().c_str());
1389 log.displayNL(" - %d bots", group->bots().size());
1390 for (uint k=0; k<group->bots().size(); ++k)
1392 CBot const* bot = group->bots()[k];
1393 if (bot)
1394 log.displayNL(" Bot '%s' %s", bot->getName().c_str(), bot->getAliasString().c_str());
1395 else
1396 log.displayNL(" Bot <NULL>");
1399 else
1400 log.displayNL(" Group <NULL>");
1407 return true;
1410 // spireSpawnSquad 1 fyros spire group machine zone
1412 NLMISC_COMMAND(spireSpawnSquad, "Spawns a squad in an spire", "<instance_number> <continent> <spire> <group_template> <state_machine> <spawn_zone> [<respawnTimeInSec>=5*60]")
1414 if (args.size() != 6)
1415 return false;
1417 uint32 instanceNumber = std::numeric_limits<uint32>::max();
1418 fromString(args[0], instanceNumber);
1419 string continentName = args[1];
1420 string spireName = args[2];
1421 string dynGroupName = args[3];
1422 string stateMachineName = args[4];
1423 string zoneName = args[5];
1424 uint32 respawnTimeGC = 5*60*10;
1425 if ( args.size() > 6 )
1427 NLMISC::fromString(args[6], respawnTimeGC);
1428 respawnTimeGC *= 10;
1431 for (size_t i=0; i<5; ++i)
1432 if (args[i]=="")
1433 return false;
1435 bool done = false;
1436 bool instanceFound = false;
1437 bool continentFound = false;
1438 bool spireFound = false;
1439 if (instanceNumber<CAIS::instance().AIList().size())
1441 CAIInstance* const aiinstance = CAIS::instance().AIList()[instanceNumber];
1442 if (aiinstance)
1444 instanceFound = true;
1445 for (uint i=0; i<aiinstance->continents().size() && !done; ++i)
1447 CContinent* const continent = aiinstance->continents()[i];
1448 if (!continent || continentName!=continent->getName())
1449 continue;
1450 continentFound = true;
1451 for (uint j=0; j<continent->spires().size() && !done; ++j)
1453 CSpire* const spire = continent->spires()[j];
1454 if (!spire || spireName!=spire->getName())
1455 continue;
1456 spireFound = true;
1457 spire->createSquad(dynGroupName, stateMachineName, "", zoneName, 0, respawnTimeGC, SPIREENUMS::UnknownPVPSide);
1458 done = true;
1463 if (!done)
1465 SPIRE_WRN("Could not spawn a new squad");
1466 log.displayNL("Could not spawn a new squad");
1467 if (!instanceFound)
1468 log.displayNL( "Instance not found" );
1469 if (!continentFound)
1470 log.displayNL( "Continent not found" );
1471 if (!spireFound)
1472 log.displayNL( "Spire not found" );
1474 return true;
1479 * Return the spire corresponding to the alias, or NULL if not found (with a nlwarning)
1481 CSpire* CSpire::getSpireByAlias( TAIAlias spireAlias )
1483 bool instanceFound = false;
1484 bool continentFound = false;
1485 bool spireFound = false;
1486 for (uint i=0; i<CAIS::instance().AIList().size(); ++i)
1488 CAIInstance* const aiinstance = CAIS::instance().AIList()[i];
1489 if (aiinstance)
1491 instanceFound = true;
1492 for (uint i=0; i<aiinstance->continents().size(); ++i)
1494 CContinent* const continent = aiinstance->continents()[i];
1495 if (!continent)
1496 continue;
1497 continentFound = true;
1498 for (uint j=0; j<continent->spires().size(); ++j)
1500 CSpire* spire = continent->spires()[j];
1501 if (!spire || spireAlias!=spire->getAlias())
1502 continue;
1503 return spire;
1508 if (!instanceFound)
1509 SPIRE_WRN( "Instance not found" );
1510 if (!continentFound)
1511 SPIRE_WRN( "Continent not found" );
1512 if (!spireFound)
1513 SPIRE_WRN( "Spire %s not found", LigoConfig.aliasToString( spireAlias ).c_str() );
1514 return NULL;
1518 void spireCreateSquad(uint32 spireAlias, uint32 dynGroupAlias, uint32 zoneAlias, uint32 spawnOrder)
1520 CSpire *spire = CSpire::getSpireByAlias( spireAlias );
1521 if ( spire )
1522 spire->createSquad(dynGroupAlias, zoneAlias, spawnOrder);
1525 void spireSpawnSquad(uint32 spireAlias, uint32 groupId)
1527 CSpire *spire = CSpire::getSpireByAlias( spireAlias );
1528 if ( spire )
1529 spire->spawnSquad(groupId);
1532 void spireDespawnSquad(uint32 spireAlias, uint32 groupId)
1534 CSpire *spire = CSpire::getSpireByAlias( spireAlias );
1535 if ( spire )
1536 spire->despawnSquad(groupId);
1539 void spireDeleteSquad(uint32 spireAlias, uint32 groupId)
1541 CSpire *spire = CSpire::getSpireByAlias( spireAlias );
1542 if ( spire )
1543 spire->deleteSquad(groupId);
1546 void spireDespawnAllSquads(uint32 spireAlias)
1548 CSpire *spire = CSpire::getSpireByAlias( spireAlias );
1549 if ( spire )
1550 spire->despawnAllSquads();
1554 NLMISC_COMMAND(spireAliasSpawnSquad, "Spawns a squad in an spire (respawn time = 5 min)", "<spire_alias> <group_alias> <spawn_zone_alias>")
1556 if (args.size()!=3)
1557 return false;
1559 for (size_t i=0; i<3; ++i)
1560 if (args[i]=="")
1561 return false;
1563 uint32 spireAlias = LigoConfig.aliasFromString(args[0]);
1564 uint32 dynGroupAlias = LigoConfig.aliasFromString(args[1]);
1565 uint32 zoneAlias = LigoConfig.aliasFromString(args[2]);
1566 string stateMachineName = "default_squad_manager";
1568 CSpire *spire = CSpire::getSpireByAlias(spireAlias);
1569 if (spire)
1570 spire->createSquad(dynGroupAlias, zoneAlias, 0, 5*60*10, SPIREENUMS::UnknownPVPSide);
1572 return true;
1575 CBot* CSpire::getBuildingBotByAlias(TAIAlias alias)
1577 CGroup* group = getBuildingGroup();
1578 if (group)
1579 return group->bots().getChildByAlias(alias);
1580 else
1581 return NULL;
1584 NLMISC_COMMAND(spireSetBuildingBotSheet, "Set the sheet of an spire building", "<spire_alias> <building_alias> <bot_sheet>")
1586 if (args.size()!=3)
1587 return false;
1589 for (size_t i=0; i<3; ++i)
1590 if (args[i]=="")
1591 return false;
1593 uint32 spireAlias = LigoConfig.aliasFromString(args[0]);
1594 uint32 buildingAlias = LigoConfig.aliasFromString(args[1]);
1595 NLMISC::CSheetId buildingBotSheet = NLMISC::CSheetId(args[2]);;
1597 CSpire* spire = CSpire::getSpireByAlias(spireAlias);
1598 if (spire)
1599 spire->setBuildingBotSheet(buildingAlias, buildingBotSheet, true, "");
1601 return true;
1605 // Call this macro, then do the code that will must done only if the spire is found in this instance
1606 // The data you have access to after this macro:
1607 // - CSpire *spire
1608 // - msgStruct params;
1609 #define IF_GET_SPIRE_FOR_MSG( msgStruct ) \
1610 msgStruct params; \
1611 msgin.serial( params ); \
1612 CSpire *spire = CSpire::getSpireByAlias( params.Spire ); \
1613 if ( spire )
1616 void cbSpireCreateSquad( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1618 IF_GET_SPIRE_FOR_MSG( CSpireCreateSquadMsg )
1619 spire->createSquad(params.Group, params.Zone, params.CreateOrder, params.RespawnTimeS*10, params.Side);
1622 void cbSpireSpawnSquad( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1624 IF_GET_SPIRE_FOR_MSG( CSpireSpawnSquadMsg )
1625 spire->spawnSquad(params.GroupId);
1628 void cbSpireDespawnSquad( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1630 IF_GET_SPIRE_FOR_MSG( CSpireDespawnSquadMsg )
1631 spire->despawnSquad(params.GroupId);
1634 void cbSpireDeleteSquad( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1636 IF_GET_SPIRE_FOR_MSG( CSpireDeleteSquadMsg )
1637 spire->deleteSquad(params.GroupId);
1640 void cbSpireDespawnAllSquads( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1642 IF_GET_SPIRE_FOR_MSG( CSpireDespawnAllSquadsMsg )
1643 spire->despawnAllSquads();
1646 void cbSpireSetOwner( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1648 IF_GET_SPIRE_FOR_MSG( CSetSpireOwner )
1649 spire->setOwnerAlliance( params.Owner );
1652 void cbSpireSetAttacker( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1654 IF_GET_SPIRE_FOR_MSG( CSetSpireAttacker )
1655 spire->setAttackerAlliance( params.Attacker );
1658 void cbSpireSetState( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1660 IF_GET_SPIRE_FOR_MSG( CSpireSetStateMsg )
1661 spire->setState( params.State );
1664 void cbSpireEvent( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1666 IF_GET_SPIRE_FOR_MSG( CSpireEventMsg )
1667 spire->triggerSpecialEvent(params.Event);
1670 void cbSpireSetBuildingBotSheet( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId )
1672 IF_GET_SPIRE_FOR_MSG( CSpireSetBuildingBotSheetMsg )
1673 spire->setBuildingBotSheet(params.Building, params.SheetId, params.AutoSpawnDespawn, params.CustomName);
1676 #include "event_reaction_include.h"
1677 #endif