// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "ai_spire.h" #include "ai_instance.h" #include "ais_actions.h" using namespace AITYPES; using namespace std; using namespace CAISActionEnums; extern CAIInstance* currentInstance; DEFINE_ACTION(ContextGlobal, SPIREMGR) { nlassertex(currentInstance != NULL, ("No AIInstance created !")); CAIInstance* aiInstance = currentInstance ; CWorkPtr::aiInstance(aiInstance); // set the current AIInstance. // get hold of the manager's slot id - note that managers are identified by slot and not by alias! uint32 alias; string spireName; string mapName; string filename; if (!getArgs(args, name(), alias, spireName, mapName, filename)) return; string mgrName = "spire_manager_"+spireName; // see whether the manager is already loaded CManager* mgr = aiInstance->managers().getChildByName(mgrName); // not found so look for a free slot if (!mgr) aiInstance->newMgr(MgrTypeNpc, 0, mgrName, mapName, filename); else mgr->registerForFile(filename); mgr = aiInstance->managers().getChildByName(mgrName); CMgrNpc* mgrNpc = dynamic_cast(mgr); if (!mgrNpc) return; // setup the working manager pointer and exit CWorkPtr::mgr(mgrNpc); CWorkPtr::eventReactionContainer(mgrNpc->getStateMachine()); // set workptr state to this state CContextStack::setContext(ContextNpcMgr); } DEFINE_ACTION(ContextEventContainer, SPIRSTAT) // spire state { CStateMachine* container = CWorkPtr::eventReactionContainer(); if (!container) return; uint32 alias; string spireName; if (!getArgs(args, name(), alias, spireName)) return; string stateName = "spire_state_"+spireName; CAIStatePositional* state = new CAIStatePositional(container, alias, stateName); container->states().addAliasChild(state); // set workptr::state to this state CWorkPtr::stateState(container->states()[0]); if (!CWorkPtr::stateState()) { nlwarning("Failed to select state %s", LigoConfig.aliasToString(alias).c_str()); return; } // set workptr state to this state CContextStack::setContext(ContextPositionalState); } DEFINE_ACTION(ContextNpcMgr, SPIREGRP) { CMgrNpc* mgr = CWorkPtr::mgrNpc(); if (!mgr) return; uint32 alias; string spireName; if (!getArgs(args, name(), alias, spireName)) return; string grpName = "spire_group_"+spireName; CGroupNpc* grp = new CGroupNpc(mgr, alias, grpName, RYAI_MAP_CRUNCH::Nothing); grp->setAutoSpawn(false); mgr->groups().addChild(grp); CWorkPtr::grp(grp); if (!CWorkPtr::grpNpc()) { nlwarning("Failed to select spire group %s as not found in manager: %s", grpName.c_str(), CWorkPtr::mgrNpc()->getName().c_str()); return; } CStateMachine* stateMachine = CWorkPtr::eventReactionContainer(); if (stateMachine) grp->setStartState(stateMachine->cstStates()[0]); CContextStack::setContext(ContextNpcGrp); } DEFINE_ACTION(ContextNpcGrp, SPIREBOT) { CGroupNpc* grp = CWorkPtr::grpNpc(); if (!grp) return; uint32 alias; string spireName; if (!getArgs(args, name(), alias, spireName)) return; string botName = "spire_bot_"+spireName; CBotNpc* bot = new CBotNpc(grp, alias, botName); grp->bots().addChild(bot); CWorkPtr::bot(bot); if (!CWorkPtr::botNpc()) { nlwarning("Failed to select spire bot %s as not found in group: %s", botName.c_str(), CWorkPtr::grpNpc()->getName().c_str()); return; } if (bot->getChat().isNull()) bot->newChat(); bot->getChat()->add(bot->getAIInstance(), "op:spire"); bot->setStuck(true); // set workptr state to this state CContextStack::setContext(ContextNpcBot); } DEFINE_ACTION(ContextNpcBot, SPIRSHTS) { CGroupNpc* grp = CWorkPtr::grpNpc(); if (!grp) return; CBotNpc* bot = CWorkPtr::botNpc(); if (!bot) return; FOREACHC(itArg, std::vector, args) { string str, name, sheet; itArg->get(str); AI_SHARE::stringToKeywordAndTail(str, name, sheet); grp->setStrLogicVar(NLMISC::CStringMapper::map("$sheet_spire_"+name), sheet); } } #if 0 #include "continent.h" #include "ai_grp_npc.h" #include "game_share/people.h" #include "ai_profile_npc.h" #include "continent_inline.h" #include "dyn_grp_inline.h" using namespace std; using namespace NLMISC; CFileDisplayer SpireDisplayer("spires.log"); CLog SpireDbgLog(CLog::LOG_DEBUG), SpireInfLog(CLog::LOG_INFO), SpireWrnLog(CLog::LOG_WARNING), SpireErrLog(CLog::LOG_ERROR); namespace SPIREHELPERS { static std::map spireFactions; bool isAttackingFaction(uint32 factionIndex, CAIEntityPhysical const* player) { std::map::const_iterator it = spireFactions.find(player->spireAlias()); return it!=spireFactions.end() && it->second==factionIndex; } } ////////////////////////////////////////////////////////////////////////////// // CSpire // ////////////////////////////////////////////////////////////////////////////// //std::set ChangedSpires; //CSpire::TSpireIndex CSpire::_Spires; CSpire::CSpire(CContinent* owner, uint32 alias, std::string const& name, std::string const& filename) : CAliasChild(owner, alias, name) , CAliasTreeRoot(filename) , _OwnerAllianceId(InvalidAllianceId) , _AttackerAllianceId(InvalidAllianceId) , _State(SPIREENUMS::UnknownSpireState) { static bool logInitDone = false; if ( ! logInitDone ) { SpireDbgLog.addDisplayer( &SpireDisplayer ); SpireInfLog.addDisplayer( &SpireDisplayer ); SpireWrnLog.addDisplayer( &SpireDisplayer ); logInitDone = true; } SPIRE_DBG("Creating spire %s' (%s)", name.c_str(), getAliasFullName().c_str()); if (LogSpireDebug) SPIRE_DBG("Creating spire '%s'", getAliasFullName().c_str()); _SpireName = getName(); CSpireManager* manager = NULL; // Create default squad manager manager = new CSpireSquadManager(this, 0, "default_squad_manager", filename); if (manager) { _Managers.addChild(manager); manager->init(); } // Create default building manager manager = new CSpireManager(this, 0, "default_building_manager", filename); if (manager) { _Managers.addChild(manager); manager->init(); CGroupNpc* group = new CGroupNpc(manager, NULL, /*AStarFlag*/RYAI_MAP_CRUNCH::Nothing); if (group) { manager->groups().addAliasChild(group); group->setAutoSpawn(false); group->setName("default_building_group"); group->clearParameters(); group->setPlayerAttackable(false); group->setBotAttackable(false); group->setBotsAreNamedFlag(); } } } CSpire::~CSpire() { if (LogSpireDebug) SPIRE_DBG("Deleting spire '%s'", getAliasFullName().c_str()); _SpawnZones.clear(); } std::string CSpire::getOneLineInfoString() const { return std::string("Spire '") + getName() + "' " + getAliasString() + ", State=" + SPIREENUMS::toString(_State); } std::string CSpire::getFullName() const { return std::string(getOwner()->getFullName() +":"+ getName()); } std::string CSpire::getIndexString() const { return getOwner()->getIndexString()+NLMISC::toString(":o%u", getChildIndex()); } /* std::string CSpire::getPlaceOwnerFullName() const { return getFullName(); } std::string CSpire::getPlaceOwnerIndexString() const { return getIndexString(); } */ CAIInstance* CSpire::getAIInstance() const { return getOwner()->getAIInstance(); } std::string CSpire::getManagerIndexString(CManager const* manager) const { return getIndexString()+NLMISC::toString(":m%u", manager->getChildIndex()); } IAliasCont* CSpire::getAliasCont(TAIType type) { switch (type) { case AITypeSpireSquadFamily: SPIRE_WRN( "Obsolete squad family node under spire %s", getName().c_str() ); return NULL; case AITypeSpireSpawnZone: return &_SpawnZones; case AITypeManager: return &_Managers; case AITypeSpireManager: return &_Managers; case AITypeSpireBuilding: return getBuildingGroup()->getAliasCont(AITypeBot); default: return NULL; } } CAliasTreeOwner* CSpire::createChild(IAliasCont* cont, CAIAliasDescriptionNode* aliasTree) { if (!cont) return NULL; CAliasTreeOwner* child = NULL; switch(aliasTree->getType()) { // create the child and adds it to the corresponding position. case AITypeSpireSpawnZone: child = new CSpireSpawnZone(this, aliasTree); break; case AITypeManager: child = new CSpireSquadManager(this, aliasTree->getAlias(), aliasTree->getName()); break; case AITypeSpireManager: child = new CSpireSquadManager(this, aliasTree->getAlias(), aliasTree->getName()); break; case AITypeSpireBuilding: return getBuildingGroup()->createChild(cont, aliasTree); } if (child) cont->addAliasChild(child); return child; } CGroup* CSpire::getBuildingGroup() { CSpireManager* manager = _Managers.getChildByName("default_building_manager"); return manager->groups().getChildByName("default_building_group"); } void CSpire::setTribe(const std::string &tribeName) { // The tribe is only populated by the NPCs of the squads _Tribe = tribeName; if (LogSpireDebug) SPIRE_DBG("setting tribe '%s' in '%s' as owner for spire '%s'", tribeName.c_str(), getOwner()->getName().c_str(), getAliasFullName().c_str()); } void CSpire::setOwnerAlliance( TAllianceId ownerAllianceId ) { if (_OwnerAllianceId!=ownerAllianceId) { // if the old owner was a tribe if (_OwnerAllianceId==InvalidAllianceId) { triggerSpecialEvent(SPIREENUMS::TribeOwnershipEnd); SPIREHELPERS::spireFactions.erase(getAlias()); } else triggerSpecialEvent(SPIREENUMS::GuildOwnershipEnd); } std::swap(_OwnerAllianceId, ownerAllianceId); // 'ownerAllianceId' contains old owner alliance id if (_OwnerAllianceId!=ownerAllianceId) { triggerSpecialEvent(SPIREENUMS::OwnerChanged); // if the new owner is a tribe if (_OwnerAllianceId==InvalidAllianceId) { SPIREHELPERS::spireFactions.insert(make_pair(getAlias(), CStaticFames::getInstance().getFactionIndex(_Tribe))); triggerSpecialEvent(SPIREENUMS::TribeOwnershipBegin); } else triggerSpecialEvent(SPIREENUMS::GuildOwnershipBegin); } } void CSpire::setAttackerAlliance( TAllianceId attackerAllianceId ) { std::swap(_AttackerAllianceId, attackerAllianceId); // 'attackerAllianceId' contains old attacker alliance id if (_AttackerAllianceId!=attackerAllianceId) { triggerSpecialEvent(SPIREENUMS::AttackerChanged); } // Update the enemies of the current squads of the spire FOREACH( im, CAliasCont, _Managers ) im->setEnemies( _AttackerAllianceId ); } void CSpire::setState( SPIREENUMS::TSpireState state ) { if (_State!=state) { if (_State==SPIREENUMS::Peace) triggerSpecialEvent(SPIREENUMS::PeaceStateEnd); } std::swap(_State, state); // 'state' contains old _State if (_State!=state) { triggerSpecialEvent(SPIREENUMS::StateChanged); if (_State==SPIREENUMS::Peace) triggerSpecialEvent(SPIREENUMS::PeaceStateBegin); } } void CSpire::update() { // FOREACH(it, CAliasCont, _SquadFamilies) it->update(); // FOREACH(it, CAliasCont, _SpawnZones) it->update(); FOREACH(it, CAliasCont, _Managers) it->update(); } void CSpire::addZone(CSpireSpawnZone* zone) { #if !FINAL_VERSION if (_ZoneList.find(NLMISC::CStringMapper::map(zone->getName()))!=_ZoneList.end()) SPIRE_WRN("this SpireSpawnZone have the same name than another: %s", zone->getName().c_str()); #endif _ZoneList[NLMISC::CStringMapper::map(zone->getName())] = zone; } void CSpire::removeZone(CSpireSpawnZone* zone) { _ZoneList.erase(NLMISC::CStringMapper::map(zone->getName())); } CSpireSpawnZone* CSpire::getZone(NLMISC::TStringId zoneName) { return _ZoneList[zoneName]; } void CSpire::serviceEvent(CServiceEvent const& info) { if (info.getServiceName()=="EGS" && info.getEventType()==CServiceEvent::SERVICE_DOWN) { // Delete all the squad groups CSpireManager* manager = _Managers.getChildByName("default_squad_manager"); if (manager) manager->groups().clear(); } FOREACH(itManager, CAliasCont, _Managers) { CSpireManager* manager = *itManager; manager->serviceEvent(info); } } bool CSpire::spawn() { // Spawn spire managers CCont::iterator itManager, itManagerEnd(_Managers.end()); for (itManager=_Managers.begin(); itManager!=itManagerEnd; ++itManager) { CSpireManager* manager = *itManager; manager->spawn(); } // We should check individual errors, but fake success here :) return true; } bool CSpire::despawn() { // Despawn instance managers CCont::iterator itManager, itManagerEnd(_Managers.end()); for (itManager=_Managers.begin(); itManager!=itManagerEnd; ++itManager) { CSpireManager* manager = *itManager; manager->despawnMgr(); } // We should check individual errors, but fake success here :) return true; } //----------------------------------------------------------------------------- std::string CSpire::getStateName() const { return SPIREENUMS::toString(_State); } ////////////////////////////////////////////////////////////////////////////// // CSpireSquadFamily // ////////////////////////////////////////////////////////////////////////////// IAliasCont* CSpireSquadFamily::getAliasCont(TAIType type) { switch (type) { case AITypeGroupTemplate: case AITypeGroupTemplateMultiLevel: return &_GroupDescs; default: return NULL; } } CAliasTreeOwner* CSpireSquadFamily::createChild(IAliasCont* cont, CAIAliasDescriptionNode* aliasTree) { if (!cont) return NULL; CAliasTreeOwner* child = NULL; switch (aliasTree->getType()) { case AITypeSquadTemplateVariant: child = new CGroupDesc(this, aliasTree->getAlias(), aliasTree->getParent()->getName()+":"+aliasTree->getName()); break; case AITypeGroupTemplate: case AITypeGroupTemplateMultiLevel: child = new CGroupDesc(this, aliasTree->getAlias(), aliasTree->getName()); break; } if (child) cont->addAliasChild(child); return child; } std::string CSpireSquadFamily::getFullName() const { // return std::string(getOwner()->getFullName() +":"+ getName()); return getName(); } std::string CSpireSquadFamily::getIndexString() const { return getOwner()->getIndexString()+NLMISC::toString(":sf%u", getChildIndex()); } ////////////////////////////////////////////////////////////////////////////// // CGroupDesc // ////////////////////////////////////////////////////////////////////////////// template <> size_t const CGroupDesc::_MultiLevelSheetCount = 20; ////////////////////////////////////////////////////////////////////////////// // CBotDesc // ////////////////////////////////////////////////////////////////////////////// template <> size_t const CBotDesc::_MultiLevelSheetCount = 20; ////////////////////////////////////////////////////////////////////////////// // CSpireSpawnZone // ////////////////////////////////////////////////////////////////////////////// CSpireSpawnZone::CSpireSpawnZone(CSpire* owner, CAIAliasDescriptionNode* adn) : CAIPlaceXYR(owner, adn) { owner->addZone(this); } CSpireSpawnZone::~CSpireSpawnZone() { static_cast(getOwner())->removeZone(this); } std::string CSpireSpawnZone::getFullName() const { return std::string(getOwner()->getFullName() +":"+ getName()); } std::string CSpireSpawnZone::getIndexString() const { return getOwner()->getIndexString()+NLMISC::toString(":%u", getChildIndex()); } ////////////////////////////////////////////////////////////////////////////// // CSpireManager // ////////////////////////////////////////////////////////////////////////////// CSpireManager::CSpireManager(CSpire* parent, uint32 alias, std::string const& name, std::string const& filename) : CMgrNpc(parent, alias, name, filename) , _AutoSpawn(false) { registerEvents(); } CSpireManager::~CSpireManager() { unregisterEvents(); // need be called otherwise the state manager will be unhappy when the CAIEvent objects are destroyed } std::string CSpireManager::getOneLineInfoString() const { return std::string("Spire manager '") + getName() + "'"; } void CSpireManager::update() { CMgrNpc::update(); } IAliasCont* CSpireManager::getAliasCont(TAIType type) { // IAliasCont* cont = NULL; // switch (type) // { // default: // break; // } // if (cont) // return cont; // else return CMgrNpc::getAliasCont(type); } CAliasTreeOwner* CSpireManager::createChild(IAliasCont* cont, CAIAliasDescriptionNode* aliasTree) { // CAliasTreeOwner* child = NULL; // switch (aliasTree->getType()) // { // default: // break; // } // if (child) // cont->addAliasChild(child); // if (child) // return child; // else return CMgrNpc::createChild(cont, aliasTree); } void CSpireManager::registerEvents() { _StateMachine.addEvent( "spire_peace_state_begin", EventSpirePeaceStateBegin ); _StateMachine.addEvent( "spire_peace_state_end", EventSpirePeaceStateEnd ); _StateMachine.addEvent( "spire_tribe_ownership_begin", EventSpireTribeOwnershipBegin ); _StateMachine.addEvent( "spire_tribe_ownership_end", EventSpireTribeOwnershipEnd ); _StateMachine.addEvent( "spire_guild_ownership_begin", EventSpireGuildOwnershipBegin ); _StateMachine.addEvent( "spire_guild_ownership_end", EventSpireGuildOwnershipEnd ); _StateMachine.addEvent( "spire_owner_changed", EventSpireOwnerChanged ); _StateMachine.addEvent( "spire_attacker_changed", EventSpireAttackerChanged ); _StateMachine.addEvent( "spire_state_changed", EventSpireStateChanged ); } void CSpireManager::unregisterEvents() { _StateMachine.delEvent( "spire_peace_state_begin" ); _StateMachine.delEvent( "spire_peace_state_end" ); _StateMachine.delEvent( "spire_tribe_ownership_begin" ); _StateMachine.delEvent( "spire_tribe_ownership_end" ); _StateMachine.delEvent( "spire_guild_ownership_begin" ); _StateMachine.delEvent( "spire_guild_ownership_end" ); _StateMachine.delEvent( "spire_owner_changed" ); _StateMachine.delEvent( "spire_attacker_changed" ); _StateMachine.delEvent( "spire_state_changed" ); } void CSpireManager::autoSpawnBegin() { if (!_AutoSpawn) return; FOREACH(itGroup, CCont, groups()) { CGroupNpc* group = static_cast(*itGroup); if (group) { CSpawnGroupNpc* spawn = group->getSpawnObj(); if (spawn) spawn->spawnBots(); } } } void CSpireManager::autoSpawnEnd() { if (!_AutoSpawn) return; FOREACH(itGroup, CCont, groups()) { CGroupNpc* group = static_cast(*itGroup); if (group) { CSpawnGroupNpc* spawn = group->getSpawnObj(); if (spawn) spawn->despawnBots(1); } } } void CSpireManager::setEnemies( TAllianceId attackerAllianceId ) { FOREACH( ig, CAliasCont, _Groups ) { // Attack only the declared ennemies of the spire CGroupNpc *grp = static_cast(*ig); grp->ennemyFaction().clearExtra(); grp->ennemyFaction().addExtraProperty(attackerAllianceId); } } ////////////////////////////////////////////////////////////////////////////// // CSpireSquadManager // ////////////////////////////////////////////////////////////////////////////// CSpireSquadManager::CSpireSquadManager(CSpire* parent, uint32 alias, std::string const& name, std::string const& filename) : CSpireManager(parent, alias, name, filename) { // Create init state CAIState* state = new CAIStatePositional(getStateMachine(), 0, "spire_squad_init"); IAIProfileFactory* aiProfile = lookupAIGrpProfile("squad"); state->setActivityProfile(aiProfile); getStateMachine()->states().addChild(state); CAIEventDescription eventDescription; CAIEventActionNode::TSmartPtr eventAction; CAIEventReaction* event; // Create event handler for start of state eventDescription.EventType = "start_of_state"; // eventDescription.StateKeywords.push_back(""); // eventDescription.NamedStates.push_back(""); // eventDescription.GroupKeywords.push_back(""); // eventDescription.NamedGroups.push_back(""); // Create event action eventAction = new CAIEventActionNode; eventAction->Action = "code"; eventAction->Weight = 1; eventAction->Args.push_back("print(\"CREATING A SQUAD\");"); // eventAction->Args.push_back("()setFactionProp(\"faction\", \"foo\");"); // eventAction->Args.push_back("()setFactionProp(\"ennemyFaction\", \"bar\");"); // eventAction->Args.push_back("()setFactionProp(\"friendFaction\", \"baf\");"); eventAction->Args.push_back("()setHealer(1);"); // Register event action eventDescription.Action = eventAction; eventAction = NULL; // Register event handler event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType); event->processEventDescription(&eventDescription, getStateMachine()); getStateMachine()->eventReactions().addChild(event); event = NULL; // Create event handler for group death eventDescription.EventType = "group_eliminated"; // eventDescription.StateKeywords.push_back(""); // eventDescription.NamedStates.push_back(""); // eventDescription.GroupKeywords.push_back(""); // eventDescription.NamedGroups.push_back(""); // Create event action eventAction = new CAIEventActionNode; eventAction->Action = "spire_report_squad_death"; eventAction->Weight = 1; // eventAction->Args.push_back(""); // Register event action eventDescription.Action = eventAction; eventAction = NULL; // Register event handler event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType); event->processEventDescription(&eventDescription, getStateMachine()); getStateMachine()->eventReactions().addChild(event); event = NULL; // Create event handler for bot death eventDescription.EventType = "bot_killed"; // eventDescription.StateKeywords.push_back(""); // eventDescription.NamedStates.push_back(""); // eventDescription.GroupKeywords.push_back(""); // eventDescription.NamedGroups.push_back(""); // Create event action eventAction = new CAIEventActionNode; eventAction->Action = "spire_send_squad_status"; eventAction->Weight = 1; // eventAction->Args.push_back(""); // Register event action eventDescription.Action = eventAction; eventAction = NULL; // Register event handler event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType); event->processEventDescription(&eventDescription, getStateMachine()); getStateMachine()->eventReactions().addChild(event); event = NULL; // Create event handler for bot death eventDescription.EventType = "squad_leader_killed"; // eventDescription.StateKeywords.push_back(""); // eventDescription.NamedStates.push_back(""); // eventDescription.GroupKeywords.push_back(""); // eventDescription.NamedGroups.push_back(""); // Create event action eventAction = new CAIEventActionNode; eventAction->Action = "multi_actions"; eventAction->Weight = 1; eventAction->Children.resize(2); eventAction->Children[0] = new CAIEventActionNode; eventAction->Children[0]->Action = "spire_report_squad_leader_death"; eventAction->Children[0]->Weight = 1; // eventAction->Children[0]->Args.push_back(""); eventAction->Children[1] = new CAIEventActionNode; eventAction->Children[1]->Action = "code"; eventAction->Children[1]->Weight = 1; eventAction->Children[1]->Args.push_back("()setAutoSpawn(0);"); #ifdef NL_DEBUG eventAction->Children[1]->Args.push_back("print(\"INFINITE RESPAWN TIME FOR SQUAD\");"); #endif // Register event action eventDescription.Action = eventAction; eventAction = NULL; // Register event handler event = new CAIEventReaction(getStateMachine(), 0, eventDescription.EventType); event->processEventDescription(&eventDescription, getStateMachine()); getStateMachine()->eventReactions().addChild(event); event = NULL; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void CSpire::createSquad(string const& dynGroupName, string const& stateMachineName, string const& initialStateName, string const& zoneName, uint32 spawnOrder, uint32 respawTimeGC, SPIREENUMS::TPVPSide side) { IManagerParent* const managerParent = getOwner()->getOwner(); CAIInstance* const aiInstance = dynamic_cast(managerParent); if (!aiInstance) return; CSpireSpawnZone const* spawnZone = getZone(CStringMapper::map(zoneName)); if (!spawnZone) { SPIRE_WRN("newNpcChildGroup failed : spawnZone Not Found ! for StateMachine : %s", stateMachineName.c_str()); return; } CGroupDesc const* groupDesc = NULL; FOREACH(itGroupDesc, CSquadLinks, _SquadLinks) { if ((*itGroupDesc).second->getName()==dynGroupName) { groupDesc = (*itGroupDesc).second; goto groupFound; } } groupFound: if (!groupDesc) { SPIRE_WRN("createSquad failed: No Group Found"); return; } // Find the state machine as a manager CManager* manager = NULL; FOREACH(itCont, CCont, aiInstance->managers()) { if (itCont->getName()==stateMachineName) { manager = *itCont; break; } } if (!manager) { FOREACH(itCont, CCont, managers()) { if (itCont->getName()==stateMachineName) { manager = *itCont; break; } } } if (!manager) { SPIRE_WRN("createSquad failed : Unknown stateMachine %s", stateMachineName.c_str()); return; } // Find the state machine as a npc manager CSpireSquadManager* spireManager = dynamic_cast(manager); if (!spireManager) { SPIRE_WRN("createSquad failed : Not an spire state machine !: ", stateMachineName.c_str()); return; } createSquad(groupDesc, spireManager, initialStateName, spawnZone, spawnOrder, respawTimeGC, side); } void CSpire::createSquad(uint32 dynGroupAlias, uint32 zoneAlias, uint32 spawnOrder, uint32 respawTimeGC, SPIREENUMS::TPVPSide side) { IManagerParent* const managerParent = getOwner()->getOwner(); CAIInstance* const aiInstance = dynamic_cast(managerParent); if (!aiInstance) return; CSpireSpawnZone const* spawnZone = spawnZones().getChildByAlias(zoneAlias); if (!spawnZone) { SPIRE_WRN("createSquad failed: spawn zone %s not found", LigoConfig.aliasToString(zoneAlias).c_str()); return; } CGroupDesc const* groupDesc = NULL; // Find the group template. // :TODO: Replace it with a faster map access. groupDesc = getSquad( dynGroupAlias ); if (!groupDesc) { SPIRE_WRN("createSquad failed: group %s not found", LigoConfig.aliasToString(dynGroupAlias).c_str()); return; } // Find the state machine as a manager CSpireSquadManager* manager = dynamic_cast(managers().getChildByName("default_squad_manager")); if (!manager) { SPIRE_WRN("createSquad failed: default state machine not found! (<- this is a code bug)"); return; } createSquad(groupDesc, manager, "", spawnZone, spawnOrder, respawTimeGC, side); } void CSpire::createSquad(CGroupDesc const* groupDesc, CSpireSquadManager* manager, string const& initialStateName, CSpireSpawnZone const* spawnZone, uint32 createOrder, uint32 respawTimeGC, SPIREENUMS::TPVPSide side) { SPIRE_DBG("Creating a squad"); CAIVector const& spawnPosition = spawnZone->midPos(); sint32 baseLevel = -1; double dispersionRadius = spawnZone->getRadius(); // Save the creator state bool const savePlayerAttackable = groupDesc->getGDPlayerAttackable(); bool const saveBotAttackable = groupDesc->getGDBotAttackable(); // PlayerAttackable must be false as it it sent to the EGS in BotDescriptionMessage to set the // property 'Attackable'. Squads are not attackable unless a player is in war with the owner of // the spire (using botchatprogram instead of the property 'Attackable'). // BotAttackable must be true, otherwise the EGS sets it as invulnerable (not attackable). groupDesc->setGDPlayerAttackable(false); groupDesc->setGDBotAttackable(true); // Create the group CGroupNpc* const grp = groupDesc->createNpcGroup(manager, spawnPosition, dispersionRadius, baseLevel, false); // Restore the creator state groupDesc->setGDPlayerAttackable(savePlayerAttackable); groupDesc->setGDBotAttackable(saveBotAttackable); // Verify that the group was created if (!grp) { SPIRE_WRN("createSquad failed: group %s cannot spawn", LigoConfig.aliasToString(groupDesc->getAlias()).c_str()); return; } // Set the new group parameters // Let the EGS destroys squads explicitely because when a group is destroyed in the AIS its groupId can be reused // and 2 squads would have the same groupId in the EGS (it asserts) grp->autoDestroy(false); grp->setAutoSpawn(true); // grp->getPersistentStateInstance()->setParentStateInstance(entity->getPersistentStateInstance()); grp->initDynGrp(groupDesc, NULL); // Set color uint8 color = (uint8)(grp->getChildIndex() % 8); grp->setColour(color); // Get the state machine CStateMachine const* stateMachine = manager->getStateMachine(); #if !FINAL_VERSION // Verify that we have a state in the state machine if (stateMachine->cstStates().size()==0) nlerror("no state defined for StateMachine in Manager %s", manager->getFullName().c_str()); #endif // Set the group in that state CAIState* initialState = NULL; if (!initialStateName.empty()) { // FOREACH(itState, CCont, stateMachine->states()) for (size_t i=0; icstStates().size(); ++i) { CAIState* state = stateMachine->cstStates()[i]; if (state->getName()==initialStateName) initialState = state; } } if (initialState==NULL) initialState = stateMachine->cstStates()[0]; // sets the first state (must exist!). grp->setStartState(initialState); // Do not assist friends because it would lead to exploits /*if ( _OwnerGuild != InvalidGuildId ) { //grp->faction().addExtraProperty(_OwnerGuild); // TODO: set the GuildId for the squad npcs? //grp->friendFaction().addExtraProperty(_OwnerGuild); // will be defended by the squad } else { // A tribe owns the spire and all players are ennemies // CPropertyId tribeFaction(CGrpProfileFaction::fameFactionToScriptFaction(_OwnerTribe)); //grp->faction().addProperty(tribeFaction); //grp->friendFaction().addProperty(tribeFaction); // will be defended by the squad //grp->ennemyFaction().addProperty(CPropertyId("Player")); }*/ // Set guild id of members of the squad (for the tribe case, these *are* the tribe as well) // This was removed because CBotNpc::spawn() now uses getOwner()->getOwner()->getOwner() to access the outpsot /*FOREACH(ib, CAliasCont, grp->bots()) { CBotNpc *bot = static_cast(*ib); bot->setOwnerSpire(this); }*/ grp->setSpireSide(side); // Attack only the declared ennemies of the spire if (side==SPIREENUMS::SpireOwner) { // grp->faction ().addProperty(NLMISC::toString("spire:%s:defender", getAliasString().c_str())); // grp->friendFaction().addProperty(NLMISC::toString("spire:%s:defender", getAliasString().c_str())); grp->ennemyFaction().addProperty(NLMISC::toString("spire:%s:attacker", getAliasString().c_str())); } if (side==SPIREENUMS::SpireAttacker) { // grp->faction ().addProperty(NLMISC::toString("spire:%s:attacker", getAliasString().c_str())); // grp->friendFaction().addProperty(NLMISC::toString("spire:%s:attacker", getAliasString().c_str())); grp->ennemyFaction().addProperty(NLMISC::toString("spire:%s:defender", getAliasString().c_str())); } grp->_AggroRange = 25; grp->_UpdateNbTicks = 10; grp->respawnTime() = respawTimeGC; grp->updateStateInstance(); // Directly call his first state (to retrieve associated params). if (createOrder!=0) { CSpireSquadCreatedMsg params; params.Spire = this->getAlias(); params.CreateOrder = createOrder; params.GroupId = reinterpret_cast(grp); sendSpireMessage("SPIRE_SQUAD_CREATED", params); } SPIRE_DBG( "Spire %s: squad created defending 0x%x against 0x%x, respawnTime=%u gc", getName().c_str(), _OwnerAllianceId, _AttackerAllianceId, respawTimeGC ); } void CSpire::spawnSquad(uint32 groupId) { SPIRE_DBG( "Spire %s: Spawning squad 0x%08x", getName().c_str(), groupId ); FOREACH(itManager, CAliasCont, _Managers) { CSpireManager* manager = *itManager; FOREACH(itGroup, CAliasCont, manager->groups()) { CGroup* group = *itGroup; CGroupNpc* groupNpc = static_cast(group); uint32 thisGroupId = reinterpret_cast(groupNpc); if (groupId==thisGroupId) { group->getSpawnObj()->spawnBots(); CSpireSquadSpawnedMsg params; params.Spire = this->getAlias(); params.GroupId = groupId; sendSpireMessage("SPIRE_SQUAD_SPAWNED", params); SPIRE_DBG( "\t\tSpawned" ); return; } } } SPIRE_WRN("No squad to spawn with group id 0x%08x. Valid group ids are:", groupId); FOREACH(itManager, CAliasCont, _Managers) { CSpireManager* manager = *itManager; FOREACH(itGroup, CAliasCont, manager->groups()) { CGroup* group = *itGroup; CGroupNpc* groupNpc = static_cast(group); uint32 thisGroupId = reinterpret_cast(groupNpc); SPIRE_WRN("- 0x%08x", thisGroupId); } } } void CSpire::despawnSquad(uint32 groupId) { SPIRE_DBG( "Spire %s: Despawning squad 0x%08x", getName().c_str(), groupId ); FOREACH(itManager, CAliasCont, _Managers) { CSpireManager* manager = *itManager; FOREACH(itGroup, CAliasCont, manager->groups()) { CGroup* group = *itGroup; CGroupNpc* groupNpc = static_cast(group); uint32 thisGroupId = reinterpret_cast(groupNpc); if (groupId==thisGroupId) { group->despawnBots(); CSpireSquadDespawnedMsg params; params.Spire = this->getAlias(); params.GroupId = groupId; sendSpireMessage("SPIRE_SQUAD_DESPAWNED", params); return; } } } SPIRE_WRN("No squad to despawn"); } void CSpire::deleteSquad(uint32 groupId) { SPIRE_DBG( "Spire %s: deleting squad 0x%08x", getName().c_str(), groupId ); FOREACH(itManager, CAliasCont, _Managers) { CSpireManager* manager = *itManager; FOREACH(itGroup, CAliasCont, manager->groups()) { CGroup* group = *itGroup; CGroupNpc* groupNpc = static_cast(group); uint32 thisGroupId = reinterpret_cast(groupNpc); if (groupId==thisGroupId) { manager->groups().removeChildByIndex(group->getChildIndex()); // No message here since this is called by squad destructor in EGS return; } } } SPIRE_WRN("No squad to delete"); } void CSpire::sendSpireSquadStatus(CGroupNpc* group) { uint32 alias = this->getAlias(); uint32 groupId = reinterpret_cast(group); bool groupAlive = false; bool leaderAlive = group->getSquadLeader()!=NULL; uint32 botCount = 0; // Persistent status // Spawn dependent status CSpawnGroup* spawnGroup = group->getSpawnObj(); if (spawnGroup) { groupAlive = spawnGroup->isGroupAlive(); } NLNET::CMessage msgout("SPIRE_SQUAD_STATUS"); msgout.serial(alias); msgout.serial(groupId); msgout.serial(groupAlive); msgout.serial(leaderAlive); msgout.serial(botCount); sendMessageViaMirror("EGS", msgout); } void CSpire::squadLeaderDied(CGroupNpc* group) { uint32 alias = this->getAlias(); uint32 groupId = reinterpret_cast(group); NLNET::CMessage msgout("SPIRE_SQUAD_LEADER_DIED"); msgout.serial(alias); msgout.serial(groupId); sendMessageViaMirror("EGS", msgout); } void CSpire::squadDied(CGroupNpc* group) { uint32 alias = this->getAlias(); uint32 groupId = reinterpret_cast(group); NLNET::CMessage msgout("SPIRE_SQUAD_DIED"); msgout.serial(alias); msgout.serial(groupId); sendMessageViaMirror("EGS", msgout); } void CSpire::triggerSpecialEvent(SPIREENUMS::TSpecialSpireEvent eventId) { // Managers handlers FOREACH(itManager, CCont, _Managers) { CSpireManager* manager = *itManager; if (manager) { CAIEvent* event = NULL; switch (eventId) { case SPIREENUMS::PeaceStateBegin: event = &manager->EventSpirePeaceStateBegin; break; case SPIREENUMS::PeaceStateEnd: event = &manager->EventSpirePeaceStateEnd; break; case SPIREENUMS::TribeOwnershipBegin: event = &manager->EventSpireTribeOwnershipBegin; break; case SPIREENUMS::TribeOwnershipEnd: event = &manager->EventSpireTribeOwnershipEnd; break; case SPIREENUMS::GuildOwnershipBegin: event = &manager->EventSpireGuildOwnershipBegin; break; case SPIREENUMS::GuildOwnershipEnd: event = &manager->EventSpireGuildOwnershipEnd; break; case SPIREENUMS::OwnerChanged: event = &manager->EventSpireOwnerChanged; break; case SPIREENUMS::AttackerChanged: event = &manager->EventSpireAttackerChanged; break; case SPIREENUMS::StateChanged: event = &manager->EventSpireStateChanged; break; } if (event) { FOREACH(itGroup, CCont, manager->groups()) { CGroupNpc* group = static_cast(*itGroup); if (group) group->processStateEvent(*event); } } } } // Special handlers switch (eventId) { case SPIREENUMS::TribeOwnershipBegin: { FOREACH(itManager, CCont, _Managers) { CSpireManager* manager = *itManager; if (manager) manager->autoSpawnBegin(); } break; } case SPIREENUMS::TribeOwnershipEnd: { FOREACH(itManager, CCont, _Managers) { CSpireManager* manager = *itManager; if (manager) manager->autoSpawnEnd(); } break; } } } void CSpire::setBuildingBotSheet(uint32 buildingAlias, NLMISC::CSheetId sheetId, bool autoSpawnDespawn, const std::string & customName) { CBot * bot = getBuildingBotByAlias(buildingAlias); if (bot == NULL) { SPIRE_WRN( "cannot find building bot %s", LigoConfig.aliasToString( buildingAlias ).c_str() ); return; } AISHEETS::ICreatureCPtr const sheet = AISHEETS::CSheets::getInstance()->lookup(sheetId); if (sheetId!=NLMISC::CSheetId::Unknown && !sheet.isNull()) { bot->setCustomName(customName); bot->triggerSetSheet(sheet); if (autoSpawnDespawn && !bot->isSpawned()) bot->spawn(); } else { if (autoSpawnDespawn && bot->isSpawned()) bot->despawnBot(); } } void CSpire::despawnAllSquads() { FOREACH(itManager, CAliasCont, _Managers) { CSpireManager* manager = *itManager; CSpireSquadManager* sqManager = dynamic_cast(manager); if (sqManager) { FOREACH(itGroup, CAliasCont, sqManager->groups()) { CGroup* group = *itGroup; group->despawnBots(); } } } } template void CSpire::sendSpireMessage(std::string const& msgName, T& paramStruct) { NLNET::CMessage msgout(msgName); msgout.serial(paramStruct); sendMessageViaMirror(std::string("EGS"), msgout); } ////////////////////////////////////////////////////////////////////////////// // Commands // ////////////////////////////////////////////////////////////////////////////// NLMISC_COMMAND(displaySpires, "list the available spire", "") { if (args.size() > 0) return false; uint32 instanceNumber = ~0; for (uint i=0; icontinents().size(); ++i) { CContinent *const continent = aii->continents()[i]; if ( !continent || ( !continentName.empty() && continentName!=continent->getName())) continue; log.displayNL("Spires in continent '%s':", continent->getName().c_str()); for (uint j=0; jspires().size(); ++j) { CSpire const* spire = continent->spires()[j]; if (!spire) continue; log.displayNL(" %s", spire->getOneLineInfoString().c_str()); log.displayNL(" - %d group descs", spire->squadLinks().size()); for (CSpire::CSquadLinks::const_iterator isl=spire->squadLinks().begin(); isl!=spire->squadLinks().end(); ++isl ) { CGroupDesc const* gd = (*isl).second; if (!gd) continue; log.displayNL(" Group desc '%s' %s", gd->getName().c_str(), gd->getAliasString().c_str()); } log.displayNL(" - %d spawn zones", spire->spawnZones().size()); for (uint j=0; jspawnZones().size(); ++j) { CSpireSpawnZone const* sz = spire->spawnZones()[j]; if (!sz) continue; log.displayNL(" SpawnZone '%s' %s (%s)", sz->getName().c_str(), sz->getAliasString().c_str(), sz->midPos().toString().c_str()); } log.displayNL(" - %d state machines", spire->managers().size()); for (uint j=0; jmanagers().size(); ++j) { CSpireManager* manager = spire->managers()[j]; if (!manager) continue; log.displayNL(" State machine '%s' %s", manager->getName().c_str(), manager->getAliasString().c_str()); log.displayNL(" - %d states", manager->getStateMachine()->states().size()); for (uint j=0; jgetStateMachine()->states().size(); ++j) { CAIState const* state = manager->getStateMachine()->states()[j]; if (!state) continue; log.displayNL(" State '%s' %s", state->getName().c_str(), state->getAliasString().c_str()); } log.displayNL(" - %d groups", manager->groups().size()); for (uint j=0; jgroups().size(); ++j) { CGroup const* group = manager->groups()[j]; if (group) { log.displayNL(" Group '%s' %s", group->getName().c_str(), group->getAliasString().c_str()); log.displayNL(" - %d bots", group->bots().size()); for (uint k=0; kbots().size(); ++k) { CBot const* bot = group->bots()[k]; if (bot) log.displayNL(" Bot '%s' %s", bot->getName().c_str(), bot->getAliasString().c_str()); else log.displayNL(" Bot "); } } else log.displayNL(" Group "); } } } } } return true; } // spireSpawnSquad 1 fyros spire group machine zone NLMISC_COMMAND(spireSpawnSquad, "Spawns a squad in an spire", " [=5*60]") { if (args.size() != 6) return false; uint32 instanceNumber = ~0; fromString(args[0], instanceNumber); string continentName = args[1]; string spireName = args[2]; string dynGroupName = args[3]; string stateMachineName = args[4]; string zoneName = args[5]; uint32 respawnTimeGC = 5*60*10; if ( args.size() > 6 ) respawnTimeGC = atoi( args[6].c_str() ) * 10; for (size_t i=0; i<5; ++i) if (args[i]=="") return false; bool done = false; bool instanceFound = false; bool continentFound = false; bool spireFound = false; if (instanceNumbercontinents().size() && !done; ++i) { CContinent* const continent = aiinstance->continents()[i]; if (!continent || continentName!=continent->getName()) continue; continentFound = true; for (uint j=0; jspires().size() && !done; ++j) { CSpire* const spire = continent->spires()[j]; if (!spire || spireName!=spire->getName()) continue; spireFound = true; spire->createSquad(dynGroupName, stateMachineName, "", zoneName, 0, respawnTimeGC, SPIREENUMS::UnknownPVPSide); done = true; } } } } if (!done) { SPIRE_WRN("Could not spawn a new squad"); log.displayNL("Could not spawn a new squad"); if (!instanceFound) log.displayNL( "Instance not found" ); if (!continentFound) log.displayNL( "Continent not found" ); if (!spireFound) log.displayNL( "Spire not found" ); } return true; } /* * Return the spire corresponding to the alias, or NULL if not found (with a nlwarning) */ CSpire* CSpire::getSpireByAlias( TAIAlias spireAlias ) { bool instanceFound = false; bool continentFound = false; bool spireFound = false; for (uint i=0; icontinents().size(); ++i) { CContinent* const continent = aiinstance->continents()[i]; if (!continent) continue; continentFound = true; for (uint j=0; jspires().size(); ++j) { CSpire* spire = continent->spires()[j]; if (!spire || spireAlias!=spire->getAlias()) continue; return spire; } } } } if (!instanceFound) SPIRE_WRN( "Instance not found" ); if (!continentFound) SPIRE_WRN( "Continent not found" ); if (!spireFound) SPIRE_WRN( "Spire %s not found", LigoConfig.aliasToString( spireAlias ).c_str() ); return NULL; } /* void spireCreateSquad(uint32 spireAlias, uint32 dynGroupAlias, uint32 zoneAlias, uint32 spawnOrder) { CSpire *spire = CSpire::getSpireByAlias( spireAlias ); if ( spire ) spire->createSquad(dynGroupAlias, zoneAlias, spawnOrder); } void spireSpawnSquad(uint32 spireAlias, uint32 groupId) { CSpire *spire = CSpire::getSpireByAlias( spireAlias ); if ( spire ) spire->spawnSquad(groupId); } void spireDespawnSquad(uint32 spireAlias, uint32 groupId) { CSpire *spire = CSpire::getSpireByAlias( spireAlias ); if ( spire ) spire->despawnSquad(groupId); } void spireDeleteSquad(uint32 spireAlias, uint32 groupId) { CSpire *spire = CSpire::getSpireByAlias( spireAlias ); if ( spire ) spire->deleteSquad(groupId); } void spireDespawnAllSquads(uint32 spireAlias) { CSpire *spire = CSpire::getSpireByAlias( spireAlias ); if ( spire ) spire->despawnAllSquads(); } */ NLMISC_COMMAND(spireAliasSpawnSquad, "Spawns a squad in an spire (respawn time = 5 min)", " ") { if (args.size()!=3) return false; for (size_t i=0; i<3; ++i) if (args[i]=="") return false; uint32 spireAlias = LigoConfig.aliasFromString(args[0]); uint32 dynGroupAlias = LigoConfig.aliasFromString(args[1]); uint32 zoneAlias = LigoConfig.aliasFromString(args[2]); string stateMachineName = "default_squad_manager"; CSpire *spire = CSpire::getSpireByAlias(spireAlias); if (spire) spire->createSquad(dynGroupAlias, zoneAlias, 0, 5*60*10, SPIREENUMS::UnknownPVPSide); return true; } CBot* CSpire::getBuildingBotByAlias(TAIAlias alias) { CGroup* group = getBuildingGroup(); if (group) return group->bots().getChildByAlias(alias); else return NULL; } NLMISC_COMMAND(spireSetBuildingBotSheet, "Set the sheet of an spire building", " ") { if (args.size()!=3) return false; for (size_t i=0; i<3; ++i) if (args[i]=="") return false; uint32 spireAlias = LigoConfig.aliasFromString(args[0]); uint32 buildingAlias = LigoConfig.aliasFromString(args[1]); NLMISC::CSheetId buildingBotSheet = NLMISC::CSheetId(args[2]);; CSpire* spire = CSpire::getSpireByAlias(spireAlias); if (spire) spire->setBuildingBotSheet(buildingAlias, buildingBotSheet, true, ""); return true; } // Call this macro, then do the code that will must done only if the spire is found in this instance // The data you have access to after this macro: // - CSpire *spire // - msgStruct params; #define IF_GET_SPIRE_FOR_MSG( msgStruct ) \ msgStruct params; \ msgin.serial( params ); \ CSpire *spire = CSpire::getSpireByAlias( params.Spire ); \ if ( spire ) void cbSpireCreateSquad( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSpireCreateSquadMsg ) spire->createSquad(params.Group, params.Zone, params.CreateOrder, params.RespawnTimeS*10, params.Side); } void cbSpireSpawnSquad( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSpireSpawnSquadMsg ) spire->spawnSquad(params.GroupId); } void cbSpireDespawnSquad( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSpireDespawnSquadMsg ) spire->despawnSquad(params.GroupId); } void cbSpireDeleteSquad( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSpireDeleteSquadMsg ) spire->deleteSquad(params.GroupId); } void cbSpireDespawnAllSquads( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSpireDespawnAllSquadsMsg ) spire->despawnAllSquads(); } void cbSpireSetOwner( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSetSpireOwner ) spire->setOwnerAlliance( params.Owner ); } void cbSpireSetAttacker( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSetSpireAttacker ) spire->setAttackerAlliance( params.Attacker ); } void cbSpireSetState( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSpireSetStateMsg ) spire->setState( params.State ); } void cbSpireEvent( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSpireEventMsg ) spire->triggerSpecialEvent(params.Event); } void cbSpireSetBuildingBotSheet( NLNET::CMessage& msgin, const std::string &serviceName, uint16 serviceId ) { IF_GET_SPIRE_FOR_MSG( CSpireSetBuildingBotSheetMsg ) spire->setBuildingBotSheet(params.Building, params.SheetId, params.AutoSpawnDespawn, params.CustomName); } #include "event_reaction_include.h" #endif