Added ai command setEquipment
[ryzomcore.git] / ryzom / server / src / ai_service / ai_grp.cpp
blobcb0b1bee5a69ad1a3dc26683fbf764629a1f5a22
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "stdpch.h"
20 #include "ai_grp.h"
21 #include "visual_properties_interface.h"
22 #include "ai_profile_npc.h"
24 using namespace MULTI_LINE_FORMATER;
26 //////////////////////////////////////////////////////////////////////
27 // Construction/Destruction
28 //////////////////////////////////////////////////////////////////////
30 //--------------------------------------------------------------------------
31 // METHODS for debugging stuff
32 //--------------------------------------------------------------------------
34 bool GrpHistoryRecordLog = true;
35 CAIVector lastTriedPos;
37 CGroup::CGroup (CManager *owner, RYAI_MAP_CRUNCH::TAStarFlag denyFlags, CAIAliasDescriptionNode *aliasTree) :
38 CAliasChild<CManager>(owner,aliasTree),
39 CPersistent<CSpawnGroup>(),
40 _EscortTeamId(CTEAM::InvalidTeamId),
41 _EscortRange(30),
42 _AutoSpawn(true),
43 _DenyFlags(denyFlags),
44 _AutoDestroy(false),
45 _AggroRange(0),
46 _UpdateNbTicks(30)
48 owner->getAIInstance()->addGroupInfo(this);
51 CGroup::CGroup (CManager *owner, RYAI_MAP_CRUNCH::TAStarFlag denyFlags, uint32 alias, std::string const& name) :
52 CAliasChild<CManager>(owner, alias, name),
53 CPersistent<CSpawnGroup>(),
54 _EscortTeamId(CTEAM::InvalidTeamId),
55 _EscortRange(30),
56 _AutoSpawn(true),
57 _DenyFlags(denyFlags),
58 _AutoDestroy(false),
59 _AggroRange(0),
60 _UpdateNbTicks(30)
62 owner->getAIInstance()->addGroupInfo(this);
65 CGroup::~CGroup ()
67 getAIInstance()->removeGroupInfo(this, this);
68 getOwner()->removeFromSpawnList (this);
69 if (isSpawned())
71 despawnGrp ();
76 CBot* CGroup::getLeader()
78 FOREACH(itBot, CCont<CBot>, bots())
80 CSpawnBot* const bot = itBot->getSpawnObj();
81 if (bot && bot->isAlive())
82 return *itBot;
84 // no bots alive, no leader !
85 return NULL;
88 CBot* CGroup::getSquadLeader(bool checkAliveStatus)
90 CCont<CBot>::iterator itBot = bots().begin();
91 if (itBot!=bots().end())
93 CSpawnBot* const bot = itBot->getSpawnObj();
94 if (bot && (!checkAliveStatus || bot->isAlive()))
95 return *itBot;
97 // first bot not alive, no squad leader !
98 return NULL;
101 void CGroup::serviceEvent (const CServiceEvent &info)
103 CCont<CBot>::iterator it=bots().begin(), itEnd=bots().end();
104 while (it!=itEnd)
106 it->serviceEvent (info);
107 ++it;
112 void CGroup::despawnBots ()
114 for (CCont<CBot>::iterator it=_Bots.begin(), itEnd=_Bots.end(); it!=itEnd;++it)
116 if (it->isSpawned())
117 it->despawnBot();
122 std::string CGroup::getIndexString() const
124 return getOwner()->getIndexString()+NLMISC::toString(":g%u", getChildIndex());
127 std::string CGroup::getOneLineInfoString() const
129 return std::string("Group '") + getName() + "'";
132 std::vector<std::string> CGroup::getMultiLineInfoString() const
134 std::vector<std::string> container;
136 pushTitle(container, "CGroup");
137 pushEntry(container, "id=" + getIndexString());
138 container.back() += " alias=" + getAliasString();
139 container.back() += " name=" + getName();
140 pushEntry(container, "fullname=" + getFullName());
141 pushEntry(container, "autoSpawn=" + NLMISC::toString(_AutoSpawn));
142 pushEntry(container, "aggroRange=" + NLMISC::toString(_AggroRange));
143 container.back() += " updateNbTicks=" + NLMISC::toString(_UpdateNbTicks);
144 if (isSpawned())
146 std::vector<std::string> strings = getSpawnObj()->getMultiLineInfoString();
147 FOREACHC(it, std::vector<std::string>, strings)
148 pushEntry(container, *it);
150 else
151 pushEntry(container, "<not spawned>");
152 pushFooter(container);
154 return container;
157 std::string CGroup::getFullName() const
159 return std::string(getOwner()->getFullName()+":"+getName());
162 void CGroup::lastBotDespawned()
164 // send message
167 void CGroup::firstBotSpawned()
169 // send message
172 //////////////////////////////////////////////////////////////////////////////
173 // CSpawnGroup //
174 //////////////////////////////////////////////////////////////////////////////
176 CSpawnGroup::~CSpawnGroup()
178 FOREACH(it, CCont<CBot>,bots())
180 if ((*it)->isSpawned())
181 (*it)->despawnBot();
184 getPersistent().despawnBots();
186 // clear profiles
187 _MovingProfile = CProfilePtr();
188 _FightProfile = CProfilePtr();
189 _ActivityProfile = CProfilePtr();
190 _PunctualHoldActivityProfile = CProfilePtr();
191 _PunctualHoldMovingProfile = CProfilePtr();
194 bool CSpawnGroup::calcCenterPos(CAIVector& grp_pos, bool allowDeadBot)
196 if (bots().size()<=0)
197 return false;
199 double x(0), y(0);
200 uint count(0);
202 FOREACH(it, CCont<CBot>, bots())
204 CSpawnBot const* const spawnBot = it->getSpawnObj();
205 if (!spawnBot || (!allowDeadBot && !spawnBot->isAlive()))
206 continue;
208 x += spawnBot->pos().x().asDouble();
209 y += spawnBot->pos().y().asDouble();
210 ++count;
212 if (count==0)
213 return false;
215 grp_pos.setX(x/count);
216 grp_pos.setY(y/count);
217 return true;
220 void CSpawnGroup::spawnBotOfGroup()
222 CCont<CBot>::iterator it = bots().begin();
223 CCont<CBot>::iterator itEnd = bots().end();
224 while (it!=itEnd)
226 CBot* bot = *it;
227 if (!bot->isSpawned())
229 bool ok= bot->spawn();
230 // code removed by Sadge because it didn't fix the problem it was added for
231 // if (ok)
232 // {
233 // // the spawn succeeded
234 // // make sure the bot isn't in the despawn list
235 // for (uint32 i= _BotsToDespawn.size(); i--;)
236 // {
237 // if (_BotsToDespawn[i].getBotIndex()== bot->getChildIndex())
238 // {
239 // nldebug("Removing bot from the despawn list because they just respawned: %s",bot->getFullName().c_str());
240 // _BotsToDespawn[i]= _BotsToDespawn.back();
241 // _BotsToDespawn.pop_back();
242 // }
243 // }
244 // }
245 if (!ok)
247 // the spawn failed
248 std::string name;
250 if (!bot->getFullName().empty())
251 name = bot->getFullName();
252 else
254 if (!bot->getOwner()->getFullName().empty())
255 name = std::string("from group ") + bot->getOwner()->getFullName();
256 else
257 name = std::string("Unknown");
260 if (bot->getSheet()->SheetId()==NLMISC::CSheetId::Unknown)
261 nlwarning("***> Spawn failed position(%s), UNKNOWN SHEET! Bot %s ", lastTriedPos.toString().c_str(), name.c_str());
262 else
263 nlwarning("***> Spawn failed position(%s), sheetId(%s) Bot %s ", lastTriedPos.toString().c_str(), bot->getSheet()->SheetId().toString().c_str(), name.c_str());
266 ++it;
270 void CSpawnGroup::addBotToDespawnAndRespawnTime(CBot* bot, uint32 despawnTime, uint32 respawnTime)
272 nlassert(bot->isSpawned());
273 nlassert(bot->getOwner()==&getPersistent());
275 uint32 const botIndex = bot->getChildIndex();
277 FOREACH(it, std::vector<CBotToSpawn>, _BotsToDespawn)
279 if (it->getBotIndex()==botIndex)
281 *it = CBotToSpawn(botIndex, despawnTime, respawnTime);
282 return;
285 _BotsToDespawn.push_back(CBotToSpawn(botIndex, despawnTime, respawnTime));
288 void CSpawnGroup::checkDespawn()
290 if (_BotsToDespawn.empty())
291 return;
293 //FOREACH_NOINC(it, std::vector<CBotToSpawn>, _BotsToDespawn)
294 for(uint32 i = 0; i < _BotsToDespawn.size();)
296 CBotToSpawn& botToDespawn = _BotsToDespawn[i];
297 if (botToDespawn.waitingDespawnTimeOver())
299 if (botToDespawn.getBotIndex()>=getPersistent().bots().size())
301 STOP("Array overflow in despawn code!");
303 else if (getPersistent().bots()[botToDespawn.getBotIndex()]==NULL)
305 STOP("Trying to despawn a bot who doesn't exist!!");
307 else
309 getPersistent().bots()[botToDespawn.getBotIndex()]->despawnBot();
310 if (getPersistent().isAutoSpawn())
311 _BotsToRespawn.push_back(botToDespawn);
314 // pop this entry out of the bots to despawn vector
315 // ace: we don't use iterator because when pop_back(), all iterators are invalidated
316 _BotsToDespawn[i] = _BotsToDespawn.back();
317 _BotsToDespawn.pop_back();
318 continue;
320 i++;
323 if (_NbSpawnedBot==0 && _BotsToRespawn.size()==0)
325 // Warn the parent manager that this group is now dead.
326 getPersistent().getOwner()->getOwner()->groupDead(&getPersistent());
327 if (getPersistent()._AutoDestroy)
328 getPersistent().getOwner()->groups().removeChildByIndex(getPersistent().getChildIndex());
333 void CSpawnGroup::incSpawnedBot(CBot& spawnBot)
335 #if !FINAL_VERSION
336 uint32 botIndex = spawnBot.getChildIndex();
337 for (uint32 i=(uint32)_BotsToRespawn.size(); i--; )
339 if (_BotsToRespawn[i].getBotIndex()==botIndex)
341 nldebug("Removing bot from _BotsToRespawn because they just respawned: %s",spawnBot.getFullName().c_str());
342 // nlwarning("WARNING!!! Old assert \"_BotsToRespawn[i].getBotIndex()!=botIndex\" would have failed");
343 _BotsToRespawn[i]=_BotsToRespawn.back();
344 _BotsToRespawn.pop_back();
347 for (uint32 i=(uint32)_BotsToDespawn.size(); i--; )
349 if (_BotsToDespawn[i].getBotIndex()==botIndex)
351 nldebug("Removing bot from _BotsToDespawn because they just respawned: %s",spawnBot.getFullName().c_str());
352 // nlwarning("WARNING!!! Old assert \"_BotsToDespawn[i].getBotIndex()!=botIndex\" would have failed");
353 _BotsToDespawn[i]=_BotsToDespawn.back();
354 _BotsToDespawn.pop_back();
357 #endif
358 if (_NbSpawnedBot==0)
360 getPersistent().firstBotSpawned();
362 _NbSpawnedBot++;
365 void CSpawnGroup::decSpawnedBot()
367 --_NbSpawnedBot;
368 if (_NbSpawnedBot==0)
370 getPersistent().lastBotDespawned();
374 void CSpawnGroup::checkRespawn()
376 // respawn if there is not too much dead .. (no more than one at each tick).
377 if (_BotsToRespawn.size()<=0)
378 return;
380 // Send url to EGS
381 std::string url = getUrl();
382 std::string actionName = getActionName();
383 CCreatureSetUrlMsg msg;
385 //FOREACH_NOINC(it, std::vector<CBotToSpawn>, _BotsToRespawn)
386 for(uint32 i = 0; i < _BotsToRespawn.size();)
388 CBotToSpawn const& botToSpawn = _BotsToRespawn[i];
389 if (botToSpawn.waitingRespawnTimeOver())
391 CBot* botPt = getPersistent().bots()[botToSpawn.getBotIndex()];
393 CBotToSpawn const botToSpawn = _BotsToRespawn.back();
395 // remove the entry
396 _BotsToRespawn[i] = _BotsToRespawn.back();
397 _BotsToRespawn.pop_back();
399 if (botPt->isSpawned())
401 nlwarning("CSpawnGroup::checkRespawn : trying to respawn a spawned bot");
403 if (botPt->isSpawned() || botPt->reSpawn(false))
405 CSpawnBot* pbot = botPt->getSpawnObj();
406 if (pbot!=NULL)
408 msg.Entities.push_back(pbot->dataSetRow());
410 continue; // directly test the same it (the next in fact).
412 else
414 _BotsToRespawn.insert(_BotsToRespawn.begin(), botToSpawn); // push_front so the end doesn't change.
417 ++i;
420 if(url != "")
422 msg.ActionName = actionName;
423 msg.Url = url;
424 msg.send(egsString);
429 CBot* CSpawnGroup::findLeader()
431 FOREACH(itBot, CCont<CBot>, bots())
433 CBot* bot = *itBot;
434 if (bot->isSpawned())
436 if (bot->getSpawnObj()->isAlive())
437 return bot;
440 return NULL;
443 std::vector<std::string> CSpawnGroup::getMultiLineInfoString() const
445 std::vector<std::string> container;
447 pushTitle(container, "CSpawnGroup");
448 pushEntry(container, "move profile: " + _MovingProfile.getOneLineInfoString());
449 pushEntry(container, "activity profile: " + _ActivityProfile.getOneLineInfoString());
450 pushEntry(container, "fight profile: " + _FightProfile.getOneLineInfoString());
451 pushFooter(container);
453 return container;
456 NLMISC::CSmartPtr<CAIPlace const> CSpawnGroup::buildFirstHitPlace(TDataSetRow const& aggroBot) const
458 if (_ActivityProfile.getAIProfileType()==AITYPES::ACTIVITY_SQUAD)
459 return static_cast<CGrpProfileSquad*>(_ActivityProfile.getAIProfile())->buildFirstHitPlace(aggroBot);
460 return NULL;
463 void CSpawnGroup::addAggroFor(TDataSetRow const& bot, float aggro, bool forceReturnAggro, NLMISC::CSmartPtr<CAIPlace const> place)
465 CGroup& grp = getPersistent();
466 FOREACH(itBot, CCont<CBot>, grp.bots())
468 CBot* pBot = *itBot;
469 if (pBot)
471 CSpawnBot* spBot = pBot->getSpawnObj();
472 if (spBot)
474 spBot->addAggroFor(bot, aggro, forceReturnAggro, place, false);
479 void CSpawnGroup::setAggroMinimumFor(TDataSetRow const& bot, float aggro, bool forceReturnAggro, NLMISC::CSmartPtr<CAIPlace const> place)
481 CGroup& grp = getPersistent();
482 FOREACH(itBot, CCont<CBot>, grp.bots())
484 CBot* pBot = *itBot;
485 if (pBot)
487 CSpawnBot* spBot = pBot->getSpawnObj();
488 if (spBot)
490 spBot->setAggroMinimumFor(bot, aggro, forceReturnAggro, place, false);
496 bool CSpawnGroup::haveAggro() const
498 CGroup const& group = getPersistent();
499 FOREACHC(itBot, CCont<CBot>, group.bots())
501 CBot const* pBot = *itBot;
502 if (pBot)
504 CSpawnBot const* spBot = pBot->getSpawnObj();
505 if (spBot && spBot->haveAggro())
506 return true;
509 return false;
512 bool CSpawnGroup::haveAggroOrReturnPlace() const
514 CGroup const& group = getPersistent();
515 FOREACHC(itBot, CCont<CBot>, group.bots())
517 CBot const* pBot = *itBot;
518 if (pBot)
520 CSpawnBot const* spBot = pBot->getSpawnObj();
521 if (spBot && spBot->haveAggroOrReturnPlace())
522 return true;
525 return false;