Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / ai_service / ai.cpp
blob49144fa9dd5a138f90e73ff5f7603512604f9e23
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"
21 #include <functional>
23 #include "child_container.h"
24 #include "ai_mgr.h"
25 #include "ai_entity_matrix.h"
26 #include "ai_player.h"
27 #include "ai_mgr_pet.h"
28 #include "ai_grp.h"
29 #include "ai_mgr_fauna.h"
30 #include "ai_mgr_npc.h"
31 #include "ai_bot_npc.h"
32 #include "ai_grp_npc.h"
33 #include "ai_grp_pet.h"
35 #include "ai_script_data_manager.h"
37 #include "ais_user_models.h"
38 #include "continent.h"
39 #include "client_message.h"
40 #include "ai_outpost.h"
41 // Georges
42 #include "nel/georges/u_form_loader.h"
43 #include "nel/georges/u_form_elm.h"
44 #include "nel/georges/u_form.h"
45 #include "nel/georges/u_form_dfn.h"
46 // Game share
47 #include "game_share/emote_list_parser.h"
48 #include "game_share/backup_service_interface.h"
50 #include "ai_variables.h"
51 #include "server_share/r2_variables.h"
53 using namespace NLMISC;
54 using namespace NLNET;
55 using namespace std;
56 using namespace NLGEORGES;
58 //--------------------------------------------------------------------------
59 // SINGLETON DATA
60 //--------------------------------------------------------------------------
63 CAIS *CAIS::_Instance = NULL;
65 CRandom CAIS::_random;
67 const std::string disengageString("DISENGAGE");
68 const std::string egsString("EGS");
71 const uint32 Default_MaxPlayers=5000;
72 const uint32 Default_MaxBotsPet=Default_MaxPlayers*4;
73 const uint32 Default_MaxBotsFauna=40000;
74 const uint32 Default_MaxBotsNpc=20000;
75 const uint32 Default_MaxBotsFx=200;
77 CAIS &CAIS::instance()
79 if (_Instance == NULL)
81 _Instance = new CAIS();
82 // init the AI engine
83 _Instance->initAI();
86 return *_Instance;
90 CAIS::CAIS()
91 : _PetBotCounter(TotalMaxPet),
92 _FaunaBotCounter(TotalMaxFauna),
93 _NpcBotCounter(TotalMaxNpc)
95 // _initialised=false;
96 _TotalBotsSpawned = 0;
97 _ClientCreatureDebug=false;
100 void setMaxPetCallBack(IVariable &var)
102 uint32 newMax=NLMISC::safe_cast<CVariable<uint32>*>(&var)->get();
103 if (CAIS::instanceCreated())
104 CAIS::instance()._PetBotCounter.setMax(newMax);
106 void setMaxFaunaCallBack(IVariable &var)
108 uint32 newMax=NLMISC::safe_cast<CVariable<uint32>*>(&var)->get();
109 if (CAIS::instanceCreated())
110 CAIS::instance()._FaunaBotCounter.setMax(newMax);
112 void setMaxNpcCallBack(IVariable &var)
114 uint32 newMax=NLMISC::safe_cast<CVariable<uint32>*>(&var)->get();
115 if (CAIS::instanceCreated())
116 CAIS::instance()._NpcBotCounter.setMax(newMax);
119 CVariable<uint32> TotalMaxPlayer("ai", "NbPlayersLimit", "Security absolute limit to the number of Player", Default_MaxPlayers, 0, true );
120 CVariable<uint32> TotalMaxPet("ai", "NbPetLimit", "Security absolute limit to the number of Pets", Default_MaxBotsPet, 0, true, setMaxPetCallBack );
121 CVariable<uint32> TotalMaxFauna("ai", "NbFaunaLimit", "Security absolute limit to the number of Faunas", Default_MaxBotsFauna, 0, true, setMaxFaunaCallBack );
122 CVariable<uint32> TotalMaxNpc("ai", "NbNpcLimit", "Security absolute limit to the number of Npcs", Default_MaxBotsNpc, 0, true, setMaxNpcCallBack );
123 CVariable<uint32> TotalMaxFx("ai", "NbFxLimit", "Security absolute limit to the number of Fx", Default_MaxBotsFx, 0, true );
125 CVariable<string> BotRepopFx("ai", "BotRepopFx", "Fx sheet to use when changing the sheet of a bot", string(), 0, true );
127 //--------------------------------------------------------------------------
128 // DATA TABLES FOR ENTITY MATRIX
129 //--------------------------------------------------------------------------
131 // a series of tables giving the minimum iterator table forms for entity matrix iterators for all sizes up to 127m
132 static uint32 EntityMatrixTbl0[] = { 3, 3, 3};
133 static uint32 EntityMatrixTbl16[] = { 3, 5, 5, 5, 3};
134 static uint32 EntityMatrixTbl23[] = { 5, 5, 5, 5, 5};
135 static uint32 EntityMatrixTbl32[] = { 3, 5, 7, 7, 7, 5, 3};
136 static uint32 EntityMatrixTbl36[] = { 5, 7, 7, 7, 7, 7, 5};
137 static uint32 EntityMatrixTbl46[] = { 7, 7, 7, 7, 7, 7, 7};
138 static uint32 EntityMatrixTbl48[] = { 3, 7, 7, 9, 9, 9, 7, 7, 3};
139 static uint32 EntityMatrixTbl51[] = { 5, 7, 9, 9, 9, 9, 9, 7, 5};
140 static uint32 EntityMatrixTbl58[] = { 7, 9, 9, 9, 9, 9, 9, 9, 7};
141 static uint32 EntityMatrixTbl64[] = { 3, 7, 9, 9, 11, 11, 11, 9, 9, 7, 3};
142 static uint32 EntityMatrixTbl66[] = { 5, 7, 9, 11, 11, 11, 11, 11, 9, 7, 5};
143 static uint32 EntityMatrixTbl68[] = { 5, 9, 9, 11, 11, 11, 11, 11, 9, 9, 5};
144 static uint32 EntityMatrixTbl72[] = { 7, 9, 11, 11, 11, 11, 11, 11, 11, 9, 7};
145 static uint32 EntityMatrixTbl80[] = { 3, 9, 11, 11, 11, 13, 13, 13, 11, 11, 11, 9, 3};
146 static uint32 EntityMatrixTbl82[] = { 5, 9, 11, 11, 13, 13, 13, 13, 13, 11, 11, 9, 5};
147 static uint32 EntityMatrixTbl87[] = { 7, 9, 11, 13, 13, 13, 13, 13, 13, 13, 11, 9, 7};
148 static uint32 EntityMatrixTbl91[] = { 7, 11, 11, 13, 13, 13, 13, 13, 13, 13, 11, 11, 7};
149 static uint32 EntityMatrixTbl94[] = { 9, 11, 13, 13, 13, 13, 13, 13, 13, 13, 13, 11, 9};
150 static uint32 EntityMatrixTbl96[] = { 3, 9, 11, 13, 13, 13, 15, 15, 15, 13, 13, 13, 11, 9, 3};
151 static uint32 EntityMatrixTbl98[] = { 5, 9, 11, 13, 13, 15, 15, 15, 15, 15, 13, 13, 11, 9, 5};
152 static uint32 EntityMatrixTbl102[] = { 7, 9, 11, 13, 15, 15, 15, 15, 15, 15, 15, 13, 11, 9, 7};
153 static uint32 EntityMatrixTbl103[] = { 7, 11, 13, 13, 15, 15, 15, 15, 15, 15, 15, 13, 13, 11, 7};
154 static uint32 EntityMatrixTbl108[] = { 9, 11, 13, 15, 15, 15, 15, 15, 15, 15, 15, 15, 13, 11, 9};
155 static uint32 EntityMatrixTbl112[] = { 3, 9, 11, 13, 15, 15, 15, 17, 17, 17, 15, 15, 15, 13, 11, 9, 3};
156 static uint32 EntityMatrixTbl114[] = { 5, 9, 13, 13, 15, 15, 17, 17, 17, 17, 17, 15, 15, 13, 13, 9, 5};
157 static uint32 EntityMatrixTbl116[] = { 5, 11, 13, 15, 15, 15, 17, 17, 17, 17, 17, 15, 15, 15, 13, 11, 5};
158 static uint32 EntityMatrixTbl117[] = { 7, 11, 13, 15, 15, 17, 17, 17, 17, 17, 17, 17, 15, 15, 13, 11, 7};
159 static uint32 EntityMatrixTbl122[] = { 9, 11, 13, 15, 17, 17, 17, 17, 17, 17, 17, 17, 17, 15, 13, 11, 9};
160 static uint32 EntityMatrixTbl125[] = { 9, 13, 15, 15, 17, 17, 17, 17, 17, 17, 17, 17, 17, 15, 15, 13, 9};
162 // a few larger special case matrices
163 static uint32 EntityMatrixTblUpTo150[] = { 7, 11, 15, 17, 17, 19, 19, 21, 21, 21, 21, 21, 21, 21, 19, 19, 17, 17, 15, 11, 7};
164 static uint32 EntityMatrixTblUpTo200[] = { 9, 13, 17, 19, 21, 23, 23, 25, 25, 27, 27, 27, 27, 27, 27, 27, 27, 27, 25, 25, 23, 23, 21, 19, 17, 13, 9};
165 static uint32 EntityMatrixTblUpTo250[] = {11, 15, 19, 23, 25, 27, 27, 29, 29, 31, 31, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 31, 31, 29, 29, 27, 27, 25, 23, 19, 15, 11};
167 static void initLinearMatrixIteratorTables(std::vector<CAIEntityMatrixIteratorTblLinear *> &vect)
169 // initialise the vector with the first table
170 vect.push_back(new CAIEntityMatrixIteratorTblLinear(&(EntityMatrixTbl0[0]),3));
172 // local macro undefined at end of function
173 #define ADD_TBL(d) \
175 while (vect.size()<d) \
176 vect.push_back(vect[vect.size()-1]); \
177 vect.push_back(new CAIEntityMatrixIteratorTblLinear(EntityMatrixTbl##d,sizeof(EntityMatrixTbl##d)/sizeof(EntityMatrixTbl##d[0]))); \
180 // setup the tables ...
181 ADD_TBL(16) ADD_TBL(23)
182 ADD_TBL(32) ADD_TBL(36) ADD_TBL(46)
183 ADD_TBL(48) ADD_TBL(51) ADD_TBL(58)
184 ADD_TBL(64) ADD_TBL(66) ADD_TBL(68) ADD_TBL(72)
185 ADD_TBL(80) ADD_TBL(82) ADD_TBL(87) ADD_TBL(91) ADD_TBL(94)
186 ADD_TBL(96) ADD_TBL(98) ADD_TBL(102) ADD_TBL(103) ADD_TBL(108)
187 ADD_TBL(112) ADD_TBL(114) ADD_TBL(116) ADD_TBL(117) ADD_TBL(122) ADD_TBL(125)
189 #undef ADD_TBL
192 bool CAIS::markTagForDelete(const std::string &filename)
194 const TStringId fileId = CStringMapper::map(filename);
195 for (CCont<CAIInstance>::iterator it=_AIInstances.begin(), itEnd=_AIInstances.end(); it!=itEnd;++it)
197 // first: tag the dynamic regions in the continents
198 for_each(it->continents().begin(), it->continents().end(),
199 bind2nd(mem_fun(&CContinent::markTagForDelete), fileId));
201 for_each(it->managers().begin(),it->managers().end(),
202 CAliasTreeRoot::CMarkTagForDelete(fileId));
204 return true;
207 void CAIS::deleteTaggedAlias(const std::string &filename)
209 const TStringId fileId = CStringMapper::map(filename);
210 FOREACH(it, CCont<CAIInstance>, _AIInstances)
212 // first: tag the dynamic regions in the continents
213 for_each(it->continents().begin(), it->continents().end(),
214 bind2nd(mem_fun(&CContinent::deleteTaggedAlias),fileId));
216 for_each(it->managers().begin(),it->managers().end(),
217 CAliasTreeRoot::CDeleteTagged<CManager>(it->managers()));
223 uint32 CAIS::getEmotNumber(const std::string &name)
225 std::map<std::string, uint32>::iterator it(_EmotNames.find(name));
226 if (it==_EmotNames.end())
227 return std::numeric_limits<uint32>::max();
228 return it->second;
233 bool CAIS::advanceUserTimer (uint32 nbTicks)
235 // for each manager, look for a timer event
236 for_each(AIList().begin(), AIList().end(), bind2nd(mem_fun(&CAIInstance::advanceUserTimer),nbTicks) );
237 return true;
242 // initialise the singleton
243 void CAIS::initAI()
245 // if (_initialised)
246 // return;
247 // _initialised=true;
248 nlinfo("---------- Initialising AI Singleton ----------");
250 // setup the random number generator
251 _random.srand( (sint32)NLMISC::CTime::getLocalTime() );
253 // allocate RAM for the players
255 // setup the standard iterator tables for scanning the entity matrices
256 _matrixIterator2x2.push_back(-1,-1); _matrixIterator2x2.push_back(1,0);
257 _matrixIterator2x2.push_back(-1, 1); _matrixIterator2x2.push_back(1,0);
259 _matrixIterator3x3.push_back(-1,-1); _matrixIterator3x3.push_back(1,0); _matrixIterator3x3.push_back(1,0);
260 _matrixIterator3x3.push_back(-2, 1); _matrixIterator3x3.push_back(1,0); _matrixIterator3x3.push_back(1,0);
261 _matrixIterator3x3.push_back(-2, 1); _matrixIterator3x3.push_back(1,0); _matrixIterator3x3.push_back(1,0);
263 // setup the set of linear iterator tables for generating visions of given distances
264 initLinearMatrixIteratorTables(_matrixIteratorsByDistance);
266 EMOTE_LIST_PARSER::initEmoteList(_EmotNames);
268 // init the client message callbacks
269 CAIClientMessages::init();
273 uint32 CAIS::createAIInstance(const std::string &continentName, uint32 instanceNumber)
275 // first, check that an instance with this number is not already running
277 for (CCont<CAIInstance>::iterator it=_AIInstances.begin(), itEnd=_AIInstances.end();it!=itEnd;++it)
279 if (it->getInstanceNumber()!=instanceNumber)
280 continue;
282 nlwarning("CAIS::createAIInstance: instance number %u is already in use, can't create new instance.", instanceNumber);
283 return std::numeric_limits<uint32>::max();
286 CAIInstance *aii = _AIInstances.addChild(new CAIInstance(this));
288 // ok, set the continent name and instance number
289 aii->initInstance(continentName, instanceNumber);
291 return aii->getChildIndex();
294 void CAIS::destroyAIInstance(uint32 instanceNumber, bool displayWarningIfInstanceNotExist)
296 // this method is not fully tested for a Ryzom shard
297 // but it should work as expected for a Ring shard
298 nlassert(IsRingShard.get());
300 CRefPtr<CAIInstance> aii = getAIInstance(instanceNumber);
301 if (aii == NULL)
303 if (displayWarningIfInstanceNotExist)
305 nlwarning("AI instance %u does not exist but it was asked to delete here", instanceNumber);
307 return;
309 aii->despawn();
310 _AIInstances.removeChildByIndex(aii->getChildIndex());
311 nlassert(aii == NULL);
313 // notify the EGS
314 if (EGSHasMirrorReady)
316 CReportAIInstanceDespawnMsg msg;
317 msg.InstanceNumbers.push_back(instanceNumber);
318 msg.send("EGS");
323 // release the singleton before program exit
324 void CAIS::release ()
326 // force an update to save the persistent var if needed
327 updatePersistentVariables();
329 // erase all ai instance.
330 AIList().clear();
332 CAIUserModelManager::getInstance()->destroyInstance();
333 // release the client message callbacks
334 CAIClientMessages::release();
337 // free up the vision matrix iterator tables
338 if (!_matrixIteratorsByDistance.empty())
340 for (uint i=0;i<_matrixIteratorsByDistance.size();)
342 // erase the iterator table
343 delete _matrixIteratorsByDistance[i];
344 // run i forwards past repeated refs to the iterator tbl that we just deleted
345 for (++i;i<_matrixIteratorsByDistance.size() && _matrixIteratorsByDistance[i]==_matrixIteratorsByDistance[i-1];++i) {}
347 _matrixIteratorsByDistance.clear();
349 _Instance = NULL;
350 delete this;
353 void CAIS::serviceEvent (const CServiceEvent &info)
355 if (info.getEventType() == CServiceEvent::SERVICE_UP && info.getServiceName() == "EGS")
357 // send the list of available collision data
358 CReportAICollisionAvailableMsg msg;
359 msg.ContinentsCollision = CWorldContainer::getContinentList();
360 msg.send(info.getServiceId());
363 // event on all ai instance
365 // for_each(_AIInstances.begin(), _AIInstances.end(), bind2nd(mem_fun1(&CAIInstance::serviceEvent), info));
366 // don't compile coz we need to pass an object and not a reference (info). have to build an object that represents the reference.
368 FOREACH(it, CCont<CAIInstance>, _AIInstances)
369 it->serviceEvent (info);
373 //--------------------------------------------------------------------------
374 // update() & save()
375 //--------------------------------------------------------------------------
377 // the update routine called once per tick
378 // this is the routine that calls the managers' updates
379 extern void execBufferedCommands();
380 extern void execNamedEntityChanges();
382 void CAIS::update()
384 if (!EGSHasMirrorReady)
385 return;
387 H_AUTO(AIUpdate);
390 // Init stat counters
391 AISStat::countersBegin();
393 // Execute buffered Task
394 uint32 tick = CTimeInterface::gameCycle();
395 _TickedTaskList.execute(tick);
397 // Execute buffered functions that need to be executed in the correct context
398 execBufferedCommands();
401 execNamedEntityChanges();
403 // Update AI instances
404 FOREACH(it, CCont<CAIInstance>, CAIS::instance().AIList())
405 (*it)->CAIInstance::update();
407 // Send systematic messages to EGS
408 if (EGSHasMirrorReady)
410 // send the fauna description message to EGS then clear the content.
411 if (!_FaunaDescriptionList.Bots.empty())
413 nlassert(_FaunaDescriptionList.Bots.size() == _FaunaDescriptionList.GrpAlias.size());
414 _FaunaDescriptionList.send("EGS");
415 _FaunaDescriptionList.Bots.clear();
416 _FaunaDescriptionList.GrpAlias.clear();
418 // send agglomerated hp changes
419 if (!_CreatureChangeHPList.Entities.empty())
421 nlassert(_CreatureChangeHPList.Entities.size()==_CreatureChangeHPList.DeltaHp.size());
422 _CreatureChangeHPList.send("EGS");
423 _CreatureChangeHPList.Entities.clear();
424 _CreatureChangeHPList.DeltaHp.clear();
426 if (!_CreatureChangeMaxHPList.Entities.empty())
428 nlassert(_CreatureChangeMaxHPList.Entities.size()==_CreatureChangeMaxHPList.MaxHp.size());
429 nlassert(_CreatureChangeMaxHPList.Entities.size()==_CreatureChangeMaxHPList.SetFull.size());
430 _CreatureChangeMaxHPList.send("EGS");
431 _CreatureChangeMaxHPList.Entities.clear();
432 _CreatureChangeMaxHPList.MaxHp.clear();
433 _CreatureChangeMaxHPList.SetFull.clear();
438 // update persistent variables every 1024 tick if AI script data manager is flagged
439 if ((tick & 0x3FF) == 0)
441 updatePersistentVariables();
444 //TODO: UserModelManager must send UserModels to EGS if not done yet
445 //CAIUserModelManager::getInstance()->sendUserModels();
446 // Terminate counters and store stats in an accessible place
447 AISStat::countersEnd();
450 // provoke a general 'save to backup' across the whole service
451 void CAIS::save()
453 nlinfo("*** save() NOT IMPLEMENTED YET ***");
457 //--------------------------------------------------------------------------
458 // management of iterator tables for vision matrices
459 //--------------------------------------------------------------------------
461 const CAIEntityMatrixIteratorTblLinear* CAIS::bestLinearMatrixIteratorTbl(uint32 distInMeters)
463 #if !FINAL_VERSION
464 nlassert(!_matrixIteratorsByDistance.empty());
465 #endif
467 if (distInMeters >= _matrixIteratorsByDistance.size())
469 //nlwarning("Try to access to a Vision Matrix to far %u the farest is only %u", distInMeters, _matrixIteratorsByDistance.size());
470 return _matrixIteratorsByDistance.back();
473 return _matrixIteratorsByDistance[distInMeters];
476 int getInt64FromStr (const char* str)
478 if(str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
479 return (int) atoiInt64(str+2,16);
480 return (int) atoiInt64(str,10);
483 // all these dynamics casts can be throwned away ..
484 CAIInstance* CAIS::tryToGetAIInstance(const char* str)
486 return dynamic_cast<CAIInstance*> (tryToGetEntity(str,CAIS::AI_INSTANCE));
489 CContinent *CAIS::tryToGetContinent (const char *str)
491 return dynamic_cast<CContinent*> (tryToGetEntity(str,CAIS::AI_CONTINENT));
494 CRegion *CAIS::tryToGetRegion (const char *str)
496 return dynamic_cast<CRegion*> (tryToGetEntity(str,CAIS::AI_REGION));
499 CCellZone *CAIS::tryToGetCellZone (const char *str)
501 return dynamic_cast<CCellZone*> (tryToGetEntity(str,CAIS::AI_CELL_ZONE));
504 CFamilyBehavior *CAIS::tryToGetFamilyBehavior (const char *str)
506 return dynamic_cast<CFamilyBehavior*> (tryToGetEntity(str,CAIS::AI_FAMILY_BEHAVIOR));
510 CManager* CAIS::tryToGetManager(const char* str)
512 return dynamic_cast<CManager*> (tryToGetEntity(str,CAIS::AI_MANAGER));
515 CGroup* CAIS::tryToGetGroup(const char* str)
517 return dynamic_cast<CGroup*> (tryToGetEntity(str,CAIS::AI_GROUP));
520 CBot* CAIS::tryToGetBot(const char* str)
522 return dynamic_cast<CBot*> (tryToGetEntity(str,CAIS::AI_BOT));
525 CAIEntity* CAIS::tryToGetAIEntity(const char* str)
527 return dynamic_cast<CAIEntity*> (tryToGetEntity(str));
530 CAIEntityPhysical* CAIS::tryToGetEntityPhysical(const char* str)
532 CEntityId entityId;
533 entityId.fromString(str);
534 return CAIS::getEntityPhysical(CMirrors::DataSet->getDataSetRow(entityId));
537 CAIEntity* CAIS::tryToGetEntity(const char* str, TSearchType searchType)
539 CAIInstance *aii = NULL;
540 CManager *mgr = NULL;
541 CBot *bot = NULL;
542 CGroup *grp = NULL;
545 vector<string> parts;
546 explode(string(str), string(":"), parts, false);
548 if (parts.empty() || parts[0].empty())
549 return NULL;
551 // skip AIS number if any
552 if (parts[0].substr(0, 4) == "AIS_")
553 parts.erase(parts.begin());
555 // check
556 if (parts.empty() || parts[0].empty()) return NULL;
558 // instance index
559 uint32 index = atoui(parts[0].c_str());
560 if (index >= CAIS::instance().AIList().size())
561 goto tryWithEntityId;
562 aii = CAIS::AIList()[index];
563 if (!aii)
564 goto tryWithEntityId;
565 if (searchType==CAIS::AI_INSTANCE
566 || (searchType == CAIS::AI_UNDEFINED && parts.size() == 1))
567 return aii;
569 parts.erase(parts.begin());
571 // check
572 if (parts.empty() || parts[0].empty()) return NULL;
574 // branch on static or dynamic system
575 // manager index
576 if (parts[0].find("dyn_") == 0)
578 // parse dynamic id
580 // continent index
581 index = atoui(parts[0].substr(4).c_str());
582 if (index >= aii->continents().size())
583 return NULL;
584 CContinent *continent = aii->continents()[index];
585 if (searchType==CAIS::AI_CONTINENT
586 || (searchType == CAIS::AI_UNDEFINED && parts.size() == 1))
587 return continent;
589 parts.erase(parts.begin());
591 // check
592 if (parts.empty() || parts[0].empty()) return NULL;
594 // region index
595 index = atoui(parts[0].c_str());
596 if (index >= continent->regions().size())
597 return NULL;
598 CRegion *region = continent->regions()[index];
599 if (searchType==CAIS::AI_REGION
600 || (searchType == CAIS::AI_UNDEFINED && parts.size() == 1))
601 return region;
603 parts.erase(parts.begin());
605 // check
606 if (parts.empty() || parts[0].empty()) return NULL;
608 // cellzone index
609 index = atoui(parts[0].c_str());
610 if (index >= region->cellZones().size())
611 return NULL;
612 CCellZone *cz = region->cellZones()[index];
613 if (searchType==CAIS::AI_CELL_ZONE
614 || (searchType == CAIS::AI_UNDEFINED && parts.size() == 1))
615 return cz;
617 parts.erase(parts.begin());
619 // check
620 if (parts.empty() || parts[0].empty()) return NULL;
622 // family behavior index
623 index = atoui(parts[0].c_str());
624 if (index >= cz->familyBehaviors().size())
625 return NULL;
626 CFamilyBehavior *fb = cz->familyBehaviors()[index];
627 if (searchType==CAIS::AI_FAMILY_BEHAVIOR
628 || (searchType == CAIS::AI_UNDEFINED && parts.size() == 1))
629 return fb;
631 parts.erase(parts.begin());
633 // check
634 if (parts.empty() || parts[0].empty())
635 return NULL;
637 // manager index
638 if (parts[0] == "npc")
639 mgr = fb->mgrNpc();
640 else if (parts[0] == "fauna")
641 mgr = fb->mgrFauna();
643 if (!mgr)
644 return NULL;
646 if (searchType==CAIS::AI_MANAGER
647 || (searchType == CAIS::AI_UNDEFINED && parts.size() == 1)
648 || mgr == NULL)
649 return mgr;
651 parts.erase(parts.begin());
653 // check
654 if (parts.empty() || parts[0].empty()) return NULL;
656 else
658 // parse static id
660 // Manager index
661 index = atoui(parts[0].c_str());
662 if (index >= aii->managers().size())
663 return NULL;
664 mgr = aii->managers()[index];
665 if (searchType==CAIS::AI_MANAGER
666 || (searchType == CAIS::AI_UNDEFINED && parts.size() == 1)
667 || mgr == NULL)
668 return mgr;
670 parts.erase(parts.begin());
673 // check
674 if (parts.empty() || parts[0].empty()) return NULL;
677 // group index
678 index = atoui(parts[0].c_str());
679 if (index >= mgr->groups().size())
680 return NULL;
681 grp = mgr->groups()[index];
682 if (searchType==CAIS::AI_GROUP
683 || (searchType == CAIS::AI_UNDEFINED && parts.size() == 1))
684 return grp;
686 parts.erase(parts.begin());
688 // check
689 if (parts.empty() || parts[0].empty()) return NULL;
691 // bot index
692 index = atoui(parts[0].c_str());
693 if (index >= grp->bots().size())
694 return NULL;
695 bot = grp->bots()[index];
696 if (searchType==CAIS::AI_BOT
697 || (searchType == CAIS::AI_UNDEFINED && parts.size() == 1))
698 return bot;
700 // what ?
701 return NULL;
703 tryWithEntityId:
705 CEntityId entityId;
706 entityId.fromString(str);
708 if (entityId.isUnknownId())
709 return NULL;
711 CCont<CAIInstance>::iterator instanceIt=CAIS::instance().AIList().begin(), instanceItEnd=CAIS::instance().AIList().end();
713 while (instanceIt!=instanceItEnd)
715 CAIInstance *instancePtr=*instanceIt;
717 CCont<CManager>::iterator it=instancePtr->managers().begin(), itEnd=instancePtr->managers().end();
719 while (it!=itEnd)
721 CManager *mgrPtr = *it;
723 CGroup *grpPtr = mgrPtr->getNextValidGroupChild ();
724 while (grpPtr)
726 CBot *botPtr = grpPtr->getNextValidBotChild();
727 while (botPtr)
729 if ( botPtr->isSpawned()
730 && botPtr->getSpawnObj()->getEntityId() == entityId)
731 return dynamic_cast<CAIEntity*> (botPtr);
732 botPtr = grpPtr->getNextValidBotChild (botPtr);
734 grpPtr=mgrPtr->getNextValidGroupChild (grpPtr);
736 ++it;
738 ++instanceIt;
740 return NULL;
748 //--------------------------------------------------------------------------
749 // manageing the set of maps
750 //--------------------------------------------------------------------------
752 CAIEntityPhysical *CAIS::getEntityPhysical(const TDataSetRow& row)
754 CHashMap<int,NLMISC::CDbgPtr<CAIEntityPhysical> >::iterator it(_CAIEntityByDataSetRow.find(row.getIndex()));
756 if (it!=_CAIEntityByDataSetRow.end())
757 return (*it).second;
758 else
759 return NULL;
760 // the code below generates an error .. :( hu !
764 //-------------------------------------------------------------------
765 // Interface to bot chat - callbacks called when bots start or
766 // stop chatting with player(s)
767 //-------------------------------------------------------------------
769 void CAIS::beginBotChat(const TDataSetRow &bot,const TDataSetRow &player)
771 #ifdef NL_DEBUG
772 /// Is this still true?
773 nlwarning("Chat can't work now as bot are now splitted in persistent and spawnable part. Have to rework on this part.");
774 #endif
776 // get a pointer to the bot
777 CSpawnBotNpc* botNpc=dynamic_cast<CSpawnBotNpc*>(CAIS::getEntityPhysical(bot));
778 if (!botNpc)
780 // nlwarning("CAIS::beginBotChat(): Bot chat message identifies an entity that isn't an NPC!!!");
781 return;
784 // get a pointer to the player
785 CBotPlayer* plrPtr = dynamic_cast<CBotPlayer*>(CAIS::getEntityPhysical(player));
786 if (plrPtr==NULL)
788 // nlwarning("CAIS::beginBotChat(): Bot chat message identifies an unknown player!!!");
789 return;
792 // have the bot register the chat
793 botNpc->beginBotChat(plrPtr);
796 void CAIS::endBotChat(const TDataSetRow &bot, const TDataSetRow &player)
798 // get a pointer to the bot
799 CSpawnBotNpc* botNpc=dynamic_cast<CSpawnBotNpc*>(CAIS::getEntityPhysical(bot));
800 if (!botNpc)
802 // nlwarning("CAIS::endBotChat(): Bot chat message identifies an entity that isn't an NPC!!!");
803 return;
806 // get a pointer to the player
807 CBotPlayer* plrPtr = dynamic_cast<CBotPlayer*>(CAIS::getEntityPhysical(player));
808 if (!plrPtr)
810 // nlwarning("CAIS::endBotChat(): Bot chat message identifies an unknown player!!!");
811 return;
814 // have the bot register the chat end
815 botNpc->endBotChat(plrPtr);
818 void CAIS::beginDynChat(const TDataSetRow &bot)
820 // get a pointer to the bot
821 CSpawnBotNpc* botNpc=dynamic_cast<CSpawnBotNpc*>(CAIS::getEntityPhysical(bot));
822 if (!botNpc)
824 // nlwarning("CAIS::beginBotChat(): Bot chat message identifies an entity that isn't an NPC!!!");
825 return;
828 // have the bot register the chat
829 botNpc->beginDynChat();
830 nldebug( "DYNCHT: E%u: %u dyn chats", bot.getIndex(), botNpc->getNbActiveDynChats() );
833 void CAIS::endDynChat(const TDataSetRow &bot)
835 // get a pointer to the bot
836 CSpawnBotNpc* botNpc=dynamic_cast<CSpawnBotNpc*>(CAIS::getEntityPhysical(bot));
837 if (!botNpc)
839 // nlwarning("CAIS::endBotChat(): Bot chat message identifies an entity that isn't an NPC!!!");
840 return;
843 // have the bot register the chat end
844 botNpc->endDynChat();
845 nldebug( "DYNCHT: E%u: %u dyn chats", bot.getIndex(), botNpc->getNbActiveDynChats() );
849 void CAIPlaceXYR::display(CStringWriter &stringWriter) const
851 stringWriter.append("XYR: ("+_pos.x().toString()
852 +" "
853 +_pos.y().toString()
854 +" "+toString(_pos.h())
855 +") Radius "
856 +toString(_radius)
857 +" "
858 +getName());
860 // nlinfo("XYR: (%s,%s,%d) x %f :%s",_pos.x().toString().c_str(),_pos.y().toString().c_str(),_pos.h(),_radius,getName().c_str());
864 void CAIS::warnBadInstanceMsgImp(const std::string &serviceName, TServiceId serviceId, CWarnBadInstanceMsgImp &msg)
866 // EGS says that an instance is spoofing an instance number or using a bad static instance number/continent name association.
867 // we must despawn/delete the aiinstance
869 FOREACH(it, CCont<CAIInstance>, _AIInstances)
871 if ((*it)->getInstanceNumber()!=msg.InstanceNumber)
872 continue;
874 // ok, we found the bad guy !
875 nlwarning("CAIS::warnBadInstanceMsgImp: despawning AIInstance %u, instance number %u, continent '%s'",
876 (*it)->getChildIndex(), msg.InstanceNumber, (*it)->getContinentName().c_str());
877 _AIInstances.removeChildByIndex((*it)->getChildIndex());
878 return;
881 // not found
882 nlwarning("CAIS::warnBadInstanceMsgImp: can't find AIInstance with instance number %u ! Can't despawn it", msg.InstanceNumber);
885 void CAIS::updatePersistentVariables()
887 if (CAIScriptDataManager::getInstance()->needsPersistentVarUpdate() == true)
889 // sending data to bs
890 CPersistentDataRecord pdr("AiTokenFamily");
892 CAIScriptDataManager::getInstance()->getPersistentVariables().store(pdr);
894 uint32 bufSize= pdr.totalDataSize();
895 vector<char> buffer;
896 buffer.resize(bufSize);
897 pdr.toBuffer(&buffer[0],bufSize);
899 CBackupMsgSaveFile msg( CAIScriptDataManager::getInstance()->makePdrFileName(), CBackupMsgSaveFile::SaveFile, Bsi );
900 msg.DataMsg.serialBuffer((uint8*)&buffer[0], bufSize);
902 Bsi.sendFile( msg );
903 CAIScriptDataManager::getInstance()->clearDirtyFlag();
907 CAIInstance *CAIS::getAIInstance(uint32 instanceNumber)
909 FOREACH(it, CCont<CAIInstance>, _AIInstances)
911 if ((*it)->getInstanceNumber()==instanceNumber)
912 return *it;
914 return NULL;