Fix crash with fame and new player
[ryzomcore.git] / ryzom / server / src / ai_service / commands.cpp
blob10db3a862ab1e699fb3dc680b5b1d200e5272640
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 "continent.h"
21 #include "continent_inline.h"
22 #include "ai_mgr.h"
23 #include "ai_grp.h"
24 #include "ai_bot.h"
25 #include "ai_entity_matrix.h"
26 #include "ai_player.h"
27 #include "ai_mgr_fauna.h"
28 #include "ai_grp_fauna.h"
29 #include "ai_grp_npc.h"
30 #include "ai_grp_pet.h"
31 #include "ai_bot_npc.h"
32 #include "mirrors.h"
33 #include "server_share/mission_messages.h"
34 #include "game_share/fame.h"
35 #include "server_share/used_continent.h"
36 #include "ai_outpost.h"
37 #include "script_compiler.h"
38 #include "ais_actions.h"
39 #include "fx_entity_manager.h"
40 #include "ai_script_data_manager.h"
41 #include "commands.h"
43 #include "ais_user_models.h"
45 extern bool GrpHistoryRecordLog;
46 extern NLLIGO::CLigoConfig LigoConfig;
48 using namespace NLMISC;
49 using namespace NLNET;
50 using namespace std;
51 using namespace AITYPES;
52 using namespace AICOMP;
53 using namespace AIVM;
55 //////////////////////////////////////////////////////////////////////////////
56 // New set of commands //
57 //////////////////////////////////////////////////////////////////////////////
59 //- Generic commands ---------------------------------------------------------
61 RYAI_TEMPLATED_COMMAND(listInstances, "display the list of ai instances", "[<filter>]", CAIInstance, buildInstanceList, displayList)
62 RYAI_TEMPLATED_COMMAND(listContinents, "display the list of continents", "[<filter>]", CContinent, buildContinentList, displayList)
63 RYAI_TEMPLATED_COMMAND(listRegions, "display the list of regions", "[<filter>]", CRegion, buildRegionList, displayList)
64 RYAI_TEMPLATED_COMMAND(listCellZones, "display the list of cell zones", "[<filter>]", CCellZone, buildCellZoneList, displayList)
65 RYAI_TEMPLATED_COMMAND(listFamilyBehaviours, "display the list of family behaviours", "[<filter>]", CFamilyBehavior, buildFamilyBehaviorList, displayList)
66 RYAI_TEMPLATED_COMMAND(listOutposts, "display the list of outposts", "[<filter>]", COutpost, buildOutpostList, displayList)
67 RYAI_TEMPLATED_COMMAND(listManagers, "display the list of managers", "[<filter>]", CManager, buildManagerList, displayList)
68 RYAI_TEMPLATED_COMMAND(listNpcManagers, "display the list of managers", "[<filter>]", CManager, buildNpcManagerList, displayList)
69 RYAI_TEMPLATED_COMMAND(listGroups, "display the list of groups", "[<filter>]", CGroup, buildGroupList, displayList)
70 RYAI_TEMPLATED_COMMAND(listBots, "display the list of bots", "[<filter>]", CBot, buildBotList, displayList)
71 RYAI_TEMPLATED_COMMAND(listPlayers, "display the list of players", "[<filter>]", CBotPlayer, buildPlayerList, displayList)
72 RYAI_TEMPLATED_COMMAND(listFaunaPlaces, "display the list of fauna places", "[<filter>]", CAIPlace, buildFaunaPlaceList, displayList)
74 RYAI_TEMPLATED_COMMAND(enableFaunaPlace, "enable a fauna place", "[<filter>]", CAIPlace, buildFaunaPlaceList, spawnList)
75 RYAI_TEMPLATED_COMMAND(disableFaunaPlace, "disable a fauna place", "[<filter>]", CAIPlace, buildFaunaPlaceList, despawnList)
79 RYAI_TEMPLATED_COMMAND(displayInstances, "display extensively the list of ai instances", "[<filter>]", CAIInstance, buildInstanceList, displayListEx)
80 RYAI_TEMPLATED_COMMAND(displayContinents, "display extensively the list of continents", "[<filter>]", CContinent, buildContinentList, displayListEx)
81 RYAI_TEMPLATED_COMMAND(displayRegions, "display extensively the list of regions", "[<filter>]", CRegion, buildRegionList, displayListEx)
82 RYAI_TEMPLATED_COMMAND(displayCellZones, "display extensively the list of cell zones", "[<filter>]", CCellZone, buildCellZoneList, displayListEx)
83 RYAI_TEMPLATED_COMMAND(displayFamilyBehaviours, "display extensively the list of family behaviours", "[<filter>]", CFamilyBehavior, buildFamilyBehaviorList, displayListEx)
84 //RYAI_TEMPLATED_COMMAND(displayOutposts, "display extensively the list of outposts", "[<filter>]", COutpost, buildOutpostList, displayListEx)
85 RYAI_TEMPLATED_COMMAND(displayManagers, "display extensively the list of managers", "[<filter>]", CManager, buildManagerList, displayListEx)
86 RYAI_TEMPLATED_COMMAND(displayGroups, "display extensively the list of groups", "[<filter>]", CGroup, buildGroupList, displayListEx)
87 RYAI_TEMPLATED_COMMAND(displayBots, "display extensively the list of bots", "[<filter>]", CBot, buildBotList, displayListEx)
88 RYAI_TEMPLATED_COMMAND(displayPlayers, "display extensively the list of players", "[<filter>]", CBotPlayer, buildPlayerList, displayListEx)
90 RYAI_TEMPLATED_COMMAND(spawnInstances, "spawns the ai instances", "[<filter>]", CAIInstance, buildInstanceList, spawnList)
91 //RYAI_TEMPLATED_COMMAND(spawnContinents, "spawns the continents", "[<filter>]", CContinent, buildContinentList, spawnList)
92 //RYAI_TEMPLATED_COMMAND(spawnRegions, "spawns the regions", "[<filter>]", CRegion, buildRegionList, spawnList)
93 //RYAI_TEMPLATED_COMMAND(spawnCellZones, "spawns the cell zones", "[<filter>]", CCellZone, buildCellZoneList, spawnList)
94 //RYAI_TEMPLATED_COMMAND(spawnFamilyBehaviours, "spawns the family behaviours", "[<filter>]", CFamilyBehavior, buildFamilyBehaviorList, spawnList)
95 //RYAI_TEMPLATED_COMMAND(spawnOutposts, "spawns the outposts", "[<filter>]", COutpost, buildOutpostList, spawnList)
96 RYAI_TEMPLATED_COMMAND(spawnManagers, "spawns the managers", "[<filter>]", CManager, buildManagerList, spawnList)
97 RYAI_TEMPLATED_COMMAND(spawnGroups, "spawns the groups", "[<filter>]", CGroup, buildGroupList, spawnList)
98 //RYAI_TEMPLATED_COMMAND(spawnBots, "spawns the bots", "[<filter>]", CBot, buildBotList, spawnList)
99 //RYAI_TEMPLATED_COMMAND(spawnPlayers, "spawns the players", "[<filter>]", CBotPlayer, buildPlayerList, spawnList)
101 RYAI_TEMPLATED_COMMAND(despawnInstances, "despawns the ai instances", "[<filter>]", CAIInstance, buildInstanceList, despawnList)
102 //RYAI_TEMPLATED_COMMAND(despawnContinents, "despawns the continents", "[<filter>]", CContinent, buildContinentList, despawnList)
103 //RYAI_TEMPLATED_COMMAND(despawnRegions, "despawns the regions", "[<filter>]", CRegion, buildRegionList, despawnList)
104 //RYAI_TEMPLATED_COMMAND(despawnCellZones, "despawns the cell zones", "[<filter>]", CCellZone, buildCellZoneList, despawnList)
105 //RYAI_TEMPLATED_COMMAND(despawnFamilyBehaviours, "despawns the family behaviours", "[<filter>]", CFamilyBehavior, buildFamilyBehaviorList, despawnList)
106 //RYAI_TEMPLATED_COMMAND(despawnOutposts, "despawns the outposts", "[<filter>]", COutpost, buildOutpostList, despawnList)
107 RYAI_TEMPLATED_COMMAND(despawnManagers, "despawns the managers", "[<filter>]", CManager, buildManagerList, despawnList)
108 RYAI_TEMPLATED_COMMAND(despawnGroups, "despawns the groups", "[<filter>]", CGroup, buildGroupList, despawnList)
109 //RYAI_TEMPLATED_COMMAND(despawnBots, "despawns the bots", "[<filter>]", CBot, buildBotList, despawnList)
110 //RYAI_TEMPLATED_COMMAND(despawnPlayers, "despawns the players", "[<filter>]", CBotPlayer, buildPlayerList, despawnList)
112 //- Special commands ---------------------------------------------------------
114 NLMISC_COMMAND(search, "search all the data tree for a name part","<name_part>")
116 if (args.size() != 1)
117 return false;
120 log.displayNL("- Search results in instances ------------------------------------------------");
121 std::deque<CAIInstance*> container;
122 buildInstanceList(container);
123 displayList(log, container, args[0]);
127 log.displayNL("- Search results in continents -----------------------------------------------");
128 std::deque<CContinent*> container;
129 buildContinentList(container);
130 displayList(log, container, args[0]);
134 log.displayNL("- Search results in regions --------------------------------------------------");
135 std::deque<CRegion*> container;
136 buildRegionList(container);
137 displayList(log, container, args[0]);
141 log.displayNL("- Search results in cell zones -----------------------------------------------");
142 std::deque<CCellZone*> container;
143 buildCellZoneList(container);
144 displayList(log, container, args[0]);
148 log.displayNL("- Search results in family behaviors -----------------------------------------");
149 std::deque<CFamilyBehavior*> container;
150 buildFamilyBehaviorList(container);
151 displayList(log, container, args[0]);
155 log.displayNL("- Search results in outposts -------------------------------------------------");
156 std::deque<COutpost*> container;
157 buildOutpostList(container);
158 displayList(log, container, args[0]);
162 log.displayNL("- Search results in managers -------------------------------------------------");
163 std::deque<CManager*> container;
164 buildManagerList(container);
165 displayList(log, container, args[0]);
169 log.displayNL("- Search results in groups ---------------------------------------------------");
170 std::deque<CGroup*> container;
171 buildGroupList(container);
172 displayList(log, container, args[0]);
176 log.displayNL("- Search results in bots -----------------------------------------------------");
177 std::deque<CBot*> container;
178 buildBotList(container);
179 displayList(log, container, args[0]);
183 log.displayNL("- Search results in players --------------------------------------------------");
184 std::deque<CBotPlayer*> container;
185 buildPlayerList(container);
186 displayList(log, container, args[0]);
189 return true;
192 //----------------------------------------------------------------------------
194 NLMISC_COMMAND(eventCreateNpcGroup, "create an event npc group", "<aiInstanceId> <nbBots> <sheet> <x> <y> [<dispersionRadius=10m> [<spawnBots=true> [<orientation=random|-360..360> [<name>]]]]")
196 if (args.size()<5)
197 return false;
199 CLogStringWriter stringWriter(&log);
201 CAIInstance* aiInstance = NULL;
203 uint32 aiInstanceId = NLMISC::atoui(args[0].c_str());
204 if (aiInstanceId>=CAIS::instance().aiinstances().size())
206 stringWriter.append("Invalid AI Instance Number");
207 return true;
209 aiInstance = CAIS::instance().aiinstances()[aiInstanceId];
210 if (!aiInstance)
212 stringWriter.append("AI Instance do not exists");
213 return true;
217 uint32 nbBots = NLMISC::atoui(args[1].c_str());
218 if (nbBots<=0)
220 stringWriter.append("invalid bot count");
221 return true;
224 NLMISC::CSheetId sheetId(args[2]);
225 if (sheetId==NLMISC::CSheetId::Unknown)
226 sheetId = args[2] + ".creature";
227 if (sheetId==NLMISC::CSheetId::Unknown)
229 stringWriter.append("invalid sheet id");
230 return true;
233 double x, y;
234 NLMISC::fromString(args[3], x);
235 NLMISC::fromString(args[4], y);
237 double dispersionRadius = 10.;
238 if (args.size()>5)
240 dispersionRadius = atof(args[5].c_str());
241 if (dispersionRadius<0.)
243 stringWriter.append("invalid dispersion radius");
244 return true;
248 bool spawnBots = true;
249 if (args.size()>6)
251 NLMISC::fromString(args[6], spawnBots);
254 double orientation = 6.666;
255 if (args.size()>7 && args[7] != "random")
257 NLMISC::fromString(args[7], orientation);
258 orientation = orientation / 360.0 * (NLMISC::Pi * 2.0);
261 std::string botsName;
262 if (args.size()>8) botsName = args[8];
264 aiInstance->eventCreateNpcGroup(nbBots, sheetId, CAIVector(x, y), dispersionRadius, spawnBots, orientation, botsName, "");
266 return true;
269 //----------------------------------------------------------------------------
271 NLMISC_COMMAND(listFxEntities, "", "[<filter>]")
273 if (args.size()>0)
274 displayList(log, CFxEntityManager::getInstance()->getEntities(), args[0]);
275 else
276 displayList(log, CFxEntityManager::getInstance()->getEntities());
277 return true;
280 //////////////////////////////////////////////////////////////////////////////
282 //////////////////////////////////////////////////////////////////////////////
283 // Old set of commands //
284 //////////////////////////////////////////////////////////////////////////////
286 // Dump the road/zone connectivity
287 NLMISC_COMMAND(dumpRoadCon, "dump road/cell connectivity graph","<continentName> [<ai instance number = 0>]")
289 if (args.size() > 2)
290 return false;
292 uint instanceIndex = 0;
294 if (args.size() == 2)
295 NLMISC::fromString(args[1], instanceIndex);
297 if (instanceIndex >= CAIS::instance().AIList().size())
299 log.displayNL("ai index %u is out of range ! (only %u ai instance)",
300 instanceIndex,
301 CAIS::instance().AIList().size());
302 return false;
305 CAIInstance *aii = CAIS::instance().AIList()[instanceIndex];
307 for (uint i=0; i<aii->continents().size(); ++i)
309 CContinent *cont = aii->continents()[i];
310 if (!cont)
311 continue;
313 if ( args.empty()
314 || cont->getName()==args[0])
316 log.displayRawNL("Dumping connection in '%s' (@ %p):",
317 cont->getName().c_str(),
318 cont);
320 CAliasCont<CRegion> &regions = cont->regions();
322 for (uint i=0; i<regions.size(); ++i)
324 CRegion *region = regions[i];
325 if (!region)
326 continue;
328 CAliasCont<CCellZone> &cellZones = region->cellZones();
330 for (uint i=0; i<cellZones.size(); ++i)
332 CCellZone *czone = cellZones[i];
333 if (!czone) continue;
334 for (uint j=0; j<czone->cells().size(); ++j)
336 CCell *cell = czone->cells()[j];
337 if (!cell) continue;
339 set<NLMISC::CDbgPtr<CCell> >::iterator first(cell->_NeighbourCells.begin()), last(cell->_NeighbourCells.end());
340 for (; first != last; ++first)
342 nldebug("Link '%s' => '%s'", cell->getName().c_str(), (*first)->getName().c_str());
348 for (uint i=0; i<cellZones.size(); ++i)
350 CCellZone *czone = cellZones[i];
351 if (!czone) continue;
352 for (uint j=0; j<czone->cells().size(); ++j)
354 CCell *cell = czone->cells()[j];
355 if (!cell) continue;
356 // bound the point into the cell
357 for (uint k=0; k<cell->npcZoneCount(); ++k)
359 CNpcZone *nz = cell->npcZone(k);
360 if (!nz)
361 continue;
363 for (uint l=0; l<nz->roads().size(); ++l)
365 nldebug("NpcZone '%s' host road '%s'", nz->getAliasTreeOwner().getName().c_str(), nz->roads()[l]->getName().c_str());
370 CAliasCont<CRoad> &roads = cell->roads();
371 for (uint i=0; i<roads.size(); ++i)
373 CRoad *road = roads[i];
374 if (!road)
375 continue;
376 // clear existing link;
377 nldebug("Road '%s' link from '%s' %s to '%s' %s", road->getName().c_str(),
378 road->startZone().isNULL() ? "none" : road->startZone()->getAliasTreeOwner().getName().c_str(),
379 road->startExternal() ? "(external)" : "",
380 road->endZone().isNULL() ? "none" : road->endZone()->getAliasTreeOwner().getName().c_str(),
381 road->endExternal() ? "(external)" : "");
391 return true;
394 bool dumpContinentImp(uint instanceIndex, const std::string &continentName, NLMISC::CLog &log);
395 // Dump the structure of a dynamic continent
396 NLMISC_COMMAND(dumpContinent, "dump the structure of a continent","<continentName> [<ai instance number = 0>]")
398 if (args.size() > 2 || args.size() < 1)
399 return false;
401 uint instanceIndex = 0;
403 if (args.size() == 2)
404 NLMISC::fromString(args[1], instanceIndex);
406 if (instanceIndex >= CAIS::instance().AIList().size())
408 log.displayNL("ai index %u is out of range ! (only %u ai instance)",
409 instanceIndex,
410 CAIS::instance().AIList().size());
411 return false;
414 return dumpContinentImp(instanceIndex, args[0], log);
417 bool dumpContinentImp(uint instanceIndex, const std::string &continentName, NLMISC::CLog &log)
419 CAIInstance *aii = CAIS::instance().AIList()[instanceIndex];
421 for (uint i=0; i<aii->continents().size(); ++i)
423 CContinent *cont = aii->continents()[i];
424 if (!cont) continue;
426 if (cont->getName()==continentName)
428 log.displayRawNL("Dumping continent '%s' (@ %p):",
429 cont->getName().c_str(),
430 cont);
432 for (uint j=0; j<cont->regions().size(); ++j)
434 CRegion *region = cont->regions()[j];
435 if (!region)
437 log.displayNL(" +- %u null entry", j);
438 continue;
441 log.displayNL(" +- Region '%s'%s @ %p",
442 region->getName().c_str(),
443 region->getAliasString().c_str(),
444 static_cast<CAliasTreeOwner*>(region));
446 for (uint k=0; k<region->cellZones().size(); ++k)
448 CCellZone *cz = region->cellZones()[k];
449 if (!cz)
451 log.displayNL(" | +- %u null entry", k);
452 continue;
455 log.displayNL(" | +- CellZone '%s'%s @ %p",
456 cz->getName().c_str(),
457 cz->getAliasString().c_str(),
458 static_cast<CAliasTreeOwner*>(cz));
460 for (uint l=0; l<cz->cells().size(); ++l)
462 CCell *cell = cz->cells()[l];
463 if (!cell)
465 log.displayNL(" | | +- %u null entry", l);
466 continue;
469 log.displayNL(" | | +- Cell '%s'%s @ %p",
470 cell->getName().c_str(),
471 cell->getAliasString().c_str(),
472 static_cast<CAliasTreeOwner*>(cell));
474 for (uint m=0; m<cell->npcZoneCount(); ++m)
476 CNpcZone *nz = cell->npcZone(m);
477 if (!nz)
479 log.displayNL(" | | | +- %u null entry", m);
480 continue;
483 // log.displayNL(" | | | +- NpcZone '%s' (alias A:%u @ %p)", nz->getName().c_str(), nz->getAlias(), static_cast<CAliasTreeOwner*>(nz));
484 log.displayNL(" | | | +- NpcZone '%s'%s",
485 nz->getAliasTreeOwner().getName().c_str(),
486 nz->getAliasTreeOwner().getAliasString().c_str());
490 for (uint k=0; k<cell->roads().size(); ++k)
492 CRoad *road = cell->roads()[k];
493 if (!road)
495 log.displayNL(" | | +- %u null entry", k);
496 continue;
499 log.displayNL(" | | +- Road '%s'%s @ %p",
500 road->getName().c_str(),
501 road->getAliasString().c_str(),
502 static_cast<CAliasTreeOwner*>(road));
505 for (uint m=0; m<cell->faunaZones().size(); ++m)
507 CFaunaZone *fz = cell->faunaZones()[m];
508 if (!fz)
510 log.displayNL(" | | | +- %u null entry", m);
511 continue;
514 log.displayNL(" | | | +- FaunaZone '%s'%s @ %p",
515 fz->getName().c_str(),
516 fz->getAliasString().c_str(),
517 static_cast<CAliasTreeOwner*>(fz));
523 // no more to do
524 return true;
528 log.displayNL("Can't find continent '%s' in ai instance %u",
529 continentName.c_str(),
530 instanceIndex);
532 return true;
537 // Load a collision map
538 NLMISC_COMMAND(loadContinent, "load a continent collision map","<landName>")
540 if (args.size() != 1)
541 return false;
543 CWorldContainer::loadContinent(args[0]);
545 return true;
549 CAIInstance *currentInstance = NULL;
551 NLMISC_COMMAND(createDynamicAIInstance, "Create a new dynamic AIInstance","")
553 if (args.size() != 1)
554 return false;
556 // find an unused continent id
557 uint32 in;
558 NLMISC::fromString(args[0], in);
559 if( !CAIS::instance().getAIInstance(in) )
561 std::string name= NLMISC::toString("ring_%d",in);
562 const int index = CAIS::instance().createAIInstance(name, in);
564 nlinfo("AIInstance %u created for continent '%s' (Instance Index : %u)", in, name.c_str(), index);
568 // activate the current AIInstance
569 currentInstance = CAIS::instance().getAIInstance(in); //CAIS::instance().getAIInstance(continentInstanceId);
570 CWorkPtr::aiInstance(currentInstance);
571 return true;
574 NLMISC_COMMAND(createStaticAIInstance, "Create a new static AIInstance for a given continent.","<continentName>")
576 if (args.size() != 1)
577 return false;
579 CUsedContinent &uc = CUsedContinent::instance();
581 const uint32 in = uc.getInstanceForContinent(args[0]);
582 if (in == std::numeric_limits<uint32>::max())
584 nlwarning("The continent '%s' is unknow or not active. Can't create instance, FATAL", args[0].c_str());
585 nlassert(in != ~0);
586 // nlassertex(in != ~0, ("The continent '%s' is unknow or not active. Can't create instance, FATAL", args[0].c_str()));
589 if (!CAIS::instance().getAIInstance(in))
591 const int index = CAIS::instance().createAIInstance(args[0], in);
592 nlinfo("AIInstance %u created for continent '%s' (Instance Index : %u)",
593 in, args[0].c_str(), index);
596 // activate the current AIInstance
597 currentInstance = CAIS::instance().getAIInstance(in); //CAIS::instance().getAIInstance(continentInstanceId);
598 return true;
601 NLMISC_COMMAND(autoConfig, "Automaticaly load collision map, create AIInstance and load the primitives","")
603 if (!args.empty())
604 return false;
606 CUsedContinent &uc = CUsedContinent::instance();
608 log.displayNL("AIS Auto config with %u continents...", uc.getContinents().size());
609 for (uint i=0; i<uc.getContinents().size(); ++i)
611 const CUsedContinent::TContinentInfo &ci = uc.getContinents()[i];
613 // translate logical continent name
614 const string &phyName = uc.getPhysicalContinentName(ci.ContinentName);
616 // load the collision map
617 ICommand::execute(toString("loadContinent %s", phyName.c_str()), log);
618 // create the AI Instance
619 ICommand::execute(toString("createStaticAIInstance %s", ci.ContinentName.c_str()), log);
620 // load the active maps
621 ICommand::execute(toString("loadMapsFromCommon %s_all", ci.ContinentName.c_str()), log);
624 return true;
627 bool getParameter(const std::string &srcStr, const std::string &keyWord, std::string &returnStr)
629 if (srcStr.find(keyWord)!=std::string::npos)
631 returnStr=srcStr.substr(keyWord.size(),std::string::npos);
632 return true;
634 returnStr=std::string();
635 return false;
638 //-------------------------------------------------------------------------
639 // set/get the energy value for a family (global version)
640 NLMISC_COMMAND(energy, "set or get the effective energy (affects group type).","[cellZone-<cellZoneName>] [family-<familyName>] [value-<value>] [detailled]")
642 std::string family;
643 std::string cellZoneName;
644 uint32 value=~0;
645 bool detailled=false;
647 CLogStringWriter stringWriter(&log);
650 for (uint32 i=0;i<args.size();i++)
652 const std::string &str=args[i];
653 string res;
655 if (getParameter(str,"cellZone-",res))
657 cellZoneName=res;
660 if (getParameter(str,"family-",res))
662 family = res;
665 if (getParameter(str,"value-",res))
667 float v=float(atof(res.c_str()));
668 clamp(v,0,1);
669 value =uint32(v * ENERGY_SCALE);
672 if (getParameter(str,"detailled",res))
674 detailled=true;
679 const CStringFilter familyFilter(family);
681 for (uint i=0; i<CAIS::instance().AIList().size(); ++i)
683 CAIInstance *aii = CAIS::instance().AIList()[i];
684 if (!aii)
685 continue;
687 for (uint j=0; j<aii->continents().size(); ++j)
689 CContinent *cont = aii->continents()[j];
690 if (!cont)
691 continue;
693 for (uint k=0; k<cont->regions().size(); ++k)
695 CRegion *r = cont->regions()[k];
696 if (!r)
697 continue;
699 for (uint l=0; l<r->cellZones().size(); ++l)
701 CCellZone *cz = r->cellZones()[l];
702 if (!cz)
703 continue;
705 if ( !cellZoneName.empty()
706 && cz->getAliasFullName()!=cellZoneName)
707 continue;
709 if (value==~0)
710 stringWriter.append("");
712 for (uint m=0; m<cz->_Families.size(); ++m)
714 CFamilyBehavior *fb = cz->_Families[m];
716 if (!fb)
717 // TODO
718 // || ( !family.empty()
719 // && familyFilter!=fb->getFamily().getFamilyName()))
721 continue;
724 if (value==~0) // not for affectation.
726 fb->displayLogOld (stringWriter, detailled);
728 else
730 fb->setEffectiveLevel (value);
737 return true;
741 class CDoOnFamily
743 public:
744 CDoOnFamily()
746 virtual ~CDoOnFamily()
748 virtual void doOnFamily (CFamilyBehavior *fb) const = 0;
749 virtual void doOnCellZone (CCellZone *cz) const = 0;
750 protected:
751 private:
755 bool doOnFamily (const std::vector<std::string> &args, CDoOnFamily *fam)
757 std::string family;
758 std::string cellZoneName;
760 for (uint32 i=0;i<args.size();i++)
762 const std::string &str=args[i];
763 string res;
765 if (getParameter(str,"cellZone-",res))
766 cellZoneName=res;
768 if (getParameter(str,"family-",res))
769 family = res;
772 const CStringFilter familyFilter(family);
774 FOREACH(aiiIt, CCont<CAIInstance>, CAIS::instance().AIList())
776 FOREACH(contIt, CCont<CContinent>, (*aiiIt)->continents())
778 FOREACH(rIt, CCont<CRegion>, (*contIt)->regions())
780 FOREACH(czIt, CCont<CCellZone>, (*rIt)->cellZones())
782 if ( !cellZoneName.empty()
783 && czIt->getAliasFullName()!=cellZoneName)
784 continue;
786 fam->doOnCellZone(*czIt);
788 FOREACH(fb, CCont<CFamilyBehavior>, czIt->_Families)
790 if ( !family.empty()
791 && familyFilter!=fb->getName())
792 continue;
794 fam->doOnFamily(*fb);
800 return true;
804 class CDoOnFamilyCommand
805 :public CDoOnFamily
807 public:
808 CDoOnFamilyCommand (const std::vector<std::string> &args, NLMISC::CLog &log)
809 :_stringWriter(&log)
811 _index=~0;
812 _value=-1;
813 _detailled=false;
814 for (uint32 i=0;i<args.size();i++)
816 const std::string &str=args[i];
817 string res;
818 if (getParameter(str,"index-",res))
819 NLMISC::fromString(res, _index);
820 if (getParameter(str,"value-",res))
821 _value=float(atof(res.c_str()));
822 _detailled|=getParameter(str,"detailled",res);
826 void doOnFamily(CFamilyBehavior *fb) const
828 if (_value==-1) // not for affectation.
830 fb->displayLogOld (_stringWriter, _detailled);
831 return;
833 if (_index==~0) // all indexs ?
835 for (uint32 nrjIndex=0;nrjIndex<4;nrjIndex++)
836 fb->setModifier (_value, nrjIndex);
837 return;
839 fb->setModifier (_value, (uint32)_index);
842 virtual void doOnCellZone(CCellZone *cz) const
844 if (_value==-1)
845 _stringWriter.append("");
847 protected:
848 private:
849 uint32 _index;
850 float _value;
851 bool _detailled;
852 mutable CLogStringWriter _stringWriter;
856 NLMISC_COMMAND(energyscalemodifier, "set or get the energy scale (affects group number).","[cellZone-<cellZoneName>] [family-<familyName>] [index-<index>] [value-<value>] [detailled]")
858 CDoOnFamilyCommand command(args, log);
859 return doOnFamily (args, &command);
862 NLMISC_COMMAND(energyScaleModifier2, "set or get the energy scale (affects group number).","[--cellZone=<cellZoneName>] [--family=<familyName>] [--index=<index>] [--value=<value>] [--detailled]")
864 std::string cellZoneName;
865 std::string familyName;
866 int index = -1;
867 float value = -1.f;
868 bool detailed = false;
869 for (size_t i=0; i<args.size(); ++i)
871 std::string const& str = args[i];
872 string res;
873 if (getParameter(str, "--cellZone=", res))
874 cellZoneName = res;
875 if (getParameter(str, "--family=", res))
876 familyName = res;
877 if (getParameter(str, "--index=", res))
878 fromString(res, index);
879 if (getParameter(str, "--value=", res))
880 fromString(res, value);
881 if (str == "--detailed")
882 detailed = true;
884 if (value<0.f)
886 // Display
887 std::vector<size_t> widths(10, 0);
888 CFamilyBehavior::checkLogHeadersWidths(widths, index, detailed);
889 FOREACH(itInstance, CCont<CAIInstance>, CAIS::instance().AIList())
891 FOREACH(itContinent, CCont<CContinent>, itInstance->continents())
893 FOREACH(itRegion, CCont<CRegion>, itContinent->regions())
895 FOREACH(itCellZone, CCont<CCellZone>, itRegion->cellZones())
897 CCellZone* cellZone = *itCellZone;
898 if (!cellZone || !cellZoneName.empty() && cellZone->getName()!=cellZoneName)
899 continue;
900 FOREACH(itFamilyBehavior, CCont<CFamilyBehavior>, cellZone->familyBehaviors())
902 CFamilyBehavior* familyBehavior = *itFamilyBehavior;
903 if (!familyBehavior || !familyName.empty() && familyBehavior->getName()!=familyName)
904 continue;
905 familyBehavior->checkLogWidths(widths, index, detailed);
911 CLogStringWriter stringWriter(&log);
912 CFamilyBehavior::displayLogLine(stringWriter, index, detailed, widths);
913 CFamilyBehavior::displayLogHeaders(stringWriter, index, detailed, widths);
914 CFamilyBehavior::displayLogLine(stringWriter, index, detailed, widths);
915 FOREACH(itInstance, CCont<CAIInstance>, CAIS::instance().AIList())
917 FOREACH(itContinent, CCont<CContinent>, itInstance->continents())
919 FOREACH(itRegion, CCont<CRegion>, itContinent->regions())
921 FOREACH(itCellZone, CCont<CCellZone>, itRegion->cellZones())
923 CCellZone* cellZone = *itCellZone;
924 if (!cellZone || !cellZoneName.empty() && cellZone->getName()!=cellZoneName)
925 continue;
926 FOREACH(itFamilyBehavior, CCont<CFamilyBehavior>, cellZone->familyBehaviors())
928 CFamilyBehavior* familyBehavior = *itFamilyBehavior;
929 if (!familyBehavior || !familyName.empty() && familyBehavior->getName()!=familyName)
930 continue;
931 familyBehavior->displayLog(stringWriter, index, detailed, widths);
937 CFamilyBehavior::displayLogLine(stringWriter, index, detailed, widths);
939 else
941 // Change value
943 return true;
948 NLMISC_COMMAND(globalEnergy, "set or get the effective energy for a family.","[<familyName> [<value>]]")
950 if (args.size() > 2)
951 return false;
953 string family;
955 CLogStringWriter stringWriter(&log);
957 if (args.size() > 0)
959 family=args[0];
962 uint32 value;
963 if (args.size() == 2)
965 float v = float(atof(args[1].c_str()));
966 clamp(v,0,1);
967 stringWriter.append("Setting effective energy level for '"+family+"' to "+toString(v));
968 value = uint32(v * ENERGY_SCALE);
971 for (uint i=0; i<CAIS::instance().AIList().size(); ++i)
973 CAIInstance *aii = CAIS::instance().AIList()[i];
974 if (!aii)
975 continue;
977 for (uint j=0; j<aii->continents().size(); ++j)
979 CContinent *cont = aii->continents()[j];
980 if (!cont)
981 continue;
983 for (uint k=0; k<cont->regions().size(); ++k)
985 CRegion *r = cont->regions()[k];
986 if (!r)
987 continue;
989 for (uint l=0; l<r->cellZones().size(); ++l)
991 CCellZone *cz = r->cellZones()[l];
992 if (!cz)
993 continue;
995 stringWriter.append("");
997 for (uint m=0; m<cz->_Families.size(); ++m)
999 CFamilyBehavior *fb = cz->_Families[m];
1000 if (!fb)
1001 continue;
1003 if (args.size() ==0
1004 || ( args.size() == 1
1005 && family == fb->getName())
1008 fb->displayLogOld (stringWriter, args.size()==1);
1009 continue;
1012 if ( args.size() == 2
1013 && family == fb->getName())
1015 fb->setEffectiveLevel(value);
1022 return true;
1025 //-------------------------------------------------------------------------
1026 // memory report
1027 // NLMISC_COMMAND(statMemory, "generate a memory usage statistic file","<begin|end>")
1028 // {
1029 // if (args.size() != 1)
1030 // return false;
1032 // CLogStringWriter stringWriter(&log);
1034 // if (args[0] == "begin")
1035 // {
1036 // stringWriter.append("Writing begin memory state in 'memory_report_begin.csv'...");
1037 // NLMEMORY::StatisticsReport("memory_report_begin.csv", false);
1038 // stringWriter.append("Memory stat Done.");
1039 // }
1040 // else if (args[0] == "end")
1041 // {
1042 // stringWriter.append("Writing end memory state report in 'memory_report_end.csv'...");
1043 // NLMEMORY::StatisticsReport("memory_report_end.csv", false);
1044 // stringWriter.append("Memory stat Done.");
1045 // }
1046 // else
1047 // return false;
1049 // return true;
1050 // }
1052 //-------------------------------------------------------------------------
1053 // set a group variable
1055 NLMISC_COMMAND(setGroupVar,"display the logic var of the group in the given AI Instance","<aiInstanceId> <group_name|group_alias> <varId> <value>")
1057 if (args.size()!=4)
1058 return false;
1060 CGroup *grp = NULL;
1062 CLogStringWriter stringWriter(&log);
1064 CAIInstance *aiInstance=NULL;
1066 uint32 aiInstanceId = NLMISC::atoui(args[0].c_str());
1067 if (aiInstanceId>CAIS::instance().AIList().size())
1069 stringWriter.append("Invalid AI Instance Number");
1070 return false;
1072 aiInstance=CAIS::instance().AIList()[aiInstanceId];
1073 if (!aiInstance)
1075 stringWriter.append("AI Instance do not exists");
1076 return false;
1081 // first, try to find the group by alias
1082 uint32 alias = NLMISC::atoui(args[1].c_str());
1083 if (alias != 0)
1085 grp = aiInstance->findGroup(alias);
1088 if (grp == NULL)
1090 /// try to find the group bt name
1091 std::vector<CGroup*> grps;
1092 aiInstance->findGroup(grps, args[1]);
1093 if (grps.size() > 1)
1095 std::string s;
1096 for (uint i=0; i<grps.size(); ++i)
1098 s += NLMISC::toString("%s ", grps[i]->aliasTreeOwner()->getAliasString().c_str());
1100 stringWriter.append("More than one group have name '"+args[1]+"', listing alias :");
1101 stringWriter.append(s);
1103 return false;
1105 else if (grps.empty())
1107 stringWriter.append("No group correspond to name '"+args[1]+"'");
1108 return false;
1110 else
1112 grp = grps.front();
1116 // retreive the varID.
1117 // uint32 varId = NLMISC::atoui(args[2].c_str());
1118 NLMISC::TStringId varId=CStringMapper::map(args[2]); // NLMISC::atoui(args[2].c_str());
1119 float value = float(atof(args[3].c_str()));
1122 CStateInstance *stateInstance=grp->getPersistentStateInstance();
1123 stringWriter.append(grp->aliasTreeOwner()->getName()+":"+toString(*varId)+" = "+toString(value)+" (old value : "+ toString(stateInstance->getLogicVar(varId))+" )");
1124 stateInstance->setLogicVar(varId, value);
1125 return true;
1129 //-------------------------------------------------------------------------
1130 // display group variable
1132 NLMISC_COMMAND(displayGroupVar,"display the logic var of the group in the given AI Instance","<aIInstanceId> <group_name|group_alias>")
1134 if (args.size()!=2)
1135 return false;
1137 CLogStringWriter stringWriter(&log);
1139 CAIInstance *aiInstance=NULL;
1141 uint32 aiInstanceId = NLMISC::atoui(args[0].c_str());
1142 if (aiInstanceId>CAIS::instance().AIList().size())
1144 stringWriter.append("Invalid AI Instance Number");
1145 return false;
1147 aiInstance=CAIS::instance().AIList()[aiInstanceId];
1148 if (!aiInstance)
1150 stringWriter.append("AI Instance do not exists");
1151 return false;
1156 CGroup *grp = NULL;
1158 // first, try to find the group by alias
1159 uint32 alias = NLMISC::atoui(args[1].c_str());
1160 if (alias != 0)
1162 grp = aiInstance->findGroup(alias);
1165 if (grp == NULL)
1167 /// try to find the group bt name
1168 std::vector<CGroup*> grps;
1169 aiInstance->findGroup(grps, args[1]);
1170 if (grps.size() > 1)
1172 std::string s;
1173 for (uint i=0; i<grps.size(); ++i)
1175 s += NLMISC::toString("%s ", grps[i]->aliasTreeOwner()->getAliasString().c_str());
1177 stringWriter.append("More than one group have name '"+args[1]+"', listing alias :");
1178 stringWriter.append(s);
1179 return false;
1181 else if (grps.empty())
1183 stringWriter.append("No group correspond to name '"+args[1]+"'");
1184 return false;
1186 else
1188 grp = grps.front();
1192 stringWriter.append("Logic var of group '"+grp->aliasTreeOwner()->getName()+"'");
1195 // parser les variables pour outputer le contenu ..
1198 const CStateInstance *stateInstance=grp->getPersistentStateInstance();
1200 string str;
1201 stateInstance->logicVarsToString(str);
1202 stringWriter.append(str);
1206 return true;
1211 //-------------------------------------------------------------------------
1212 // display the player teams data
1214 NLMISC_COMMAND(displayPlayerTeams,"display all the player teams"," [<-no_detail>]")
1216 bool noDetail = false;
1217 if (args.size()>1)
1218 return false;
1220 if ( !args.empty()
1221 && args[args.size()-1]=="-no_detail")
1222 noDetail = true;
1224 CCont<CAIInstance>::iterator it=CAIS::instance().AIList().begin(), itEnd=CAIS::instance().AIList().end();
1226 CLogStringWriter stringWriter(&log);
1228 while (it!=itEnd)
1230 std::vector<uint16> teamIds;
1231 CAIInstance *aiInstance=*it;
1232 aiInstance->getPlayerMgr()->getTeamIds(teamIds);
1234 if (teamIds.empty())
1236 continue;
1239 std::vector<uint16>::iterator first(teamIds.begin()), last(teamIds.end());
1240 for (; first != last; ++first)
1242 int id = *first;
1244 stringWriter.append("Player Team "+toString(id)+" :");
1246 if (!noDetail)
1248 const std::set<TDataSetRow> &team = aiInstance->getPlayerMgr()->getPlayerTeam(uint16(id));
1249 std::set<TDataSetRow>::const_iterator first(team.begin()), last(team.end());
1250 for (; first != last; ++first)
1252 stringWriter.append(" Row "+toString((*first).getIndex())+" : "+CMirrors::DataSet->getEntityId(*first).toString());
1257 ++it;
1259 return true;
1262 //-------------------------------------------------------------------------
1263 // set the escrot team ID for a group
1265 NLMISC_COMMAND(setEscortId,"set the escort team id for a group in the given aIInstance","<aIInstanceId> <teamId> <groupAlias>|<groupName>")
1267 if (args.size()!=3)
1268 return false;
1270 CLogStringWriter stringWriter(&log);
1272 CAIInstance *aiInstance=NULL;
1274 uint32 aiInstanceId = NLMISC::atoui(args[0].c_str());
1275 if (aiInstanceId>CAIS::instance().AIList().size())
1277 stringWriter.append("Invalid AI Instance Number");
1278 return false;
1280 aiInstance=CAIS::instance().AIList()[aiInstanceId];
1281 if (!aiInstance)
1283 stringWriter.append("AI Instance do not exists");
1284 return false;
1288 CGroup *grp = NULL;
1290 // first, try to find the group by alias
1291 uint32 alias = NLMISC::atoui(args[2].c_str());
1292 if (alias != 0)
1294 grp = aiInstance->findGroup(alias);
1297 if (grp == NULL)
1299 /// try to find the group bt name
1300 std::vector<CGroup*> grps;
1301 aiInstance->findGroup(grps, args[2]);
1302 if (grps.size() > 1)
1304 std::string s;
1305 for (uint i=0; i<grps.size(); ++i)
1307 s += NLMISC::toString("%s ", grps[i]->aliasTreeOwner()->getAliasString().c_str());
1309 stringWriter.append("More than one group have name '"+args[2]+"', listing alias :");
1310 stringWriter.append(s);
1311 return false;
1313 else if (grps.empty())
1315 stringWriter.append("No group correspond to name"+args[2]);
1316 return false;
1318 else
1320 grp = grps.front();
1324 uint16 teamId = uint16(NLMISC::atoui(args[1].c_str()));
1325 stringWriter.append("Setting escort teamId "
1326 +toString(teamId)
1327 +" on group '"
1328 +args[2]
1329 +"'"
1330 +grp->aliasTreeOwner()->getAliasString().c_str());
1331 grp->setEscortTeamId(teamId);
1333 return true;
1337 //-------------------------------------------------------------------------
1338 // buffered commands facility
1339 typedef vector<string> TCommand;
1340 typedef vector<TCommand> TCommandList;
1341 static vector<string> bufferedRetStrings;
1342 void clearBufferedRetStrings()
1344 bufferedRetStrings.clear();
1347 TCommandList setEventCommands;
1348 TCommandList scriptCommands;
1349 TCommandList scriptCommands2;
1350 TCommandList scriptCommandsBotById;
1351 TCommandList scriptCommandsGroupByName;
1352 TCommandList loadScriptCommands;
1354 bool execSetEvent( CStringWriter& stringWriter, TCommand const& args);
1355 bool execScript( CStringWriter& stringWriter, TCommand const& args);
1356 bool execScript2( CStringWriter& stringWriter, TCommand const& args);
1357 bool execScriptBotById( CStringWriter& stringWriter, TCommand const& args);
1358 bool execScriptGroupByName( CStringWriter& stringWriter, TCommand const& args);
1359 bool execLoadScript(CStringWriter& stringWriter, TCommand const& args);
1361 void execBufferedCommands()
1363 vector<string> retStrings;
1364 CArrayStringWriter sw(retStrings);
1366 FOREACHC(it, TCommandList, setEventCommands)
1368 execSetEvent(sw, *it);
1370 setEventCommands.clear();
1371 FOREACHC(it, TCommandList, scriptCommands)
1373 execScript(sw, *it);
1375 scriptCommands.clear();
1376 FOREACHC(it, TCommandList, scriptCommands2)
1378 execScript2(sw, *it);
1380 scriptCommands2.clear();
1381 FOREACHC(it, TCommandList, scriptCommandsBotById)
1383 execScriptBotById(sw, *it);
1385 scriptCommandsBotById.clear();
1386 FOREACHC(it, TCommandList, scriptCommandsGroupByName)
1388 execScriptGroupByName(sw, *it);
1390 scriptCommandsGroupByName.clear();
1391 FOREACHC(it, TCommandList, loadScriptCommands)
1393 execLoadScript(sw, *it);
1395 loadScriptCommands.clear();
1397 // Show ret commands
1398 FOREACHC(strIt, vector<string>, retStrings)
1399 nlwarning(strIt->c_str());
1400 bufferedRetStrings.insert(bufferedRetStrings.end(), retStrings.begin(), retStrings.end());
1404 //-------------------------------------------------------------------------
1405 // set a user event on a group
1406 bool execSetEvent(CStringWriter &stringWriter, const vector<string> &args)
1408 // Temporize setEvent commands.
1409 if ( args.size() != 3
1410 && !( args.size() == 4
1411 && args[1] == "-no_detail"))
1412 return false;
1414 CAIInstance *aiInstance=NULL;
1416 const uint32 aiInstanceId = NLMISC::atoui(args[0].c_str());
1417 if (aiInstanceId>CAIS::instance().AIList().size())
1419 stringWriter.append("Invalid AI Instance Number");
1420 return false;
1422 aiInstance=CAIS::instance().AIList()[aiInstanceId];
1423 if (!aiInstance)
1425 stringWriter.append("AI Instance do not exists");
1426 return false;
1431 bool noDetail = false;
1433 if (args.size() == 4)
1434 noDetail = true;
1436 uint32 eventId = NLMISC::atoui(args[1].c_str());
1437 NLMISC::clamp(eventId, 0u, 9u);
1439 CGroup *grp = NULL;
1441 // first, try to find the group by alias
1442 uint32 alias = NLMISC::atoui(args[2].c_str());
1443 if (alias != 0)
1445 grp = aiInstance->findGroup(alias);
1447 if (!grp)
1448 return false;
1450 stringWriter.append("Setting event "+toString(eventId)+" on groups '"+grp->aliasTreeOwner()->getName()+"' ("+toString(grp->getChildIndex())+")");
1451 grp->setEvent(eventId);
1452 return true;
1455 std::vector<CGroup*> grps;
1456 if (!grp)
1458 /// try to find the group bot name
1459 aiInstance->findGroup(grps, args[2]);
1460 if (grps.size() > 1)
1462 if (noDetail)
1464 std::string s;
1465 for (uint i=0; i<grps.size(); ++i)
1467 s += NLMISC::toString("%s ", grps[i]->aliasTreeOwner()->getAliasString().c_str());
1469 stringWriter.append("More than one group have name '"+args[2]+"', listing alias :");
1470 stringWriter.append(s);
1471 return false;
1474 else if (grps.empty())
1476 stringWriter.append("No group correspond to name "+ args[2]);
1477 return false;
1481 stringWriter.append("Setting event "+toString(eventId)+" on groups '"+args[2]+"'");
1483 for (uint i=0; i<grps.size(); ++i)
1484 grps[i]->setEvent(eventId);
1486 return true;
1489 NLMISC_COMMAND(setEvent,"set an event for a group in the given aIInstance [buffered]","<aIInstanceId> [<-no_detail>] <eventId> <groupAlias>|<groupName>")
1491 clearBufferedRetStrings();
1492 setEventCommands.push_back(args);
1493 return true;
1496 //-------------------------------------------------------------------------
1497 // executes a script on groups matching a specified filter (1st arg)
1498 bool execScript(CStringWriter& stringWriter, TCommand const& args)
1500 if (args.size()<1)
1501 return false;
1503 string const& groupName = args[0];
1504 typedef vector<CGroup*> TGroupContainer;
1505 TGroupContainer grps;
1507 /// try to find the group bot name
1508 buildFilteredGroupList(grps, groupName);
1509 if (grps.empty())
1511 stringWriter.append("No group correspond to name "+ groupName);
1512 return false;
1516 stringWriter.append("do script on groups '"+groupName+"'");
1518 if (args.size()>1)
1520 vector<string> codeLines;
1521 for (size_t i=1; i<args.size(); ++i)
1522 codeLines.push_back(args[i]);
1524 CSmartPtr<const CByteCode> codePtr = CCompiler::getInstance().compileCode(codeLines, "script Command");
1526 FOREACHC(itGrp, TGroupContainer, grps)
1528 CGroup* grp = *itGrp;
1529 if (grp->getPersistentStateInstance())
1530 grp->getPersistentStateInstance()->interpretCode(NULL, codePtr);
1533 else
1535 FOREACHC(itGrp, TGroupContainer, grps)
1537 CGroup* grp = *itGrp;
1538 if (grp->getPersistentStateInstance())
1540 stringWriter.append("Group: "+grp->getFullName());
1541 grp->getPersistentStateInstance()->dumpVarsAndFunctions(stringWriter);
1545 return true;
1548 //-------------------------------------------------------------------------
1549 // executes a script on groups containing a bot matching a specified filter (1st arg)
1550 bool execScript2(CStringWriter& stringWriter, TCommand const& args)
1552 if (args.size()<1)
1553 return false;
1555 string const& botName = args[0];
1556 typedef set<CGroup*> TGroupContainer;
1557 TGroupContainer grps;
1559 vector<CBot*> bots;
1560 /// try to find the bot name
1561 buildFilteredBotList(bots, botName);
1562 if (bots.empty())
1564 stringWriter.append("No bot correspond to name "+ botName);
1565 return false;
1567 else
1569 FOREACH(itBot, vector<CBot*>, bots)
1571 CBot* bot = *itBot;
1572 CGroup* group = bot->getOwner();
1573 // if (group->getOwner()==_EventNpcManager) // This would restrict the command to event groups
1574 grps.insert(group);
1579 stringWriter.append("do script on groups containing bot '"+botName+"'");
1581 if (args.size()>1)
1583 vector<string> codeLines;
1584 for (size_t i=1; i<args.size(); ++i)
1585 codeLines.push_back(args[i]);
1587 CSmartPtr<const CByteCode> codePtr = CCompiler::getInstance().compileCode(codeLines, "script2 Command");
1589 FOREACHC(itGrp, TGroupContainer, grps)
1591 CGroup* grp = *itGrp;
1592 if (grp->getPersistentStateInstance())
1593 grp->getPersistentStateInstance()->interpretCode(NULL, codePtr);
1596 else
1598 FOREACHC(itGrp, TGroupContainer, grps)
1600 CGroup* grp = *itGrp;
1601 if (grp->getPersistentStateInstance())
1603 stringWriter.append("Group: "+grp->getFullName());
1604 grp->getPersistentStateInstance()->dumpVarsAndFunctions(stringWriter);
1608 return true;
1611 //-------------------------------------------------------------------------
1612 // executes a script on groups containing a bot given its entity id
1613 bool execScriptBotById(CStringWriter& stringWriter, TCommand const& args)
1615 if (args.size()<2)
1616 return false;
1618 NLMISC::CEntityId botId = NLMISC::CEntityId(args[0]);
1619 if (botId==NLMISC::CEntityId::Unknown)
1620 return false;
1621 CAIEntityPhysical* entity = CAIEntityPhysicalLocator::getInstance()->getEntity(botId);
1622 CSpawnBotNpc* bot = dynamic_cast<CSpawnBotNpc*>(entity);
1623 if (!bot)
1624 return false;
1625 if (!bot->getPersistent().getOwner())
1626 return false;
1627 if (!bot->getPersistent().getOwner()->getPersistentStateInstance())
1628 return false;
1630 vector<string> codeLines;
1631 for (size_t i=1; i<args.size(); ++i)
1632 codeLines.push_back(args[i]);
1634 CSmartPtr<const CByteCode> codePtr = CCompiler::getInstance().compileCode(codeLines, "script2 Command");
1636 bot->getPersistent().getOwner()->getPersistentStateInstance()->interpretCode(NULL, codePtr);
1638 return true;
1641 //-------------------------------------------------------------------------
1642 // executes a script on groups containing a bot given its entity id
1643 bool execScriptGroupByName(CStringWriter& stringWriter, TCommand const& args)
1645 if (args.size()<2)
1646 return false;
1648 string const& groupName = args[0];
1649 // NLMISC::CEntityId botId = NLMISC::CEntityId(args[0]);
1650 // if (botId==NLMISC::CEntityId::Unknown)
1651 // return false;
1652 CGroupNpc* group = dynamic_cast<CGroupNpc*>(CAliasTreeOwnerLocator::getInstance()->getEntity(groupName));
1653 if (!group)
1654 return false;
1655 if (!group->getPersistentStateInstance())
1656 return false;
1658 vector<string> codeLines;
1659 for (size_t i=1; i<args.size(); ++i)
1660 codeLines.push_back(args[i]);
1662 CSmartPtr<const CByteCode> codePtr = CCompiler::getInstance().compileCode(codeLines, "script2 Command");
1664 group->getPersistentStateInstance()->interpretCode(NULL, codePtr);
1666 return true;
1669 NLMISC_COMMAND(getDatasetId,"get datasetid of bots with name matchiong the given filter", "<groupFilter>")
1671 if (args.size()!=1)
1672 return false;
1674 string const& botName = args[0];
1675 string DatasetIds;
1677 vector<CBot*> bots;
1678 /// try to find the bot name
1679 buildFilteredBotList(bots, botName);
1680 if (bots.empty())
1682 log.displayNL("ERR: No bot correspond to name %s", botName.c_str());
1683 return true;
1685 else
1687 FOREACH(itBot, vector<CBot*>, bots)
1689 CBot* bot = *itBot;
1690 CSpawnBot* spawnBot = bot->getSpawnObj();
1691 if (spawnBot!=NULL)
1692 DatasetIds += spawnBot->dataSetRow().toString()+"|";
1696 log.displayNL("%s", DatasetIds.c_str());
1697 return true;
1700 NLMISC_COMMAND(script,"execute a script for groups matching the given filter [buffered]","<groupFilter> <code>")
1702 clearBufferedRetStrings();
1703 scriptCommands.push_back(args);
1704 return true;
1707 NLMISC_COMMAND(script2,"execute a script for groups containing a bot matching the given filter [buffered]","<groupFilter> <code>")
1709 clearBufferedRetStrings();
1710 scriptCommands2.push_back(args);
1711 return true;
1714 NLMISC_COMMAND(scriptHex,"execute a hex-encoded script for a group in the given aIInstance [buffered]","<groupName> <hexcode>")
1716 vector<string> _args = args;
1717 _args[1] = scriptHex_decode(_args[1]);
1718 clearBufferedRetStrings();
1719 scriptCommands.push_back(_args);
1720 return true;
1723 static const char* hexEncoderTcl =
1724 "proc copy_encoded {} {"
1725 " # Get the args from the text fields"
1726 " set group [ .group.name get 1.0 end ]"
1727 " set script [ .script get 1.0 end ]"
1728 " # Initiate the AIS command"
1729 " set output [concat \"scriptHex\" ${group}]"
1730 " append output \" \""
1731 " # Convert the script itself into an hex string (-1 to remove trailing newline)"
1732 " for {set i 0} {$i < [string length $script]-1} {incr i} {"
1733 " # Get the character"
1734 " set c [string index $script $i]"
1735 " # Get its ascii value"
1736 " scan $c %c n"
1737 " # Print it as 2 hex digits"
1738 " append output [format %02x $n]"
1739 " }"
1740 " # Replace the clipboard with the AIS command"
1741 " clipboard clear"
1742 " clipboard append $output"
1745 "frame .group"
1746 "pack .group -anchor w -fill x"
1747 "label .group.label -text \"Group:\""
1748 "pack .group.label -side left"
1749 "text .group.name -height 1 -width 70"
1750 "pack .group.name -fill x"
1751 "text .script"
1752 "pack .script -fill both -expand 1"
1753 "button .button -text \"Copy encoded!\""
1754 "pack .button -side bottom"
1756 "bind .button <ButtonPress-1> {"
1757 " copy_encoded"
1761 NLMISC_COMMAND(hexEncoder,"prints a script that can be used to encode a text for use with scriptHex","<language>")
1763 if (args.size()!=1)
1764 return false;
1766 if (args[0]=="tcl")
1768 log.displayNL("%s", hexEncoderTcl);
1770 else
1772 log.displayNL("Invalid language name! Valid languages are: tcl");
1774 return true;
1777 //-------------------------------------------------------------------------
1778 // set a user event on a group
1779 bool execLoadScript(CStringWriter& stringWriter, vector<string> const& args)
1781 if (args.size()!=3)
1782 return false;
1784 CAIInstance* aiInstance = NULL;
1786 uint32 const aiInstanceId = NLMISC::atoui(args[0].c_str());
1787 if (aiInstanceId>CAIS::instance().AIList().size())
1789 stringWriter.append("Invalid AI Instance Number");
1790 return false;
1792 aiInstance=CAIS::instance().AIList()[aiInstanceId];
1793 if (!aiInstance)
1795 stringWriter.append("AI Instance do not exists");
1796 return false;
1800 bool noDetail = false;
1802 string const& groupName = args[1];
1803 std::vector<CGroup*> grps;
1805 /// try to find the group bot name
1806 aiInstance->findGroup(grps, groupName);
1807 if (grps.size() > 1)
1809 if (noDetail)
1811 std::string s;
1812 for (uint i=0; i<grps.size(); ++i)
1814 s += NLMISC::toString("%s ", grps[i]->aliasTreeOwner()->getAliasString().c_str());
1816 stringWriter.append("More than one group have name '"+groupName+"', listing alias :");
1817 stringWriter.append(s);
1818 return false;
1821 else if (grps.empty())
1823 stringWriter.append("No group correspond to name "+ groupName);
1824 return false;
1828 stringWriter.append("do script on groups '"+groupName+"'");
1832 NLMISC::CIFile file(NLMISC::CPath::lookup(args[2]));
1834 vector<string> lines;
1835 while (!file.eof())
1837 const size_t bufferSize = 4*1024;
1838 char buffer[bufferSize];
1839 file.getline(buffer, bufferSize);
1840 lines.push_back(buffer);
1842 // Compile the buffer
1843 CSmartPtr<const CByteCode> codePtr=CCompiler::getInstance().compileCode(lines, "script Command");
1845 // Interpret the code for each group
1846 FOREACHC(itGrp, vector<CGroup*>, grps)
1847 (*itGrp)->getPersistentStateInstance()->interpretCode(NULL, codePtr);
1849 catch (const EPathNotFound &)
1851 nlwarning("Path not found while loading AIS script %s", args[2].c_str());
1852 return false;
1854 return true;
1857 NLMISC_COMMAND(loadScript, "execute a script from a file for a group in the given aIInstance [buffered]", "<aIInstanceId> <groupName> <filename>")
1859 clearBufferedRetStrings();
1860 loadScriptCommands.push_back(args);
1861 return true;
1864 NLMISC_COMMAND(getInfo,"display returned values of buffered commands","")
1866 CLogStringWriter stringWriter(&log);
1868 FOREACHC(strIt, vector<string>, bufferedRetStrings)
1870 stringWriter.append(*strIt);
1873 return true;
1877 //-------------------------------------------------------------------------
1878 // DISPLAYING Managers, Groups and Bots
1880 static void displayNode(const CAIAliasDescriptionNode *node,uint indent=0)
1882 nlinfo("%*s- %s %-12s - %s",
1883 indent,
1885 node->getAliasString().c_str(),
1886 getName(node->getType()),
1887 node->fullName().c_str());
1888 for (uint i=0;i<node->getChildCount();++i)
1889 displayNode(node->getChild(i),indent+2);
1892 NLMISC_COMMAND(displayNodeTreeMgr,"display node tree for given manager(s)","<manager id>[...]")
1894 if(args.size()<1)
1895 return false;
1897 for (uint i=0;i<args.size();++i)
1899 CManager* ManagerPtr = CAIS::instance().tryToGetManager(args[i].c_str());
1900 if (ManagerPtr)
1902 nlinfo("Manager: %d",i);
1903 displayNode(ManagerPtr->getAliasTreeOwner()->getAliasNode());
1904 continue;
1906 nlwarning("Failed to find mgr: %s",args[i].c_str());
1908 return true;
1912 NLMISC_COMMAND(displayTarget,"display bot target status for given bot(s) or player(s)","<bot id>[...]")
1914 if(args.size() <1)
1915 return false;
1917 CLogStringWriter stringWriter(&log);
1919 for (uint i=0;i<args.size();++i)
1921 CAIEntityPhysical* EntityPtr = CAIS::instance().tryToGetEntityPhysical(args[i].c_str());
1922 if (!EntityPtr)
1924 // log.displayNL("=> can't find entity: %s", args[i].c_str());
1925 continue;
1928 CAIEntityPhysical *phys=EntityPtr->getTarget();
1930 if (!phys)
1932 log.displayNL("=> bot %s have no target", args[i].c_str());
1933 continue;
1936 bool found=false;
1938 switch (phys->getRyzomType())
1940 case RYZOMID::npc:
1941 case RYZOMID::creature:
1942 case RYZOMID::pack_animal:
1943 break;
1944 case RYZOMID::player:
1945 log.displayNL("=> target is a player");
1946 break;
1947 default:
1949 CSpawnBot* spawnBot=dynamic_cast<CSpawnBot*>(phys);
1950 if (spawnBot)
1952 vector<string> strings = spawnBot->getPersistent().getMultiLineInfoString();
1953 FOREACHC(itString, vector<string>, strings)
1954 log.displayNL("%s", itString->c_str());
1955 found=true;
1959 break;
1962 if (!found)
1964 log.displayNL("=> can't display information for the target of: %s", args[i].c_str());
1968 return true;
1971 NLMISC_COMMAND(displayVision3x3,"display 3x3 cell vision centred on a given coordinate in the given aIInstance","<aiInstance> <x><y>")
1973 if(args.size()!=3)
1974 return false;
1976 CAIInstance *aiInstance=NULL;
1978 uint32 aiInstanceId = NLMISC::atoui(args[0].c_str());
1979 if (aiInstanceId>CAIS::instance().AIList().size())
1981 log.displayNL("Invalid AI Instance Number");
1982 return false;
1984 aiInstance=CAIS::instance().AIList()[aiInstanceId];
1985 if (!aiInstance)
1987 log.displayNL("AI Instance do not exists");
1988 return false;
1992 double dx, dy;
1993 NLMISC::fromString(args[1], dx);
1994 NLMISC::fromString(args[2], dy);
1996 CAICoord x, y;
1997 x = dx;
1998 y = dy;
1999 log.displayNL("3x3 Vision around (%.3f,%.3f)", x.asDouble(), y.asDouble());
2001 uint32 botCount=0;
2002 uint32 plrCount=0;
2004 CAIVector position(x,y);
2007 CAIEntityMatrix<CPersistentOfPhysical>::CEntityIteratorRandom it;
2008 for (it=aiInstance->playerMatrix().beginEntities(CAIS::instance().matrixIterator3x3(),position);!it.end();++it)
2010 ++plrCount;
2011 // log.displayNL("=> PLR: %s (%s)", (*it).id().toString().c_str(), (*it).pos().toString().c_str());
2012 if ((*it).isSpawned())
2013 log.displayNL("=> (messageToChange)PLR: %d (%s)", (*it).getSpawnObj()->dataSetRow().getIndex(), (*it).getSpawnObj()->pos().toString().c_str());
2018 CAIEntityMatrix<CPersistentOfPhysical>::CEntityIteratorRandom it;
2019 for (it=aiInstance->botMatrix().beginEntities(CAIS::instance().matrixIterator3x3(),position);!it.end();++it)
2021 CPersistentOfPhysical &persRef=(*it);
2022 if (!persRef.isSpawned())
2023 continue;
2025 ++botCount;
2026 CBot* botPtr=NLMISC::safe_cast<CBot*>(&persRef);
2028 if (botPtr->getAliasTreeOwner())
2029 log.displayNL("=> BOT: %s (%s)", botPtr->getAliasTreeOwner()->getName().c_str(), persRef.getSpawnObj()->pos().toString().c_str());
2030 else
2031 log.displayNL("=> BOT: unknown (%s)", persRef.getSpawnObj()->pos().toString().c_str());
2033 // log.displayNL("=> BOT: %s (%s)", (*it).id().toString().c_str(), (*it).pos().toString().c_str());
2037 log.displayNL("Entites found: %d bots, %d players, total: %d", botCount, plrCount, botCount+plrCount);
2039 return true;
2042 NLMISC_COMMAND(displayVisionRadius,"display roughly 'radius' cell vision centred on a given coordinate in the given aIInstance","<aIInstance> <x><y>[<radius>=100]")
2044 if ( args.size()!=3
2045 && args.size()!=4 )
2046 return false;
2048 CAIInstance *aiInstance=NULL;
2050 uint32 aiInstanceId = NLMISC::atoui(args[0].c_str());
2051 if (aiInstanceId>CAIS::instance().AIList().size())
2053 log.displayNL("Invalid AI Instance Number");
2054 return false;
2056 aiInstance=CAIS::instance().AIList()[aiInstanceId];
2057 if (!aiInstance)
2059 log.displayNL("AI Instance do not exists");
2060 return false;
2064 uint32 dist=100;
2065 CAICoord x, y;
2066 x=atof(args[1].c_str());
2067 y=atof(args[2].c_str());
2068 if (args.size()==4)
2069 NLMISC::fromString(args[3], dist);
2070 log.displayNL("%dm Vision around (%.3f,%.3f)", dist, x.asDouble(), y.asDouble());
2072 uint32 botCount=0;
2073 uint32 plrCount=0;
2075 const CAIEntityMatrixIteratorTblLinear *tbl=CAIS::instance().bestLinearMatrixIteratorTbl(dist);
2077 CAIEntityMatrix<CPersistentOfPhysical>::CEntityIteratorLinear it;
2079 CAIVector position(x,y);
2080 for (it=aiInstance->playerMatrix().beginEntities(tbl,position);!it.end();++it)
2082 ++plrCount;
2083 const CPersistentOfPhysical& entityPtr = (*it);
2084 const CBotPlayer* const playerPtr=dynamic_cast<const CBotPlayer* const>(&entityPtr);
2085 if (!playerPtr)
2086 continue;
2088 // have to implement players.
2089 #ifdef NL_DEBUG
2090 nlwarning("Not Implemented");
2091 #endif
2092 // log.displayNL("=> PLR: %s (%s)", (*it).id().toString().c_str(), (*it).pos().toString().c_str());
2093 // log.displayNL("=> PLR: %s (%s)", (*it).id().toString().c_str(), (*it).pos().toString().c_str());
2096 for (it=aiInstance->botMatrix().beginEntities(tbl,position);!it.end();++it)
2098 if ((*it).isSpawned())
2100 ++botCount;
2101 // log.displayNL("=> BOT: %s (%s)", (*it).id().toString().c_str(), (*it).pos().toString().c_str());
2102 log.displayNL("=> (messageToChange)BOT: %d (%s)", (*it).getSpawnObj()->dataSetRow().getIndex(), (*it).getSpawnObj()->pos().toString().c_str());
2106 log.displayNL("Entites found: %d bots, %d players, total: %d", botCount, plrCount, botCount+plrCount);
2107 return true;
2113 NLMISC_COMMAND(countEntitesInVisionMatrix,"scan the vision matrix for entities in the given aiInstance","<aiInstance>")
2115 if (args.size()!=1)
2116 return false;
2118 CAIInstance *aiInstance=NULL;
2120 uint32 aiInstanceId = NLMISC::atoui(args[0].c_str());
2121 if (aiInstanceId>CAIS::instance().AIList().size())
2123 log.displayNL("Invalid AI Instance Number");
2124 return false;
2126 aiInstance=CAIS::instance().AIList()[aiInstanceId];
2127 if (!aiInstance)
2129 log.displayNL("AI Instance do not exists");
2130 return false;
2134 // build an iterator table for our scan
2135 CAIEntityMatrixIteratorTblRandom tbl;
2136 tbl.push_back(0,0);
2137 for (int i=0;i<256;++i)
2139 for (int j=0;j<255;++j)
2140 tbl.push_back(1,0);
2141 if (i<255)
2142 tbl.push_back(-255,1);
2145 // some variables
2146 CAIEntityMatrix<CPersistentOfPhysical>::CCellTblIteratorRandom it;
2147 uint32 botCount=0;
2148 uint32 plrCount=0;
2150 CAIVector position(0,0);
2151 // count entities in bot matrix
2152 for (it=aiInstance->botMatrix().beginCells(&tbl,position);!it.end();++it)
2154 for (CEntityListLink<CPersistentOfPhysical> *listLink=(*it)->next();listLink!=*it;listLink=listLink->next())
2155 ++botCount;
2158 // count entities in player matrix
2159 for (it=aiInstance->playerMatrix().beginCells(&tbl,position);!it.end();++it)
2161 for (CEntityListLink<CPersistentOfPhysical> *listLink=(*it)->next();listLink!=*it;listLink=listLink->next())
2162 ++plrCount;
2165 // display the results
2166 log.displayNL("Entites found: %d bots, %d players, total: %d", botCount, plrCount, botCount+plrCount);
2168 return true;
2172 //-------------------------------------------------------------------------
2173 // DISPLAYING Places
2175 NLMISC_COMMAND(displayPlaces,"display the list of places for specified manager","[<manager id>]")
2177 if(args.size() !=1)
2178 return false;
2180 // manager specified so lookup manager by name
2181 CMgrFauna* mgrFaunaPtr = dynamic_cast<CMgrFauna*>(CAIS::instance().tryToGetManager(args[0].c_str()));
2182 if (mgrFaunaPtr==NULL)
2183 return false;
2185 CLogStringWriter stringWriter(&log);
2187 CCont<CGroup >::iterator it = mgrFaunaPtr->groups().begin();
2188 CCont<CGroup >::iterator itEnd = mgrFaunaPtr->groups().end();
2189 while (it!=itEnd)
2191 NLMISC::safe_cast<CGrpFauna*>(*it)->displayPlaces(stringWriter);
2192 ++it;
2194 return true;
2198 //-------------------------------------------------------------------------
2199 // WATCHES FOR TRACKING MGR, GRP & BOT OBJECTS
2201 static std::string WATCH0,WATCH1,WATCH2,WATCH3,WATCH4,
2202 WATCH5,WATCH6,WATCH7,WATCH8,WATCH9;
2203 static std::string *watchStrings[]=
2205 &WATCH0,&WATCH1,&WATCH2,&WATCH3,&WATCH4,
2206 &WATCH5,&WATCH6,&WATCH7,&WATCH8,&WATCH9
2209 static CAIEntity* watchEntity[sizeof(watchStrings)/sizeof(watchStrings[0])];
2210 static uint watchIdx[sizeof(watchStrings)/sizeof(watchStrings[0])];
2212 NLMISC_VARIABLE(string, WATCH0, "watch string 0");
2213 NLMISC_VARIABLE(string, WATCH1, "watch string 1");
2214 NLMISC_VARIABLE(string, WATCH2, "watch string 2");
2215 NLMISC_VARIABLE(string, WATCH3, "watch string 3");
2216 NLMISC_VARIABLE(string, WATCH4, "watch string 4");
2217 NLMISC_VARIABLE(string, WATCH5, "watch string 5");
2218 NLMISC_VARIABLE(string, WATCH6, "watch string 6");
2219 NLMISC_VARIABLE(string, WATCH7, "watch string 7");
2220 NLMISC_VARIABLE(string, WATCH8, "watch string 8");
2221 NLMISC_VARIABLE(string, WATCH9, "watch string 9");
2224 bool FAUNA_GRAPH_USES_DEBUG_TIME = false;
2225 NLMISC_VARIABLE(bool, FAUNA_GRAPH_USES_DEBUG_TIME, "force fauna graph to use local time (for debug)");
2227 // global routine called by the service main update()
2229 void UpdateWatches()
2231 // if (!CAIS::initialised())
2232 // return;
2234 for (uint i=0;i<sizeof(watchStrings)/sizeof(watchStrings[0]);++i)
2236 if (watchEntity[i])
2237 *watchStrings[i] = watchEntity[i]->getOneLineInfoString();
2238 else
2239 *watchStrings[i] = string("<NULL ENTITY>");
2244 void removeFromWatch(CAIEntity *entity)
2246 for (uint i=0;i<sizeof(watchStrings)/sizeof(watchStrings[0]);++i)
2248 if (watchEntity[i]==entity)
2249 watchEntity[i]=NULL;
2255 NLMISC_COMMAND(setWatch,"setup one of the watch variables","<watch id> <mgr, grp or bot id> [<index>]")
2257 if (args.size()!=2 && args.size()!=3)
2258 return false;
2260 uint idx;
2261 NLMISC::fromString(args[0], idx);
2262 if ( toString(idx)!=args[0]
2263 || idx>=sizeof(watchStrings)/sizeof(watchStrings[0]))
2264 return false;
2266 CAIEntity* CAIEntityPtr = CAIS::instance().tryToGetAIEntity(args[1].c_str());
2268 if (!CAIEntityPtr)
2269 return true;
2271 watchEntity[idx]=CAIEntityPtr;
2273 if (args.size()==3)
2274 NLMISC::fromString(args[2], watchIdx[idx]);
2275 else
2276 watchIdx[idx]=0;
2277 return true;
2280 static bool setBotRecordHistory(std::vector<std::string> args,bool onOff)
2282 if (args.size()==0)
2284 CAIInstance* instancePtr = CAIS::instance().AIList().getNextValidChild();
2285 while (instancePtr!=NULL)
2287 CManager* mgrPtr = instancePtr->managers().getNextValidChild();
2288 while (mgrPtr!=NULL)
2290 CGroup* grpPtr=mgrPtr->getNextValidGroupChild();
2291 while (grpPtr!=NULL)
2293 grpPtr->getDebugHistory()->setRecording(onOff);
2295 CBot* botPtr = grpPtr->getNextValidBotChild();
2296 while (botPtr!=NULL)
2298 botPtr->getDebugHistory()->setRecording(onOff);
2300 botPtr=grpPtr->getNextValidBotChild(botPtr);
2302 grpPtr=mgrPtr->getNextValidGroupChild(grpPtr);
2304 mgrPtr=instancePtr->managers().getNextValidChild(mgrPtr);
2306 instancePtr=CAIS::instance().AIList().getNextValidChild(instancePtr);
2309 else
2311 CAIInstance* instancePtr = CAIS::instance().AIList().getNextValidChild();
2312 while (instancePtr!=NULL)
2314 CManager* mgrPtr = instancePtr->managers().getNextValidChild();
2315 while (mgrPtr!=NULL)
2317 CGroup* grpPtr=mgrPtr->getNextValidGroupChild();
2318 while (grpPtr!=NULL)
2320 if (onOff)
2321 grpPtr->getDebugHistory()->setRecording(onOff);
2323 CBot* botPtr = grpPtr->getNextValidBotChild();
2324 while (botPtr!=NULL)
2326 for (uint i=0;i<args.size();++i)
2327 if (NLMISC::nlstricmp(botPtr->getAliasTreeOwner()->getName(),args[i])==0)
2329 botPtr->getDebugHistory()->setRecording(onOff);
2331 botPtr=grpPtr->getNextValidBotChild(botPtr);
2333 grpPtr=mgrPtr->getNextValidGroupChild(grpPtr);
2335 mgrPtr=instancePtr->managers().getNextValidChild(mgrPtr);
2337 instancePtr=CAIS::instance().AIList().getNextValidChild(instancePtr);
2340 return true;
2343 NLMISC_COMMAND(botHistoryRecordBegin,"setup history recording for all or named entities","[<bot name> [...]]")
2345 return setBotRecordHistory(args,true);
2348 NLMISC_COMMAND(botHistoryRecordEnd,"setup history recording for all or named entities","[<bot name> [...]]")
2350 return setBotRecordHistory(args,false);
2353 NLMISC_COMMAND(botViewHistory,"view recorded history for named entity","<bot name>")
2355 if (args.size()==0)
2356 return false;
2358 CAIInstance* instancePtr = CAIS::instance().AIList().getNextValidChild();
2359 while (instancePtr!=NULL)
2361 CManager* mgrPtr = instancePtr->managers().getNextValidChild();
2362 while (mgrPtr!=NULL)
2364 CGroup* grpPtr=mgrPtr->getNextValidGroupChild();
2365 while (grpPtr!=NULL)
2367 CBot* botPtr = grpPtr->getNextValidBotChild();
2368 while (botPtr!=NULL)
2370 for (uint i=0;i<args.size();++i)
2372 if (NLMISC::nlstricmp(botPtr->getAliasTreeOwner()->getName(),args[i])==0)
2374 botPtr->getDebugHistory()->writeAsInfo();
2375 break; // don't need to write info more than one time.
2379 botPtr=grpPtr->getNextValidBotChild(botPtr);
2381 grpPtr=mgrPtr->getNextValidGroupChild(grpPtr);
2383 mgrPtr=instancePtr->managers().getNextValidChild(mgrPtr);
2385 instancePtr=CAIS::instance().AIList().getNextValidChild(instancePtr);
2387 return true;
2391 NLMISC_COMMAND(grpHistoryRecordLog,"toggle grp history recorder 'nlinfo' logging","")
2393 GrpHistoryRecordLog=!GrpHistoryRecordLog;
2395 nlinfo("GrpHistoryRecordLog: %s",GrpHistoryRecordLog?"ON":"OFF");
2396 return true;
2400 //-------------------------------------------------------------------------
2401 // DISPLAYING VISION OF FAUNA GROUPS
2403 NLMISC_COMMAND(displayFaunaGrpVision,"display the vision of a fauna group","<grp id>")
2405 return false;
2408 //-------------------------------------------------------------------------
2409 // MANIPULATING STATE OF FAUNA GROUPS
2411 NLMISC_COMMAND(advanceGrpState,"advance the group to the next state in its cycle","<grp id>")
2413 if(args.size() !=1)
2414 return false;
2416 CGrpFauna *grp=dynamic_cast<CGrpFauna *>(CAIS::instance().tryToGetGroup(args[0].c_str()));
2417 if (!grp)
2419 log.displayNL("Failed to identify group: %s",args[0].c_str());
2420 return true;
2422 if (!grp->isSpawned())
2424 log.displayNL("Group not spawned: %s",args[0].c_str());
2426 else
2428 grp->getSpawnObj()->resetTimer();
2430 return true;
2433 NLMISC_COMMAND(setGrpTimers,"set the timer values for a given group","<grp id> <eat time> <rest time>")
2435 if(args.size()!=3)
2436 return false;
2438 CGrpFauna *grp=dynamic_cast<CGrpFauna *>(CAIS::instance().tryToGetGroup(args[0].c_str()));
2439 if (!grp)
2441 log.displayNL("Failed to identify group: %s",args[0].c_str());
2442 return true;
2445 uint32 eatTime, restTime;
2446 NLMISC::fromString(args[1], eatTime);
2447 NLMISC::fromString(args[2], restTime);
2449 if (eatTime<1 || restTime<1)
2451 log.displayNL("Invalid time parameters");
2452 return true;
2455 grp->setTimer(CGrpFauna::EAT_TIME, eatTime*10);
2456 grp->setTimer(CGrpFauna::REST_TIME, restTime*10);
2457 return true;
2460 //-------------------------------------------------------------------------
2461 // RUNNING THE AI UPDATE FOR TESTING OFFLINE
2463 void cbTick();
2464 extern uint ForceTicks;
2466 NLMISC_COMMAND(updateAI,"call CAIS::update() (simulate a tick off-line)","[tick]")
2468 if(args.size() >1)
2469 return false;
2471 // if there's an argument make sure its a positive integer
2472 if (args.size()==1)
2474 uint tick;
2475 NLMISC::fromString(args[0], tick);
2476 if ((tick < 1) || (toString(tick)!=args[0]))
2477 return false;
2479 ForceTicks = tick;
2480 return true;
2483 cbTick();
2485 return true;
2490 NLMISC_COMMAND(addPetsToPlayer,"Add some pets specified with a sheet to the specified player.","<player id> <nb pets> <pet_sheet>")
2492 if ( args.size() !=3 )
2493 return false;
2495 #ifdef NL_DEBUG
2496 nlstopex(("Not Implemented"));
2497 #endif
2498 return true;
2501 //-------------------------------------------------------------------------
2502 // DISPLAYING FIGHT SHEET.
2504 NLMISC_COMMAND(displayFightSheet,"display the sheet","<sheet name>")
2506 if (args.size() !=1)
2508 log.displayNL("One argument needed");
2509 return false;
2512 AISHEETS::ICreatureCPtr sheet = AISHEETS::CSheets::getInstance()->lookup(CSheetId(args[0]));
2513 if (!sheet)
2515 log.displayNL("Unknown sheet %s", args[0].c_str());
2516 return true;
2518 if (sheet->SheetId()==NLMISC::CSheetId::Unknown)
2520 std::string creatureString=args[0]+std::string(".creature");
2521 sheet = /*const_cast<AISHEETS::ICreature*>(*/AISHEETS::CSheets::getInstance()->lookup(CSheetId(creatureString))/*)*/;
2524 if (sheet->SheetId()==NLMISC::CSheetId::Unknown)
2526 log.displayNL("Failed to identify sheet: %s",args[0].c_str());
2527 return false;
2530 log.displayNL("all these values are used to compute a score for a possible new target");
2531 log.displayNL("beware the fact that in this version we used 'level' to represent relative force, it may be changed, so don't take too much time tuning courage");
2533 log.displayNL("- DistModulator [0 n]: %f value=1/(1+distance*DistModulator)", sheet->DistModulator());
2534 log.displayNL("value means the distance sensitivity of the bot, equals to zero means the bot never mind the distance");
2536 log.displayNL("- TargetModulator [0 n]: %f value=1/(1+nbTarget*TargetModulator)", sheet->TargetModulator());
2537 log.displayNL("value means the number of attacker sensitivity of the bot, equals to zero means the bot never mind the number of attackers on the target");
2539 log.displayNL("- ScoreModulator [0 1]: %f score>ScoreModulator", sheet->ScoreModulator());
2540 log.displayNL("value means the minimum value (threshold) needed for the bot to attack, 0 means always, 1 never (also impossible)");
2542 log.displayNL("- FearModulator [0 1]: %f score>FearModulator", sheet->FearModulator());
2543 log.displayNL("value means the minimum value (threshold) needed for the bot to flee, 0 means always, 1 never (also impossible)");
2545 log.displayNL("- LifeLevelModulator [0 1]: %f value=LifeLevelModulator*lifeCoef+(1.f-LifeLevelModulator)*levelCoef", sheet->LifeLevelModulator());
2546 log.displayNL("value means the ratio between the life and level ratio, 1 means life is only take in count, 0 means level only take in count");
2548 log.displayNL("- CourageModulator [-n +n]: %f", sheet->CourageModulator());
2549 log.displayNL("value used to make a bot courageous or feared, -n the bot is feared, +n its courageous");
2551 log.displayNL("- GroupCohesionModulator [0 1]: %f", sheet->GroupCohesionModulator());
2552 log.displayNL("value used to make bots of a group aware of each other, 0 each bot is individual, 1 they fight in group");
2554 log.displayNL("- GroupDispersion [0 1]: %f", sheet->GroupDispersion());
2555 log.displayNL("value used to make bots of a group far or not of each other, 0 each all bots are at the same place, 1 they go everywere in the place");
2557 return true;
2562 // all these values are used to compute a score for a possible new target
2563 // beware the fact that in this version we used 'level' to represent relative force, it may be changed, so don't take too much time tuning courage
2565 // - DistModulator [0 n]: value=1/(1+distance*DistModulator)
2566 // value means the distance sensitivity of the bot, equals to zero means the bot never mind the distance
2568 // - TargetModulator [0 n]: value=1/(1+nbTarget*TargetModulator)
2569 // value means the number of attacker sensitivity of the bot, equals to zero means the bot never mind the number of attackers on the target
2571 // - ScoreModulator [0 1]: score>ScoreModulator
2572 // value means the minimum value (threshold) needed for the bot to attack, 0 means always, 1 never (also impossible)
2574 // - FearModulator [0 1]: score>FearModulator
2575 // value means the minimum value (threshold) needed for the bot to flee, 0 means always, 1 never (also impossible)
2577 // - LifeLevelModulator [0 1]: value=LifeLevelModulator*lifeCoef+(1.f-LifeLevelModulator)*levelCoef
2578 // value means the ratio between the life and level ratio, 1 means life is only take in count, 0 means level only take in count
2580 // - CourageModulator [-n +n]:
2581 // value used to make a bot courageous or feared, -n the bot is feared, +n its courageous
2583 // - GroupCohesionModulator [0 1]:
2584 // value used to make bots of a group aware of each other, 0 each bot is individual, 1 they fight in group
2586 NLMISC_COMMAND(setFightSheet,"change a value in the fight sheet","<sheet name> <value name> <value> (use name without 'modulator', ex: 'Dist')")
2588 if (args.size() !=3)
2590 log.displayNL("three argument needed");
2591 return false;
2594 AISHEETS::ICreature *sheet=const_cast<AISHEETS::CCreature*>(AISHEETS::CSheets::getInstance()->lookup(CSheetId(args[0])));
2595 if (sheet->SheetId==NLMISC::CSheetId::Unknown)
2597 std::string creatureString=args[0]+std::string(".creature");
2598 sheet=const_cast<AISHEETS::ICreature*>(AISHEETS::CSheets::getInstance()->lookup(CSheetId(creatureString)));
2601 if (sheet->SheetId==NLMISC::CSheetId::Unknown)
2603 log.displayNL("Failed to identify sheet: %s",args[0].c_str());
2604 return false;
2607 float value = float(atof(args[2].c_str()));
2609 if (NLMISC::nlstricmp(args[1].c_str(), "dist")==0)
2611 if (value<0)
2613 log.displayNL("Failed, out of bounds, values accepted are [0 +n]");
2614 return false;
2616 sheet->DistModulator=value;
2617 log.displayNL("Done, DistModulator=%f", value);
2618 return true;
2621 if (NLMISC::nlstricmp(args[1].c_str(), "target")==0)
2623 if (value<0)
2625 log.displayNL("Failed, out of bounds, values accepted are [0 +n]");
2626 return false;
2628 sheet->TargetModulator=value;
2629 log.displayNL("Done, TargetModulator=%f", value);
2630 return true;
2633 if (NLMISC::nlstricmp(args[1].c_str(), "score")==0)
2635 if (value<0 || value>1)
2637 log.displayNL("Failed, out of bounds, values accepted are [0 +1]");
2638 return false;
2640 sheet->ScoreModulator=value;
2641 log.displayNL("Done, ScoreModulator=%f", value);
2642 return true;
2645 if (NLMISC::nlstricmp(args[1].c_str(), "fear")==0)
2647 if (value<0 || value>1)
2649 log.displayNL("Failed, out of bounds, values accepted are [0 +1]");
2650 return false;
2652 sheet->FearModulator=value;
2653 log.displayNL("Done, FearModulator=%f", value);
2654 return true;
2657 if (NLMISC::nlstricmp(args[1].c_str(), "LifeLevel")==0)
2659 if (value<0 || value>1)
2661 log.displayNL("Failed, out of bounds, values accepted are [0 +1]");
2662 return false;
2664 sheet->LifeLevelModulator=value;
2665 log.displayNL("Done, LifeLevelModulator=%f", value);
2666 return true;
2669 if (NLMISC::nlstricmp(args[1].c_str(), "Courage")==0)
2671 sheet->CourageModulator=value;
2672 log.displayNL("Done, CourageModulator=%f", value);
2673 return true;
2676 if (NLMISC::nlstricmp(args[1].c_str(), "GroupCohesion")==0)
2678 if (value<0 || value>1)
2680 log.displayNL("Failed, out of bounds, values accepted are [0 +1]");
2681 return false;
2683 sheet->GroupCohesionModulator=value;
2684 log.displayNL("Done, GroupCohesionModulator=%f", value);
2685 return true;
2688 if (NLMISC::nlstricmp(args[1].c_str(), "GroupDispersion")==0)
2690 if (value<0 || value>1)
2692 log.displayNL("Failed, out of bounds, values accepted are [0 +1]");
2693 return false;
2695 sheet->GroupDispersion=value;
2696 log.displayNL("Done, GroupDispersion=%f", value);
2697 return true;
2700 log.displayNL("Failed to identify %s", args[1].c_str());
2701 return false;
2704 static void botSetPosition(CBot* bot, std::vector<std::string> const& args, std::string const& botid, float x, float y, uint z, NLMISC::CLog& log)
2706 CSpawnBot* spawnBot = bot->getSpawnObj();
2707 if (spawnBot!=NULL)
2709 std::string botname = bot->getAliasTreeOwner()->getName();
2710 NLMISC::CEntityId eid = spawnBot->getEntityId();
2711 std::string eidstr = eid.toString();
2712 if (botid=="*" || (botname!="")&&(botname.find(botid)!=std::string::npos) || eidstr.find(botid)!=std::string::npos)
2714 CAIPosMirror p = spawnBot->pos();
2715 if (args.size()>0)
2717 if (args.size()==3)
2718 z = p.h();
2719 spawnBot->setPos(CAIPos(x, y, z, p.theta()));
2721 p = spawnBot->pos();
2722 if (botname!="")
2723 log.displayNL("Bot position for %s %s is %f;%f;%d", eidstr.c_str(), botname.c_str(), p.x().asDouble(), p.y().asDouble(), p.h());
2724 else
2725 log.displayNL("Bot position for %s is %f;%f;%d", eidstr.c_str(), p.x().asDouble(), p.y().asDouble(), p.h());
2730 static void botSetPosition(CGroup* grp, std::vector<std::string> const& args, std::string const& botid, float x, float y, uint z, NLMISC::CLog& log)
2732 FOREACH (itBot, CCont<CBot>, grp->bots())
2734 botSetPosition(*itBot, args, botid, x, y, z, log);
2738 static void botSetPosition(CManager* mgr, std::vector<std::string> const& args, std::string const& botid, float x, float y, uint z, NLMISC::CLog& log)
2740 FOREACH (itGroup, CCont<CGroup>, mgr->groups())
2742 botSetPosition(*itGroup, args, botid, x, y, z, log);
2746 NLMISC_COMMAND(botSetPosition,"set the position of one or several bots","<eid> [<x> <y> [<z>]]")
2748 if (args.size()!=1 && args.size()!=3 && args.size()!=4)
2749 return false;
2751 std::string botid = args[0];
2752 float x = 0.f;
2753 float y = 0.f;
2754 uint z = 0;
2755 if (args.size()>1)
2757 x = (float)atof(args[1].c_str());
2758 y = (float)atof(args[2].c_str());
2759 if (args.size()==4)
2760 NLMISC::fromString(args[3], z);
2763 // For each bot
2764 FOREACH (itInstance, CCont<CAIInstance>, CAIS::instance().AIList())
2766 FOREACH (itManager, CCont<CManager>, itInstance->managers())
2768 botSetPosition(*itManager, args, botid, x, y, z, log);
2770 FOREACH (itCont, CCont<CContinent>, itInstance->continents())
2772 FOREACH (itRegion, CCont<CRegion>, itCont->regions())
2774 FOREACH (itCellZone, CCont<CCellZone>, itRegion->cellZones())
2776 FOREACH (itFamilyBehavior, CCont<CFamilyBehavior>, itCellZone->familyBehaviors())
2778 botSetPosition(itFamilyBehavior->mgrNpc(), args, botid, x, y, z, log);
2779 botSetPosition(itFamilyBehavior->mgrFauna(), args, botid, x, y, z, log);
2785 return true;
2788 NLMISC_COMMAND(helpAboutId, "display a short explanation about id used in ai commands", "")
2790 log.displayNL("AI Identifier are a string composed as follow :");
2791 log.displayNL(" [AIS_<serice_id>:]{[<instance_idx>][:mgr_idx][:grp_idx][:bot_idx] | dyn_<cont_idx>[:<region_idx>][:<cellzone_idx>][:<family_idx>][:fauna|:npc]}");
2792 log.displayNL(" e.g. : - AIS_138:1:2:3:4 for a 'static' bot");
2793 log.displayNL(" - AIS_138:dyn_0:2:3:4:npc for a 'dynmaic' npc manager");
2794 log.displayNL("The initial 'AIS_<serivce_id>:' is optional.");
2795 log.displayNL("Most of the commands that need an AI id support 'multi selection' by specifying only part of the id.");
2796 return true;
2799 NLMISC_COMMAND(despawnEntity, "despawn an entity.","[entityId]")
2801 if (args.size()!=1)
2802 return false;
2804 const std::string &entityStr=args[0];
2805 const CEntityId entity(entityStr.c_str());
2807 const TDataSetRow dataSetRow=TheDataset.getDataSetRow(entity);
2809 CAIEntityPhysical *const phys=CAIS::instance().getEntityPhysical(dataSetRow);
2811 if (!phys) { return true;}
2813 switch(phys->getRyzomType())
2815 case RYZOMID::creature:
2816 case RYZOMID::npc:
2818 CSpawnBot *const bot=safe_cast<CSpawnBot*>(phys);
2819 if (!bot)
2820 break;
2822 bot->getPersistent().getGroup().bots().removeChildByIndex(bot->getPersistent().getChildIndex());
2824 break;
2825 case RYZOMID::pack_animal:
2827 CSpawnBotPet *const pet=safe_cast<CSpawnBotPet*>(phys);
2828 if (!pet)
2829 break;
2831 pet->getPersistent().setDespawn();
2833 break;
2834 default:
2835 break;
2838 return true;
2841 /* Unload a primitive file
2842 * Unreference all the managers and the regions that are registered for this file.
2844 NLMISC_COMMAND(unloadPrimitiveFile,"unload a primitive file","<file name>")
2846 if (args.size()!=1)
2847 return false;
2849 // Get the string ID
2850 const NLMISC::TStringId stringId=NLMISC::CStringMapper::map(CFile::getFilenameWithoutExtension(CFile::getFilename(args[0])));
2852 uint managerUnreferenced = 0;
2853 uint continentUnreferenced = 0;
2855 // Parse AI instance
2856 CAIInstance *aiInstance = CWorkPtr::aiInstance();
2857 if (aiInstance)
2859 // Parse managers
2860 uint i;
2861 for (i=0; i<aiInstance->managers().size(); i++)
2863 CSmartPtr<CManager> manager=aiInstance->managers()[i];
2864 if (manager)
2866 // Remove this manager
2867 if (manager->isRegisteredForFile (stringId))
2869 aiInstance->managers().removeChildByIndex (i);
2870 managerUnreferenced++;
2872 // Check the pointer is not referenced anymore
2873 nlassert (manager->getRefCount() == 1);
2878 // Parse continents
2879 for (i=0; i<aiInstance->continents().size(); i++)
2881 CContinent *continent=aiInstance->continents()[i];
2882 if (continent)
2884 // Parse regions
2885 uint j;
2886 for (j=0; j<continent->regions().size(); j++)
2888 CSmartPtr<CRegion> region=continent->regions()[j];
2889 if (region)
2891 // Remove this region
2892 if (region->isRegisteredForFile (stringId))
2894 continent->regions().removeChildByIndex (j);
2895 continentUnreferenced++;
2897 // Check the pointer is not referenced anymore
2898 nlassert (region->getRefCount() == 1);
2904 aiInstance=CAIS::instance().AIList().getNextValidChild(aiInstance);
2905 uint32 primAlias = LigoConfig.getFileStaticAliasMapping(CFile::getFilename(args[0]));
2906 nldebug("<unloadPrimitiveFile> Sending alias '%u' to AIS for custom data range deletion", primAlias);
2907 CAIUserModelManager::getInstance()->deleteCustomDataByPrimAlias(primAlias);
2908 log.displayNL("unloadPrimitiveFile %s : %d manager removed, %d region removed", args[0].c_str(), managerUnreferenced, continentUnreferenced);
2910 else
2911 log.displayNL("unloadPrimitiveFile failed : no active ai instance");
2913 return true;
2916 //////////////////////////////////////////////////////////////////////////////
2917 // Bug simulation //
2918 //////////////////////////////////////////////////////////////////////////////
2920 static bool bugSimulationInited = false;
2921 static bool bugSimulationTextInited = false;
2922 static int const bugSimulationCount = 10;
2923 static bool simulateBugs[bugSimulationCount];
2924 static char const* simulateBugTexts[bugSimulationCount];
2926 inline
2927 static void initBugSimulations()
2929 if (!bugSimulationInited)
2931 bugSimulationInited = true;
2932 for (int i=0; i<bugSimulationCount; ++i)
2934 simulateBugs[i] = false;
2939 inline
2940 static void initBugSimulationTexts()
2942 if (!bugSimulationTextInited)
2944 bugSimulationTextInited = true;
2945 for (int i=0; i<bugSimulationCount; ++i)
2946 simulateBugTexts[i] = "[No bug with this id] ";
2948 simulateBugTexts[0] = "Bots didn't use range weapons ";
2949 simulateBugTexts[1] = "Assign. a string var in another group ";
2950 simulateBugTexts[2] = "Destination reach detection was delayed ";
2951 simulateBugTexts[3] = "Npc grp behav. wasn't updtd often enough ";
2952 simulateBugTexts[4] = "User event only worked in AI instance 0 ";
2953 simulateBugTexts[5] = "Mektoubs following in Water ";
2954 simulateBugTexts[6] = "When looted, fauna respawned immediately ";
2955 simulateBugTexts[7] = "Added a member init. in normal profile ";
2956 simulateBugTexts[8] = "Repulsion vector calc. was misordered ";
2960 inline
2961 static char const* simulateBugText(int bugId)
2963 initBugSimulations();
2964 if (bugId>=0 && bugId<bugSimulationCount)
2965 return simulateBugTexts[bugId];
2966 else
2967 return NULL;
2970 /// Past this declaration where needed
2971 extern bool simulateBug(int bugId);
2973 bool simulateBug(int bugId)
2975 initBugSimulations();
2976 if (bugId>=0 && bugId<bugSimulationCount)
2977 return simulateBugs[bugId];
2978 else
2979 return false;
2982 NLMISC_COMMAND(simulateBug, "simulate an old AIS bug; command is one of 'list', 'enable', 'disable'; enable and disable take as command_arg the id of the bug to simulate","<command> [<command_arg>]")
2985 if (args.size()>=1)
2987 if (args[0] == "list")
2989 if (args.size()==1)
2991 initBugSimulations();
2992 initBugSimulationTexts();
2993 log.displayNL("Bug simulations");
2994 log.displayNL("Id|Description |State");
2995 for (int i=0; i<bugSimulationCount; ++i)
2997 log.displayNL("%02d|%s|%s", i, simulateBugText(i), simulateBugs[i]?"on":"off");
2999 return true;
3002 else if (args[0] == "enable")
3004 if (args.size()==2)
3006 initBugSimulations();
3007 if (args[1]=="all")
3009 for (int i=0; i<bugSimulationCount; ++i)
3010 simulateBugs[i] = true;
3012 else
3014 sint i;
3015 NLMISC::fromString(args[1], i);
3016 if (i>=0 && i<bugSimulationCount)
3017 simulateBugs[i] = true;
3018 else
3019 log.displayNL("No bug simulation with id %02d", i);
3021 return true;
3024 else if (args[0] == "disable")
3026 if (args.size()==2)
3028 initBugSimulations();
3029 if (args[1]=="all")
3031 for (sint i=0; i<bugSimulationCount; ++i)
3032 simulateBugs[i] = false;
3034 else
3036 sint i;
3037 NLMISC::fromString(args[1], i);
3038 if (i>=0 && i<bugSimulationCount)
3039 simulateBugs[i] = false;
3040 else
3041 log.displayNL("No bug simulation with id %02d", i);
3043 return true;
3047 return false;
3051 static void displayTime(const CRyzomTime &rt, NLMISC::CLog &log)
3053 std::string result;
3054 result = NLMISC::toString("hh:mm = %d:%d; ", (int) floorf(rt.getRyzomTime()) , (int) floorf(60.f * fmodf(rt.getRyzomTime(), 1.f)));
3055 log.displayNL(result.c_str());
3056 uint32 month = rt.getRyzomMonth();
3057 MONTH::EMonth monthInCycle = rt.getRyzomMonthInCurrentCycle();
3058 std::string monthName = MONTH::toString((MONTH::EMonth) monthInCycle);
3059 uint32 dayOfMonth = rt.getRyzomDayOfMonth();
3060 std::string dayName = WEEKDAY::toString((WEEKDAY::EWeekDay) rt.getRyzomDayOfWeek());
3061 result = NLMISC::toString("mm:dd:yy = %d:%d:%d (%s:%s)",
3062 (int) (month + 1),
3063 (int) (dayOfMonth + 1),
3064 (int) rt.getRyzomYear(),
3065 monthName.c_str(),
3066 dayName.c_str());
3067 log.displayNL(result.c_str());
3068 log.displayNL("day of year = %d/%d", (int) (rt.getRyzomDayOfYear() + 1), (int) RYZOM_YEAR_IN_DAY);
3069 log.displayNL("season = %d/4 (%s)", (int) rt.getRyzomSeason() + 1, EGSPD::CSeason::toString(rt.getRyzomSeason()).c_str());
3072 NLMISC_COMMAND(time, "Display current time.", "<>")
3074 if (!args.empty()) return false;
3075 const CRyzomTime &rt = CTimeInterface::getRyzomTime();
3076 displayTime(rt, log);
3077 return true;
3080 NLMISC_COMMAND(localTime, "Display current local time (debug time).", "<>")
3082 if (!args.empty()) return false;
3083 const CRyzomTime &rt = CTimeInterface::getRyzomDebugTime();
3084 displayTime(rt, log);
3085 return true;
3089 struct CRyzomDate
3091 float Time;
3092 uint Day;
3093 uint Year;
3096 static void getRyzomDebugDate(CRyzomDate &rd)
3098 const CRyzomTime &rt = CTimeInterface::getRyzomDebugTime();
3099 rd.Time = rt.getRyzomTime();
3100 rd.Day = rt.getRyzomDayOfYear();
3101 rd.Year = rt.getRyzomYear();
3104 static void setRyzomDebugDate(CRyzomDate &rd)
3106 CRyzomTime &rt = CTimeInterface::getRyzomDebugTime();
3107 rt.updateRyzomClock((uint32) (rd.Time * RYZOM_HOURS_IN_TICKS) + (rd.Day + rd.Year * RYZOM_YEAR_IN_DAY) * RYZOM_DAY_IN_TICKS);
3110 NLMISC_COMMAND(setDebugHour, "set the current debug hour", "<hour>")
3112 if (args.size() != 1) return false;
3113 sint hour;
3114 if (!fromString(args[0], hour)) return false;
3115 CRyzomDate rd;
3116 getRyzomDebugDate(rd);
3117 rd.Time = fmodf(rd.Time, 1.f) + (float) hour;
3118 setRyzomDebugDate(rd);
3119 return true;
3122 NLMISC_COMMAND(setDebugDayOfYear, "set the current debug day of year (first day has index 1)", "<day>")
3124 if (args.size() != 1) return false;
3125 sint day;
3126 if (!fromString(args[0], day)) return false;
3127 CRyzomDate rd;
3128 getRyzomDebugDate(rd);
3129 rd.Day = day - 1; // for the user, days start at '1'
3130 setRyzomDebugDate(rd);
3131 return true;
3135 // setPersistentVar setname:varName value
3137 NLMISC_COMMAND(setPersistentVar, "sets an AI script persistent var", "<command> [<command_arg>]")
3139 if (args.size() == 2)
3141 std::string varName = args[0].c_str();
3142 std::string value = args[1].c_str();
3144 CAIScriptDataManager::getInstance()->setVar(varName, value);
3146 log.displayNL("Var '%s' set to '%s'", varName.c_str(), value.c_str());
3147 return true;
3150 return false;
3154 // listPersistentVar
3156 NLMISC_COMMAND(listPersistentVar, "display all persistent vars", "")
3158 if (!args.empty()) return false;
3160 const CPersistentVariables &persistentVar = CAIScriptDataManager::getInstance()->getPersistentVariables();
3162 const TVariableSets &variableSet = persistentVar.getVariableSet();
3164 for (TVariableSets::const_iterator i = variableSet.begin(); i != variableSet.end(); ++i)
3166 log.displayNL("#Set: '%s'#", i->first.c_str());
3167 for (TVariables::const_iterator j = i->second.Variables.begin(); j != i->second.Variables.end(); ++j)
3169 log.displayNL("Name: '%s' -- Value: '%s'", j->first.c_str(), j->second.c_str());
3173 return true;
3178 // getPersistentVar setname:varname
3180 NLMISC_COMMAND(getPersistentVarAsString, "get a persistent ai var", "")
3182 if (args.size() == 1)
3184 std::string varName = args[0];
3186 std::string value = CAIScriptDataManager::getInstance()->getVar_s(varName);
3187 log.displayNL("Variable '%s' has value '%s'", varName.c_str(), value.c_str() );
3188 return true;
3191 return false;
3195 // getPersistentVar setname:varname
3197 NLMISC_COMMAND(getPersistentVarAsFloat, "get a persistent ai var", "")
3199 if (args.size() == 1)
3201 std::string varName = args[0];
3203 float value = CAIScriptDataManager::getInstance()->getVar_f(varName);
3204 nlinfo("Variable '%s' has value '%f'", varName.c_str(), value );
3205 return true;
3208 return false;
3211 NLMISC_COMMAND(deletePersistentVar, "deletes an AI script persistent var", "")
3213 if (args.size() == 1)
3215 std::string varName = args[0].c_str();
3217 CAIScriptDataManager::getInstance()->deleteVar(varName);
3219 log.displayNL("Var '%s' deleted", varName.c_str());
3220 return true;
3223 return false;
3227 //----------------------------------------------------------------------------