Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / ai_service / ai_outpost.cpp
blob4a30a09b913ad2a4283bd7cee7ec349621d1aed7
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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"
21 #include "ai_outpost.h"
22 #include "continent.h"
23 #include "ai_grp_npc.h"
24 #include "game_share/people.h"
25 #include "ai_profile_npc.h"
27 #include "continent_inline.h"
28 #include "dyn_grp_inline.h"
30 using namespace std;
31 using namespace NLMISC;
32 using namespace AITYPES;
36 CFileDisplayer OutpostDisplayer("outposts.log");
37 CLog OutpostDbgLog(CLog::LOG_DEBUG), OutpostInfLog(CLog::LOG_INFO), OutpostWrnLog(CLog::LOG_WARNING), OutpostErrLog(CLog::LOG_ERROR);
40 namespace OUTPOSTHELPERS {
42 static std::map<uint32, uint32> outpostFactions;
44 bool isAttackingFaction(uint32 factionIndex, CAIEntityPhysical const* player)
46 std::map<uint32, uint32>::const_iterator it = outpostFactions.find(player->outpostAlias());
47 return it!=outpostFactions.end() && it->second==factionIndex;
52 //////////////////////////////////////////////////////////////////////////////
53 // COutpost //
54 //////////////////////////////////////////////////////////////////////////////
56 //std::set<CContinent*> ChangedOutposts;
57 //COutpost::TOutpostIndex COutpost::_Outposts;
59 COutpost::COutpost(CContinent* owner, uint32 alias, std::string const& name, std::string const& filename)
60 : CAliasChild<CContinent>(owner, alias, name)
61 , CAliasTreeRoot(filename)
62 , _OwnerAllianceId(InvalidAllianceId)
63 , _AttackerAllianceId(InvalidAllianceId)
64 , _State(OUTPOSTENUMS::UnknownOutpostState)
67 static bool logInitDone = false;
68 if ( ! logInitDone )
70 OutpostDbgLog.addDisplayer( &OutpostDisplayer );
71 OutpostInfLog.addDisplayer( &OutpostDisplayer );
72 OutpostWrnLog.addDisplayer( &OutpostDisplayer );
73 logInitDone = true;
76 OUTPOST_DBG("Creating outpost %s' (%s)", name.c_str(), getAliasFullName().c_str());
77 if (LogOutpostDebug)
78 OUTPOST_DBG("Creating outpost '%s'", getAliasFullName().c_str());
80 _OutpostName = getName();
81 COutpostManager* manager = NULL;
82 // Create default squad manager
83 manager = new COutpostSquadManager(this, 0, "default_squad_manager", filename);
84 if (manager)
86 _Managers.addChild(manager);
87 manager->init();
89 // Create default building manager
90 manager = new COutpostManager(this, 0, "default_building_manager", filename);
91 if (manager)
93 _Managers.addChild(manager);
94 manager->init();
95 CGroupNpc* group = new CGroupNpc(manager, NULL, /*AStarFlag*/RYAI_MAP_CRUNCH::Nothing);
96 if (group)
98 manager->groups().addAliasChild(group);
99 group->setAutoSpawn(false);
100 group->setName("default_building_group");
101 group->clearParameters();
102 group->setPlayerAttackable(false);
103 group->setBotAttackable(false);
104 group->setBotsAreNamedFlag();
109 COutpost::~COutpost()
111 if (LogOutpostDebug)
112 OUTPOST_DBG("Deleting outpost '%s'", getAliasFullName().c_str());
114 _SpawnZones.clear();
117 std::string COutpost::getOneLineInfoString() const
119 return std::string("Outpost '") + getName() + "' " + getAliasString() + ", State=" + OUTPOSTENUMS::toString(_State);
122 std::string COutpost::getFullName() const
124 return std::string(getOwner()->getFullName() +":"+ getName());
127 std::string COutpost::getIndexString() const
129 return getOwner()->getIndexString()+NLMISC::toString(":o%u", getChildIndex());
132 std::string COutpost::getPlaceOwnerFullName() const
134 return getFullName();
137 std::string COutpost::getPlaceOwnerIndexString() const
139 return getIndexString();
142 CAIInstance* COutpost::getAIInstance() const
144 return getOwner()->getAIInstance();
147 std::string COutpost::getManagerIndexString(CManager const* manager) const
149 return getIndexString()+NLMISC::toString(":m%u", manager->getChildIndex());
152 IAliasCont* COutpost::getAliasCont(TAIType type)
154 switch (type)
156 case AITypeOutpostSquadFamily:
157 OUTPOST_WRN( "Obsolete squad family node under outpost %s", getName().c_str() );
158 return NULL;
159 case AITypeOutpostSpawnZone:
160 return &_SpawnZones;
161 case AITypeManager:
162 return &_Managers;
163 case AITypeOutpostManager:
164 return &_Managers;
165 case AITypeOutpostBuilding:
166 return getBuildingGroup()->getAliasCont(AITypeBot);
167 default:
168 return NULL;
173 CAliasTreeOwner* COutpost::createChild(IAliasCont* cont, CAIAliasDescriptionNode* aliasTree)
175 if (!cont)
176 return NULL;
178 CAliasTreeOwner* child = NULL;
180 switch(aliasTree->getType())
182 // create the child and adds it to the corresponding position.
183 case AITypeOutpostSpawnZone:
184 child = new COutpostSpawnZone(this, aliasTree);
185 break;
186 case AITypeManager:
187 child = new COutpostSquadManager(this, aliasTree->getAlias(), aliasTree->getName());
188 break;
189 case AITypeOutpostManager:
190 child = new COutpostSquadManager(this, aliasTree->getAlias(), aliasTree->getName());
191 break;
192 case AITypeOutpostBuilding:
193 return getBuildingGroup()->createChild(cont, aliasTree);
196 if (child)
197 cont->addAliasChild(child);
198 return child;
201 CGroup* COutpost::getBuildingGroup()
203 COutpostManager* manager = _Managers.getChildByName("default_building_manager");
204 return manager->groups().getChildByName("default_building_group");
207 void COutpost::setTribe(const std::string &tribeName)
209 // The tribe is only populated by the NPCs of the squads
210 _Tribe = tribeName;
211 if (LogOutpostDebug)
212 OUTPOST_DBG("setting tribe '%s' in '%s' as owner for outpost '%s'",
213 tribeName.c_str(),
214 getOwner()->getName().c_str(),
215 getAliasFullName().c_str());
218 void COutpost::setOwnerAlliance( TAllianceId ownerAllianceId )
220 if (_OwnerAllianceId!=ownerAllianceId)
222 // if the old owner was a tribe
223 if (_OwnerAllianceId==InvalidAllianceId)
225 triggerSpecialEvent(OUTPOSTENUMS::TribeOwnershipEnd);
226 OUTPOSTHELPERS::outpostFactions.erase(getAlias());
228 else
229 triggerSpecialEvent(OUTPOSTENUMS::GuildOwnershipEnd);
231 std::swap(_OwnerAllianceId, ownerAllianceId); // 'ownerAllianceId' contains old owner alliance id
232 if (_OwnerAllianceId!=ownerAllianceId)
234 triggerSpecialEvent(OUTPOSTENUMS::OwnerChanged);
235 // if the new owner is a tribe
236 if (_OwnerAllianceId==InvalidAllianceId)
238 OUTPOSTHELPERS::outpostFactions.insert(make_pair(getAlias(), CStaticFames::getInstance().getFactionIndex(_Tribe)));
239 triggerSpecialEvent(OUTPOSTENUMS::TribeOwnershipBegin);
241 else
242 triggerSpecialEvent(OUTPOSTENUMS::GuildOwnershipBegin);
246 void COutpost::setAttackerAlliance( TAllianceId attackerAllianceId )
248 std::swap(_AttackerAllianceId, attackerAllianceId); // 'attackerAllianceId' contains old attacker alliance id
249 if (_AttackerAllianceId!=attackerAllianceId)
251 triggerSpecialEvent(OUTPOSTENUMS::AttackerChanged);
254 // Update the enemies of the current squads of the outpost
255 FOREACH( im, CAliasCont<COutpostManager>, _Managers )
256 im->setEnemies( _AttackerAllianceId );
259 void COutpost::setState( OUTPOSTENUMS::TOutpostState state )
261 if (_State!=state)
263 if (_State==OUTPOSTENUMS::Peace)
264 triggerSpecialEvent(OUTPOSTENUMS::PeaceStateEnd);
266 std::swap(_State, state); // 'state' contains old _State
267 if (_State!=state)
269 triggerSpecialEvent(OUTPOSTENUMS::StateChanged);
270 if (_State==OUTPOSTENUMS::Peace)
271 triggerSpecialEvent(OUTPOSTENUMS::PeaceStateBegin);
275 void COutpost::update()
277 // FOREACH(it, CAliasCont<COutpostSquadFamily>, _SquadFamilies) it->update();
278 // FOREACH(it, CAliasCont<COutpostSpawnZone>, _SpawnZones) it->update();
279 FOREACH(it, CAliasCont<COutpostManager>, _Managers) it->update();
282 void COutpost::addZone(COutpostSpawnZone* zone)
284 #if !FINAL_VERSION
285 if (_ZoneList.find(NLMISC::CStringMapper::map(zone->getName()))!=_ZoneList.end())
286 OUTPOST_WRN("this OutpostSpawnZone have the same name than another: %s", zone->getName().c_str());
287 #endif
288 _ZoneList[NLMISC::CStringMapper::map(zone->getName())] = zone;
291 void COutpost::removeZone(COutpostSpawnZone* zone)
293 _ZoneList.erase(NLMISC::CStringMapper::map(zone->getName()));
296 COutpostSpawnZone* COutpost::getZone(NLMISC::TStringId zoneName)
298 return _ZoneList[zoneName];
301 void COutpost::serviceEvent(CServiceEvent const& info)
303 if (info.getServiceName()=="EGS" && info.getEventType()==CServiceEvent::SERVICE_DOWN)
305 // Delete all the squad groups
306 COutpostManager* manager = _Managers.getChildByName("default_squad_manager");
307 if (manager)
308 manager->groups().clear();
310 FOREACH(itManager, CAliasCont<COutpostManager>, _Managers)
312 COutpostManager* manager = *itManager;
313 manager->serviceEvent(info);
317 bool COutpost::spawn()
319 // Spawn outpost managers
320 CCont<COutpostManager>::iterator itManager, itManagerEnd(_Managers.end());
321 for (itManager=_Managers.begin(); itManager!=itManagerEnd; ++itManager)
323 COutpostManager* manager = *itManager;
324 manager->spawn();
326 // We should check individual errors, but fake success here :)
327 return true;
330 bool COutpost::despawn()
332 // Despawn instance managers
333 CCont<COutpostManager>::iterator itManager, itManagerEnd(_Managers.end());
334 for (itManager=_Managers.begin(); itManager!=itManagerEnd; ++itManager)
336 COutpostManager* manager = *itManager;
337 manager->despawnMgr();
339 // We should check individual errors, but fake success here :)
340 return true;
343 //-----------------------------------------------------------------------------
344 std::string COutpost::getStateName() const
346 return OUTPOSTENUMS::toString(_State);
349 //////////////////////////////////////////////////////////////////////////////
350 // COutpostSquadFamily //
351 //////////////////////////////////////////////////////////////////////////////
353 IAliasCont* COutpostSquadFamily::getAliasCont(TAIType type)
355 switch (type)
357 case AITypeGroupTemplate:
358 case AITypeGroupTemplateMultiLevel:
359 return &_GroupDescs;
360 default:
361 return NULL;
366 CAliasTreeOwner* COutpostSquadFamily::createChild(IAliasCont* cont, CAIAliasDescriptionNode* aliasTree)
368 if (!cont)
369 return NULL;
371 CAliasTreeOwner* child = NULL;
373 switch (aliasTree->getType())
375 case AITypeSquadTemplateVariant:
376 child = new CGroupDesc<COutpostSquadFamily>(this, aliasTree->getAlias(), aliasTree->getParent()->getName()+":"+aliasTree->getName());
377 break;
378 case AITypeGroupTemplate:
379 case AITypeGroupTemplateMultiLevel:
380 child = new CGroupDesc<COutpostSquadFamily>(this, aliasTree->getAlias(), aliasTree->getName());
381 break;
384 if (child)
385 cont->addAliasChild(child);
386 return child;
389 std::string COutpostSquadFamily::getFullName() const
391 // return std::string(getOwner()->getFullName() +":"+ getName());
392 return getName();
395 std::string COutpostSquadFamily::getIndexString() const
397 return getOwner()->getIndexString()+NLMISC::toString(":sf%u", getChildIndex());
400 //////////////////////////////////////////////////////////////////////////////
401 // CGroupDesc //
402 //////////////////////////////////////////////////////////////////////////////
404 template <> size_t const CGroupDesc<COutpostSquadFamily>::_MultiLevelSheetCount = 20;
406 //////////////////////////////////////////////////////////////////////////////
407 // CBotDesc //
408 //////////////////////////////////////////////////////////////////////////////
410 template <> size_t const CBotDesc<COutpostSquadFamily>::_MultiLevelSheetCount = 20;
412 //////////////////////////////////////////////////////////////////////////////
413 // COutpostSpawnZone //
414 //////////////////////////////////////////////////////////////////////////////
416 COutpostSpawnZone::COutpostSpawnZone(COutpost* owner, CAIAliasDescriptionNode* adn)
417 : CAIPlaceXYR(owner, adn)
419 owner->addZone(this);
422 COutpostSpawnZone::~COutpostSpawnZone()
424 static_cast<COutpost*>(getOwner())->removeZone(this);
427 std::string COutpostSpawnZone::getFullName() const
429 return std::string(getOwner()->getFullName() +":"+ getName());
432 std::string COutpostSpawnZone::getIndexString() const
434 return getOwner()->getIndexString()+NLMISC::toString(":%u", getChildIndex());
437 //////////////////////////////////////////////////////////////////////////////
438 // COutpostManager //
439 //////////////////////////////////////////////////////////////////////////////
441 COutpostManager::COutpostManager(COutpost* parent, uint32 alias, std::string const& name, std::string const& filename)
442 : CMgrNpc(parent, alias, name, filename)
443 , _AutoSpawn(false)
445 registerEvents();
448 COutpostManager::~COutpostManager()
450 unregisterEvents(); // need be called otherwise the state manager will be unhappy when the CAIEvent objects are destroyed
453 std::string COutpostManager::getOneLineInfoString() const
455 return std::string("Outpost manager '") + getName() + "'";
458 void COutpostManager::update()
460 CMgrNpc::update();
463 IAliasCont* COutpostManager::getAliasCont(TAIType type)
465 // IAliasCont* cont = NULL;
466 // switch (type)
467 // {
468 // default:
469 // break;
470 // }
471 // if (cont)
472 // return cont;
473 // else
474 return CMgrNpc::getAliasCont(type);
477 CAliasTreeOwner* COutpostManager::createChild(IAliasCont* cont, CAIAliasDescriptionNode* aliasTree)
479 // CAliasTreeOwner* child = NULL;
480 // switch (aliasTree->getType())
481 // {
482 // default:
483 // break;
484 // }
485 // if (child)
486 // cont->addAliasChild(child);
487 // if (child)
488 // return child;
489 // else
490 return CMgrNpc::createChild(cont, aliasTree);
493 void COutpostManager::registerEvents()
495 _StateMachine.addEvent( "outpost_peace_state_begin", EventOutpostPeaceStateBegin );
496 _StateMachine.addEvent( "outpost_peace_state_end", EventOutpostPeaceStateEnd );
497 _StateMachine.addEvent( "outpost_tribe_ownership_begin", EventOutpostTribeOwnershipBegin );
498 _StateMachine.addEvent( "outpost_tribe_ownership_end", EventOutpostTribeOwnershipEnd );
499 _StateMachine.addEvent( "outpost_guild_ownership_begin", EventOutpostGuildOwnershipBegin );
500 _StateMachine.addEvent( "outpost_guild_ownership_end", EventOutpostGuildOwnershipEnd );
501 _StateMachine.addEvent( "outpost_owner_changed", EventOutpostOwnerChanged );
502 _StateMachine.addEvent( "outpost_attacker_changed", EventOutpostAttackerChanged );
503 _StateMachine.addEvent( "outpost_state_changed", EventOutpostStateChanged );
506 void COutpostManager::unregisterEvents()
508 _StateMachine.delEvent( "outpost_peace_state_begin" );
509 _StateMachine.delEvent( "outpost_peace_state_end" );
510 _StateMachine.delEvent( "outpost_tribe_ownership_begin" );
511 _StateMachine.delEvent( "outpost_tribe_ownership_end" );
512 _StateMachine.delEvent( "outpost_guild_ownership_begin" );
513 _StateMachine.delEvent( "outpost_guild_ownership_end" );
514 _StateMachine.delEvent( "outpost_owner_changed" );
515 _StateMachine.delEvent( "outpost_attacker_changed" );
516 _StateMachine.delEvent( "outpost_state_changed" );
519 void COutpostManager::autoSpawnBegin()
521 if (!_AutoSpawn)
522 return;
523 FOREACH(itGroup, CCont<CGroup>, groups())
525 CGroupNpc* group = static_cast<CGroupNpc*>(*itGroup);
526 if (group)
528 CSpawnGroupNpc* spawn = group->getSpawnObj();
529 if (spawn)
530 spawn->spawnBots();
535 void COutpostManager::autoSpawnEnd()
537 if (!_AutoSpawn)
538 return;
539 FOREACH(itGroup, CCont<CGroup>, groups())
541 CGroupNpc* group = static_cast<CGroupNpc*>(*itGroup);
542 if (group)
544 CSpawnGroupNpc* spawn = group->getSpawnObj();
545 if (spawn)
546 spawn->despawnBots(1);
551 void COutpostManager::setEnemies( TAllianceId attackerAllianceId )
553 FOREACH( ig, CAliasCont<CGroup>, _Groups )
555 // Attack only the declared ennemies of the outpost
556 CGroupNpc *grp = static_cast<CGroupNpc*>(*ig);
557 grp->ennemyFaction().clearExtra();
558 grp->ennemyFaction().addExtraProperty(attackerAllianceId);
562 //////////////////////////////////////////////////////////////////////////////
563 // COutpostSquadManager //
564 //////////////////////////////////////////////////////////////////////////////
566 COutpostSquadManager::COutpostSquadManager(COutpost* parent, uint32 alias, std::string const& name, std::string const& filename)
567 : COutpostManager(parent, alias, name, filename)
569 // Create init state
570 CAIState* state = new CAIStatePositional(getStateMachine(), 0, "outpost_squad_init");
571 IAIProfileFactory* aiProfile = lookupAIGrpProfile("squad");
572 state->setActivityProfile(aiProfile);
573 getStateMachine()->states().addChild(state);
575 CAIEventDescription eventDescription;
576 CAIEventActionNode::TSmartPtr eventAction;
577 CAIEventReaction* event;
579 // Create event handler for start of state
580 eventDescription.EventType = "start_of_state";
581 // eventDescription.StateKeywords.push_back("");
582 // eventDescription.NamedStates.push_back("");
583 // eventDescription.GroupKeywords.push_back("");
584 // eventDescription.NamedGroups.push_back("");
586 // Create event action
587 eventAction = new CAIEventActionNode;
588 eventAction->Action = "code";
589 eventAction->Weight = 1;
590 eventAction->Args.push_back("print(\"CREATING A SQUAD\");");
591 // eventAction->Args.push_back("()setFactionProp(\"faction\", \"foo\");");
592 // eventAction->Args.push_back("()setFactionProp(\"ennemyFaction\", \"bar\");");
593 // eventAction->Args.push_back("()setFactionProp(\"friendFaction\", \"baf\");");
594 eventAction->Args.push_back("()setHealer(1);");
596 // Register event action
597 eventDescription.Action = eventAction;
598 eventAction = NULL;
600 // Register event handler
601 // FIXME: 0 == CAIAliasDescriptionNode instance
602 event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType);
603 event->processEventDescription(&eventDescription, getStateMachine());
604 getStateMachine()->eventReactions().addChild(event);
605 event = NULL;
607 // Create event handler for group death
608 eventDescription.EventType = "group_eliminated";
609 // eventDescription.StateKeywords.push_back("");
610 // eventDescription.NamedStates.push_back("");
611 // eventDescription.GroupKeywords.push_back("");
612 // eventDescription.NamedGroups.push_back("");
614 // Create event action
615 eventAction = new CAIEventActionNode;
616 eventAction->Action = "outpost_report_squad_death";
617 eventAction->Weight = 1;
618 // eventAction->Args.push_back("");
620 // Register event action
621 eventDescription.Action = eventAction;
622 eventAction = NULL;
624 // Register event handler
625 // FIXME: 0 == CAIAliasDescriptionNode instance
626 event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType);
627 event->processEventDescription(&eventDescription, getStateMachine());
628 getStateMachine()->eventReactions().addChild(event);
629 event = NULL;
631 // Create event handler for bot death
632 eventDescription.EventType = "bot_killed";
633 // eventDescription.StateKeywords.push_back("");
634 // eventDescription.NamedStates.push_back("");
635 // eventDescription.GroupKeywords.push_back("");
636 // eventDescription.NamedGroups.push_back("");
638 // Create event action
639 eventAction = new CAIEventActionNode;
640 eventAction->Action = "outpost_send_squad_status";
641 eventAction->Weight = 1;
642 // eventAction->Args.push_back("");
644 // Register event action
645 eventDescription.Action = eventAction;
646 eventAction = NULL;
648 // Register event handler
649 // FIXME: 0 == CAIAliasDescriptionNode instance
650 event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType);
651 event->processEventDescription(&eventDescription, getStateMachine());
652 getStateMachine()->eventReactions().addChild(event);
653 event = NULL;
655 // Create event handler for bot death
656 eventDescription.EventType = "squad_leader_killed";
657 // eventDescription.StateKeywords.push_back("");
658 // eventDescription.NamedStates.push_back("");
659 // eventDescription.GroupKeywords.push_back("");
660 // eventDescription.NamedGroups.push_back("");
662 // Create event action
663 eventAction = new CAIEventActionNode;
664 eventAction->Action = "multi_actions";
665 eventAction->Weight = 1;
666 eventAction->Children.resize(2);
667 eventAction->Children[0] = new CAIEventActionNode;
668 eventAction->Children[0]->Action = "outpost_report_squad_leader_death";
669 eventAction->Children[0]->Weight = 1;
670 // eventAction->Children[0]->Args.push_back("");
671 eventAction->Children[1] = new CAIEventActionNode;
672 eventAction->Children[1]->Action = "code";
673 eventAction->Children[1]->Weight = 1;
674 eventAction->Children[1]->Args.push_back("()setAutoSpawn(0);");
675 #ifdef NL_DEBUG
676 eventAction->Children[1]->Args.push_back("print(\"INFINITE RESPAWN TIME FOR SQUAD\");");
677 #endif
679 // Register event action
680 eventDescription.Action = eventAction;
681 eventAction = NULL;
683 // Register event handler
684 // FIXME: 0 == CAIAliasDescriptionNode instance
685 event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType);
686 event->processEventDescription(&eventDescription, getStateMachine());
687 getStateMachine()->eventReactions().addChild(event);
688 event = NULL;
691 //////////////////////////////////////////////////////////////////////////////
692 //////////////////////////////////////////////////////////////////////////////
693 //////////////////////////////////////////////////////////////////////////////
695 void COutpost::createSquad(string const& dynGroupName, string const& stateMachineName, string const& initialStateName, string const& zoneName, uint32 spawnOrder, uint32 respawTimeGC, OUTPOSTENUMS::TPVPSide side)
697 IManagerParent* const managerParent = getOwner()->getOwner();
698 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
699 if (!aiInstance)
700 return;
702 COutpostSpawnZone const* spawnZone = getZone(CStringMapper::map(zoneName));
703 if (!spawnZone)
705 OUTPOST_WRN("newNpcChildGroup failed : spawnZone Not Found ! for StateMachine : %s", stateMachineName.c_str());
706 return;
709 CGroupDesc<COutpostSquadFamily> const* groupDesc = NULL;
711 FOREACH(itGroupDesc, CSquadLinks, _SquadLinks)
713 if ((*itGroupDesc).second->getName()==dynGroupName)
715 groupDesc = (*itGroupDesc).second;
716 goto groupFound;
719 groupFound:
720 if (!groupDesc)
722 OUTPOST_WRN("createSquad failed: No Group Found");
723 return;
726 // Find the state machine as a manager
727 CManager* manager = NULL;
728 FOREACH(itCont, CCont<CManager>, aiInstance->managers())
730 if (itCont->getName()==stateMachineName)
732 manager = *itCont;
733 break;
736 if (!manager)
738 FOREACH(itCont, CCont<COutpostManager>, managers())
740 if (itCont->getName()==stateMachineName)
742 manager = *itCont;
743 break;
747 if (!manager)
749 OUTPOST_WRN("createSquad failed : Unknown stateMachine %s", stateMachineName.c_str());
750 return;
752 // Find the state machine as a npc manager
753 COutpostSquadManager* outpostManager = dynamic_cast<COutpostSquadManager*>(manager);
754 if (!outpostManager)
756 OUTPOST_WRN("createSquad failed : Not an outpost state machine !: ", stateMachineName.c_str());
757 return;
759 createSquad(groupDesc, outpostManager, initialStateName, spawnZone, spawnOrder, respawTimeGC, side);
762 void COutpost::createSquad(uint32 dynGroupAlias, uint32 zoneAlias, uint32 spawnOrder, uint32 respawTimeGC, OUTPOSTENUMS::TPVPSide side)
764 IManagerParent* const managerParent = getOwner()->getOwner();
765 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
766 if (!aiInstance)
767 return;
769 COutpostSpawnZone const* spawnZone = spawnZones().getChildByAlias(zoneAlias);
770 if (!spawnZone)
772 OUTPOST_WRN("createSquad failed: spawn zone %s not found", LigoConfig.aliasToString(zoneAlias).c_str());
773 return;
776 CGroupDesc<COutpostSquadFamily> const* groupDesc = NULL;
778 // Find the group template.
779 // :TODO: Replace it with a faster map access.
780 groupDesc = getSquad( dynGroupAlias );
781 if (!groupDesc)
783 OUTPOST_WRN("createSquad failed: group %s not found", LigoConfig.aliasToString(dynGroupAlias).c_str());
784 return;
787 // Find the state machine as a manager
788 COutpostSquadManager* manager = dynamic_cast<COutpostSquadManager*>(managers().getChildByName("default_squad_manager"));
789 if (!manager)
791 OUTPOST_WRN("createSquad failed: default state machine not found! (<- this is a code bug)");
792 return;
794 createSquad(groupDesc, manager, "", spawnZone, spawnOrder, respawTimeGC, side);
797 void COutpost::createSquad(CGroupDesc<COutpostSquadFamily> const* groupDesc, COutpostSquadManager* manager, string const& initialStateName, COutpostSpawnZone const* spawnZone, uint32 createOrder, uint32 respawTimeGC, OUTPOSTENUMS::TPVPSide side)
799 OUTPOST_DBG("Creating a squad");
800 CAIVector const& spawnPosition = spawnZone->midPos();
801 sint32 baseLevel = -1;
802 double dispersionRadius = spawnZone->getRadius();
803 // Save the creator state
804 bool const savePlayerAttackable = groupDesc->getGDPlayerAttackable();
805 bool const saveBotAttackable = groupDesc->getGDBotAttackable();
806 // PlayerAttackable must be false as it it sent to the EGS in BotDescriptionMessage to set the
807 // property 'Attackable'. Squads are not attackable unless a player is in war with the owner of
808 // the outpost (using botchatprogram instead of the property 'Attackable').
809 // BotAttackable must be true, otherwise the EGS sets it as invulnerable (not attackable).
810 groupDesc->setGDPlayerAttackable(false);
811 groupDesc->setGDBotAttackable(true);
812 // Create the group
813 CGroupNpc* const grp = groupDesc->createNpcGroup(manager, spawnPosition, dispersionRadius, baseLevel, false);
814 // Restore the creator state
815 groupDesc->setGDPlayerAttackable(savePlayerAttackable);
816 groupDesc->setGDBotAttackable(saveBotAttackable);
817 // Verify that the group was created
818 if (!grp)
820 OUTPOST_WRN("createSquad failed: group %s cannot spawn", LigoConfig.aliasToString(groupDesc->getAlias()).c_str());
821 return;
823 // Set the new group parameters
824 // Let the EGS destroys squads explicitely because when a group is destroyed in the AIS its groupId can be reused
825 // and 2 squads would have the same groupId in the EGS (it asserts)
826 grp->autoDestroy(false);
827 grp->setAutoSpawn(true);
828 // grp->getPersistentStateInstance()->setParentStateInstance(entity->getPersistentStateInstance());
829 grp->initDynGrp(groupDesc, NULL);
830 // Set color
831 uint8 color = (uint8)(grp->getChildIndex() % 8);
832 grp->setColour(color);
833 // Get the state machine
834 CStateMachine const* stateMachine = manager->getStateMachine();
835 #if !FINAL_VERSION
836 // Verify that we have a state in the state machine
837 if (stateMachine->cstStates().size()==0)
838 nlerror("no state defined for StateMachine in Manager %s", manager->getFullName().c_str());
839 #endif
840 // Set the group in that state
841 CAIState* initialState = NULL;
842 if (!initialStateName.empty())
844 // FOREACH(itState, CCont<CAIState>, stateMachine->states())
845 for (size_t i=0; i<stateMachine->cstStates().size(); ++i)
847 CAIState* state = stateMachine->cstStates()[(uint32)i];
848 if (state->getName()==initialStateName)
849 initialState = state;
852 if (initialState==NULL)
853 initialState = stateMachine->cstStates()[0]; // sets the first state (must exist!).
854 grp->setStartState(initialState);
856 // Do not assist friends because it would lead to exploits
857 /*if ( _OwnerGuild != InvalidGuildId )
859 //grp->faction().addExtraProperty(_OwnerGuild); // TODO: set the GuildId for the squad npcs?
860 //grp->friendFaction().addExtraProperty(_OwnerGuild); // will be defended by the squad
862 else
864 // A tribe owns the outpost and all players are ennemies
865 // CPropertyId tribeFaction(CGrpProfileFaction::fameFactionToScriptFaction(_OwnerTribe));
866 //grp->faction().addProperty(tribeFaction);
867 //grp->friendFaction().addProperty(tribeFaction); // will be defended by the squad
868 //grp->ennemyFaction().addProperty(CPropertyId("Player"));
871 // Set guild id of members of the squad (for the tribe case, these *are* the tribe as well)
872 // This was removed because CBotNpc::spawn() now uses getOwner()->getOwner()->getOwner() to access the outpsot
873 /*FOREACH(ib, CAliasCont<CBot>, grp->bots())
875 CBotNpc *bot = static_cast<CBotNpc*>(*ib);
876 bot->setOwnerOutpost(this);
879 grp->setOutpostSide(side);
880 grp->setOutpostFactions(getAliasString(), side);
882 grp->_AggroRange = 25;
883 grp->_UpdateNbTicks = 10;
884 grp->respawnTime() = respawTimeGC;
886 grp->updateStateInstance(); // Directly call his first state (to retrieve associated params).
888 if (createOrder!=0)
890 COutpostSquadCreatedMsg params;
891 params.Outpost = this->getAlias();
892 params.CreateOrder = createOrder;
893 // Bug #847: Just downcast the pointer to make the groupId, the collision in 64b is negligible
894 //params.GroupId = reinterpret_cast<uint32>(grp);
895 params.GroupId = (uint32)(size_t)(void*)grp;
896 sendOutpostMessage("OUTPOST_SQUAD_CREATED", params);
899 OUTPOST_DBG( "Outpost %s: squad created defending 0x%x against 0x%x, respawnTime=%u gc", getName().c_str(), _OwnerAllianceId, _AttackerAllianceId, respawTimeGC );
902 void COutpost::spawnSquad(uint32 groupId)
904 OUTPOST_DBG( "Outpost %s: Spawning squad 0x%08x", getName().c_str(), groupId );
906 setAttackerAlliance(_AttackerAllianceId);
909 FOREACH(itManager, CAliasCont<COutpostManager>, _Managers)
911 COutpostManager* manager = *itManager;
912 FOREACH(itGroup, CAliasCont<CGroup>, manager->groups())
914 CGroup* group = *itGroup;
915 CGroupNpc* groupNpc = static_cast<CGroupNpc*>(group);
916 // Bug #847: Just downcast the pointer to make the groupId, the collision in 64b is negligible
917 //uint32 thisGroupId = reinterpret_cast<uint32>(groupNpc);
918 uint32 thisGroupId = (uint32)(size_t)(void*)groupNpc;
919 if (groupId==thisGroupId)
921 group->getSpawnObj()->spawnBots();
922 COutpostSquadSpawnedMsg params;
923 params.Outpost = this->getAlias();
924 params.GroupId = groupId;
925 sendOutpostMessage("OUTPOST_SQUAD_SPAWNED", params);
926 OUTPOST_DBG( "\t\tSpawned" );
927 return;
931 OUTPOST_WRN("No squad to spawn with group id 0x%08x. Valid group ids are:", groupId);
932 FOREACH(itManager, CAliasCont<COutpostManager>, _Managers)
934 COutpostManager* manager = *itManager;
935 FOREACH(itGroup, CAliasCont<CGroup>, manager->groups())
937 CGroup* group = *itGroup;
938 CGroupNpc* groupNpc = static_cast<CGroupNpc*>(group);
939 // Bug #847: Just downcast the pointer to make the groupId, the collision in 64b is negligible
940 //uint32 thisGroupId = reinterpret_cast<uint32>(groupNpc);
941 uint32 thisGroupId = (uint32)(size_t)(void*)groupNpc;
942 OUTPOST_WRN("- 0x%08x", thisGroupId);
947 void COutpost::despawnSquad(uint32 groupId)
949 OUTPOST_DBG( "Outpost %s: Despawning squad 0x%08x", getName().c_str(), groupId );
950 FOREACH(itManager, CAliasCont<COutpostManager>, _Managers)
952 COutpostManager* manager = *itManager;
953 FOREACH(itGroup, CAliasCont<CGroup>, manager->groups())
955 CGroup* group = *itGroup;
956 CGroupNpc* groupNpc = static_cast<CGroupNpc*>(group);
957 // Bug #847: Just downcast the pointer to make the groupId, the collision in 64b is negligible
958 //uint32 thisGroupId = reinterpret_cast<uint32>(groupNpc);
959 uint32 thisGroupId = (uint32)(size_t)(void*)groupNpc;
960 if (groupId==thisGroupId)
962 group->despawnBots();
963 COutpostSquadDespawnedMsg params;
964 params.Outpost = this->getAlias();
965 params.GroupId = groupId;
966 sendOutpostMessage("OUTPOST_SQUAD_DESPAWNED", params);
967 return;
971 OUTPOST_WRN("No squad to despawn");
974 void COutpost::deleteSquad(uint32 groupId)
976 OUTPOST_DBG( "Outpost %s: deleting squad 0x%08x", getName().c_str(), groupId );
977 FOREACH(itManager, CAliasCont<COutpostManager>, _Managers)
979 COutpostManager* manager = *itManager;
980 FOREACH(itGroup, CAliasCont<CGroup>, manager->groups())
982 CGroup* group = *itGroup;
983 CGroupNpc* groupNpc = static_cast<CGroupNpc*>(group);
984 // Bug #847: Just downcast the pointer to make the groupId, the collision in 64b is negligible
985 //uint32 thisGroupId = reinterpret_cast<uint32>(groupNpc);
986 uint32 thisGroupId = (uint32)(size_t)(void*)groupNpc;
987 if (groupId==thisGroupId)
989 manager->groups().removeChildByIndex(group->getChildIndex());
990 // No message here since this is called by squad destructor in EGS
991 return;
995 OUTPOST_WRN("No squad to delete");
998 void COutpost::sendOutpostSquadStatus(CGroupNpc* group)
1000 uint32 alias = this->getAlias();
1001 // Bug #847: Just downcast the pointer to make the groupId, the collision in 64b is negligible
1002 //uint32 groupId = reinterpret_cast<uint32>(group);
1003 uint32 groupId = (uint32)(size_t)(void*)group;
1004 bool groupAlive = false;
1005 bool leaderAlive = group->getSquadLeader()!=NULL;
1006 uint32 botCount = 0;
1007 // Persistent status
1008 // Spawn dependent status
1009 CSpawnGroup* spawnGroup = group->getSpawnObj();
1010 if (spawnGroup)
1012 groupAlive = spawnGroup->isGroupAlive();
1014 NLNET::CMessage msgout("OUTPOST_SQUAD_STATUS");
1015 msgout.serial(alias);
1016 msgout.serial(groupId);
1017 msgout.serial(groupAlive);
1018 msgout.serial(leaderAlive);
1019 msgout.serial(botCount);
1020 sendMessageViaMirror("EGS", msgout);
1023 void COutpost::squadLeaderDied(CGroupNpc* group)
1025 uint32 alias = this->getAlias();
1026 // Bug #847: Just downcast the pointer to make the groupId, the collision in 64b is negligible
1027 //uint32 groupId = reinterpret_cast<uint32>(group);
1028 uint32 groupId = (uint32)(size_t)(void*)group;
1029 NLNET::CMessage msgout("OUTPOST_SQUAD_LEADER_DIED");
1030 msgout.serial(alias);
1031 msgout.serial(groupId);
1032 sendMessageViaMirror("EGS", msgout);
1035 void COutpost::squadDied(CGroupNpc* group)
1037 uint32 alias = this->getAlias();
1038 // Bug #847: Just downcast the pointer to make the groupId, the collision in 64b is negligible
1039 //uint32 groupId = reinterpret_cast<uint32>(group);
1040 uint32 groupId = (uint32)(size_t)(void*)group;
1041 NLNET::CMessage msgout("OUTPOST_SQUAD_DIED");
1042 msgout.serial(alias);
1043 msgout.serial(groupId);
1044 sendMessageViaMirror("EGS", msgout);
1047 void COutpost::triggerSpecialEvent(OUTPOSTENUMS::TSpecialOutpostEvent eventId)
1049 // Managers handlers
1050 FOREACH(itManager, CCont<COutpostManager>, _Managers)
1052 COutpostManager* manager = *itManager;
1053 if (manager)
1055 CAIEvent* event = NULL;
1056 switch (eventId)
1058 case OUTPOSTENUMS::PeaceStateBegin: event = &manager->EventOutpostPeaceStateBegin; break;
1059 case OUTPOSTENUMS::PeaceStateEnd: event = &manager->EventOutpostPeaceStateEnd; break;
1060 case OUTPOSTENUMS::TribeOwnershipBegin: event = &manager->EventOutpostTribeOwnershipBegin; break;
1061 case OUTPOSTENUMS::TribeOwnershipEnd: event = &manager->EventOutpostTribeOwnershipEnd; break;
1062 case OUTPOSTENUMS::GuildOwnershipBegin: event = &manager->EventOutpostGuildOwnershipBegin; break;
1063 case OUTPOSTENUMS::GuildOwnershipEnd: event = &manager->EventOutpostGuildOwnershipEnd; break;
1064 case OUTPOSTENUMS::OwnerChanged: event = &manager->EventOutpostOwnerChanged; break;
1065 case OUTPOSTENUMS::AttackerChanged: event = &manager->EventOutpostAttackerChanged; break;
1066 case OUTPOSTENUMS::StateChanged: event = &manager->EventOutpostStateChanged; break;
1068 if (event)
1070 FOREACH(itGroup, CCont<CGroup>, manager->groups())
1072 CGroupNpc* group = static_cast<CGroupNpc*>(*itGroup);
1073 if (group)
1074 group->processStateEvent(*event);
1079 // Special handlers
1080 switch (eventId)
1082 case OUTPOSTENUMS::TribeOwnershipBegin:
1084 FOREACH(itManager, CCont<COutpostManager>, _Managers)
1086 COutpostManager* manager = *itManager;
1087 if (manager)
1088 manager->autoSpawnBegin();
1090 break;
1092 case OUTPOSTENUMS::TribeOwnershipEnd:
1094 FOREACH(itManager, CCont<COutpostManager>, _Managers)
1096 COutpostManager* manager = *itManager;
1097 if (manager)
1098 manager->autoSpawnEnd();
1100 break;
1105 void COutpost::setBuildingBotSheet(uint32 buildingAlias, NLMISC::CSheetId sheetId, bool autoSpawnDespawn, const std::string & customName)
1107 CBot * bot = getBuildingBotByAlias(buildingAlias);
1108 if (bot == NULL)
1110 OUTPOST_WRN( "cannot find building bot %s", LigoConfig.aliasToString( buildingAlias ).c_str() );
1111 return;
1114 AISHEETS::ICreatureCPtr const sheet = AISHEETS::CSheets::getInstance()->lookup(sheetId);
1115 if (sheetId!=NLMISC::CSheetId::Unknown && !sheet.isNull())
1117 bot->setCustomName(customName);
1118 bot->triggerSetSheet(sheet);
1119 if (autoSpawnDespawn && !bot->isSpawned())
1120 bot->spawn();
1122 else
1124 if (autoSpawnDespawn && bot->isSpawned())
1125 bot->despawnBot();
1129 void COutpost::despawnAllSquads()
1131 FOREACH(itManager, CAliasCont<COutpostManager>, _Managers)
1133 COutpostManager* manager = *itManager;
1134 COutpostSquadManager* sqManager = dynamic_cast<COutpostSquadManager*>(manager);
1135 if (sqManager)
1137 FOREACH(itGroup, CAliasCont<CGroup>, sqManager->groups())
1139 CGroup* group = *itGroup;
1140 group->despawnBots();
1146 template <class T>
1147 void COutpost::sendOutpostMessage(std::string const& msgName, T& paramStruct)
1149 NLNET::CMessage msgout(msgName);
1150 msgout.serial(paramStruct);
1151 sendMessageViaMirror(std::string("EGS"), msgout);
1154 //////////////////////////////////////////////////////////////////////////////
1155 // Commands //
1156 //////////////////////////////////////////////////////////////////////////////
1158 NLMISC_COMMAND(displayOutposts, "list the available outpost", "")
1160 if (args.size() > 0)
1161 return false;
1163 uint32 instanceNumber = std::numeric_limits<uint32>::max();
1164 for (uint i=0; i<CAIS::instance().AIList().size(); ++i)
1166 CAIInstance *const aii = CAIS::instance().AIList()[i];
1167 if (!aii)
1169 log.displayNL("No current ai instance, can't look for outpost");
1170 continue;
1173 string continentName;
1174 if (!args.empty())
1175 continentName = args[0];
1177 // retreive the oupost
1178 for (uint i=0; i<aii->continents().size(); ++i)
1180 CContinent *const continent = aii->continents()[i];
1181 if ( !continent
1182 || ( !continentName.empty()
1183 && continentName!=continent->getName()))
1184 continue;
1186 log.displayNL("Outposts in continent '%s':", continent->getName().c_str());
1187 for (uint j=0; j<continent->outposts().size(); ++j)
1189 COutpost const* outpost = continent->outposts()[j];
1190 if (!outpost)
1191 continue;
1193 log.displayNL(" %s", outpost->getOneLineInfoString().c_str());
1194 log.displayNL(" - %d group descs", outpost->squadLinks().size());
1195 for (COutpost::CSquadLinks::const_iterator isl=outpost->squadLinks().begin(); isl!=outpost->squadLinks().end(); ++isl )
1197 CGroupDesc<COutpostSquadFamily> const* gd = (*isl).second;
1198 if (!gd)
1199 continue;
1201 log.displayNL(" Group desc '%s' %s", gd->getName().c_str(), gd->getAliasString().c_str());
1204 log.displayNL(" - %d spawn zones", outpost->spawnZones().size());
1205 for (uint j=0; j<outpost->spawnZones().size(); ++j)
1207 COutpostSpawnZone const* sz = outpost->spawnZones()[j];
1208 if (!sz)
1209 continue;
1211 log.displayNL(" SpawnZone '%s' %s (%s)", sz->getName().c_str(), sz->getAliasString().c_str(), sz->midPos().toString().c_str());
1213 log.displayNL(" - %d state machines", outpost->managers().size());
1214 for (uint j=0; j<outpost->managers().size(); ++j)
1216 COutpostManager* manager = outpost->managers()[j];
1217 if (!manager)
1218 continue;
1220 log.displayNL(" State machine '%s' %s", manager->getName().c_str(), manager->getAliasString().c_str());
1221 log.displayNL(" - %d states", manager->getStateMachine()->states().size());
1222 for (uint j=0; j<manager->getStateMachine()->states().size(); ++j)
1224 CAIState const* state = manager->getStateMachine()->states()[j];
1225 if (!state)
1226 continue;
1228 log.displayNL(" State '%s' %s", state->getName().c_str(), state->getAliasString().c_str());
1230 log.displayNL(" - %d groups", manager->groups().size());
1231 for (uint j=0; j<manager->groups().size(); ++j)
1233 CGroup const* group = manager->groups()[j];
1234 if (group)
1236 log.displayNL(" Group '%s' %s", group->getName().c_str(), group->getAliasString().c_str());
1237 log.displayNL(" - %d bots", group->bots().size());
1238 for (uint k=0; k<group->bots().size(); ++k)
1240 CBot const* bot = group->bots()[k];
1241 if (bot)
1242 log.displayNL(" Bot '%s' %s", bot->getName().c_str(), bot->getAliasString().c_str());
1243 else
1244 log.displayNL(" Bot <NULL>");
1247 else
1248 log.displayNL(" Group <NULL>");
1255 return true;
1258 // outpostSpawnSquad 1 fyros outpost group machine zone
1260 NLMISC_COMMAND(outpostSpawnSquad, "Spawns a squad in an outpost", "<instance_number> <continent> <outpost> <group_template> <state_machine> <spawn_zone> [<respawnTimeInSec>=5*60]")
1262 if (args.size() != 6)
1263 return false;
1265 uint32 instanceNumber = std::numeric_limits<uint32>::max();
1266 fromString(args[0], instanceNumber);
1267 string continentName = args[1];
1268 string outpostName = args[2];
1269 string dynGroupName = args[3];
1270 string stateMachineName = args[4];
1271 string zoneName = args[5];
1272 uint32 respawnTimeGC = 5*60*10;
1273 if ( args.size() > 6 )
1275 NLMISC::fromString(args[6], respawnTimeGC);
1276 respawnTimeGC *= 10;
1279 for (size_t i=0; i<5; ++i)
1280 if (args[i]=="")
1281 return false;
1283 bool done = false;
1284 bool instanceFound = false;
1285 bool continentFound = false;
1286 bool outpostFound = false;
1287 if (instanceNumber<CAIS::instance().AIList().size())
1289 CAIInstance* const aiinstance = CAIS::instance().AIList()[instanceNumber];
1290 if (aiinstance)
1292 instanceFound = true;
1293 for (uint i=0; i<aiinstance->continents().size() && !done; ++i)
1295 CContinent* const continent = aiinstance->continents()[i];
1296 if (!continent || continentName!=continent->getName())
1297 continue;
1298 continentFound = true;
1299 for (uint j=0; j<continent->outposts().size() && !done; ++j)
1301 COutpost* const outpost = continent->outposts()[j];
1302 if (!outpost || outpostName!=outpost->getName())
1303 continue;
1304 outpostFound = true;
1305 outpost->createSquad(dynGroupName, stateMachineName, "", zoneName, 0, respawnTimeGC, OUTPOSTENUMS::UnknownPVPSide);
1306 done = true;
1311 if (!done)
1313 OUTPOST_WRN("Could not spawn a new squad");
1314 log.displayNL("Could not spawn a new squad");
1315 if (!instanceFound)
1316 log.displayNL( "Instance not found" );
1317 if (!continentFound)
1318 log.displayNL( "Continent not found" );
1319 if (!outpostFound)
1320 log.displayNL( "Outpost not found" );
1322 return true;
1327 * Return the outpost corresponding to the alias, or NULL if not found (with a nlwarning)
1329 COutpost* COutpost::getOutpostByAlias( TAIAlias outpostAlias )
1331 bool instanceFound = false;
1332 bool continentFound = false;
1333 bool outpostFound = false;
1334 for (uint i=0; i<CAIS::instance().AIList().size(); ++i)
1336 CAIInstance* const aiinstance = CAIS::instance().AIList()[i];
1337 if (aiinstance)
1339 instanceFound = true;
1340 for (uint i=0; i<aiinstance->continents().size(); ++i)
1342 CContinent* const continent = aiinstance->continents()[i];
1343 if (!continent)
1344 continue;
1345 continentFound = true;
1346 for (uint j=0; j<continent->outposts().size(); ++j)
1348 COutpost* outpost = continent->outposts()[j];
1349 if (!outpost || outpostAlias!=outpost->getAlias())
1350 continue;
1351 return outpost;
1356 if (!instanceFound)
1357 OUTPOST_WRN( "Instance not found" );
1358 if (!continentFound)
1359 OUTPOST_WRN( "Continent not found" );
1360 if (!outpostFound)
1361 OUTPOST_WRN( "Outpost %s not found", LigoConfig.aliasToString( outpostAlias ).c_str() );
1362 return NULL;
1366 void outpostCreateSquad(uint32 outpostAlias, uint32 dynGroupAlias, uint32 zoneAlias, uint32 spawnOrder)
1368 COutpost *outpost = COutpost::getOutpostByAlias( outpostAlias );
1369 if ( outpost )
1370 outpost->createSquad(dynGroupAlias, zoneAlias, spawnOrder);
1373 void outpostSpawnSquad(uint32 outpostAlias, uint32 groupId)
1375 COutpost *outpost = COutpost::getOutpostByAlias( outpostAlias );
1376 if ( outpost )
1377 outpost->spawnSquad(groupId);
1380 void outpostDespawnSquad(uint32 outpostAlias, uint32 groupId)
1382 COutpost *outpost = COutpost::getOutpostByAlias( outpostAlias );
1383 if ( outpost )
1384 outpost->despawnSquad(groupId);
1387 void outpostDeleteSquad(uint32 outpostAlias, uint32 groupId)
1389 COutpost *outpost = COutpost::getOutpostByAlias( outpostAlias );
1390 if ( outpost )
1391 outpost->deleteSquad(groupId);
1394 void outpostDespawnAllSquads(uint32 outpostAlias)
1396 COutpost *outpost = COutpost::getOutpostByAlias( outpostAlias );
1397 if ( outpost )
1398 outpost->despawnAllSquads();
1402 NLMISC_COMMAND(outpostAliasSpawnSquad, "Spawns a squad in an outpost (respawn time = 5 min)", "<outpost_alias> <group_alias> <spawn_zone_alias>")
1404 if (args.size()!=3)
1405 return false;
1407 for (size_t i=0; i<3; ++i)
1408 if (args[i]=="")
1409 return false;
1411 uint32 outpostAlias = LigoConfig.aliasFromString(args[0]);
1412 uint32 dynGroupAlias = LigoConfig.aliasFromString(args[1]);
1413 uint32 zoneAlias = LigoConfig.aliasFromString(args[2]);
1414 string stateMachineName = "default_squad_manager";
1416 COutpost *outpost = COutpost::getOutpostByAlias(outpostAlias);
1417 if (outpost)
1418 outpost->createSquad(dynGroupAlias, zoneAlias, 0, 5*60*10, OUTPOSTENUMS::UnknownPVPSide);
1420 return true;
1423 CBot* COutpost::getBuildingBotByAlias(TAIAlias alias)
1425 CGroup* group = getBuildingGroup();
1426 if (group)
1427 return group->bots().getChildByAlias(alias);
1428 else
1429 return NULL;
1432 NLMISC_COMMAND(outpostSetBuildingBotSheet, "Set the sheet of an outpost building", "<outpost_alias> <building_alias> <bot_sheet>")
1434 if (args.size()!=3)
1435 return false;
1437 for (size_t i=0; i<3; ++i)
1438 if (args[i]=="")
1439 return false;
1441 uint32 outpostAlias = LigoConfig.aliasFromString(args[0]);
1442 uint32 buildingAlias = LigoConfig.aliasFromString(args[1]);
1443 NLMISC::CSheetId buildingBotSheet = NLMISC::CSheetId(args[2]);;
1445 COutpost* outpost = COutpost::getOutpostByAlias(outpostAlias);
1446 if (outpost)
1447 outpost->setBuildingBotSheet(buildingAlias, buildingBotSheet, true, "");
1449 return true;
1453 // Call this macro, then do the code that will must done only if the outpost is found in this instance
1454 // The data you have access to after this macro:
1455 // - COutpost *outpost
1456 // - msgStruct params;
1457 #define IF_GET_OUTPOST_FOR_MSG( msgStruct ) \
1458 msgStruct params; \
1459 msgin.serial( params ); \
1460 COutpost *outpost = COutpost::getOutpostByAlias( params.Outpost ); \
1461 if ( outpost )
1464 void cbOutpostCreateSquad( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1466 IF_GET_OUTPOST_FOR_MSG( COutpostCreateSquadMsg )
1467 outpost->createSquad(params.Group, params.Zone, params.CreateOrder, params.RespawnTimeS*10, params.Side);
1470 void cbOutpostSpawnSquad( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1472 IF_GET_OUTPOST_FOR_MSG( COutpostSpawnSquadMsg )
1473 outpost->spawnSquad(params.GroupId);
1476 void cbOutpostDespawnSquad( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1478 IF_GET_OUTPOST_FOR_MSG( COutpostDespawnSquadMsg )
1479 outpost->despawnSquad(params.GroupId);
1482 void cbOutpostDeleteSquad( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1484 IF_GET_OUTPOST_FOR_MSG( COutpostDeleteSquadMsg )
1485 outpost->deleteSquad(params.GroupId);
1488 void cbOutpostDespawnAllSquads( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1490 IF_GET_OUTPOST_FOR_MSG( COutpostDespawnAllSquadsMsg )
1491 outpost->despawnAllSquads();
1494 void cbOutpostSetOwner( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1496 IF_GET_OUTPOST_FOR_MSG( CSetOutpostOwner )
1497 outpost->setOwnerAlliance( params.Owner );
1500 void cbOutpostSetAttacker( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1502 IF_GET_OUTPOST_FOR_MSG( CSetOutpostAttacker )
1503 outpost->setAttackerAlliance( params.Attacker );
1506 void cbOutpostSetState( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1508 IF_GET_OUTPOST_FOR_MSG( COutpostSetStateMsg )
1509 outpost->setState( params.State );
1512 void cbOutpostEvent( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1514 IF_GET_OUTPOST_FOR_MSG( COutpostEventMsg )
1515 outpost->triggerSpecialEvent(params.Event);
1518 void cbOutpostSetBuildingBotSheet( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )
1520 IF_GET_OUTPOST_FOR_MSG( COutpostSetBuildingBotSheetMsg )
1521 outpost->setBuildingBotSheet(params.Building, params.SheetId, params.AutoSpawnDespawn, params.CustomName);
1525 #include "event_reaction_include.h"