Added ai command setEquipment
[ryzomcore.git] / ryzom / server / src / ai_service / ais_user_models.cpp
blob06871dd870ddb00a3f531d1d20fbc4f912d57d4c
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/>.
17 #include "stdpch.h"
18 #include "ais_user_models.h"
19 #include "ai_instance.h"
20 #include "ais_actions.h"
21 #include "nel/misc/sstring.h"
22 #include "nel/misc/algo.h"
26 using namespace std;
27 using namespace NLMISC;
28 using namespace NLNET;
29 using namespace AITYPES;
30 using namespace CAISActionEnums;
32 /**
33 * This manager is used by the dynamic creature system, allowing leveldesigners to modify a npc's basesheet attributes,
34 * or to define custom loot tables.
35 * First, the primitive is parsed in order to find usermodels and/or custom loot tables (see primitive_parser.cpp,
36 * methods: parsePrimCustomLootTable, parsePrimUserModelList).
37 * The datas are stored in a specific class (CSCriptData for userModels, CCustomLootTableManager for clt). These classes
38 * are defined in game_share so that they can be re-used egs side.
39 * The datas are then sent to EGS, trough 2 AIActions "USR_MDL" for user models and "CUSTOMLT" for custom loot tables
40 * The real objects CDynamicSheet and CLootTables are built egs-side by the egs CDynamicSheetManager.
44 CAIUserModelManager* CAIUserModelManager::_instance = 0;
46 /************************************************************************/
47 /* UTILS */
48 /************************************************************************/
49 void stripWhitespaces(std::string& str)
51 if(str.empty()) return;
53 string::size_type startIndex = str.find_first_not_of(" ");
54 string::size_type endIndex = str.find_last_not_of(" ");
55 std::string tmp = str;
56 str.erase();
58 str = tmp.substr(startIndex, (endIndex-startIndex+ 1) );
62 std::string removeComment(const std::string &str)
64 string::size_type newPos= str.find("//",0);
66 if (newPos != string::npos)
68 if (newPos == 0)
69 return "";
70 else
71 return str.substr(0, newPos);
73 return str;
77 /************************************************************************/
78 /* AI_ACTIONS */
79 /************************************************************************/
81 /**
82 * used to send usermodels to EGS
84 DEFINE_ACTION(ContextGlobal,USR_MDL)
86 //not true anymore : primAlias also pushed in the vector
87 /*if (args.size() % 3 != 0)
88 return;*/
90 TScripts scriptMap;
91 std::vector<CAIActions::CArg>::const_iterator it = args.begin();
93 uint32 primAlias;
94 string modelId;
96 for (it = args.begin(); it != args.end();++it)
98 if (it == args.begin())
100 if (it->get(primAlias) == false)
102 return;
104 continue;
106 modelId = it->toString();
107 string sheetId((++it)->toString());
108 string script((++it)->toString());
110 //will contain all script info and the base sheet id
111 TScriptContent scriptContent;
112 //first push base sheet Id
113 scriptContent.push_back(sheetId);
115 //build a temporary vector. Each element of the vector is a script line
116 std::vector<string> tmpVector;
117 splitString(script, "\n", tmpVector);
119 std::vector<string>::iterator tmpIt;
120 for (tmpIt = tmpVector.begin(); tmpIt != tmpVector.end(); ++tmpIt)
122 //remove comment from the line and push back the line only if the line wasn't just a comment
123 std::string noComment = removeComment(*tmpIt);
124 stripWhitespaces(noComment);
125 if (noComment != "")
126 scriptContent.push_back(noComment);
129 //add the usermodel to the manager's map
130 CAIUserModelManager::getInstance()->addToUserModels(primAlias, modelId, scriptContent);
133 CContextStack::setContext(ContextGlobal);
135 //send msg to EGS if EGS up
136 if (EGSHasMirrorReady)
138 if (modelId.size() > 4 && modelId[0] == 'A' && modelId[1] == 'R' && modelId[2] == 'K' && modelId[3] == '_') // Ark user model (only one)
139 CAIUserModelManager::getInstance()->sendUserModel(primAlias, modelId);
140 else
141 CAIUserModelManager::getInstance()->sendUserModels();
146 * used to send custom loot tables
148 DEFINE_ACTION(ContextGlobal,CUSTOMLT)
150 std::vector<CAIActions::CArg>::const_iterator it = args.begin();;
152 uint32 tablesNb;
153 if (it->get(tablesNb) == false)
155 nlwarning("<CAIUserModelManager::CUSTOMLT>Unable to retrieve number of parsed loot tables, abort.");
156 return;
158 nldebug("<CAIUserModelManager::CUSTOMLT>Number of parsed loot tables: %u", tablesNb);
159 ++it;
162 uint32 primAlias;
163 if (it->get(primAlias) == false)
165 nlwarning("<CAIUserModelManager::CUSTOMLT>Unable to retrieve primitive alias, abort.");
166 return;
169 TCustomLootTable customLootTables;
171 //for each loot table
172 for (uint i = 0; i < tablesNb; ++i)
174 ++it;
176 //gets number of loot sets in a loot table
177 uint32 lootSetsNb;
178 if (it->get(lootSetsNb) == false)
180 return;
183 //then gets all info relative to the loot table (id, money values)
184 std::string lootTableId((++it)->toString());
185 float moneyProba;
186 if ((++it)->get(moneyProba) == false)
188 nlwarning("<CAIUserModelManager::CUSTOMLT> unable to get moneyDropProbability");
189 return;
191 if (moneyProba < 0.0 || moneyProba > 1.0)
193 nlwarning("<CAIUserModelManager::CUSTOMLT> invalid moneyDropProbability, don't send custom loot tables info to EGS");
194 return;
197 float moneyFactor;
198 if ((++it)->get(moneyFactor) == false)
200 nlwarning("<CAIUserModelManager::CUSTOMLT> unable to get moneyFactor");
201 return;
203 if (moneyFactor < 0.0)
205 nlwarning("<CAIUserModelManager::CUSTOMLT> invalid moneyFactor, don't send custom loot tables info to EGS");
206 return;
209 uint32 moneyBase;
210 if ((++it)->get(moneyBase) == false)
212 nlwarning("<CAIUserModelManager::CUSTOMLT> unable to get moneyBase");
213 return;
215 if (moneyBase < 0)
217 nlwarning("<CAIUserModelManager::CUSTOMLT> invalid moneyBase, don't send custom loot tables info to EGS");
218 return;
222 TScripts lootSets;
223 //for each loot set inside the current table
224 for (uint j = 0; j < lootSetsNb; ++j)
226 std::string dropProba((++it)->toString());
227 std::string script((++it)->toString());
229 TScriptContent lootSetContent;
231 std::vector<string> tmpVector;
232 splitString(script, "\n", tmpVector);
234 std::vector<string>::iterator tmpIt;
235 for (tmpIt = tmpVector.begin(); tmpIt != tmpVector.end(); ++tmpIt)
237 std::string noComment = removeComment(*tmpIt);
238 stripWhitespaces(noComment);
239 if (noComment != "")
240 lootSetContent.push_back(noComment);
242 uint16 proba;
243 NLMISC::fromString(dropProba, proba);
244 // FIXME: test on proba value...
245 if (proba == 0 || proba > 100)
247 nlwarning("<CUSTOMLT> invalid drop proba value for lootset %i in custom loot table '%s', skip the lootset",
248 j + 1, lootTableId.c_str() );
249 continue;
251 lootSets.insert(make_pair(CCustomElementId(0, dropProba), lootSetContent));
254 if (lootSets.empty())
256 nlwarning("<CUSTOMLT> Don't add empty lootsets to customloot table, skip loot table '%s'.", lootTableId.c_str());
257 continue;
260 nldebug("<CAIUserModelManager> Adding table '%s' to manager with primAlias '%u'", lootTableId.c_str(), primAlias);
261 CAIUserModelManager::getInstance()->addCustomLootTable(primAlias, lootTableId,lootSets,
262 moneyProba, moneyFactor, moneyBase);
265 CContextStack::setContext(ContextGlobal);
267 //send msg to EGS if EGS up
268 if (EGSHasMirrorReady)
270 CAIUserModelManager::getInstance()->sendCustomLootTables();
275 CAIUserModelManager *CAIUserModelManager::getInstance()
277 if (_instance==0)
279 _instance = new CAIUserModelManager();
280 _instance->init();
282 return _instance;
285 void CAIUserModelManager::destroyInstance()
287 delete _instance;
288 _instance = 0;
291 CAIUserModelManager::CAIUserModelManager()
296 CAIUserModelManager::~CAIUserModelManager()
301 void CAIUserModelManager::init()
303 nldebug("<CAIUserModelManager> Manager initialized.");
306 void CAIUserModelManager::addToUserModels(uint32 primAlias,
307 const std::string &userModelId,
308 const TScriptContent &userModel)
310 if (userModelId.size() > 4 && userModelId[0] == 'A' && userModelId[1] == 'R' && userModelId[2] == 'K' && userModelId[3] == '_') // Ark user model (can be updated)
312 CCustomElementId id(primAlias, userModelId);
313 TScripts::iterator it = _UserModels.Scripts.find(id);
314 if (it != _UserModels.Scripts.end())
315 _UserModels.Scripts.erase(it);
318 bool inserted = _UserModels.Scripts.insert(make_pair(CCustomElementId(primAlias, userModelId), userModel)).second;
319 if (!inserted)
321 nlwarning("<AIUserModelManager::addToUserModels> tried to register twice the same user model with id: '%s'", userModelId.c_str());
322 return;
324 nldebug("<AIUserModelManager::addToUserModels> Added usermodel '%s' with alias '%u'", userModelId.c_str(), primAlias);
327 void CAIUserModelManager::sendUserModel(uint32 primAlias, const std::string &userModelId)
329 NLNET::CMessage msgout("USER_MODEL");
331 CCustomElementId id(primAlias, userModelId);
332 TScripts::iterator it = _UserModels.Scripts.find(id);
333 if (it == _UserModels.Scripts.end())
334 return;
336 CScriptData scriptData;
337 scriptData.Scripts.insert(make_pair(id, it->second));
338 msgout.serial(const_cast<CScriptData&>(scriptData));
340 nlinfo("Sending %u user models to EGS", scriptData.Scripts.size());
341 sendMessageViaMirror("EGS", msgout);
344 void CAIUserModelManager::sendUserModels()
346 NLNET::CMessage msgout("USER_MODELS");
347 const CScriptData &scriptData = CAIUserModelManager::getInstance()->getUserModels();
348 msgout.serial(const_cast<CScriptData&>(scriptData));
350 nldebug("<CAIUserModelManager> Sending %u user models to EGS", scriptData.Scripts.size());
351 sendMessageViaMirror("EGS", msgout);
354 bool CAIUserModelManager::isUserModel(uint32 primAlias, const std::string &userModelId) const
356 CCustomElementId id(primAlias, userModelId);
358 return _UserModels.Scripts.find(id) != _UserModels.Scripts.end();
361 bool CAIUserModelManager::isCustomLootTable(uint32 primAlias, const std::string &lootTableId) const
363 CCustomElementId id(primAlias, lootTableId);
365 return _CustomLootTables.Tables.find(id) != _CustomLootTables.Tables.end();
369 void CAIUserModelManager::sendCustomLootTables()
371 nldebug("<CAIUserModelManager> Sending custom loot tables to EGS");
372 NLNET::CMessage msgout("CUSTOM_LOOT_TABLES");
373 CCustomLootTableManager customLootTable = CAIUserModelManager::getInstance()->getCustomLootTables();
374 msgout.serial(customLootTable);
375 sendMessageViaMirror("EGS", msgout);
378 void CAIUserModelManager::addCustomLootTable(uint32 primAlias,
379 const std::string &tableId,
380 TScripts lootSets,
381 float moneyProba,
382 float moneyFactor,
383 uint32 moneyBase
386 if (CAIUserModelManager::getInstance()->isCustomLootTable(primAlias, tableId) == true)
388 nlwarning("<CAIUserModelManager::addCustomLootTable> Table '%s' with primAlias '%u' is already present in manager. Skipping it.", tableId.c_str(), primAlias);
389 return;
391 CScriptData tableContent;
392 tableContent.Scripts = lootSets;
393 CCustomLootTable customLootTable;
395 customLootTable.LootSets = tableContent;
396 customLootTable.MoneyProba = moneyProba;
397 customLootTable.MoneyFactor = moneyFactor;
398 customLootTable.MoneyBase = moneyBase;
400 _CustomLootTables.Tables.insert(make_pair(CCustomElementId(primAlias, tableId), customLootTable));
404 void CAIUserModelManager::deleteCustomDataByPrimAlias(uint32 primAlias)
406 CCustomElementId idLow(primAlias, "");
407 CCustomElementId idHigh(primAlias + 1, "");
408 TScripts::iterator upperBound = _UserModels.Scripts.upper_bound(idLow);
409 TScripts::iterator lowerBound = _UserModels.Scripts.lower_bound(idHigh);
410 if (upperBound != _UserModels.Scripts.end())
411 _UserModels.Scripts.erase(upperBound, lowerBound);
413 TCustomLootTable::iterator upperBoundLootTables = _CustomLootTables.Tables.upper_bound(idLow);
414 TCustomLootTable::iterator lowerBoundLootTables = _CustomLootTables.Tables.lower_bound(idHigh);
416 if (upperBoundLootTables != _CustomLootTables.Tables.end())
417 _CustomLootTables.Tables.erase(upperBoundLootTables, lowerBoundLootTables);
419 if (EGSHasMirrorReady)
421 nldebug("<CAIUserModelManager::deleteCustomData> Sending alias '%u' to EGS for data deletion", primAlias);
422 NLNET::CMessage msgout("DELCUSTOM");
423 msgout.serial(primAlias);
425 sendMessageViaMirror("EGS", msgout);