Add infos into target window
[ryzomcore.git] / ryzom / server / src / ai_share / primitive_parser.cpp
blob7b5a6a18e369eb94d14f4890e4fbdf46c1bb01f9
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "stdpch.h"
21 #include <errno.h>
23 #include "nel/misc/config_file.h"
24 #include "nel/misc/command.h"
25 #include "nel/misc/file.h"
26 #include "nel/misc/path.h"
27 #include "nel/misc/i_xml.h"
28 #include "nel/ligo/primitive.h"
29 #include "nel/ligo/primitive_utils.h"
30 #include "nel/ligo/ligo_config.h"
31 #include "nel/net/service.h"
32 #include "ai_types.h"
34 #include "ai_actions.h"
35 #include "ai_actions_dr.h"
36 #include "ai_alias_description_node.h"
37 #include "ai_share.h"
38 #include "../server_share/primitive_cfg.h"
39 #include "../server_share/used_continent.h"
41 using namespace NLMISC;
42 using namespace NLNET;
43 using namespace NLLIGO;
44 using namespace std;
45 using namespace AITYPES;
48 namespace AI_SHARE
51 // debug
52 static bool s_WriteScenarioDebugDataToFile = false;
54 static void parsePrimGroupFamilyProfileFaunaContent(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim);
55 static void parsePrimGroupFamilyProfileTribeContent(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim);
56 static void parsePrimGroupFamilyProfileNpcContent(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim);
58 //---------------------------------------------------------------------------------------
59 // THIS LINE EXISTS TO MAKE SURE THE LINKER DOESN'T THROW OUT THIS MODULE AT LINK TIME!!!
61 bool LinkWithPrimitiveParser=false;
63 // The ligo config, if NULL, you don't have called AI_SHARE::init()
64 NLLIGO::CLigoConfig *LigoConfig = NULL;
66 //---------------------------------------------------------------------------------------
67 // Stuff used for management of log messages
69 static bool VerboseLog=false;
70 #define LOG if (!VerboseLog) {} else nlinfo
73 //---------------------------------------------------------------------------------------
74 // some handy utilities for extracting common fields from prims
75 //---------------------------------------------------------------------------------------
77 static std::string nodeName(const IPrimitive *prim)
79 std::string result;
80 prim->getPropertyByName("name",result);
81 return result;
84 static TAIType nodeType(const IPrimitive *prim)
86 std::string result;
87 prim->getPropertyByName("ai_type",result);
88 return getType<TAIType>(result.c_str());
91 static TAITypeSpec nodeTypeSpec(const IPrimitive *prim)
93 std::string result;
94 prim->getPropertyByName("ai_type",result);
95 return getType<TAITypeSpec>(result.c_str());
98 static std::string nodeClass(const IPrimitive *prim)
100 std::string result;
101 prim->getPropertyByName("class",result);
102 return result;
105 std::map <const IPrimitive *,uint32> MapPrimToAlias;
106 std::map <uint32,const IPrimitive *> MapAliasToPrim;
108 uint32 nodeAlias(const IPrimitive *prim, bool canFail = false)
110 uint32 alias = 0;
111 // see if we've already got an alias for this prim node
112 if (MapPrimToAlias.find(prim)!=MapPrimToAlias.end())
114 alias=MapPrimToAlias[prim];
115 return alias;
118 TPrimitiveClassPredicate pred("alias");
119 IPrimitive *aliasNode = getPrimitiveChild(const_cast<IPrimitive*>(prim), pred);
120 if (aliasNode)
122 CPrimAlias *pa = dynamic_cast<CPrimAlias*>(aliasNode);
123 alias = pa->getFullAlias();
126 if (!canFail)
127 nlassertex(alias != 0, ("in primitive '%s'", buildPrimPath(prim).c_str()));
130 // std::string s;
131 // prim->getPropertyByName("alias",s);
133 #ifdef NL_DEBUG
134 // nlassert(!s.empty());
135 #endif
137 // // for legacy reasons the field may be called 'unique_id' instead of 'alias'
138 // if (s.empty())
139 // prim->getPropertyByName("unique_id",s);
140 // alias=NLMISC::fromString(s.c_str());
142 // // if we haven't found a sensible alias value use the prim node address
143 // if (alias==0 && s!="0")
144 // {
145 // alias=(sint32)prim;
146 // if( nodeType(prim)!=AITypeBadType
147 // && nodeType(prim)!=AITypeEventAction
148 // && nodeType(prim)!=AITypeActionZone
149 // && nodeType(prim)!=AITypeFaunaSpawnAtom) // legacy reasons .. again (bad).
150 // nlwarning("Failed to find alias for prim node: '%s': '%s' (using generated alias: %u)",
151 // buildPrimPath(prim).c_str(),
152 //// getName(nodeType(prim)),
153 // nodeName(prim).c_str(),alias);
154 // }
156 // if we haven a valid alias, ask one to the container
157 if (alias == 0)
159 CPrimitiveContext &ctx = CPrimitiveContext::instance();
160 nlassert(ctx.CurrentPrimitive);
161 alias = ctx.CurrentPrimitive->genAlias(const_cast<IPrimitive*>(prim), 0);
162 alias = ctx.CurrentPrimitive->buildFullAlias(alias);
165 // make sure the alias is unique
166 if (MapAliasToPrim.find(alias)!=MapAliasToPrim.end())
167 // && nodeClass(prim) != "npc_group_parameters" ) // <= for legacy reason
169 nlassert(false);
170 // uint32 oldAlias=alias;
171 // while (MapAliasToPrim.find(alias)!=MapAliasToPrim.end())
172 // ++alias;
173 //#if !FINAL_VERSION
174 // nlwarning("Alias %u not unique - remaping to %u",oldAlias,alias);
175 //#endif
178 // add alias to maps...
179 MapAliasToPrim[alias]=prim;
180 MapPrimToAlias[prim]=alias;
182 return alias;
185 //---------------------------------------------------------------------------------------
186 // handy routine for reading vertical pos
187 //---------------------------------------------------------------------------------------
189 static bool parseVerticalPos(const IPrimitive *prim, uint32 &verticalPos, const char *propertyName = "vertical_pos")
191 string s;
193 if (prim->getPropertyByName(propertyName, s))
195 verticalPos = verticalPosFromString(s);
196 return true;
198 else
200 verticalPos = vp_auto;
201 return false;
205 //---------------------------------------------------------------------------------------
206 // handy routine for reading the family flags
207 //---------------------------------------------------------------------------------------
209 // TODO
211 //static void parseFamilyFlag(const IPrimitive *prim, set<string> &result)
213 // static bool inited; // todo, change this as we can need to reload definitions .. (like new tribes or other ..)
214 // static vector<string> familyNames;
215 // static vector<string> tribeNames;
217 // if (!inited)
218 // {
219 // // build the list of family and tribes
220 // TPopulationFamily::getFamilyNames(familyNames);
221 // const std::vector<std::pair<std::string, NLMISC::TStringId> > &names = TPopulationFamily::getTribesNames();
223 // for (uint i=0; i<names.size(); ++i)
224 // {
225 // tribeNames.push_back(names[i].first);
226 // }
228 // inited = true;
229 // }
231 // result.clear();
232 // // read the family flags
233 // for (uint i=0; i<familyNames.size(); ++i)
234 // {
235 // if (familyNames[i] == "tribe")
236 // {
237 // // special case for tribe
238 // for (uint j=0; j<tribeNames.size(); ++j)
239 // {
240 // string flagName = tribeNames[j];
241 // string s;
242 // if (prim->getPropertyByName(flagName.c_str(), s) && s=="true")
243 // result.insert(flagName);
244 // }
245 // }
246 // else
247 // {
248 // // standard case for all other
249 // string s;
250 // if (prim->getPropertyByName(familyNames[i].c_str(), s) && s=="true")
251 // result.insert(familyNames[i]);
252 // }
254 // }
258 //---------------------------------------------------------------------------------------
259 // handy routine for scanning a node for mission sub-nodes
260 //---------------------------------------------------------------------------------------
262 static void lookForMissions(const IPrimitive *prim, std::vector<int> &missions, std::vector<std::string> &missionsNames)
264 for (uint i=0;i<prim->getNumChildren();++i)
266 // get a pointer to the child and make sure its valid
267 const IPrimitive *child;
268 if (prim->getChild(child,i))
270 if (NLMISC::nlstricmp(nodeClass(child),"mission")==0)
272 LOG("Found mission: %s: %s",
273 LigoConfig->aliasToString(nodeAlias(child)).c_str(),
274 nodeName(child).c_str());
275 missions.push_back(nodeAlias(child));
276 missionsNames.push_back(nodeName(child));
283 //---------------------------------------------------------------------------------------
284 // handy structures for dealing with folders and their sub-trees
285 //---------------------------------------------------------------------------------------
286 struct SFolderRef
288 SFolderRef() { }
289 SFolderRef(const CAIAliasDescriptionNode *node,const IPrimitive *prim) : Prim(prim), Node(node) { }
291 const IPrimitive *Prim;
292 NLMISC::CSmartPtr<const CAIAliasDescriptionNode> Node;
297 // the following variables are setup by parsePrimGrpNpc() and referenced by parsePrimNpcBot
298 //oldlevel static std::string DefaultBotLevel;
299 static std::string DefaultBotLook;
300 static uint32 DefaultBotVerticalPos = vp_auto;
301 //static std::string DefaultBotStats;
302 static std::vector<std::string> EmptyStringVector;
303 static const std::vector<std::string> *DefaultBotKeywords=&EmptyStringVector;
304 static const std::vector<std::string> *DefaultBotEquipment=&EmptyStringVector;
305 static const std::vector<std::string> *DefaultBotChat=&EmptyStringVector;
306 static std::vector<std::string> DefaultMissionNames;
307 static std::vector<int> DefaultMissions;
308 static const std::vector<std::string> *DefaultGrpParameters=&EmptyStringVector;
309 static string CurrentGroupFamily;
313 //---------------------------------------------------------------------------------------
314 // some handy utilities for manageing the treeNode trees
315 //---------------------------------------------------------------------------------------
317 // the following routine looks though the children of treeNode for one that matches prim
318 // if no child is found then treeNode is returned
319 static const CAIAliasDescriptionNode *nextTreeNode(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
321 // get hold of the node name, type and alias
322 std::string name=nodeName(prim);
323 TAIType type=nodeType(prim);
324 uint32 uniqueId=0;
325 if (type != AITYPES::AITypeBadType)
326 uniqueId = nodeAlias(prim);
328 // see if one of the children of treeNode corresponds to the primitive
329 for (uint i=0;i<treeNode->getChildCount();++i)
331 CAIAliasDescriptionNode *childNode=treeNode->getChild(i);
332 if ( childNode->getAlias()==uniqueId )
334 if ( childNode->getType()!=type
335 || childNode->getName()!=name )
337 nlwarning("nextTreeNode(): Unique ID conflict in node: (%s, %u, %s): looking for (%s, %u, %s) but found (%s, %u, %s)",
338 getName(treeNode->getType()),treeNode->getAlias(),treeNode->fullName().c_str(),
339 getName(childNode->getType()),childNode->getAlias(),childNode->fullName().c_str(),
340 getName(type),uniqueId,name.c_str());
341 continue;
343 return childNode;
347 return treeNode;
350 // the following routine recursively scans 'prim' and its children, constructing a CAIAliasDescriptionNode tree
351 // to represent ai type tree entries
352 static void buildAliasTree(CAIAliasDescriptionNode *treeNode,CAIAliasDescriptionNode *rootNode,const IPrimitive *prim,std::vector<SFolderRef> &folders)
354 // run through the node children looking for nodes with types that we recognize
355 for (uint i=0;i<prim->getNumChildren();++i)
357 // get a pointer to the child and make sure its valid
358 const IPrimitive *child;
359 if (prim->getChild(child,i))
361 // try to get a type, alias and name for the child
362 TAIType type=nodeType(child);
364 if (type==AITypeBadType)
366 buildAliasTree(treeNode,rootNode,child,folders);
367 continue;
370 // CAIAliasDescriptionNode *parentNode= (type==AITypeFolder)? rootNode: treeNode;
371 CAIAliasDescriptionNode *parentNode= treeNode;
373 uint32 uniqueId=nodeAlias(child, true);
374 std::string name=nodeName(child);
376 // make sure the name is unique
377 if (parentNode->findNodeChildByNameAndType(name,type)!=NULL)
379 LOG("Name not unique: %s: '%s:%s' @ '%s'",
380 getName(type),parentNode->fullName().c_str(),
381 name.c_str(),
382 treeNode->fullName().c_str());
385 // make sure the unique id is unique (SLOW!, must be replace with a fast hash_map access!)
386 if (rootNode->lookupAlias(uniqueId)!=NULL)
388 nlwarning("WARNING - Alias clash for '%s'%s and '%s:%s' @ '%s'",
389 rootNode->lookupAlias(uniqueId)->fullName().c_str(),
390 LigoConfig->aliasToString(uniqueId).c_str(),
391 parentNode->fullName().c_str(), name.c_str(),
392 treeNode->fullName().c_str());
395 // create a new tree node as a child of treeNode
396 NLMISC::CSmartPtr<CAIAliasDescriptionNode> node=new CAIAliasDescriptionNode(name,uniqueId,type,parentNode);
398 // parse this branch as a sub-tree of our new node
399 buildAliasTree(node,rootNode,child,folders);
401 // if this was a folder then add to the folder vector
402 if (type==AITypeFolder)
403 folders.push_back(SFolderRef(node,child));
410 //---------------------------------------------------------------------------------------
411 // routines used by the primitive file parser
412 //---------------------------------------------------------------------------------------
414 //////////////////////////////////////////////////////////////////////////
415 // States Methods
416 //////////////////////////////////////////////////////////////////////////
418 //////////////////////////////////////////////////////////////////////////
419 // predecl.
420 static void parsePrimGrpNpc(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim,const std::string initialState);
421 static void parsePrimGrpFauna(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim);
423 static void parsePrimStateChat(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
425 // read the main body of the parameters
426 const std::vector<std::string> *botKeywords=&EmptyStringVector;
427 const std::vector<std::string> *botNames=&EmptyStringVector;
428 const std::vector<std::string> *chat=&EmptyStringVector;
430 prim->getPropertyByName("bot_keyword_filter",botKeywords);
431 prim->getPropertyByName("bots_by_name",botNames);
432 prim->getPropertyByName("chat_parameters",chat);
434 // register the profile
435 CAIActions::begin(treeNode->getAlias());
436 CAIActions::exec("CHAT",treeNode->getAlias());
437 if (!botKeywords->empty()) CAIActions::execute("BOTKEYS",*botKeywords);
438 if (!botNames->empty()) CAIActions::execute("BOTNAMES",*botNames);
439 if (!chat->empty()) CAIActions::execute("CHAT",*chat);
440 CAIActions::end(treeNode->getAlias());
444 static void parsePrimStateProfile(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
446 // read the main body of the parameters
447 string movingProfile;
448 string activityProfile;
449 vector<string> *profileParams = &EmptyStringVector;
450 const std::vector<std::string> *grpKeywords=&EmptyStringVector;
451 const std::vector<std::string> *grpNames=&EmptyStringVector;
453 prim->getPropertyByName("ai_movement", movingProfile);
454 prim->getPropertyByName("ai_activity", activityProfile);
455 prim->getPropertyByName("ai_profile_params", profileParams);
456 prim->getPropertyByName("grp_keyword_filter", grpKeywords);
457 prim->getPropertyByName("grps_by_name", grpNames);
459 // register the profile
460 CAIActions::begin(treeNode->getAlias());
461 CAIActions::exec("PROFILE",treeNode->getAlias());
462 CAIActions::exec("MOVEPROF", movingProfile);
463 CAIActions::exec("ACTPROF", activityProfile);
464 CAIActions::execute("PROFPARM", *profileParams);
466 if (!grpKeywords->empty()) CAIActions::execute("GRPKEYS",*grpKeywords);
467 if (!grpNames->empty()) CAIActions::execute("GRPNAMES",*grpNames);
468 CAIActions::end(treeNode->getAlias());
471 static CTmpPropertyZone::TSmartPtr parseMachineStatePropertyZone(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
473 CTmpPropertyZone::TSmartPtr propertyZone=new CTmpPropertyZone();
475 // void setPatat (AITYPES::TVerticalPos verticalPos, const std::vector <CAIVector> &points)
477 uint numPoints=prim->getNumVector();
478 if (numPoints!=0)
480 const CPrimVector *const pointArray=prim->getPrimVector();
481 for (uint i=0;i<numPoints;++i)
483 propertyZone->points.push_back(CAIVector(pointArray[i].x,pointArray[i].y));
488 vector<string> *params = &EmptyStringVector;
489 prim->getPropertyByName("params", params);
490 for (uint i=0;i<params->size();i++)
492 // const string str=(*params)[i];
493 // CPropertyId activity=CPropertyId::create(str);
494 // propertyZone->properties.addActivity(activity);
496 propertyZone->properties.addProperty(CPropertyId::create((*params)[i]));
498 return propertyZone;
502 static CAIEventActionNode::TSmartPtr parsePrimEventAction(const CAIAliasDescriptionNode *treeNode, const IPrimitive *prim)
504 CAIEventActionNode::TSmartPtr result=new CAIEventActionNode;
506 // get hold of the node name and unique id
507 std::string name=nodeName(prim);
508 uint32 uniqueId=0;
510 result->Alias = treeNode?treeNode->getAlias():uniqueId;
512 LOG("Parsing npc event action: %s",name.c_str());
514 // read the main body of the parameters
515 std::string weightStr;
516 const std::vector<std::string> *parameters=&EmptyStringVector;
518 prim->getPropertyByName("action",result->Action);
519 prim->getPropertyByName("weight",weightStr);
520 prim->getPropertyByName("parameters",parameters);
521 NLMISC::fromString(weightStr, result->Weight);
522 result->Args=*parameters;
524 for (uint i=0;i<prim->getNumChildren();++i)
526 // get a pointer to the child and make sure its valid
527 const IPrimitive *child;
528 if (!prim->getChild(child,i))
529 continue;
531 // try to get a type for the child
532 const TAIType type=nodeType(child);
534 // it's one of ours! - so match against the types we recognise
535 switch(type)
537 case AITypeEventAction:
539 CAIEventActionNode::TSmartPtr childAction;
540 childAction=parsePrimEventAction(treeNode?nextTreeNode(treeNode,child):NULL,child);
541 if (childAction)
542 result->Children.push_back(childAction);
544 break;
545 case AITypeActionZone:
547 result->_PropertyZones.push_back(parseMachineStatePropertyZone(treeNode?nextTreeNode(treeNode,child):NULL,child));
548 result->_PropertyZones.back()->Target = CTmpPropertyZone::All;
550 break;
551 case AITypeFaunaActionZone:
553 result->_PropertyZones.push_back(parseMachineStatePropertyZone(treeNode?nextTreeNode(treeNode,child):NULL,child));
554 result->_PropertyZones.back()->Target = CTmpPropertyZone::Fauna;
556 break;
557 case AITypeNpcActionZone:
559 result->_PropertyZones.push_back(parseMachineStatePropertyZone(treeNode?nextTreeNode(treeNode,child):treeNode,child));
560 result->_PropertyZones.back()->Target = CTmpPropertyZone::Npc;
562 break;
563 case AITypeBadType:
564 case AITypeFolder:
565 // not handled there, but by caller
566 break;
567 default:
568 nlwarning("Don't know how to treat ai_type '%s'",getName(type));
569 break;
573 return result;
577 <PRIMITIVE CLASS_NAME="fauna_action_zone" TYPE="zone" R="128" G="128" B="128" A="128" AUTO_INIT="true" DELETABLE="true" NUMBERIZE="false">
578 <PARAMETER NAME="name" TYPE="string" VISIBLE="true"/>
579 <PARAMETER NAME="ai_type" TYPE="string" VISIBLE="false">
580 <DEFAULT_VALUE VALUE="FAUNA_ACTION_ZONE"/>
581 </PARAMETER>
582 <PARAMETER NAME="params" TYPE="string_array" VISIBLE="true" WIDGET_HEIGHT="100"/>
583 </PRIMITIVE>
587 static void parsePrimGroupDescriptionsForAction(const CAIAliasDescriptionNode *aliasNode,
588 const IPrimitive *prim,
589 uint32 logicActionAlias
593 // get hold of the node name and unique id
594 std::string name=nodeName(prim);
595 uint32 uniqueId=nodeAlias(prim);
597 // run through the dynsystem children looking for nodes with types that we recognise
598 for (uint i=0;i<prim->getNumChildren();++i)
600 // get a pointer to the child and make sure its valid
601 const IPrimitive *child;
602 if (prim->getChild(child, i))
604 if (nodeType(child) == AITypeBadType) continue; // skip alias node
605 const CAIAliasDescriptionNode *childTreeNode = nextTreeNode(aliasNode, child);
606 string familyTag;
607 child->getPropertyByName("family", familyTag);
608 CAIActions::exec("GRPFAM", childTreeNode, familyTag, name, logicActionAlias);
609 TAIType type = nodeType(child);
610 switch(type)
612 case AITypeGroupFamily:
614 nlwarning("Parsing a group_family, primitive is outdated. Please report to jvuarand.");
615 // parsePrimGroupFamily(nextTreeNode(aliasNode,child),child);
617 break;
619 case AITypeGroupFamilyProfileFauna:
620 parsePrimGroupFamilyProfileFaunaContent(childTreeNode, child);
621 // parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyFauna);
622 break;
624 case AITypeGroupFamilyProfileTribe:
625 parsePrimGroupFamilyProfileTribeContent(childTreeNode, child);
626 break;
627 case AITypeGroupFamilyProfileNpc:
628 parsePrimGroupFamilyProfileNpcContent(childTreeNode, child);
629 break;
631 // case AITypeGroupFamilyProfileGeneric:
632 // parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyTribe);
633 // break;
634 default:
635 CAIActions::end(childTreeNode->getAlias());
636 break;
644 // add group description to already parsed event actions
645 static void addGroupDescriptionToEventAction(const CAIAliasDescriptionNode *treeNode, const IPrimitive *prim, uint depth)
647 uint32 uniqueId=0;
648 CAIActions::begin(treeNode?treeNode->getAlias():uniqueId);
649 for (uint i=0;i<prim->getNumChildren();++i)
651 // get a pointer to the child and make sure it's valid
652 const IPrimitive *child;
653 if (!prim->getChild(child,i))
654 continue;
656 const TAIType type=nodeType(child);
658 // it's one of ours! - so match against the types we recognise
659 switch(type)
661 case AITypeEventAction:
663 addGroupDescriptionToEventAction(treeNode?nextTreeNode(treeNode,child):NULL,child, depth + 1);
665 break;
666 case AITypeActionZone:
667 case AITypeFaunaActionZone:
668 case AITypeNpcActionZone:
669 // no-op, already parsed
670 break;
671 case AITypeFolder:
673 string cname = nodeClass(child);
674 // parse optional group descriptions
675 if (cname == "group_descriptions")
677 CAIActions::exec("SETACTN", treeNode?treeNode->getAlias():uniqueId);
678 parsePrimGroupDescriptionsForAction(treeNode?nextTreeNode(treeNode,child):NULL, child, treeNode?treeNode->getAlias():uniqueId);
679 CAIActions::exec("CLRACTN");
682 break;
683 case AITypeBadType:
684 default:
685 nlwarning("Don't know how to treat ai_type '%s'",getName(type));
686 break;
689 CAIActions::end(treeNode?treeNode->getAlias():uniqueId);
693 static void parsePrimEvent(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
695 CAIEventDescription::TSmartPtr result=new CAIEventDescription;
697 // get hold of the node name and unique id
698 std::string name=nodeName(prim);
699 uint32 uniqueId=nodeAlias(prim);
701 LOG("Parsing npc event: %s",name.c_str());
703 // read the main body of the parameters
704 const std::vector<std::string> *stateKeywords=&EmptyStringVector;
705 const std::vector<std::string> *namedStates=&EmptyStringVector;
706 const std::vector<std::string> *groupKeywords=&EmptyStringVector;
707 const std::vector<std::string> *namedGroups=&EmptyStringVector;
709 prim->getPropertyByName("event",result->EventType);
712 // the event should have two children, the alias and the action
713 const IPrimitive *child;
714 std::string type;
715 if ( prim->getNumChildren()!=2
716 || !prim->getChild(child,1)
717 || !child->getPropertyByName("ai_type",type)
718 || getType<TAIType>(type.c_str())!=AITypeEventAction)
720 nlwarning("Failed to find the action associated with event: %s (in %s)",name.c_str(), treeNode?treeNode->fullName().c_str():"");
721 return;
724 result->Action=parsePrimEventAction(treeNode?nextTreeNode(treeNode,child):NULL,child);
726 prim->getPropertyByName("state_keyword_filter",stateKeywords);
727 prim->getPropertyByName("states_by_name",namedStates);
728 prim->getPropertyByName("group_keyword_filter",groupKeywords);
729 prim->getPropertyByName("groups_by_name",namedGroups);
731 result->StateKeywords= *stateKeywords;
732 result->NamedStates= *namedStates;
733 result->GroupKeywords= *groupKeywords;
734 result->NamedGroups= *namedGroups;
736 // register the event and call the parser for the associated action
737 CAIActions::begin(treeNode?treeNode->getAlias():uniqueId);
738 CAIActions::exec("EVENT",uniqueId,result);
739 CAIActions::end(treeNode?treeNode->getAlias():uniqueId);
741 // Each 'event actions' may have a group description attached to it,
742 // parse it here, because we don't want to embed those descriptions in the
743 // CAIEventDescription class
744 addGroupDescriptionToEventAction(treeNode?nextTreeNode(treeNode,child):NULL, child, 1);
745 CAIActions::exec("ENDEVENT"); // this will clear the logic actions map
749 //---------------------------------------------------------------------------------------
750 // kami routines
752 static void parsePrimBotKami(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
754 nlassert(false);
755 // get hold of the node name and unique id
756 std::string name=nodeName(prim);
757 uint32 uniqueId=nodeAlias(prim);
759 // lookup the kami type
760 std::string kamiType;
761 if (!prim->getPropertyByName("ai_kami_type",kamiType) || (kamiType!="PREACHER" && kamiType!="GUARDIAN"))
763 nlwarning("ai_kami_type property not found in kami record: %s",treeNode->fullName().c_str());
764 return;
767 // lookup the creature sheet name
768 std::string sheet;
769 if (!prim->getPropertyByName("sheet",sheet))
771 nlwarning("'sheet' property not found in kami record: %s",treeNode->fullName().c_str());
772 return;
775 // lookup x,y,theta
776 const CPrimPoint *point=dynamic_cast<const CPrimPoint *>(prim);
777 if (point==NULL)
779 nlwarning("Failed to cast to CPrimPoin kami: %s",name.c_str());
780 CAIActions::end(treeNode->getAlias());
781 return;
783 sint x=(uint32)(point->Point.x*1000);
784 sint y=(uint32)(point->Point.y*1000);
785 float theta=(float)point->Angle;
788 // do the business
789 LOG("Adding kami npc bot: %s: %s pos: (%d,%d) orientation: %.2f",kamiType.c_str(),name.c_str(),x,y,theta);
790 CAIActions::begin(treeNode->getAlias());
791 CAIActions::exec("BOTNPC",treeNode->getAlias());
792 CAIActions::exec("LOOK",sheet);
793 CAIActions::exec("STATS",25);
794 CAIActions::exec("KEYWORDS",kamiType);
795 CAIActions::exec("STARTPOS",x,y,theta);
797 if (kamiType=="PREACHER")
799 // todo: get rid of this code :o)
800 // add teleport stuff to the Kami ... this is temporary
801 std::vector<std::string> chat;
802 chat.push_back(std::string("shop: KAMI_TP_FOREST"));
803 CAIActions::execute("CHAT",chat);
806 CAIActions::end(treeNode->getAlias());
809 static void parsePrimGrpKami(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
811 // get hold of the node name and unique id
812 std::string name=nodeName(prim);
813 uint32 uniqueId=nodeAlias(prim);
815 LOG("Parsing group kami: %s",name.c_str());
817 // extract x and y coords of points from patat (if there is one)
818 // std::vector <CAIActions::CArg> points;
819 // uint numPoints=prim->getNumVector();
820 // if (numPoints!=0)
821 // {
822 // const CPrimVector *pointArray=prim->getPrimVector();
823 // for (uint i=0;i<numPoints;++i)
824 // {
825 // points.push_back(CAIActions::CArg(pointArray[i].x));
826 // points.push_back(CAIActions::CArg(pointArray[i].y));
827 // }
828 // }
830 // setup the grp context
831 CAIActions::begin(treeNode->getAlias());
832 CAIActions::exec("GRPNPC",uniqueId);
834 // commit the zone points
835 // if (!points.empty())
836 // CAIActions::execute("PATAT",points);
838 // run through the group children looking for nodes with types that we recognise
839 for (uint i=0;i<prim->getNumChildren();++i)
841 // get a pointer to the child and make sure its valid
842 const IPrimitive *child;
843 if (prim->getChild(child,i))
845 // try to get a type for the child
846 // it's one of ours! - so match against the types we recognise
847 switch(nodeType(child))
849 case AITypeBot:
850 parsePrimBotKami(nextTreeNode(treeNode,child),child);
851 break;
852 case AITypeBadType:
853 case AITypeFolder:
854 break;
855 default:
856 nlwarning("Didn't found ai_type when expecting 'BOT_NPC' in parsePrimGrpKami");
857 break;
863 CAIActions::end(treeNode->getAlias());
868 //---------------------------------------------------------------------------------------
869 // karavan routines
871 static void parsePrimBotKaravan(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
873 nlassert(false);
874 // get hold of the node name and unique id
875 std::string name=nodeName(prim);
876 uint32 uniqueId=nodeAlias(prim);
878 // lookup the karavan type
879 std::string karavanType;
880 if (!prim->getPropertyByName("ai_karavan_type",karavanType))
882 nlwarning("ai_karavan_type property not found in karavan record: %s",treeNode->fullName().c_str());
883 return;
886 // lookup the creature sheet name
887 std::string sheet;
888 if (!prim->getPropertyByName("sheet",sheet))
890 nlwarning("'sheet' property not found in karavan record: %s",treeNode->fullName().c_str());
891 return;
894 // add the bot to the current group
895 const CPrimPoint *point=dynamic_cast<const CPrimPoint *>(prim);
896 if (!point)
898 nlwarning("Failed to cast to CPrimPoin karavan: %s",name.c_str());
899 CAIActions::end(treeNode->getAlias());
900 return;
903 sint x=(uint32)(point->Point.x*1000);
904 sint y=(uint32)(point->Point.y*1000);
905 float theta=(float)point->Angle;
907 LOG("Adding karavan npc bot: %s: %s pos: (%d,%d) orientation: %.2f",karavanType.c_str(),name.c_str(),x,y,theta);
909 // do the business
910 CAIActions::begin(treeNode->getAlias());
911 CAIActions::exec("BOTNPC",treeNode->getAlias());
912 CAIActions::exec("LOOK",sheet);
913 CAIActions::exec("STATS",25);
914 CAIActions::exec("KEYWORDS",karavanType);
915 CAIActions::exec("STARTPOS",x,y,theta);
916 // if (kamiType=="")
918 // todo: get rid of this code :o)
919 // add teleport stuff to the Kami ... this is temporary
920 std::vector<std::string> chat;
921 chat.push_back(std::string("shop: KARAVAN_TP_FOREST"));
922 CAIActions::execute("CHAT",chat);
924 CAIActions::end(treeNode->getAlias());
927 static void parsePrimGrpKaravan(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
929 // get hold of the node name and unique id
930 std::string name=nodeName(prim);
931 uint32 uniqueId=nodeAlias(prim);
933 LOG("Parsing group karavan: %s",name.c_str());
935 // setup the grp context
936 CAIActions::begin(treeNode->getAlias());
937 CAIActions::exec("GRPNPC",treeNode->getAlias());
939 // run through the group children looking for nodes with types that we recognise
940 for (uint i=0;i<prim->getNumChildren();++i)
942 // get a pointer to the child and make sure its valid
943 const IPrimitive *child;
944 if (prim->getChild(child,i))
946 TAIType type=nodeType(child);
948 switch(type)
950 case AITypeBot:
951 parsePrimBotKaravan(nextTreeNode(treeNode,child),child);
952 break;
953 case AITypeFolder:
954 case AITypeBadType:
955 break;
956 default:
957 nlwarning("Unsupported ai_type in parsePrimGrpKaravan");
958 break;
964 CAIActions::end(treeNode->getAlias());
968 static void parsePrimState(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim,const char *pointsType)
970 // get hold of the node name and unique id
971 std::string name=nodeName(prim);
972 uint32 uniqueId=nodeAlias(prim);
974 LOG("Parsing npc state with %s: %s",pointsType,name.c_str());
976 // look for keywords
977 std::string moveProfile;
978 std::string activityProfile;
979 vector<string> *profileParams = &EmptyStringVector;
980 const std::vector<std::string> *keywords=&EmptyStringVector;
981 prim->getPropertyByName("grp_keywords",keywords);
982 prim->getPropertyByName("ai_movement",moveProfile);
983 prim->getPropertyByName("ai_activity",activityProfile);
984 prim->getPropertyByName("ai_profile_params", profileParams);
986 uint32 verticalPos;
987 parseVerticalPos(prim, verticalPos);
989 // extract x and y coords of points from spline or patat
990 std::vector <CAIActions::CArg> points;
991 uint numPoints=prim->getNumVector();
992 if (numPoints!=0)
994 const CPrimVector *pointArray=prim->getPrimVector();
995 for (uint i=0;i<numPoints;++i)
997 points.push_back(CAIActions::CArg(pointArray[i].x));
998 points.push_back(CAIActions::CArg(pointArray[i].y));
1001 else
1002 LOG("State has no geometry: %s: %s",pointsType,name.c_str());
1004 // create the state
1005 CAIActions::begin(treeNode->getAlias());
1006 CAIActions::exec("STATE",uniqueId);
1007 CAIActions::exec("MOVEPROF",moveProfile);
1008 CAIActions::exec("ACTPROF", activityProfile);
1009 CAIActions::execute("PROFPARM", *profileParams);
1010 CAIActions::exec("VERTPOS", verticalPos);
1011 if (!keywords->empty())
1012 CAIActions::execute("KEYWORDS",*keywords);
1013 if (!points.empty())
1014 CAIActions::execute(pointsType,points);
1016 // run through the group children looking for nodes with types that we recognise
1017 uint j;
1018 for (j=0;j<prim->getNumChildren();++j)
1020 // get a pointer to the child and make sure its valid
1021 const IPrimitive *child;
1022 if (prim->getChild(child,j))
1024 // try to get a type for the child
1025 switch (nodeType(child))
1027 case AITypeNpcStateProfile:
1028 case AITypeNpcStateChat:
1029 // this kind of node is read in the next loop
1030 // this is because any mission in a group MUST be read before
1031 // the parsing of the state profile/
1032 // parsePrimStateProfile(nextTreeNode(treeNode,child),child);
1033 break;
1034 case AITypeGrp:
1036 switch (nodeTypeSpec(child))
1038 case AITypeSpecNpc:
1039 parsePrimGrpNpc(nextTreeNode(treeNode,child),child,name);
1040 break;
1041 case AITypeSpecFauna:
1042 parsePrimGrpFauna(nextTreeNode(treeNode,child),child);
1043 break;
1044 case AITypeSpecKami: // a non-deposit kami group
1045 parsePrimGrpKami(nextTreeNode(treeNode,child),child);
1046 break;
1047 case AITypeSpecKaravan:
1048 parsePrimGrpKaravan(nextTreeNode(treeNode,child),child);
1049 break;
1051 default:
1052 nlwarning("Don't know how to treat ai_group of type '%s' in primState",getName(nodeTypeSpec(child)));
1053 break;
1057 break;
1058 case AITypeEvent:
1059 parsePrimEvent(nextTreeNode(treeNode,child),child);
1060 break;
1061 case AITypeState:
1062 parsePrimState(nextTreeNode(treeNode,child),child,"PATAT");
1063 break;
1064 case AITypeBadType:
1065 case AITypeFolder:
1066 break;
1067 default:
1068 nlwarning("Don't know how to treat ai_type '%s'",getName(nodeType(child)));
1069 break;
1075 // a second loop for state profile node.
1076 for (j=0;j<prim->getNumChildren();++j)
1078 // get a pointer to the child and make sure its valid
1079 const IPrimitive *child;
1080 if (prim->getChild(child,j))
1082 switch (nodeType(child))
1084 case AITypeNpcStateProfile:
1085 parsePrimStateProfile(nextTreeNode(treeNode,child),child);
1086 break;
1087 case AITypeNpcStateChat:
1088 parsePrimStateChat(nextTreeNode(treeNode,child),child);
1089 break;
1090 default: // we don't care unknown objets.
1091 break;
1097 CAIActions::end(treeNode->getAlias());
1100 //////////////////////////////////////////////////////////////////////////
1101 // End States Methods
1102 //////////////////////////////////////////////////////////////////////////
1107 //---------------------------------------------------------------------------------------
1108 // shared routines
1110 static void parsePrimPlaces(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
1112 // run through the group children looking for nodes with types that we recognise
1113 for (uint i=0;i<prim->getNumChildren();++i)
1115 // get a pointer to the child and make sure its valid
1116 const IPrimitive *child;
1117 if (prim->getChild(child,i))
1119 // hack because the place type
1120 std::string placeName;
1121 child->getPropertyByName("ai_place_type",placeName);
1123 // try to get a type for the child
1124 TAIType type=nodeType(child);
1125 if ( type!=AITypeBadType
1126 && type!=AITypeFolder)
1128 // get hold of the unique id
1129 uint32 uniqueId=nodeAlias(child);
1131 // it's one of ours! - so match against the types we recognise
1132 if (type == AITypePlace || type == AITypeOutpost || type == AITypePlaceFauna)
1134 // read the radius
1135 std::string radiusString;
1136 child->getPropertyByName("radius",radiusString);
1137 uint radius;
1138 NLMISC::fromString(radiusString, radius);
1139 if (radius == 0)
1141 nlwarning("Ignoring place '%s' because bad radius: '%s' (converted to int as %u)",
1142 placeName.c_str(),
1143 radiusString.c_str(),
1144 radius);
1145 continue;
1147 // if (radiusString!=toString(radius))
1148 // {
1149 // nlwarning("Ignoring place '%s' because bad radius: '%s'",placeName.c_str(),radiusString.c_str());
1150 // continue;
1151 // }
1153 // read the xy coordinates
1154 if (child->getNumVector()!=1)
1156 nlwarning("Ignoring place '%s' because num points not 1 (%d)",placeName.c_str(),child->getNumVector());
1157 continue;
1159 float x=(float)(child->getPrimVector()->x);
1160 float y=(float)(child->getPrimVector()->y);
1162 uint32 verticalPos;
1163 parseVerticalPos(child, verticalPos);
1165 if (type == AITypePlaceFauna)
1167 std::string tmpStr;
1168 uint32 stayTimeMin = 1000;
1169 uint32 stayTimeMax = 1000;
1170 uint32 index = 0;
1171 std::string indexNext;
1172 bool flagSpawn = false;
1173 bool flagFood = false;
1174 bool flagRest = false;
1176 bool active = true;
1177 bool timeDriven = false;
1178 std::string timeInterval;
1179 std::string dayInterval;
1182 if (child->getPropertyByName("visit_time_min", tmpStr))
1184 NLMISC::fromString(tmpStr, stayTimeMin);
1186 if (child->getPropertyByName("visit_time_max", tmpStr))
1188 NLMISC::fromString(tmpStr, stayTimeMax);
1190 if (child->getPropertyByName("index", tmpStr))
1192 NLMISC::fromString(tmpStr, index);
1194 child->getPropertyByName("index_next", indexNext);
1195 if (child->getPropertyByName("flag_spawn", tmpStr))
1197 flagSpawn = nlstricmp(tmpStr, "true") == 0;
1199 if (child->getPropertyByName("flag_rest", tmpStr))
1201 flagRest = nlstricmp(tmpStr, "true") == 0;
1203 if (child->getPropertyByName("flag_food", tmpStr))
1205 flagFood = nlstricmp(tmpStr, "true") == 0;
1207 if (child->getPropertyByName("active", tmpStr))
1209 active = nlstricmp(tmpStr, "true") == 0;
1211 if (child->getPropertyByName("time_driven", tmpStr))
1213 timeDriven = nlstricmp(tmpStr, "true") == 0;
1215 child->getPropertyByName("time_interval", timeInterval);
1216 child->getPropertyByName("day_interval", dayInterval);
1217 LOG("Adding place (type XYRFauna): %s at: (%.0f,%.0f) x %d (%s)",
1218 placeName.c_str(),
1219 child->getPrimVector()->x,
1220 child->getPrimVector()->y,
1221 radius,
1222 verticalPosToString((TVerticalPos)verticalPos).c_str());
1224 // add the place to the current context
1225 CAIActions::begin(uniqueId);
1226 CAIActions::exec("PLACEXYR",uniqueId,x,y,radius*1000, verticalPos);
1227 CAIActions::exec("PLXYRFAF", uniqueId, flagSpawn, flagRest, flagFood); // set flags
1228 CAIActions::exec("PLXYRFAS", uniqueId, stayTimeMin, stayTimeMax); // set stay times
1229 CAIActions::exec("PLXYRFAI", uniqueId, index, indexNext); // set indices
1230 CAIActions::exec("PLXYRFAA", uniqueId, active, timeDriven, timeInterval, dayInterval); // set indices
1231 CAIActions::end(uniqueId);
1233 else
1235 LOG("Adding place (type XYR): %s at: (%.0f,%.0f) x %d (%s)",
1236 placeName.c_str(),
1237 child->getPrimVector()->x,
1238 child->getPrimVector()->y,
1239 radius,
1240 verticalPosToString((TVerticalPos)verticalPos).c_str());
1242 // add the place to the current context
1243 CAIActions::begin(uniqueId);
1244 CAIActions::exec("PLACEXYR",uniqueId,x,y,radius*1000, verticalPos);
1245 CAIActions::end(uniqueId);
1253 struct parsePopException : public Exception
1255 parsePopException (const std::string &Reason) : Exception(Reason)
1259 static void parsePopulation(const IPrimitive *prim, std::string &sheet, uint &count)
1261 // try to get a type for the child
1262 std::string type;
1263 if (!prim->getPropertyByName("ai_type",type))
1265 throw parsePopException(std::string("ai_type not found"));
1268 // it's one of ours! - so match against the types we recognise
1269 if (NLMISC::nlstricmp(type,"FAUNA_SPAWN_ATOM")!=0)
1271 throw parsePopException(std::string("Expected ai_type FAUNA_SPAWN_ATOM but found")+type);
1274 std::string countStr;
1276 if (!prim->getPropertyByName("count",countStr))
1278 throw parsePopException(std::string("FAUNA_SPAWN_ATOM failed to find property ''count'"));
1282 string s;
1283 if (prim->getPropertyByName("creature_code", s) && !s.empty())
1284 sheet = s+".creature";
1287 NLMISC::fromString(countStr, count);
1288 if (count<=0)
1290 throw parsePopException(std::string("FAUNA_SPAWN_ATOM property 'count' invalid: ")+countStr);
1295 //---------------------------------------------------------------------------------------
1296 // fauna routines
1298 static void parsePrimGrpFaunaSpawn(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
1300 // get hold of the node name and unique id
1301 std::string name=nodeName(prim);
1302 uint32 uniqueId=nodeAlias(prim);
1304 LOG("Parsing group fauna spawn: %s",name.c_str());
1306 // we need a vector of arguments for the call to execute() at the end
1307 std::vector <CAIActions::CArg> executeArgs;
1308 executeArgs.push_back(CAIActions::CArg(uniqueId));
1310 // lookup the spawn type for the manager
1311 std::string spawnType("ALWAYS");
1312 prim->getPropertyByName("spawn_type",spawnType);
1313 executeArgs.push_back(CAIActions::CArg(spawnType));
1315 // deal with the weight
1316 std::string s;
1317 uint32 weight = 0;
1318 if (prim->getPropertyByName("weight",s))
1320 NLMISC::fromString(s, weight);
1321 if (toString(weight)!=s)
1323 nlwarning("weight invalid value: %s");
1324 weight=100;
1327 executeArgs.push_back(CAIActions::CArg(weight));
1329 // run through the group children looking for nodes with types that we recognise
1330 for (uint i=0; i<prim->getNumChildren(); ++i)
1332 // get a pointer to the child and make sure its valid
1333 const IPrimitive *child;
1334 if (!prim->getChild(child,i))
1335 continue;
1337 // not interested to parse alias nodes !
1338 if (nodeClass(child) == "alias")
1339 continue;
1343 std::string theSheet;
1344 uint count;
1345 parsePopulation (child, theSheet, count);
1346 if (theSheet.empty())
1347 continue;
1348 executeArgs.push_back(CAIActions::CArg(theSheet));
1349 executeArgs.push_back(count);
1351 catch (const parsePopException &e)
1353 nlwarning("FaunaGroup: %s of %s : %s", nodeName(child).c_str(), treeNode->fullName().c_str(), e.what());
1358 // open the parse context
1359 CAIActions::begin(treeNode->getAlias());
1361 // call the 'execution' system
1362 if ( !executeArgs.empty()
1363 && executeArgs.size()>=5)
1364 CAIActions::execute("POPVER",executeArgs);
1365 else
1366 nlwarning("FAUNA_SPAWN failed because population is empty, '%s'%s",
1367 name.c_str(),
1368 LigoConfig->aliasToString(uniqueId).c_str());
1370 // close the parse context
1371 CAIActions::end(treeNode->getAlias());
1376 static void parsePrimGrpFauna(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
1378 // get hold of the node name and unique id
1379 std::string name=nodeName(prim);
1380 uint32 uniqueId=nodeAlias(prim);
1382 // lookup the fauna type for the manager
1383 /* std::string faunaTypeStr;
1384 prim->getPropertyByName("fauna_type",faunaTypeStr);
1386 if ( getType<TFaunaType>(faunaTypeStr.c_str())==FaunaTypeBadType )
1388 nlwarning("Ignoring group %s due to unknown type: '%s'",name.c_str(),faunaTypeStr.c_str());
1389 return;
1392 // open the parse context
1393 LOG("Parsing group fauna: %s",name.c_str());
1394 CAIActions::begin(treeNode->getAlias());
1397 // Don't know what for .. ???
1398 // // get hold of the ids of the places
1399 // uint32 feedPlace=~0u, restPlace=~0u, spawnPlace=~0u;
1400 // for (uint i=0;i<treeNode->getChildCount();++i)
1401 // {
1402 // if (treeNode->getChild(i)->getType()==AITypePlace)
1403 // {
1404 // if (name=="FAUNA_FOOD") feedPlace=treeNode->getChild(i)->getAlias();
1405 // if (name=="FAUNA_REST") restPlace=treeNode->getChild(i)->getAlias();
1406 // if (name=="FAUNA_SPAWN") spawnPlace=treeNode->getChild(i)->getAlias();
1407 // }
1409 // }
1411 // setup the grp context
1412 CAIActions::exec("GRPFAUNA",uniqueId/*,faunaTypeStr*/);
1414 // create any places that we're going to reffer to later
1415 parsePrimPlaces(nextTreeNode(treeNode,prim),prim);
1417 // time variables used for determining time spent eating, rate of progress of hunger, etc
1418 std::string s;
1419 if (prim->getPropertyByName("times",s) && !s.empty())
1421 float time1=0, time2=0;
1422 sscanf(s.c_str(),"%f %f",&time1,&time2);
1423 CAIActions::exec("SETTIMES",time1,time2);
1425 else
1427 LOG("No 'times' record found: using default value: 10 10");
1428 float time1=30.0f, time2=120.0f;
1429 CAIActions::exec("SETTIMES",time1,time2);
1431 s.clear();
1432 prim->getPropertyByName("autoSpawn", s);
1433 CAIActions::exec("AUTOSPWN", uint32(nlstricmp( s.c_str(), "false") != 0));
1435 // time variables used for determining time corpses stay on ground and time before creatures respawn
1436 s.clear();
1437 prim->getPropertyByName("spawn_times",s); // This code is a nasty hack to provide legacy support
1438 if (s.empty()) // for .primitive files generated with a defective
1439 prim->getPropertyByName("Spawn_times",s); // world_editor.xml (case problem in 'spawn_times')
1440 if (!s.empty())
1442 float time1=0, time2=0, time3=-1;
1443 sscanf(s.c_str(),"%f %f %f",&time1,&time2,&time3);
1444 if(time3==-1)
1445 CAIActions::exec("SPAWTIME",time1,time2);
1446 else
1447 CAIActions::exec("SPAWTIME",time1,time2,time3);
1449 else
1451 LOG("No 'spawn times' record found: using default value: 30 120");
1452 float time1=30.0f, time2=120.0f;
1453 CAIActions::exec("SPAWTIME",time1,time2);
1456 // ring cycles.
1458 std::string cycles("");
1459 prim->getPropertyByName("cycles",cycles);
1460 CAIActions::exec("STCYCLES",cycles);
1463 // solidarity used
1464 s.clear();
1465 prim->getPropertyByName("solidarity",s);
1466 CAIActions::exec("ASSIST",uint32(nlstricmp( s.c_str(), "disabled")!=0));
1468 // run through the group children looking for nodes with types that we recognise
1469 for (uint j=0;j<prim->getNumChildren();++j)
1471 // get a pointer to the child and make sure its valid
1472 const IPrimitive *child;
1473 if (!prim->getChild(child,j))
1474 continue;
1476 // try to get a type for the child
1477 TAIType type=nodeType(child);
1478 switch(type)
1480 case AITypeGrpFaunaPop:
1481 parsePrimGrpFaunaSpawn(nextTreeNode(nextTreeNode(treeNode,prim),prim),child);
1482 break;
1483 case AITypeEvent:
1484 parsePrimEvent(nextTreeNode(treeNode,child),child);
1485 break;
1486 case AITypeBadType:
1487 case AITypeFolder:
1488 break;
1490 default:
1491 if (type!=AITypePlace && type!=AITypePlaceFauna)
1492 nlwarning("Don't know how to treat ai_type '%s'",getName(type));
1493 break;
1497 CAIActions::end(treeNode->getAlias());
1500 static void parsePrimMgrFauna(const std::string &mapName,const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim,std::vector<SFolderRef> &folders, const std::string &filename, bool firstTime=true)
1502 // get hold of the unique id
1503 uint32 uniqueId=nodeAlias(prim, true);
1505 // setup the mgr context
1506 if (firstTime)
1508 CAIActions::begin(treeNode->getAlias());
1509 CAIActions::exec("MGRFAUNA",treeNode->getAlias(),treeNode->getName(),mapName, filename);
1510 CAIActions::exec("IDTREE",treeNode);
1513 // run through the mgr children looking for nodes with types that we recognise
1514 for (uint i=0;i<prim->getNumChildren();++i)
1516 // get a pointer to the child and make sure its valid
1517 const IPrimitive *child;
1518 if (!prim->getChild(child,i))
1519 continue;
1521 // try to get a type for the child
1522 TAIType type=nodeType(child);
1524 switch(type)
1526 case AITypeGrp:
1527 parsePrimGrpFauna(nextTreeNode(treeNode,child),child);
1528 break;
1529 case AITypeState:
1530 parsePrimState(nextTreeNode(treeNode,child),child,"PATAT");
1531 break;
1532 case AITypeEvent:
1533 parsePrimEvent(nextTreeNode(treeNode,child),child);
1534 break;
1535 // this isn't an ai block so check its children
1536 case AITypeBadType:
1537 parsePrimMgrFauna(mapName,nextTreeNode(treeNode,child),child,folders,filename,false);
1538 break;
1539 case AITypeFolder:
1540 break;
1541 default:
1542 nlwarning("Found ai_type: '%s' when expecting 'GROUP_FAUNA'",getName(type));
1543 break;
1547 if (firstTime)
1548 CAIActions::end(treeNode->getAlias());
1551 static void parsePrimNPCPunctualState(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
1553 // get hold of the node name and unique id
1554 std::string name=nodeName(prim);
1555 uint32 uniqueId=nodeAlias(prim);
1557 LOG("Parsing npc punctual state: %s",name.c_str());
1559 // look for keywords
1560 const std::vector<std::string> *keywords=&EmptyStringVector;
1561 prim->getPropertyByName("grp_keywords",keywords);
1563 // create the state
1564 CAIActions::begin(treeNode->getAlias());
1565 CAIActions::exec("PUNCTUAL",uniqueId);
1566 if (!keywords->empty()) CAIActions::execute("KEYWORDS",*keywords);
1568 // run through the group children looking for nodes with types that we recognise
1569 for (uint i=0;i<prim->getNumChildren();++i)
1571 // get a pointer to the child and make sure its valid
1572 const IPrimitive *child;
1573 if (prim->getChild(child,i))
1575 switch (nodeType(child))
1577 case AITypeNpcStateProfile:
1578 parsePrimStateProfile(nextTreeNode(treeNode,child),child);
1579 break;
1580 case AITypeNpcStateChat:
1581 parsePrimStateChat(nextTreeNode(treeNode,child),child);
1582 break;
1583 case AITypeEvent:
1584 parsePrimEvent(nextTreeNode(treeNode,child),child);
1585 break;
1586 case AITypeBadType:
1587 case AITypeFolder:
1588 break;
1589 default: // we don't care unknown objets.
1590 nlwarning("Don't know how to treat ai_type '%s'",getName(nodeType(child)));
1591 break;
1597 CAIActions::end(treeNode->getAlias());
1600 static void parsePrimMgrKami(const std::string &mapName,const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim,std::vector<SFolderRef> &folders, const std::string &filename,bool firstTime=true)
1602 // get hold of the unique id
1603 uint32 uniqueId=nodeAlias(prim);
1605 // setup the mgr context
1606 if (firstTime)
1608 CAIActions::begin(treeNode->getAlias());
1609 CAIActions::exec("MGRNPC",treeNode->getAlias(),treeNode->getName(),mapName, filename);
1610 CAIActions::exec("IDTREE",treeNode);
1613 // run through the mgr children looking for nodes with types that we recognise
1614 for (uint i=0;i<prim->getNumChildren();++i)
1616 // get a pointer to the child and make sure its valid
1617 const IPrimitive *child;
1618 if (!prim->getChild(child,i))
1619 continue;
1621 // try to get a type for the child
1622 TAIType type=nodeType(child);
1624 switch(type)
1626 case AITypeNpcStateRoute:
1627 parsePrimState(nextTreeNode(treeNode,child),child,"PATH");
1628 break;
1629 case AITypeNpcStateZone:
1630 parsePrimState(nextTreeNode(treeNode,child),child,"PATAT");
1631 break;
1632 case AITypePunctualState:
1633 parsePrimNPCPunctualState(nextTreeNode(treeNode,child),child);
1634 break;
1635 case AITypeEvent:
1636 parsePrimEvent(nextTreeNode(treeNode,child),child);
1637 break;
1639 case AITypeKamiDeposit: // a deposit
1640 parsePrimState(nextTreeNode(treeNode,child),child,"PATAT");
1641 break;
1643 case AITypeBadType:
1644 parsePrimMgrKami(mapName,nextTreeNode(treeNode,child),child,folders,filename, false);
1645 break;
1646 case AITypeFolder:
1647 break;
1648 default:
1649 nlwarning("Unsupported ai_type in parsePrimMgrKami");
1650 break;
1654 if (firstTime)
1655 CAIActions::end(treeNode->getAlias());
1658 static void parsePrimMgrKaravan(const std::string &mapName,const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim,std::vector<SFolderRef> &folders, const std::string &filename,bool firstTime=true)
1660 // get hold of the unique id
1661 uint32 uniqueId=nodeAlias(prim);
1663 // setup the mgr context
1664 if (firstTime)
1666 CAIActions::begin(treeNode->getAlias());
1667 CAIActions::exec("MGRNPC",treeNode->getAlias(),treeNode->getName(),mapName, filename);
1668 CAIActions::exec("IDTREE",treeNode);
1671 // run through the mgr children looking for nodes with types that we recognise
1672 for (uint i=0;i<prim->getNumChildren();++i)
1674 // get a pointer to the child and make sure its valid
1675 const IPrimitive *child;
1676 if (prim->getChild(child,i))
1678 // try to get a type for the child
1679 TAIType type=nodeType(child);
1681 switch(type)
1683 case AITypeKaravanState:
1684 parsePrimState(nextTreeNode(treeNode,child),child,"");
1685 break;
1686 case AITypeBadType:
1687 parsePrimMgrKaravan(mapName,nextTreeNode(treeNode,child),child,folders,filename, false);
1688 break;
1689 case AITypeFolder:
1690 break;
1691 default:
1692 nlwarning("Unsupported ai_type in parsePrimMgrKaravan");
1693 break;
1699 if (firstTime)
1700 CAIActions::end(treeNode->getAlias());
1703 //---------------------------------------------------------------------------------------
1704 // npc routines
1707 void mergeEquipement(const std::vector<std::string> &grpEquip, const std::vector<std::string> &botEquip, std::vector<std::string> &result)
1709 uint i;
1710 map<string, string> equip;
1711 string key, tail;
1713 for (i=0; i<grpEquip.size(); ++i)
1715 if (stringToKeywordAndTail(grpEquip[i], key, tail))
1716 equip[key] = tail;
1718 for (i=0; i<botEquip.size(); ++i)
1720 if (stringToKeywordAndTail(botEquip[i], key, tail))
1721 equip[key] = tail;
1724 result.clear();
1725 // rebuild the final equipement
1726 map<string, string>::iterator first(equip.begin()), last(equip.end());
1727 for (; first != last; ++first)
1729 result.push_back(first->first + " : " + first->second);
1733 static void parsePrimBotNpc(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
1735 // get hold of the node name and unique id
1736 std::string name=nodeName(prim);
1737 uint32 uniqueId=nodeAlias(prim);
1739 // setup the set of parameters that are initialised by default in parsePrimGrpNpc()
1740 //oldlevel std::string levelStr; /* = DefaultBotLevel; */
1741 std::string look; // = DefaultBotLook;
1742 // std::string fight;
1743 // std::string stats; // = DefaultBotStats;
1744 const std::vector<std::string> *keywords = NULL; //DefaultBotKeywords;
1745 const std::vector<std::string> *equipment = NULL; //&EmptyStringVector;// = DefaultBotEquipment;
1746 const std::vector<std::string> *chat = NULL; //DefaultBotChat;
1747 static std::vector<int> missions;
1748 static std::vector<std::string> missionsNames;
1749 missions = DefaultMissions;
1750 missionsNames = DefaultMissionNames;
1751 std::string isStuck;
1752 uint32 verticalPos;
1754 // try to read the above parameters from prim (on failure default value persists)
1755 //oldlevel if (!prim->getPropertyByName("level", levelStr) || levelStr.empty())
1756 //oldlevel levelStr = DefaultBotLevel;
1757 if (!prim->getPropertyByName("keywords", keywords) || keywords == NULL)
1758 keywords = DefaultBotKeywords;
1759 if (!prim->getPropertyByName("equipment", equipment) || equipment == NULL)
1760 equipment = &EmptyStringVector;
1761 if (!prim->getPropertyByName("chat_parameters", chat) || chat == NULL)
1762 chat = DefaultBotChat;
1763 if (!prim->getPropertyByName("sheet_client", look) || look.empty())
1764 look = DefaultBotLook;
1765 prim->getPropertyByName("is_stuck", isStuck);
1766 lookForMissions(prim, missions, missionsNames);
1768 if (!parseVerticalPos(prim, verticalPos))
1769 verticalPos = DefaultBotVerticalPos;
1771 // build the equipement
1772 std::vector<std::string> equipmentMerged;
1773 mergeEquipement(*DefaultBotEquipment, *equipment, equipmentMerged);
1775 // lookup coordinate and orientation for the bot
1776 const CPrimPoint *point=dynamic_cast<const CPrimPoint *>(prim);
1777 if (point==NULL)
1779 nlwarning("Failed to cast to CPrimPoin bot: %s",name.c_str());
1780 return;
1782 sint x=(uint32)(point->Point.x*1000);
1783 sint y=(uint32)(point->Point.y*1000);
1784 float theta=(float)point->Angle;
1786 // setup the bots
1787 LOG("Adding npc bot: %s pos: (%d,%d) orientation: %.2f",name.c_str(),x,y,theta);
1789 CAIActions::begin(treeNode->getAlias());
1790 CAIActions::exec("BOTNPC",uniqueId);
1791 CAIActions::exec("STARTPOS",x,y,theta, verticalPos);
1792 CAIActions::exec("LOOK",look);
1793 // CAIActions::exec("STATS",stats+NLMISC::toString("_lvl_%02d",level),level);
1794 CAIActions::exec("STATS"); //,level);
1795 CAIActions::exec("ISSTUCK", uint32(nlstricmp( isStuck.c_str(), "true") == 0));
1796 CAIActions::exec("BLDNGBOT", uint32(false));
1797 // if ( !fight.empty() )
1798 // CAIActions::exec("FIGHTBRK",fight);
1799 CAIActions::execute("CHAT", *chat);
1800 CAIActions::execute("EQUIP", equipmentMerged);
1801 CAIActions::execute("KEYWORDS", *keywords);
1802 for (uint i=0; i<missions.size(); ++i)
1803 CAIActions::exec("MISSIONS", missions[i], missionsNames[i]);
1804 // CAIActions::execute("MISSIONS", missions, missionsNames);
1805 CAIActions::end(treeNode->getAlias());
1808 static void parsePrimGrpParameters(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
1810 vector<string> *profileParams = &EmptyStringVector;
1811 DefaultGrpParameters =&EmptyStringVector;
1813 prim->getPropertyByName("grp_parameters",DefaultGrpParameters);
1814 prim->getPropertyByName("ai_profile_params",profileParams);
1816 CAIActions::execute("PARAMETR",*DefaultGrpParameters);
1817 CAIActions::execute("PROFPARM",*profileParams);
1820 static void parsePrimGrpNpc(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim, const std::string initialState)
1822 // get hold of the node name and unique id
1823 std::string name=nodeName(prim);
1824 uint32 uniqueId=nodeAlias(prim);
1826 LOG("Parsing npc group: %s",name.c_str());
1828 // setup the grp context
1829 CAIActions::begin(treeNode->getAlias());
1830 CAIActions::exec("GRPNPC",treeNode->getAlias());
1832 // group parameters
1833 const std::vector<std::string> *keywords=&EmptyStringVector;
1834 prim->getPropertyByName("grp_keywords",keywords);
1835 CAIActions::execute("KEYWORDS",*keywords);
1837 string s;
1838 prim->getPropertyByName("autoSpawn", s);
1839 CAIActions::exec("AUTOSPWN", uint32(nlstricmp( s.c_str(), "false") != 0));
1841 // bot groups contain a set of default parameters for their bot children
1842 //oldlevel DefaultBotLevel.clear(); prim->getPropertyByName("bot_level",DefaultBotLevel);
1844 DefaultBotLook.clear(); prim->getPropertyByName("bot_sheet_client",DefaultBotLook);
1845 // DefaultBotStats.clear(); prim->getPropertyByName("bot_sheet_server",DefaultBotStats);
1847 DefaultBotKeywords=&EmptyStringVector; prim->getPropertyByName("bot_keywords",DefaultBotKeywords);
1848 DefaultBotEquipment=&EmptyStringVector; prim->getPropertyByName("bot_equipment",DefaultBotEquipment);
1849 DefaultBotChat=&EmptyStringVector; prim->getPropertyByName("bot_chat_parameters",DefaultBotChat);
1850 DefaultMissionNames.clear();
1851 DefaultMissions.clear(); lookForMissions(prim, DefaultMissions, DefaultMissionNames);
1854 parseVerticalPos(prim, DefaultBotVerticalPos, "bot_vertical_pos");
1856 DefaultGrpParameters =&EmptyStringVector;
1857 CAIActions::execute("PARAMETR",*DefaultGrpParameters);
1859 // count the number of bots so that we can allocate the correct space for them
1860 bool foundBots=false;
1861 for (uint j=0;!foundBots && j<prim->getNumChildren();++j)
1863 // get a pointer to the child and make sure its valid
1864 const IPrimitive *child;
1865 if (prim->getChild(child,j))
1867 // try to get a type for the child - we're looking for children of type 'NPC_BOT'
1868 TAIType type=nodeType(child);
1869 if ( type!=AITypeBadType
1870 && type==AITypeBot )
1871 foundBots=true;
1875 // parse the group parameter
1876 for (uint i=0; i<prim->getNumChildren(); ++i)
1878 const IPrimitive *child;
1879 if (prim->getChild(child,i))
1881 if (nodeClass(child) == "npc_group_parameters")
1883 parsePrimGrpParameters(nextTreeNode(treeNode,child),child);
1884 break;
1889 prim->getPropertyByName("count",s);
1890 uint botCount;
1891 NLMISC::fromString(s, botCount);
1893 if (foundBots && botCount != 0)
1895 nlwarning("Mixing of automatic and explicit bot is not supported, only explicit bot will be spawned ! (in '%s')", treeNode->fullName().c_str());
1897 // if we didn't find any explicit bots then generate a set of 'default' bots
1898 if (!foundBots)
1900 if (botCount>200 || s!=NLMISC::toString(botCount))
1902 nlwarning("Invalid 'count' (value: '%s') parameter in NPC bot group: %s",s.c_str(),treeNode->fullName().c_str());
1903 return;
1905 if (botCount==0)
1907 if (!DefaultBotLook.empty())
1909 nlwarning("No bots found in NPC group: %s",treeNode->fullName().c_str());
1910 return;
1914 CAIActions::exec("BOTCOUNT",botCount);
1915 for (uint i=0;i<botCount;++i)
1917 CAIActions::begin(i);
1918 CAIActions::exec("BOTNPC",i);
1919 CAIActions::exec("STARTPOS",0,0,0.0f, DefaultBotVerticalPos);
1920 CAIActions::exec("LOOK", DefaultBotLook);
1921 CAIActions::exec("STATS"); //, level ); // +NLMISC::toString("_lvl_%02d",level)
1922 CAIActions::execute("CHAT",*DefaultBotChat);
1923 CAIActions::execute("EQUIP",*DefaultBotEquipment);
1924 CAIActions::execute("KEYWORDS",*DefaultBotKeywords);
1925 CAIActions::end(i);
1928 else
1929 CAIActions::exec("BOTCOUNT",0); // tell the system that we are not using auto generated bots but named bots
1931 // run through the group children looking for nodes with types that we recognise
1932 for (uint i=0;i<prim->getNumChildren();++i)
1934 // get a pointer to the child and make sure its valid
1935 const IPrimitive *child;
1936 if (prim->getChild(child,i))
1938 // try to get a type for the child
1939 // it's one of ours! - so match against the types we recognise
1940 switch(nodeType(child))
1942 case AITypeBot:
1943 parsePrimBotNpc(nextTreeNode(treeNode,child),child);
1944 break;
1945 case AITypeEvent:
1946 parsePrimEvent(nextTreeNode(treeNode,child),child);
1947 break;
1948 case AITypeBadType:
1949 case AITypeFolder:
1950 // case AITypeGrpParameters:
1951 break;
1952 default:
1953 nlwarning("Don't know how to treat ai_type '%s'",getName(nodeType(child)));
1954 break;
1960 CAIActions::end(treeNode->getAlias());
1963 /*static void parsePrimNPCPunctualState(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
1965 // get hold of the node name and unique id
1966 std::string name=nodeName(prim);
1967 uint32 uniqueId=nodeAlias(prim);
1969 LOG("Parsing npc punctual state: %s",name.c_str());
1971 // look for keywords
1972 const std::vector<std::string> *keywords=&EmptyStringVector;
1973 prim->getPropertyByName("grp_keywords",keywords);
1975 // create the state
1976 CAIActions::begin(treeNode->getAlias());
1977 CAIActions::exec("PUNCTUAL",uniqueId);
1978 if (!keywords->empty()) CAIActions::execute("KEYWORDS",*keywords);
1980 // run through the group children looking for nodes with types that we recognise
1981 for (uint i=0;i<prim->getNumChildren();++i)
1983 // get a pointer to the child and make sure its valid
1984 const IPrimitive *child;
1985 if (prim->getChild(child,i))
1987 // try to get a type for the child
1988 TAIType type=nodeType(child);
1989 if ( type!=AITypeBadType
1990 && type!=AITypeFolder)
1992 if (type==AITypeNpcStateProfile)
1993 parsePrimStateProfile(nextTreeNode(treeNode,child),child);
1994 else if (type==AITypeEvent)
1995 parsePrimEvent(nextTreeNode(treeNode,child),child);
1996 else
1997 nlwarning("Don't know how to treat ai_type '%s'",getName(type));
2002 CAIActions::end(treeNode->getAlias());
2005 static void parsePrimMgrNpc(const std::string &mapName,const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim,std::vector<SFolderRef> &folders, const std::string &filename,bool firstTime=true)
2007 // get hold of the unique id
2008 uint32 uniqueId=nodeAlias(prim);
2010 // setup the mgr context
2011 if (firstTime)
2013 CAIActions::begin(treeNode->getAlias());
2014 CAIActions::exec("MGRNPC",treeNode->getAlias(),treeNode->getName(),mapName, filename);
2015 CAIActions::exec("IDTREE",treeNode);
2018 // run through the mgr children looking for nodes with types that we recognise
2019 for (uint i=0;i<prim->getNumChildren();++i)
2021 // get a pointer to the child and make sure its valid
2022 const IPrimitive *child;
2023 if (prim->getChild(child,i))
2025 switch(nodeType(child))
2027 case AITypeNpcStateRoute:
2028 parsePrimState(nextTreeNode(treeNode,child),child,"PATH");
2029 break;
2030 case AITypeNpcStateZone:
2031 parsePrimState(nextTreeNode(treeNode,child),child,"PATAT");
2032 break;
2033 case AITypeState:
2034 parsePrimState(nextTreeNode(treeNode,child),child,"PATAT");
2035 break;
2036 case AITypePunctualState:
2037 parsePrimNPCPunctualState(nextTreeNode(treeNode,child),child);
2038 break;
2039 case AITypeEvent:
2040 parsePrimEvent(nextTreeNode(treeNode,child),child);
2041 break;
2042 case AITypeGrp:
2043 parsePrimGrpNpc(nextTreeNode(treeNode,child),child,std::string());
2044 break;
2045 // uinknown so pass it..
2046 case AITypeBadType:
2047 if (nodeClass(child) != "alias")
2048 parsePrimMgrNpc(mapName,nextTreeNode(treeNode,child),child,folders,filename, false);
2049 break;
2050 case AITypeFolder:
2051 break;
2052 default:
2053 nlwarning("unrecognised ai_type in NPC manager %s: '%s'",treeNode->fullName().c_str(),getName(nodeType(child)));
2054 break;
2059 if (firstTime)
2061 // now add the folders to the manager
2062 for (uint i=0;i<folders.size();++i)
2063 parsePrimMgrNpc(mapName,folders[i].Node,folders[i].Prim,folders, filename,false);
2064 // close the manger
2065 CAIActions::end(treeNode->getAlias());
2069 static void parsePrimMgrOutpost(std::string const& mapName, CAIAliasDescriptionNode const* treeNode, IPrimitive const* prim, std::vector<SFolderRef>& folders, std::string const& filename,bool firstTime=true)
2071 // get hold of the unique id
2072 uint32 uniqueId = nodeAlias(prim);
2074 // setup the mgr context
2075 if (firstTime)
2077 std::string str;
2078 prim->getPropertyByName("manual_spawn", str);
2079 bool manualSpawn = (str == "true");
2080 CAIActions::begin(treeNode->getAlias());
2081 CAIActions::exec("MGROUTPO",treeNode->getAlias(), treeNode->getName(), mapName, filename, manualSpawn);
2082 CAIActions::exec("IDTREE",treeNode);
2085 // run through the mgr children looking for nodes with types that we recognise
2086 for (uint i=0;i<prim->getNumChildren();++i)
2088 // get a pointer to the child and make sure its valid
2089 const IPrimitive *child;
2090 if (prim->getChild(child,i))
2092 switch(nodeType(child))
2094 case AITypeNpcStateRoute:
2095 parsePrimState(nextTreeNode(treeNode,child),child,"PATH");
2096 break;
2097 case AITypeNpcStateZone:
2098 parsePrimState(nextTreeNode(treeNode,child),child,"PATAT");
2099 break;
2100 case AITypeState:
2101 parsePrimState(nextTreeNode(treeNode,child),child,"PATAT");
2102 break;
2103 case AITypePunctualState:
2104 parsePrimNPCPunctualState(nextTreeNode(treeNode,child),child);
2105 break;
2106 case AITypeEvent:
2107 parsePrimEvent(nextTreeNode(treeNode,child),child);
2108 break;
2109 case AITypeGrp:
2110 parsePrimGrpNpc(nextTreeNode(treeNode,child),child,std::string());
2111 break;
2112 // uinknown so pass it..
2113 case AITypeBadType:
2114 if (nodeClass(child) != "alias")
2115 parsePrimMgrOutpost(mapName, nextTreeNode(treeNode, child), child, folders, filename, false);
2116 break;
2117 case AITypeFolder:
2118 break;
2119 default:
2120 nlwarning("unrecognised ai_type in outpost manager %s: '%s'",treeNode->fullName().c_str(),getName(nodeType(child)));
2121 break;
2126 if (firstTime)
2128 // now add the folders to the manager
2129 for (uint i=0;i<folders.size();++i)
2130 parsePrimMgrOutpost(mapName, folders[i].Node, folders[i].Prim, folders, filename, false);
2131 // close the manger
2132 CAIActions::end(treeNode->getAlias());
2136 //---------------------------------------------------------------------------------------
2137 // parsing route nodes for managers (of all types)
2139 static void parsePrimMgr(const IPrimitive *prim,const std::string &mapName, const std::string &filename)
2141 H_AUTO( parsePrim_Mgr );
2142 // get hold of the node name and unique id
2143 std::string name=nodeName(prim);
2144 uint32 uniqueId=nodeAlias(prim);
2146 LOG("Parsing manager: %s",name.c_str());
2148 // make sure the manager type is specified and is one of ours
2149 std::string mgrTypeName;
2150 TMgrType mgrType=MgrTypeBadType;
2151 prim->getPropertyByName("ai_manager_type",mgrTypeName);
2152 mgrType=getTypeAs(mgrType,mgrTypeName.c_str());
2153 if (mgrType==MgrTypeBadType)
2155 nlwarning("Ignoring manager due to unknown type: '%s'",mgrTypeName.c_str());
2156 return;
2159 // TAITypeSpec typeSpec;
2160 // switch (mgrType)
2161 // {
2162 // case MgrTypeFauna: typeSpec = AITypeSpecFauna; break;
2163 // case MgrTypeKaravan: typeSpec = AITypeSpecKaravan; break;
2164 // case MgrTypeKami: typeSpec = AITypeSpecKami; break;
2165 //// case MgrTypeTribe: typeSpec = AITypeSpecTribe; break;
2166 // case MgrTypeNpc: typeSpec = AITypeSpecNpc; break;
2168 // // TODO: case MgrTypePet:
2169 // // TODO: case MgrTypeGuildNpc:
2171 // default: nlwarning("Unhandled ai manager type: '%s'",mgrTypeName.c_str());
2172 // }
2174 // build the tree of aliases and the vector of folders
2175 std::vector<SFolderRef> folders;
2176 NLMISC::CSmartPtr<CAIAliasDescriptionNode> aliasTree;
2178 H_AUTO( parsePrim_aliasTree );
2179 aliasTree=new CAIAliasDescriptionNode (name, uniqueId, AITypeManager, NULL);
2180 buildAliasTree(aliasTree,aliasTree,prim,folders);
2183 switch (mgrType)
2185 case MgrTypeFauna: parsePrimMgrFauna(mapName,aliasTree,prim,folders, filename); break;
2186 case MgrTypeKaravan: parsePrimMgrKaravan(mapName,aliasTree,prim,folders, filename); break;
2187 case MgrTypeKami: parsePrimMgrKami(mapName,aliasTree,prim,folders, filename); break;
2188 // case MgrTypeTribe: parsePrimMgrTribe(mapName,aliasTree,prim,folders); break;
2189 case MgrTypeNpc: parsePrimMgrNpc(mapName,aliasTree,prim,folders, filename); break;
2190 case MgrTypeOutpost: parsePrimMgrOutpost(mapName,aliasTree,prim,folders, filename); break;
2192 // TODO: case MgrTypePet:
2193 // TODO: case MgrTypeGuildNpc:
2195 default: nlwarning("Unhandled ai manager type: '%s'",mgrTypeName.c_str());
2198 CAIAliasDescriptionNode::flushUnusedAliasDescription ();
2201 //---------------------------------------------------------------------------------------
2202 // parsing spires
2204 static void parsePrimMgrSpire(std::string const& mapName, CAIAliasDescriptionNode const* treeNode, IPrimitive const* prim, std::vector<SFolderRef>& folders, std::string const& filename, bool firstTime=true)
2206 uint32 uniqueId = nodeAlias(prim);
2208 // setup the mgr context
2209 if (firstTime)
2213 parsePrimGrpSpire(treeNode, prim, "");
2215 // run through the mgr children looking for nodes with types that we recognise
2216 for (uint i=0; i<prim->getNumChildren(); ++i)
2218 // get a pointer to the child and make sure its valid
2219 IPrimitive const* child;
2220 if (prim->getChild(child, i))
2222 switch (nodeType(child))
2224 case AITypeEvent:
2225 parsePrimEvent(nextTreeNode(treeNode, child), child);
2226 break;
2227 default:
2228 nlwarning("unrecognised ai_type in NPC manager %s: '%s'",treeNode->fullName().c_str(),getName(nodeType(child)));
2229 break;
2234 CAIActions::end(treeNode->getAlias());
2237 static void parsePrimSpire(IPrimitive const* prim, std::string const& mapName, std::string const& filename)
2239 // get hold of the node name and unique id
2240 std::string name = nodeName(prim);
2241 uint32 uniqueId = nodeAlias(prim);
2243 LOG("Parsing spire: %s", name.c_str());
2245 CPrimPoint const* point = dynamic_cast<CPrimPoint const*>(prim);
2246 if (!point)
2248 nlwarning("Failed to cast spire to CPrimPoint: %s", name.c_str());
2249 return;
2251 sint x = (uint32)(point->Point.x*1000);
2252 sint y = (uint32)(point->Point.y*1000);
2253 float theta = (float)point->Angle;
2254 uint32 verticalPos;
2255 if (!parseVerticalPos(prim, verticalPos))
2256 verticalPos = DefaultBotVerticalPos;
2257 std::string effect, sheet_socle;
2258 std::vector<std::string>* sheet_spire;
2259 // if (!prim->getPropertyByName("effect", effect) || effect.empty())
2260 // {
2261 // nlwarning("No effect defined in spire %s", name.c_str());
2262 // return;
2263 // }
2264 if (!prim->getPropertyByName("sheet_socle", sheet_socle) || sheet_socle.empty())
2265 sheet_socle = DefaultBotLook;
2266 if (!prim->getPropertyByName("sheet_spire", sheet_spire) || !sheet_spire || sheet_spire->empty())
2267 sheet_spire = &EmptyStringVector;
2268 vector<string> sheets;
2269 sheets.insert(sheets.end(), "socle:"+sheet_socle);
2270 sheets.insert(sheets.end(), sheet_spire->begin(), sheet_spire->end());
2272 uint32 mgrAlias = 0;
2273 uint32 stateAlias = 0;
2274 uint32 grpAlias = uniqueId;
2275 uint32 botAlias = 0;
2277 // build the tree of aliases and the vector of folders
2278 std::vector<SFolderRef> folders;
2279 NLMISC::CSmartPtr<CAIAliasDescriptionNode> aliasTree = new CAIAliasDescriptionNode(name, uniqueId, AITypeManager, NULL);
2280 buildAliasTree(aliasTree, aliasTree, prim, folders);
2282 CAIActions::begin(mgrAlias); // mgr
2283 CAIActions::exec("SPIREMGR", mgrAlias, name, mapName, filename);
2284 CAIActions::exec("IDTREE", aliasTree);
2286 CAIActions::begin(stateAlias);
2287 CAIActions::exec("SPIRSTAT", stateAlias, name);
2289 CAIActions::begin(grpAlias); // grp
2290 CAIActions::exec("SPIREGRP", grpAlias, name);
2292 CAIActions::begin(botAlias); // bot
2293 CAIActions::exec("SPIREBOT", botAlias, name);
2294 CAIActions::exec("LOOK", sheet_socle);
2295 CAIActions::execute("SPIRSHTS", sheets);
2296 CAIActions::exec("STARTPOS", x, y, theta, verticalPos);
2297 CAIActions::end(botAlias); // bot
2299 // run through the mgr children looking for nodes with types that we recognise
2300 for (uint i=0; i<prim->getNumChildren(); ++i)
2302 // get a pointer to the child and make sure its valid
2303 IPrimitive const* child;
2304 if (prim->getChild(child, i))
2306 switch (nodeType(child))
2308 case AITypeEvent:
2309 parsePrimEvent(NULL, child);
2310 break;
2311 default:
2312 nlwarning("unrecognised ai_type in spire %s: '%s'", name.c_str(), getName(nodeType(child)));
2313 break;
2317 CAIActions::end(grpAlias); // grp
2318 CAIActions::end(stateAlias); // state
2319 CAIActions::end(mgrAlias); // mgr
2321 CAIAliasDescriptionNode::flushUnusedAliasDescription();
2324 /////////////////////////////////////////////////////////
2325 /////////////////// Dynamic system parsing //////////////
2326 /////////////////////////////////////////////////////////
2328 static void parsePrimDynFaunaZone(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2330 float x, y, r;
2331 x = prim->getPrimVector()->x;
2332 y = prim->getPrimVector()->y;
2333 string s;
2334 prim->getPropertyByName("radius", s);
2335 NLMISC::fromString(s, r);
2337 vector<string> *params = &EmptyStringVector;
2338 prim->getPropertyByName("properties", params);
2340 uint32 verticalPos;
2341 parseVerticalPos(prim, verticalPos);
2343 std::string concatStr;
2344 for (uint i = 0; i < params->size(); ++ i)
2346 concatStr += (*params)[i] + " ";
2349 //nlinfo("creating cell zone with flags : %s", concatStr.c_str());
2351 CAIActions::begin(aliasNode->getAlias());
2352 CAIActions::exec("DYNFZ", aliasNode, x, y, r, /*activities,*/ verticalPos);
2353 CAIActions::execute("ACT_PARM", *params);
2355 CAIActions::end(aliasNode->getAlias());
2357 static void parsePrimDynNpcZonePlace(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2359 float x, y, r;
2360 x = prim->getPrimVector()->x;
2361 y = prim->getPrimVector()->y;
2362 string s;
2363 prim->getPropertyByName("radius", s);
2364 NLMISC::fromString(s, r);
2366 vector<string> *params=&EmptyStringVector;
2367 prim->getPropertyByName("properties", params);
2369 uint32 verticalPos;
2370 parseVerticalPos(prim, verticalPos);
2372 CAIActions::begin(aliasNode->getAlias());
2373 CAIActions::exec("DYNNZ", aliasNode, x, y, r, verticalPos);
2375 CAIActions::execute("DYNNZPRM", *params);
2377 CAIActions::end(aliasNode->getAlias());
2379 static void parsePrimDynNpcZoneShape(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2381 uint32 verticalPos;
2382 parseVerticalPos(prim, verticalPos);
2384 // extract x and y coords of points from patate
2385 std::vector <CAIActions::CArg> args;
2386 args.push_back(aliasNode);
2387 args.push_back(verticalPos);
2388 uint numPoints=prim->getNumVector();
2389 if (numPoints!=0)
2391 const CPrimVector *pointArray=prim->getPrimVector();
2392 for (uint i=0;i<numPoints;++i)
2394 args.push_back(CAIActions::CArg(pointArray[i].x));
2395 args.push_back(CAIActions::CArg(pointArray[i].y));
2398 else
2399 LOG("Zone has no geometry"/*": %s: %s",pointsType,name.c_str()*/);
2401 vector<string> *params=&EmptyStringVector;
2402 prim->getPropertyByName("properties", params);
2404 CAIActions::begin(aliasNode->getAlias());
2405 CAIActions::execute("DYNNZSHP", args);
2407 CAIActions::execute("DYNNZPRM", *params);
2409 CAIActions::end(aliasNode->getAlias());
2411 static void parsePrimRoadTrigger(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2413 CPrimVector t1, t2, sp;
2414 float t1r = 0.f;
2415 float t2r = 0.f;
2416 float spr = 0.f;
2417 string s;
2419 for (uint i=0; i<prim->getNumChildren(); ++i)
2421 const IPrimitive *child;
2422 if (prim->getChild(child, i))
2424 if (nodeName(child) == "trigger 1")
2426 t1 = *child->getPrimVector();
2427 child->getPropertyByName("radius", s);
2428 NLMISC::fromString(s, t1r);
2430 else if (nodeName(child) == "trigger 2")
2432 t2 = *child->getPrimVector();
2433 child->getPropertyByName("radius", s);
2434 NLMISC::fromString(s, t2r);
2436 else if (nodeName(child) == "spawn")
2438 sp = *child->getPrimVector();
2439 child->getPropertyByName("radius", s);
2440 NLMISC::fromString(s, spr);
2446 CAIActions::begin(aliasNode->getAlias());
2447 CAIActions::exec("TRIGGER", aliasNode);
2449 CAIActions::exec("TRIGT1", t1.x, t1.y, t1r);
2450 CAIActions::exec("TRIGT2", t2.x, t2.y, t2r);
2451 CAIActions::exec("TRIGSP", sp.x, sp.y, spr);
2453 // TODO
2454 // set<string> flags;
2455 // parseFamilyFlag(prim, flags);
2456 // vector<string> v(flags.begin(), flags.end());
2457 // CAIActions::execute("TRIGFLG", v);
2459 CAIActions::end(aliasNode->getAlias());
2462 static void parsePrimDynRoad(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2464 // get hold of the node name and unique id
2465 std::string name=nodeName(prim);
2466 uint32 uniqueId=nodeAlias(prim);
2468 // road dificulty
2469 string s;
2470 prim->getPropertyByName("difficulty", s);
2471 float difficulty;
2472 NLMISC::fromString(s, difficulty);
2474 uint32 verticalPos;
2475 parseVerticalPos(prim, verticalPos);
2477 CAIActions::begin(aliasNode->getAlias());
2478 CAIActions::exec("DYNROAD", aliasNode, difficulty, verticalPos);
2480 // build polygon data
2481 vector<double> poly;
2482 const CPrimVector *v = prim->getPrimVector();
2483 for (uint i=0; i<prim->getNumVector(); ++i)
2485 poly.push_back(v[i].x);
2486 poly.push_back(v[i].y);
2488 CAIActions::execute("ROADGEO", poly);
2490 // run through the dynsystem children looking for nodes with types that we recognise
2491 for (uint i=0;i<prim->getNumChildren();++i)
2493 // get a pointer to the child and make sure its valid
2494 const IPrimitive *child;
2495 if (prim->getChild(child, i))
2497 switch(nodeType(child))
2499 case AITypeRoadTrigger:
2500 parsePrimRoadTrigger(nextTreeNode(aliasNode,child),child);
2501 break;
2502 default:
2503 break;
2507 CAIActions::end(aliasNode->getAlias());
2510 static void parsePrimGeomItems(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2512 // get hold of the node name and unique id
2513 std::string name=nodeName(prim);
2514 uint32 uniqueId=nodeAlias(prim);
2516 // run through the dynsystem children looking for nodes with types that we recognise
2517 for (uint i=0;i<prim->getNumChildren();++i)
2519 // get a pointer to the child and make sure its valid
2520 const IPrimitive *child;
2521 if (prim->getChild(child, i))
2523 switch(nodeType(child))
2525 case AITypeDynFaunaZone:
2526 parsePrimDynFaunaZone(nextTreeNode(aliasNode,child),child);
2527 break;
2528 case AITypeDynNpcZonePlace:
2529 parsePrimDynNpcZonePlace(nextTreeNode(aliasNode,child),child);
2530 break;
2531 case AITypeDynNpcZoneShape:
2532 parsePrimDynNpcZoneShape(nextTreeNode(aliasNode,child),child);
2533 break;
2534 case AITypeDynRoad:
2535 parsePrimDynRoad(nextTreeNode(aliasNode,child),child);
2536 break;
2537 default:
2538 break;
2544 static void parsePrimCell(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2546 // get hold of the node name and unique id
2547 std::string name=nodeName(prim);
2548 uint32 uniqueId=nodeAlias(prim);
2550 // set<string> flags;
2552 // read the family flags
2553 // TODO
2554 // parseFamilyFlag(prim, flags);
2556 CAIActions::begin(aliasNode->getAlias());
2557 CAIActions::exec("CELL", aliasNode);
2558 // build the resulting vector of family/tribe string/
2559 // vector<string> vs(flags.begin(), flags.end());
2560 // CAIActions::execute("CELLFLG", vs);
2562 // build polygon data
2563 vector<double> poly;
2564 const CPrimVector *v = prim->getPrimVector();
2565 for (uint i=0; i<prim->getNumVector(); ++i)
2567 poly.push_back(v[i].x);
2568 poly.push_back(v[i].y);
2570 CAIActions::execute("CELLGEO", poly);
2573 // run through the dynsystem children looking for nodes with types that we recognise
2574 for (uint i=0;i<prim->getNumChildren();++i)
2576 // get a pointer to the child and make sure its valid
2577 const IPrimitive *child;
2578 if (prim->getChild(child, i))
2580 string cname = nodeClass(child);
2581 if (cname == "geom_items")
2582 parsePrimGeomItems(nextTreeNode(aliasNode,child),child);
2587 CAIActions::end(aliasNode->getAlias());
2591 //void parsePrimCellZoneEnergy(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2593 // std::string family;
2594 // std::string energy;
2595 // std::string energy2;
2596 // std::string energy3;
2597 // std::string energy4;
2598 // prim->getPropertyByName("name", family);
2599 // prim->getPropertyByName("energy_0_25", energy);
2600 // prim->getPropertyByName("energy_25_50", energy2);
2601 // prim->getPropertyByName("energy_50_75", energy3);
2602 // prim->getPropertyByName("energy_75_100", energy4);
2603 // CAIActions::exec("CZ_NRJ", family, energy, energy2, energy3, energy4);
2606 static void parsePrimCellZone(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2608 // get hold of the node name and unique id
2609 std::string name=nodeName(prim);
2610 uint32 uniqueId=nodeAlias(prim);
2612 CAIActions::begin(aliasNode->getAlias());
2613 CAIActions::exec("CELLZNE", aliasNode);
2615 // run through the dynsystem children looking for nodes with types that we recognise
2616 for (uint i=0;i<prim->getNumChildren();++i)
2618 // get a pointer to the child and make sure its valid
2619 const IPrimitive *child;
2620 if (prim->getChild(child, i))
2622 switch(nodeType(child))
2624 case AITypeCell:
2625 parsePrimCell(nextTreeNode(aliasNode,child),child);
2626 break;
2627 default:
2628 break;
2634 CAIActions::end(aliasNode->getAlias());
2637 static void parsePrimCellZones(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2639 // get hold of the node name and unique id
2640 std::string name=nodeName(prim);
2641 uint32 uniqueId=nodeAlias(prim);
2643 // run through the dynsystem children looking for nodes with types that we recognise
2644 for (uint i=0;i<prim->getNumChildren();++i)
2646 // get a pointer to the child and make sure its valid
2647 const IPrimitive *child;
2648 if (prim->getChild(child, i))
2650 switch(nodeType(child))
2652 case AITypeCellZone:
2653 parsePrimCellZone(nextTreeNode(aliasNode,child),child);
2654 break;
2655 default:
2656 break;
2662 static void parsePrimBotTemplate(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim, std::string const& familyType)
2664 // get hold of the node name and unique id
2665 std::string name=nodeName(prim);
2666 uint32 uniqueId=nodeAlias(prim);
2668 string s;
2669 vector<string> *botEquip = &EmptyStringVector;
2670 string lookSheet;
2671 bool multiLevel = false;
2672 sint32 levelDelta = 0;
2674 if (nodeClass(prim) == "bot_template_npc")
2676 prim->getPropertyByName("equipment", botEquip);
2677 prim->getPropertyByName("sheet_look", lookSheet);
2679 else if (nodeClass(prim) == "bot_template_npc_ml")
2681 prim->getPropertyByName("equipment", botEquip);
2682 prim->getPropertyByName("sheet_look", lookSheet);
2683 multiLevel = true;
2684 prim->getPropertyByName("level_delta", s);
2685 NLMISC::fromString(s, levelDelta);
2687 else
2689 prim->getPropertyByName("creature_code", lookSheet);
2690 if (!lookSheet.empty())
2692 // the new code system replace the old sheet_carac or creature_type
2693 // lookSheet = lookSheet+".creature";
2695 else
2697 // read the old think
2698 #ifdef NL_DEBUG
2699 nlassert(false);
2700 #endif
2701 prim->getPropertyByName("creature_type", lookSheet);
2702 //oldlevel lookSheet = lookSheet+"_lvl_"+toString("%02u", level)+".creature";
2706 CAIActions::begin(aliasNode->getAlias());
2707 CAIActions::exec("BOTTMPL"+familyType, aliasNode, lookSheet, multiLevel); //, caracSheet);
2708 CAIActions::execute("BT_EQUI"+familyType, *botEquip);
2709 CAIActions::exec("BT_LVLD"+familyType, levelDelta);
2711 CAIActions::end(aliasNode->getAlias());
2714 static void parsePrimGroupTemplate(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim, std::string const& familyType)
2716 // get hold of the node name and unique id
2717 std::string name=nodeName(prim);
2718 uint32 uniqueId=nodeAlias(prim);
2720 // read template parameters
2721 string s;
2722 uint32 botCount;
2723 vector<string> *botEquip = &EmptyStringVector;
2724 string lookSheet;
2725 string caracSheet;
2726 vector<string> *grpParam = &EmptyStringVector;
2727 bool countMultipliedBySheet;
2728 bool seasons[4];
2729 uint32 weights[4];
2730 uint32 grpEnergyValue;
2731 bool multiLevel = false;
2732 sint32 levelDelta = 0;
2734 prim->getPropertyByName("count", s);
2735 NLMISC::fromString(s, botCount);
2737 prim->getPropertyByName("count_multiplied_by_sheet", s);
2738 countMultipliedBySheet = (s == "true");
2741 if (nodeClass(prim) == "group_template_npc")
2743 // properties only for npc bots
2744 prim->getPropertyByName("bot_equipment", botEquip);
2745 prim->getPropertyByName("bot_sheet_look", lookSheet);
2747 else if (nodeClass(prim) == "group_template_npc_ml")
2749 // properties only for npc bots
2750 prim->getPropertyByName("bot_equipment", botEquip);
2751 prim->getPropertyByName("bot_sheet_look", lookSheet);
2752 multiLevel = true;
2753 prim->getPropertyByName("level_delta", s);
2754 NLMISC::fromString(s, levelDelta);
2756 else
2758 prim->getPropertyByName("creature_code", lookSheet); //caracSheet);
2759 if (!lookSheet.empty())
2762 else
2764 // read the old think
2765 prim->getPropertyByName("creature_type", lookSheet);
2768 prim->getPropertyByName("grp_parameters", grpParam);
2769 prim->getPropertyByName("exist_in_spring", s);
2770 seasons[0] = (s == "true");
2771 prim->getPropertyByName("exist_in_summer", s);
2772 seasons[1] = (s == "true");
2773 prim->getPropertyByName("exist_in_autumn", s);
2774 seasons[2] = (s == "true");
2775 prim->getPropertyByName("exist_in_winter", s);
2776 seasons[3] = (s == "true");
2778 prim->getPropertyByName("weight_0_25", s);
2779 NLMISC::fromString(s, weights[0]);
2780 prim->getPropertyByName("weight_25_50", s);
2781 NLMISC::fromString(s, weights[1]);
2782 prim->getPropertyByName("weight_50_75", s);
2783 NLMISC::fromString(s, weights[2]);
2784 prim->getPropertyByName("weight_75_100", s);
2785 NLMISC::fromString(s, weights[3]);
2787 vector<string> *actParams = &EmptyStringVector;
2789 prim->getPropertyByName("properties", actParams);
2791 prim->getPropertyByName("total_energy_value", s);
2792 grpEnergyValue = (uint32)(ENERGY_SCALE*atof(s.c_str()));
2794 s = "ALWAYS";
2795 prim->getPropertyByName("spawn_type",s);
2796 TSpawnType st;
2797 getType(st, s.c_str());
2798 uint32 spawnType = st;
2800 CAIActions::begin(aliasNode->getAlias());
2801 CAIActions::exec("GRPTMPL", aliasNode,
2802 CurrentGroupFamily,
2803 botCount,
2804 countMultipliedBySheet,
2805 multiLevel
2807 if ( nodeClass(prim) == "squad_template_variant" )
2809 vector<string> *botSheets;
2810 if ( ! (prim->getPropertyByName("bot_sheets", botSheets) && botSheets) )
2811 nlerror( "Missing property bot_sheets in squad %s", name.c_str() );
2813 CAIActions::execute("IDTREE_F", *botSheets); // create the bot descs as well (group descs created in exec("GRPTMPL"))
2815 CAIActions::exec("GT_SHEE"+familyType, lookSheet);
2816 CAIActions::exec("GT_LVLD"+familyType, levelDelta);
2817 CAIActions::exec("GT_SEAS"+familyType, seasons[0], seasons[1], seasons[2], seasons[3]);
2818 CAIActions::exec("GT_NRG"+familyType, weights[0], weights[1], weights[2], weights[3]);
2820 if (grpEnergyValue!=0) // means not initialized.
2821 CAIActions::exec("GT_GNRJ"+familyType, grpEnergyValue);
2822 CAIActions::exec("GT_ACT"+familyType, /*activity,*/ spawnType);
2823 CAIActions::execute("GT_APRM"+familyType, *actParams);
2825 CAIActions::execute("GT_EQUI"+familyType, *botEquip);
2826 CAIActions::execute("GT_GPRM"+familyType, *grpParam);
2828 std::vector <CAIActions::CArg> executeArgs;
2830 // run through the dynsystem children looking for nodes with types that we recognise
2831 for (uint i=0;i<prim->getNumChildren();++i)
2833 // get a pointer to the child and make sure its valid
2834 const IPrimitive *child;
2835 if (prim->getChild(child, i))
2837 switch(nodeType(child))
2839 case AITypeBotTemplate:
2840 case AITypeBotTemplateMultiLevel:
2841 parsePrimBotTemplate(nextTreeNode(aliasNode,child), child, familyType);
2842 break;
2843 case AITypeFaunaSpawnAtom:
2848 std::string theSheet;
2849 uint count;
2850 parsePopulation (child, theSheet, count);
2851 executeArgs.push_back(CAIActions::CArg(theSheet));
2852 executeArgs.push_back(count);
2854 catch (const parsePopException &e)
2856 nlwarning("FaunaGroup: %s of %s : %s", nodeName(child).c_str(), aliasNode->fullName().c_str(), e.what());
2860 break;
2861 default:
2862 break;
2869 if (!executeArgs.empty())
2870 CAIActions::execute("POPVER"+familyType,executeArgs);
2872 CAIActions::execute("GT_END"+familyType);
2874 CAIActions::end(aliasNode->getAlias());
2878 static void parsePrimGroupFamilyProfileFaunaContent(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2880 CAIActions::execute("TMPPRFF");
2882 const vector<string> *foodParams = &EmptyStringVector;
2883 prim->getPropertyByName("food", foodParams);
2884 CAIActions::execute("TMPPRFFF", *foodParams);
2886 const vector<string> *restParams = &EmptyStringVector;
2887 prim->getPropertyByName("rest", restParams);
2888 CAIActions::execute("TMPPRFFR", *restParams);
2890 std::string energy;
2891 std::string energy2;
2892 std::string energy3;
2893 std::string energy4;
2894 prim->getPropertyByName("energy_0_25", energy);
2895 prim->getPropertyByName("energy_25_50", energy2);
2896 prim->getPropertyByName("energy_50_75", energy3);
2897 prim->getPropertyByName("energy_75_100", energy4);
2898 CAIActions::exec("CZ_NRJ", energy, energy2, energy3, energy4);
2900 for (uint i=0;i<prim->getNumChildren();++i)
2902 // get a pointer to the child and make sure its valid
2903 const IPrimitive *child;
2904 if (prim->getChild(child, i))
2906 switch(nodeType(child))
2908 case AITypeGroupTemplateFauna:
2909 parsePrimGroupTemplate(nextTreeNode(aliasNode,child),child,"C");
2910 break;
2911 default:
2912 break;
2920 static void parsePrimGroupFamilyProfileFauna(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2922 // get hold of the node name and unique id
2923 std::string name=nodeName(prim);
2925 string familyTag;
2926 CAIActions::exec("GRPFAM", aliasNode, familyTag);
2927 parsePrimGroupFamilyProfileFaunaContent(aliasNode, prim);
2931 static void parsePrimGroupFamilyProfileTribeContent(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2933 std::string aggro_groups;
2934 prim->getPropertyByName("aggro_groups", aggro_groups);
2936 CAIActions::exec("TMPPRFT", aggro_groups);
2938 std::string energy;
2939 std::string energy2;
2940 std::string energy3;
2941 std::string energy4;
2942 prim->getPropertyByName("energy_0_25", energy);
2943 prim->getPropertyByName("energy_25_50", energy2);
2944 prim->getPropertyByName("energy_50_75", energy3);
2945 prim->getPropertyByName("energy_75_100", energy4);
2946 CAIActions::exec("CZ_NRJ", energy, energy2, energy3, energy4);
2948 for (uint i=0;i<prim->getNumChildren();++i)
2950 // get a pointer to the child and make sure its valid
2951 const IPrimitive *child;
2952 if (prim->getChild(child, i))
2954 switch(nodeType(child))
2956 case AITypeGroupTemplate:
2957 case AITypeGroupTemplateMultiLevel:
2958 parsePrimGroupTemplate(nextTreeNode(aliasNode,child),child,"C");
2959 break;
2960 default:
2961 break;
2969 static void parsePrimGroupFamilyProfileNpcContent(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
2971 CAIActions::execute("TMPPRFN");
2974 const vector<string> *flagList = &EmptyStringVector;
2975 prim->getPropertyByName("flags", flagList);
2976 CAIActions::execute("TMPPRFNF", *flagList);
2978 std::string energy;
2979 std::string energy2;
2980 std::string energy3;
2981 std::string energy4;
2982 prim->getPropertyByName("energy_0_25", energy);
2983 prim->getPropertyByName("energy_25_50", energy2);
2984 prim->getPropertyByName("energy_50_75", energy3);
2985 prim->getPropertyByName("energy_75_100", energy4);
2986 CAIActions::exec("CZ_NRJ", energy, energy2, energy3, energy4);
2988 for (uint i=0;i<prim->getNumChildren();++i)
2990 // get a pointer to the child and make sure its valid
2991 const IPrimitive *child;
2992 if (prim->getChild(child, i))
2994 switch(nodeType(child))
2996 case AITypeGroupTemplate:
2997 case AITypeGroupTemplateMultiLevel:
2998 parsePrimGroupTemplate(nextTreeNode(aliasNode,child),child,"C");
2999 break;
3000 default:
3001 break;
3009 static void parsePrimGroupFamilyProfileTribe(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
3011 // get hold of the node name and unique id
3012 std::string name=nodeName(prim);
3014 string familyTag;
3015 prim->getPropertyByName("family", familyTag);
3017 CAIActions::exec("GRPFAM", aliasNode, familyTag);
3018 parsePrimGroupFamilyProfileTribeContent(aliasNode, prim);
3021 static void parsePrimGroupFamilyProfileNpc(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
3023 // get hold of the node name and unique id
3024 std::string name=nodeName(prim);
3025 string familyTag;
3027 CAIActions::exec("GRPFAM", aliasNode, familyTag);
3028 parsePrimGroupFamilyProfileNpcContent(aliasNode, prim);
3031 static void parsePrimGroupDescriptions(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
3033 // get hold of the node name and unique id
3034 std::string name=nodeName(prim);
3035 uint32 uniqueId=nodeAlias(prim);
3037 // run through the dynsystem children looking for nodes with types that we recognise
3038 for (uint i=0;i<prim->getNumChildren();++i)
3040 // get a pointer to the child and make sure its valid
3041 const IPrimitive *child;
3042 if (prim->getChild(child, i))
3044 switch(nodeType(child))
3046 case AITypeGroupFamily:
3048 nlwarning("Parsing a group_family, primitive is outdated. Please report to jvuarand.");
3049 // parsePrimGroupFamily(nextTreeNode(aliasNode,child),child);
3051 break;
3053 case AITypeGroupFamilyProfileFauna:
3054 parsePrimGroupFamilyProfileFauna(nextTreeNode(aliasNode,child),child);
3055 // parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyFauna);
3056 break;
3058 case AITypeGroupFamilyProfileTribe:
3059 parsePrimGroupFamilyProfileTribe(nextTreeNode(aliasNode,child),child);
3060 break;
3062 case AITypeGroupFamilyProfileNpc:
3063 parsePrimGroupFamilyProfileNpc(nextTreeNode(aliasNode,child),child);
3064 break;
3066 // case AITypeGroupFamilyProfileGeneric:
3067 // parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyTribe);
3068 // break;
3069 default:
3070 break;
3076 static void parsePrimDynRegion(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim, const std::string &filename)
3078 // get hold of the node name and unique id
3079 std::string name=nodeName(prim);
3080 uint32 uniqueId=nodeAlias(prim);
3082 CAIActions::begin(aliasNode->getAlias());
3083 CAIActions::exec("DYNREG",aliasNode, filename);
3084 CAIActions::exec("IDTREE",aliasNode);
3086 // run through the dynsystem children looking for nodes with types that we recognise
3087 for (uint i=0;i<prim->getNumChildren();++i)
3089 // get a pointer to the child and make sure its valid
3090 const IPrimitive *child;
3091 if (prim->getChild(child, i))
3093 string cname = nodeClass(child);
3095 if (cname == "cell_zones")
3096 parsePrimCellZones(nextTreeNode(aliasNode,child),child);
3097 else if (cname == "group_descriptions")
3098 parsePrimGroupDescriptions(nextTreeNode(aliasNode,child),child);
3102 CAIActions::end(aliasNode->getAlias());
3105 static void parsePrimOutpostCharge(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
3107 // get hold of the node name and unique id
3108 std::string name=nodeName(prim);
3109 uint32 uniqueId=nodeAlias(prim);
3110 string civilisation;
3111 const vector<string> *params = &EmptyStringVector;
3113 prim->getPropertyByName("civilisation", civilisation);
3114 prim->getPropertyByName("parameters", params);
3117 CAIActions::begin(aliasNode->getAlias());
3118 CAIActions::exec("CHARGE", aliasNode, civilisation);
3120 CAIActions::execute("CHGPARM", *params);
3122 CAIActions::end(aliasNode->getAlias());
3125 //static void parsePrimOutpostSquadFamily(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
3127 // // get hold of the node name and unique id
3128 // std::string name = nodeName(prim);
3129 //// uint32 uniqueId = nodeAlias(prim);
3130 // /*
3131 // string civilisation;
3132 // const vector<string> *params = &EmptyStringVector;
3134 // prim->getPropertyByName("civilisation", civilisation);
3135 // prim->getPropertyByName("parameters", params);
3136 // */
3137 // CAIActions::begin(aliasNode->getAlias());
3138 // CAIActions::exec("SQUADFAM", aliasNode);
3139 //// CAIActions::exec("IDTREE",aliasNode);
3140 // /*
3142 // CAIActions::execute("CHGPARM", *params);
3144 // */
3145 // for (uint i=0;i<prim->getNumChildren();++i)
3146 // {
3147 // // get a pointer to the child and make sure its valid
3148 // const IPrimitive *child;
3149 // if (prim->getChild(child, i))
3150 // {
3151 // switch(nodeType(child))
3152 // {
3153 // case AITypeGroupTemplate:
3154 // case AITypeGroupTemplateMultiLevel:
3155 // parsePrimGroupTemplate(nextTreeNode(aliasNode,child),child,"O");
3156 // break;
3157 // }
3159 // }
3161 // }
3163 // CAIActions::end(aliasNode->getAlias());
3166 static void parsePrimOutpostSpawnZone(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
3168 float x, y, r;
3169 x = prim->getPrimVector()->x;
3170 y = prim->getPrimVector()->y;
3171 string s;
3172 prim->getPropertyByName("radius", s);
3173 NLMISC::fromString(s, r);
3175 uint32 verticalPos;
3176 parseVerticalPos(prim, verticalPos);
3178 CAIActions::begin(aliasNode->getAlias());
3179 CAIActions::exec("SPWNZONE", aliasNode, x, y, r, verticalPos);
3180 CAIActions::end(aliasNode->getAlias());
3183 static void parsePrimOutpostBuilding(CAIAliasDescriptionNode const* aliasNode, IPrimitive const* prim)
3185 string name = nodeName(prim);
3186 uint32 uniqueId = nodeAlias(prim);
3187 float x, y, theta;
3188 const CPrimPoint *point=dynamic_cast<CPrimPoint const*>(prim);
3189 if (point==NULL)
3191 nlwarning("Failed to cast to CPrimPoin bot: %s",name.c_str());
3192 return;
3194 x = point->Point.x;
3195 y = point->Point.y;
3196 theta = point->Angle;
3197 // x = prim->getPrimVector()->x;
3198 // y = prim->getPrimVector()->y;
3199 // string s;
3200 // prim->getPropertyByName("radius", s);
3201 // r = float(atof(s.c_str()));
3203 uint32 verticalPos;
3204 parseVerticalPos(prim, verticalPos);
3205 bool isStuck = true;
3207 CAIActions::begin(aliasNode->getAlias());
3208 CAIActions::exec("BUILDING", uniqueId);
3209 CAIActions::exec("STARTPOS", (sint32)(x*1000.f), (sint32)(y*1000.f), theta, verticalPos);
3210 // CAIActions::exec("LOOK", "");
3211 CAIActions::exec("ISSTUCK", uint32(isStuck));
3212 CAIActions::exec("BLDNGBOT", uint32(true));
3213 CAIActions::end(aliasNode->getAlias());
3216 static void parsePrimBotTemplate(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim, std::string const& familyType);
3218 static void parsePrimSquadTemplateVariant(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim, const std::string& templateName)
3220 // get hold of the node name
3221 std::string name = nodeName(prim);
3223 CAIActions::begin(aliasNode->getAlias());
3224 CAIActions::exec("SQD_T_V",templateName,name);
3225 parsePrimGroupTemplate(aliasNode,prim,"O");
3227 CAIActions::end(aliasNode->getAlias());
3230 static void parsePrimSquadTemplate(const IPrimitive *prim, const std::string &mapName, const std::string &filename)
3232 // get hold of the node name and unique id
3233 string name=nodeName(prim);
3234 uint32 uniqueId=nodeAlias(prim);
3236 // build the tree of aliases and the vector of folders
3237 std::vector<SFolderRef> folders;
3238 NLMISC::CSmartPtr<CAIAliasDescriptionNode> aliasNode = new CAIAliasDescriptionNode (name, uniqueId, AITypeOutpost, NULL);
3239 buildAliasTree(aliasNode, aliasNode, prim, folders);
3241 CAIActions::begin(aliasNode->getAlias());
3242 CAIActions::exec("SQD_TMPL", aliasNode, filename);
3244 // run through the children looking for nodes with types that we recognise
3245 for (uint i=0;i<prim->getNumChildren();++i)
3247 // get a pointer to the child and make sure its valid
3248 const IPrimitive *child;
3249 if (prim->getChild(child, i))
3251 switch(nodeType(child))
3253 case AITypeSquadTemplateVariant:
3254 parsePrimSquadTemplateVariant(nextTreeNode(aliasNode,child), child, name);
3255 break;
3256 default:
3257 break;
3262 CAIActions::end(aliasNode->getAlias());
3265 static void parsePrimOutpost(const IPrimitive *prim, const std::string &mapName, const std::string &filename)
3267 // get hold of the node name and unique id
3268 string name=nodeName(prim);
3269 uint32 uniqueId=nodeAlias(prim);
3270 string familyName;
3271 string continent, s;
3272 stringToKeywordAndTail(mapName, continent, s);
3274 prim->getPropertyByName("owner_tribe", familyName);
3276 // build the tree of aliases and the vector of folders
3277 std::vector<SFolderRef> folders;
3278 NLMISC::CSmartPtr<CAIAliasDescriptionNode> aliasNode = new CAIAliasDescriptionNode (name, uniqueId, AITypeOutpost, NULL);
3279 buildAliasTree(aliasNode, aliasNode, prim, folders);
3281 CAIActions::begin(aliasNode->getAlias());
3283 // outpost general properties
3284 CAIActions::exec("OUTPOST", aliasNode, continent, filename, familyName);
3286 // link squads
3287 const char* props[] = { "tribe_squads", "tribe_squads2", "default_squads", "buyable_squads" };
3288 size_t nprops = sizeof(props)/sizeof(props[0]);
3289 for (size_t i=0; i!=nprops; ++i)
3291 vector<string>* propSquads;
3292 if (prim->getPropertyByName(props[i], propSquads) && propSquads)
3294 vector<string> squadsToLink;
3295 // Insert default variant at beginning of vector
3296 squadsToLink.push_back(continent);
3297 squadsToLink.insert( squadsToLink.end(), (*propSquads).begin(), (*propSquads).end() );
3298 CAIActions::execute("OUTP_SQD", squadsToLink );
3300 else
3301 nlerror( "Missing property %s in %s in %s", props[i], name.c_str(), filename.c_str() );
3304 CAIActions::exec("IDTREE",aliasNode);
3306 // build polygon data
3307 vector<double> poly;
3308 const CPrimVector *v = prim->getPrimVector();
3309 for (uint i=0; i<prim->getNumVector(); ++i)
3311 poly.push_back(v[i].x);
3312 poly.push_back(v[i].y);
3314 CAIActions::execute("OUTPOGEO", poly);
3316 // run through the children looking for nodes with types that we recognise
3317 for (uint i=0;i<prim->getNumChildren();++i)
3319 // get a pointer to the child and make sure its valid
3320 const IPrimitive *child;
3321 if (prim->getChild(child, i))
3323 switch(nodeType(child))
3325 // case AITypeOutpostSquadFamily:
3326 // parsePrimOutpostSquadFamily(nextTreeNode(aliasNode,child), child);
3327 // break;
3328 case AITypeOutpostSpawnZone:
3329 parsePrimOutpostSpawnZone(nextTreeNode(aliasNode,child), child);
3330 break;
3331 case AITypeOutpostBuilding:
3332 parsePrimOutpostBuilding(nextTreeNode(aliasNode,child), child);
3333 break;
3334 case AITypeManager:
3335 parsePrimMgr(child, mapName, filename);
3336 break;
3337 default:
3338 break;
3344 CAIActions::end(aliasNode->getAlias());
3347 static void parsePrimDynSystem(const IPrimitive *prim, const std::string &mapName, const std::string &filename)
3349 // get hold of the node name and unique id
3350 std::string name=nodeName(prim);
3351 uint32 uniqueId=nodeAlias(prim);
3353 string contName;
3354 prim->getPropertyByName("continent_name", contName);
3356 nlassertex(!contName.empty(), ("Error while loading dynamic system from '%s', the continent name is empty !", filename.c_str()));
3357 // build the tree of aliases and the vector of folders
3358 std::vector<SFolderRef> folders;
3359 NLMISC::CSmartPtr<CAIAliasDescriptionNode> aliasNode = new CAIAliasDescriptionNode (name, uniqueId, AITypeDynamicSystem, NULL);
3360 buildAliasTree(aliasNode, aliasNode, prim, folders);
3362 CAIActions::begin(aliasNode->getAlias());
3363 CAIActions::exec("DYNSYS", contName, mapName);
3365 // run through the dynsystem children looking for nodes with types that we recognise
3366 for (uint i=0;i<prim->getNumChildren();++i)
3368 // get a pointer to the child and make sure its valid
3369 const IPrimitive *child;
3370 if (prim->getChild(child, i))
3372 switch(nodeType(child))
3374 case AITypeDynamicRegion:
3375 parsePrimDynRegion(nextTreeNode(aliasNode,child), child, filename);
3376 break;
3377 case AITypeOutpost:
3378 parsePrimOutpost(child, mapName, filename);
3379 break;
3380 default:
3381 break;
3386 CAIActions::exec("DYN_END");
3387 CAIActions::end(aliasNode->getAlias());
3391 static void parsePrimNogoPointList(const IPrimitive *prim, const std::string &mapName, const std::string &filename)
3393 // get hold of the node name and unique id
3394 string name=nodeName(prim);
3395 uint32 uniqueId=nodeAlias(prim);
3396 NLMISC::CSmartPtr<CAIAliasDescriptionNode> aliasNode = new CAIAliasDescriptionNode (name, uniqueId, AITypeOutpost, NULL);
3398 CAIActions::begin(aliasNode->getAlias());
3400 // run through the charge children looking for nodes with types that we recognise
3401 for (uint i=0;i<prim->getNumChildren();++i)
3403 // get a pointer to the child and make sure its valid
3404 const IPrimitive *child;
3405 if (prim->getChild(child, i))
3407 switch (nodeType(child))
3409 case AITypeNogoPoint: // OutpostCharge:
3411 float x=(float)(child->getPrimVector()->x);
3412 float y=(float)(child->getPrimVector()->y);
3413 CAIActions::exec("SETNOGO", x, y);
3415 break;
3416 default:
3417 break;
3423 CAIActions::end(aliasNode->getAlias());
3426 static void parsePrimSafeZone(const IPrimitive *prim, const std::string &mapName, const std::string &filename)
3428 float x=(float)(prim->getPrimVector()->x);
3429 float y=(float)(prim->getPrimVector()->y);
3430 string radiusString;
3431 prim->getPropertyByName("radius",radiusString);
3432 float radius;
3433 NLMISC::fromString(radiusString, radius);
3435 CAIActions::exec("SAFEZONE", x, y, radius);
3439 static void parsePrimScript(const IPrimitive *prim, const std::string &mapName, const std::string &filename)
3441 string primName;
3442 const std::vector<std::string>* pcode = NULL;
3443 prim->getPropertyByName("name", primName);
3444 prim->getPropertyByName("code", pcode);
3445 std::string code;
3446 // Concat the strings inside a single one...
3447 if (pcode!=NULL && !pcode->empty())
3449 std::vector<std::string>::const_iterator it = pcode->begin(), itEnd = pcode->end();
3450 code = *it;
3451 ++it;
3452 for(; it!=itEnd; ++it)
3454 code += "\n";
3455 code += *it;
3458 // ... coz CAIActions::exec cannot handle a vector<string>
3459 CAIActions::exec("SCRIPT", primName, code);
3464 * parse a user model
3465 * a user model contains an id, a base SheetId (used later to fill unmodified attributes of the dynamic sheet)
3466 * and a script defining all attributes to be modified along with the new values
3468 static void parseUserModelListRec(const IPrimitive *prim,
3469 const std::string &mapName,
3470 const std::string &filename,
3471 std::vector<CAIActions::CArg> &args)
3473 AITYPES::TAIType type = nodeType(prim);
3474 if (type == AITypeUserModelList)
3476 // run through the list of children
3477 for (uint j = 0; j<prim->getNumChildren(); ++j)
3479 // get a pointer to the child and make sure its valid
3480 const IPrimitive *child;
3481 if (!prim->getChild(child,j))
3482 continue;
3484 // try to get a type for the child
3485 TAIType type=nodeType(child);
3487 if (type == AITypeUserModel)
3489 std::string userModelId;
3490 std::string script = "";
3491 std::string baseSheet;
3492 const std::vector<std::string> *pcode = NULL;
3493 child->getPropertyByName("name", userModelId);
3494 child->getPropertyByName("script", pcode);
3495 child->getPropertyByName("sheet_client", baseSheet);
3496 if (pcode != NULL && !pcode->empty())
3498 std::vector<std::string>::const_iterator start = pcode->begin();
3499 for(std::vector<std::string>::const_iterator it = start; it != pcode->end(); ++it)
3501 if (it != start)
3503 script += "\n";
3505 script += *it;
3508 args.push_back(CAIActions::CArg(userModelId));
3509 args.push_back(CAIActions::CArg(baseSheet));
3510 args.push_back(CAIActions::CArg(script));
3511 nldebug("<ParsePrimUserModelList> Add user model '%s'", userModelId.c_str());
3515 else
3517 for (uint i=0;i<prim->getNumChildren();++i)
3519 const IPrimitive *child;
3520 if (prim->getChild(child,i))
3521 parseUserModelListRec(child, mapName, filename, args);
3528 * Parse method called on the main user model node, which is a list of user models
3529 * builds a CArgs vector and executes an AiAction USR_MDL
3530 * This aiAction is defined in the CAIUserModelManager class
3532 static void parsePrimUserModelList(const IPrimitive *prim,
3533 const std::string &mapName,
3534 const std::string &filename,
3535 uint32 primAlias)
3537 std::vector<CAIActions::CArg> args;
3538 args.push_back(CAIActions::CArg(primAlias));
3539 parseUserModelListRec(prim, mapName, filename, args);
3540 if (args.size() == 0)
3542 nlinfo("<ParsePrimUserModelList> No User Model List found in primitive '%s'", filename.c_str());
3543 return;
3545 CAIActions::execute("USR_MDL", args);
3549 * Method called to parse a custom loot table.
3550 * A custom loot table contains an id and money values, and a list of custom loot sets.
3551 * A custom loot set contains a drop probability and a script defining what item it will drop
3552 * (item name, quantity, quality)
3554 static void parseCustomLootTableRec(const IPrimitive *prim,
3555 const std::string &mapName,
3556 const std::string &filename,
3557 std::vector<CAIActions::CArg> &args)
3559 AITYPES::TAIType type = nodeType(prim);
3560 if (type == AITypeCustomLootTable)
3562 //first push number of loot sets in the current loot table
3563 uint size = prim->getNumChildren();
3564 args.push_back(CAIActions::CArg(size));
3566 //then push loot table info
3567 std::string customTableId;
3568 std::string strMoneyBase;
3569 std::string strMoneyFactor;
3570 std::string strMoneyProba;
3572 prim->getPropertyByName("name", customTableId);
3573 prim->getPropertyByName("money_base", strMoneyBase);
3574 prim->getPropertyByName("money_factor", strMoneyFactor);
3575 prim->getPropertyByName("money_proba", strMoneyProba);
3577 args.push_back(CAIActions::CArg(customTableId));
3579 char *ptr = NULL;
3581 float moneyProba = static_cast<float>(strtod(strMoneyProba.c_str(), &ptr));
3582 if (ptr != NULL && *ptr == '\0' && errno != ERANGE)
3584 args.push_back(CAIActions::CArg(moneyProba));
3587 float moneyFactor = static_cast<float>(strtod(strMoneyFactor.c_str(), &ptr));
3588 if (ptr != NULL && *ptr == '\0' && errno != ERANGE)
3590 args.push_back(CAIActions::CArg(moneyFactor));
3593 uint32 moneyBase = static_cast<uint32>(strtol(strMoneyBase.c_str(), &ptr, 10));
3594 if (ptr != NULL && *ptr == '\0' && errno != ERANGE)
3596 args.push_back(CAIActions::CArg(moneyBase));
3599 // run through the list of children
3600 for (uint j = 0; j<prim->getNumChildren(); ++j)
3602 // get a pointer to the child and make sure its valid
3603 const IPrimitive *child;
3604 if (!prim->getChild(child,j))
3605 continue;
3607 // try to get a type for the child
3608 TAIType type=nodeType(child);
3610 if (type == AITypeCustomLootSet)
3612 std::string dropProba;
3613 std::string script = "";
3615 const std::vector<std::string> *pcode = NULL;
3616 child->getPropertyByName("drop_proba", dropProba);
3617 child->getPropertyByName("script", pcode);
3618 if (pcode != NULL && !pcode->empty())
3620 std::vector<std::string>::const_iterator start = pcode->begin();
3621 for(std::vector<std::string>::const_iterator it = start; it != pcode->end(); ++it)
3623 if (it != start)
3625 script += "\n";
3627 script += *it;
3630 args.push_back(CAIActions::CArg(dropProba));
3631 args.push_back(CAIActions::CArg(script));
3635 nldebug("<ParseCustomLootTable> Add custom loot table'%s'", customTableId.c_str());
3637 else
3639 for (uint i=0;i<prim->getNumChildren();++i)
3641 const IPrimitive *child;
3642 if (prim->getChild(child,i))
3643 parseCustomLootTableRec(child, mapName, filename, args);
3649 * Main parsing method used to build the CArgs vector containing the custom loot tables data defined in the primitive.
3650 * Called on the main node which is a list of custom loot tables
3651 * Once the parsing is done and the CArgs vector is built, an AiAction CUSTOMLT (CustomLootTables) is executed.
3652 * This aiAction is defined in the CAIUserModelManager class
3654 static void parsePrimCustomLootTable(const IPrimitive *prim,
3655 const std::string &mapName,
3656 const std::string &filename,
3657 uint32 primAlias)
3659 AITYPES::TAIType type = nodeType(prim);
3660 if (type == AITypeCustomLootTables)
3662 uint size = prim->getNumChildren();
3664 if (size == 0)
3666 nlinfo("<ParsePrimCustomLootTable> Custom loot tables folder declared but empty in primitive '%s'", filename.c_str());
3667 return;
3670 std::vector<CAIActions::CArg> args;
3672 args.push_back(CAIActions::CArg(size));
3673 args.push_back(CAIActions::CArg(primAlias));
3675 //TODO: add the primitive aliasStaticPart in the vector in order to remove all userModels/custom loot table
3676 //from AIS and EGS managers when a primitive is unloaded
3679 //args.push_back(CAIActions::CArg(nodeAlias(prim)));
3681 parseCustomLootTableRec(prim, mapName, filename, args);
3683 CAIActions::execute("CUSTOMLT", args);
3685 else
3687 for (uint i=0;i<prim->getNumChildren();++i)
3689 const IPrimitive *child;
3690 if (prim->getChild(child,i))
3691 parsePrimCustomLootTable(child, mapName, filename, primAlias);
3696 static void parsePrim(const IPrimitive *prim,const std::string &mapName, const std::string &filename)
3698 AITYPES::TAIType type = nodeType(prim);
3700 switch(type)
3702 case AITypeManager:
3704 // we're clear to parse so go ahead!
3705 parsePrimMgr(prim, mapName, filename);
3707 break;
3708 case AITypeDynamicSystem:
3710 // we're clear to parse so go ahead!
3711 parsePrimDynSystem(prim, mapName, filename);
3713 break;
3714 case AITypeSquadTemplate:
3716 parsePrimSquadTemplate(prim, mapName, filename);
3718 break;
3719 case AITypeNogoPointList:
3721 parsePrimNogoPointList(prim, mapName, filename);
3723 break;
3724 case AITypeSafeZone:
3726 parsePrimSafeZone(prim, mapName, filename);
3728 break;
3729 case AITypeScript:
3731 parsePrimScript(prim, mapName, filename);
3733 break;
3734 case AITypeSpire:
3736 parsePrimSpire(prim, mapName, filename);
3738 break;
3739 default:
3741 // this node's not a manager so checkout children
3742 for (uint i=0;i<prim->getNumChildren();++i)
3744 const IPrimitive *child;
3745 if (prim->getChild(child,i))
3746 parsePrim(child, mapName, filename);
3753 //---------------------------------------------------------------------------------------
3754 // utility routines for primitive file list management
3756 struct TFileInfo
3758 std::string FileName;
3759 std::string MapName;
3760 // uint32 FirstSlot;
3763 const uint32 HighestSlotId=1023;
3765 //void getFileSlotVector(std::vector <TFileInfo> &vect)
3767 // CPrimitiveCfg::readPrimitiveCfg();
3769 // const std::vector<std::string> &mapNames = CPrimitiveCfg::getMapNames();
3770 // std::vector<std::string>::const_iterator first(mapNames.begin()), last(mapNames.end());
3771 // for (; first != last; ++first)
3772 // {
3773 // const std::vector<std::string> &primitives = CPrimitiveCfg::getMap(*first);
3774 // std::vector<std::string>::const_iterator first2(primitives.begin()), last2(primitives.end());
3775 // for (; first2 != last2; ++first2)
3776 // {
3777 // TFileInfo fi;
3778 // fi.MapName = *first;
3779 // fi.FileName = *first2;
3780 // vect.push_back(fi);
3781 // }
3782 // }
3787 void parsePrimStream(NLMISC::IStream & stream, const std::string & streamName)
3789 H_AUTO( parsePrimStream );
3791 std::string filename = streamName;
3792 nlinfo("begin parsing prim stream: %s", filename.c_str());
3794 // normalise the file name
3795 // std::string fileName=lookupFileName(std::string(filename));
3796 if (filename.empty())
3798 nlwarning( "parse primitive stream called with empty name" );
3799 return;
3802 CPrimitives* primDoc = new CPrimitives();
3806 //stream to PrimDoc
3807 H_AUTO( streamToPrimDoc );
3808 CPrimitiveContext::instance().CurrentPrimitive = primDoc;
3809 primDoc->serial(stream);
3810 CPrimitiveContext::instance().CurrentPrimitive = NULL;
3813 catch(...)
3815 nlwarning("stream error");
3816 return;
3819 parsePrimNoStream( primDoc, streamName );
3821 delete primDoc;
3824 void parsePrimNoStream( CPrimitives* primDoc, const std::string & streamName )
3826 H_AUTO( parsePrimNoStream );
3827 using namespace AI_SHARE;
3828 using namespace NLMISC;
3830 // clear out the alias maps
3831 MapPrimToAlias.clear();
3832 MapAliasToPrim.clear();
3834 if( s_WriteScenarioDebugDataToFile ) // debug
3836 nldebug( "writing test2.primitive" );
3837 saveXmlPrimitiveFile(*primDoc, "test2.primitive");
3840 // Call init() !!
3841 nlassert (LigoConfig != NULL);
3843 CPrimitiveContext::instance().CurrentPrimitive = primDoc;
3845 //prim to AIAction
3846 // initialise the action executor
3847 CAIActions::openFile(streamName); // AJM: note this does not open a file or stream
3849 // do the real parsing work
3851 uint32 primAlias = primDoc->getAliasStaticPart();
3852 H_AUTO(parsePrimUserModelList);
3854 //first parse for user models
3855 parsePrimUserModelList((IPrimitive *)primDoc->RootNode,
3856 CPrimitiveCfg::getContinentNameOf(streamName)+":"+CFile::getFilenameWithoutExtension(CFile::getFilename(streamName)),
3857 CFile::getFilename(CFile::getFilenameWithoutExtension(CFile::getFilename(streamName))),
3858 primAlias);
3860 //then parse for custom loot table
3861 H_AUTO(parsePrimCustomLootTable);
3862 parsePrimCustomLootTable((IPrimitive *)primDoc->RootNode,
3863 CPrimitiveCfg::getContinentNameOf(streamName)+":"+CFile::getFilenameWithoutExtension(CFile::getFilename(streamName)),
3864 CFile::getFilename(CFile::getFilenameWithoutExtension(CFile::getFilename(streamName))),
3865 primAlias);
3866 H_AUTO(parsePrim);
3867 //then do the real parsing work
3868 parsePrim((IPrimitive *)primDoc->RootNode,CPrimitiveCfg::getContinentNameOf(streamName)+":"+CFile::getFilenameWithoutExtension(CFile::getFilename(streamName)), CFile::getFilename(CFile::getFilenameWithoutExtension(CFile::getFilename(streamName))));
3871 CPrimitiveContext::instance().CurrentPrimitive = NULL;
3873 // allow for action executor housekeeping
3874 CAIActions::closeFile(streamName); // AJM: note this does not close a file or a stream
3877 //---------------------------------------------------------------------------------------
3878 // the main primitive file parser routine
3879 void parsePrimFile(const std::string &filename)
3881 H_AUTO(parsePrimFile);
3883 nldebug("PARSING PRIM FILE %s", filename.c_str());
3884 // Call init() !!
3885 nlassert (LigoConfig != NULL);
3887 // clear out the alias maps
3888 MapPrimToAlias.clear();
3889 MapAliasToPrim.clear();
3891 // normalise the file name
3892 // std::string fileName=lookupFileName(std::string(filename));
3893 if (filename.empty())
3894 return;
3896 // read the file into memory and parse to generate 'prims' data tree
3897 CPrimitives prims;
3899 string sFilename;
3900 bool opened;
3901 CIFile fileIn;
3902 if (fileIn.open (filename))
3904 nlinfo("Opening %s in %s", filename.c_str(), CPath::getCurrentPath().c_str());
3905 sFilename = filename;
3906 opened = true;
3908 else
3910 // If file not found, search in path
3911 sFilename = CPath::lookup( filename, false);
3912 nlinfo("Opening in %s", filename.c_str());
3913 opened = (fileIn.open (sFilename.c_str()));
3916 nlinfo("Load&parse primitive file '%s' (in '%s')",
3917 CFile::getFilename(filename).c_str(),
3918 sFilename.c_str());
3920 // Test if binary caching is wanted
3921 bool cachePrims = true;
3922 CConfigFile::CVar *cachePrimsVar = IService::getInstance()->ConfigFile.getVarPtr("CachePrims");
3923 if (cachePrimsVar)
3925 cachePrims = cachePrimsVar->asInt() != 0;
3927 bool cachePrimsLog = false;
3928 CConfigFile::CVar *cachePrimsLogVar = IService::getInstance()->ConfigFile.getVarPtr("CachePrimsLog");
3929 if (cachePrimsLogVar)
3931 cachePrimsLog = cachePrimsLogVar->asInt() != 0;
3934 if ( opened )
3936 // lookup in binary cache before reading in XML
3937 bool readXml = true;
3938 string binFileName = NLNET::IService::getInstance()->WriteFilesDirectory.toString() +"primitive_cache/"+CFile::getFilename(filename)+".binprim";
3939 if (cachePrims
3940 && CFile::fileExists(binFileName)
3941 && CFile::getFileModificationDate(binFileName) > CFile::getFileModificationDate(sFilename))
3943 if (cachePrimsLog)
3945 // ok, the cache is here and up to date !
3946 nlinfo("Loading '%s' from binary file '%s'",
3947 sFilename.c_str(),
3948 binFileName.c_str());
3952 CIFile binFile(binFileName);
3953 CPrimitiveContext::instance().CurrentPrimitive = &prims;
3954 prims.serial(binFile);
3955 CPrimitiveContext::instance().CurrentPrimitive = NULL;
3956 // ok, all was fine, don't read in xml !
3957 readXml = false;
3959 catch(...)
3962 if (readXml)
3964 // Xml stream
3965 CIXml xmlIn;
3966 xmlIn.init (fileIn);
3968 // set the primitive context
3969 CPrimitiveContext::instance().CurrentPrimitive = &prims;
3970 // Read it
3971 if (!prims.read (xmlIn.getRootNode (), sFilename.c_str(), *LigoConfig))
3973 nlwarning ("Error reading file %s", sFilename.c_str());
3974 return;
3976 // clean the context
3977 CPrimitiveContext::instance().CurrentPrimitive = NULL;
3979 if (cachePrims)
3981 // save a binary version
3982 CFile::createDirectory(IService::getInstance()->WriteFilesDirectory.toString()+"primitive_cache");
3983 COFile saveBin(binFileName);
3984 prims.serial(saveBin);
3988 else
3990 // if file not found sFilename is the result of CPath::lookup so if not in path sFilename is an empty string
3991 nlwarning ("Failed to open file '%s' for reading.", sFilename.empty() ? filename.c_str():sFilename.c_str());
3993 return;
3996 // initialise the action executor
3997 CAIActions::openFile(sFilename);
3999 CPrimitiveContext::instance().CurrentPrimitive = &prims;
4000 // do the real parsing work
4002 uint32 primAlias = prims.getAliasStaticPart();
4003 H_AUTO(parsePrimUserModelList);
4005 //first parse for user models
4006 parsePrimUserModelList((IPrimitive *)prims.RootNode,
4007 CPrimitiveCfg::getContinentNameOf(filename)+":"+CFile::getFilenameWithoutExtension(CFile::getFilename(sFilename)),
4008 CFile::getFilename(CFile::getFilenameWithoutExtension(CFile::getFilename(sFilename))),
4009 primAlias);
4011 //then parse for custom loot table
4012 H_AUTO(parsePrimCustomLootTable);
4013 parsePrimCustomLootTable((IPrimitive *)prims.RootNode,
4014 CPrimitiveCfg::getContinentNameOf(filename)+":"+CFile::getFilenameWithoutExtension(CFile::getFilename(sFilename)),
4015 CFile::getFilename(CFile::getFilenameWithoutExtension(CFile::getFilename(sFilename))),
4016 primAlias);
4017 H_AUTO(parsePrim);
4018 parsePrim((IPrimitive *)prims.RootNode,CPrimitiveCfg::getContinentNameOf(filename)+":"+CFile::getFilenameWithoutExtension(CFile::getFilename(sFilename)), CFile::getFilename(CFile::getFilenameWithoutExtension(CFile::getFilename(sFilename))));
4021 CPrimitiveContext::instance().CurrentPrimitive = NULL;
4023 // allow for action executor housekeeping
4024 CAIActions::closeFile(sFilename);
4028 //---------------------------------------------------------------------------------------
4030 NLMISC_COMMAND(loadPdrFile,"load a primitive file. don't forget to call BuildPrimitiveDependencies","<file name>")
4032 if (args.size()!=1)
4033 return false;
4034 AI_SHARE::CAIActionsDataRecord pdr;
4035 pdr.readFile(args[0]);
4036 CAIActions::IExecutor* executer;
4037 executer = CAIActions::getExecuter();
4038 if (!executer)
4040 nlwarning("no executer");
4041 return false;
4043 pdr.applyToExecutor(*executer);
4044 return true;
4049 NLMISC_COMMAND(loadPrimitiveFile,"load a primitive file. don't forget to call BuildPrimitiveDependencies","<file name>")
4051 if (args.size()!=1)
4052 return false;
4054 if (NLMISC::CFile::getExtension(args[0]).empty())
4055 parsePrimFile(args[0]+".primitive");
4056 else
4057 parsePrimFile(args[0]);
4059 return true;
4062 // have to do this on managers coz there no more implicit correspondence ..
4064 NLMISC_COMMAND(loadMapsFromCommon,"load all primitive defined in usedPrimitives in common.cfg for the given map","<map name>")
4066 if (args.size()!=1)
4067 return false;
4069 CPrimitiveCfg::readPrimitiveCfg();
4071 // We create a static set of 'loaded primitive file' names via this method in order to avoid loading the same primitive file more than once at AIS startup
4072 static std::set<std::string> loadedPrimitives;
4074 std::vector<std::string> mapConfigNames;
4075 // load only active primitive maps...
4077 CConfigFile::CVar& usedPrimitives = IService::getInstance()->ConfigFile.getVar("UsedPrimitives");
4079 const vector<string> &basePrim = CPrimitiveCfg::getMap(args[0]);
4080 set<string> filter(basePrim.begin(), basePrim.end());
4081 for ( uint i = 0; i < usedPrimitives.size(); ++i)
4083 const vector<string> &prims = CPrimitiveCfg::getMap(usedPrimitives.asString(i));
4084 for (uint j=0; j<prims.size(); ++j)
4086 if (filter.find(prims[j]) != filter.end())
4088 // check for primitive filter
4089 CConfigFile::CVar *pvar = IService::getInstance()->ConfigFile.getVarPtr("PrimitiveFilter");
4090 if (pvar)
4092 const std::string filename = CPath::lookup(prims[j], false);
4093 bool load = true;
4094 for (uint k=0; k<pvar->size(); ++k)
4096 string nameFilter = pvar->asString(k);
4097 if (filename.find(nameFilter) != string::npos)
4099 log.displayNL("loadMap : loading of primitive '%s' canceled by PrimitiveFilter '%s'",
4100 filename.c_str(),
4101 nameFilter.c_str());
4102 load = false;
4103 break;
4107 if (!load)
4108 continue;
4111 // ensure that each primitive file is only loaded once at AIS startup
4112 if (loadedPrimitives.find(prims[j])!=loadedPrimitives.end())
4113 continue;
4114 loadedPrimitives.insert(prims[j]);
4116 // this one can be loaded
4117 ICommand::execute(toString("loadPrimitiveFile %s", prims[j].c_str()), log);
4122 return true;
4126 typedef map<string,set<string> > TLoadedPrimitiveMapSet;
4127 static TLoadedPrimitiveMapSet loadedPrimitives;
4129 NLMISC_COMMAND(loadMap,"load a complete set of primitive files","<map name>")
4131 if(args.size() !=1)
4132 return false;
4134 CPrimitiveCfg::readPrimitiveCfg();
4135 const vector<string> &map = CPrimitiveCfg::getMap(args[0]);
4137 const string continentName=CPrimitiveCfg::getContinentNameOf(args[0]);
4138 nlassert(continentName.size()>0);
4140 vector<string>::const_iterator first(map.begin()), last(map.end());
4141 for (; first != last; ++first)
4143 const std::string filename = CPath::lookup(*first, false);
4145 // check for primitive filter
4146 CConfigFile::CVar *pvar = IService::getInstance()->ConfigFile.getVarPtr("PrimitiveFilter");
4147 if (pvar)
4149 bool load = true;
4150 for (uint i=0; i<pvar->size(); ++i)
4152 string filter = pvar->asString(i);
4153 if (filename.find(filter) != string::npos)
4155 log.displayNL("loadMap : loading of primitive '%s' canceled by PrimitiveFilter '%s'",
4156 filename.c_str(),
4157 filter.c_str());
4158 load = false;
4159 break;
4163 if (!load)
4164 continue;
4167 // check primitive already loaded
4168 if (filename.empty())
4169 continue;
4171 TLoadedPrimitiveMapSet::iterator it=loadedPrimitives.find(continentName);
4172 if ( it!=loadedPrimitives.end()
4173 && it->second.find(filename)!=it->second.end())
4174 continue;
4176 // check that the continent is active
4177 CUsedContinent &uc = CUsedContinent::instance();
4178 uint32 in = uc.getInstanceForContinent(continentName);
4179 if (in == std::numeric_limits<uint32>::max())
4181 log.displayNL("loadMap : while loading map '%s', can't load primitive '%s' coz continent '%s' is not active",
4182 args[0].c_str(),
4183 filename.c_str(),
4184 continentName.c_str());
4186 else
4188 ICommand::execute(toString("createStaticAIInstance %s", continentName.c_str()), log);
4190 loadedPrimitives[continentName].insert(filename);
4191 parsePrimFile(filename);
4194 return true;
4197 NLMISC_COMMAND(unloadMap,"unload a complete set of primitive files","<map name>")
4199 if(args.size() !=1)
4200 return false;
4202 CPrimitiveCfg::readPrimitiveCfg();
4203 const vector<string> &map = CPrimitiveCfg::getMap(args[0]);
4205 const string continentName=CPrimitiveCfg::getContinentNameOf(args[0]);
4206 if (!continentName.empty())
4208 vector<string>::const_iterator first(map.begin()), last(map.end());
4209 for (; first != last; ++first)
4211 const std::string filename = CPath::lookup(*first, false);
4213 if (filename.empty())
4214 continue;
4216 // check that the continent is active
4217 CUsedContinent &uc = CUsedContinent::instance();
4218 uint32 in = uc.getInstanceForContinent(continentName);
4219 if (in == std::numeric_limits<uint32>::max())
4221 log.displayNL("unloadMap : while loading map '%s', can't load primitive '%s' coz continent '%s' is not active",
4222 args[0].c_str(),
4223 filename.c_str(),
4224 continentName.c_str());
4226 else
4227 ICommand::execute(toString("unloadPrimitiveFile %s", filename.c_str()), log);
4230 else
4231 log.displayNL("unloadMap failed : no map named %s found", args[0].c_str());
4233 // Remove this file
4234 loadedPrimitives.erase (continentName);
4236 return true;
4239 NLMISC_COMMAND(verbosePrimitiveParserLog,"Turn on or off or check the state of verbose .primitive parser logging","")
4241 if(args.size()>1)
4242 return false;
4244 if(args.size()==1)
4245 StrToBool (VerboseLog, args[0]);
4247 nlinfo("verbose Logging is %s",VerboseLog?"ON":"OFF");
4248 return true;
4251 } // end of namespace