1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
34 #include "ai_actions.h"
35 #include "ai_actions_dr.h"
36 #include "ai_alias_description_node.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
;
45 using namespace AITYPES
;
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
)
80 prim
->getPropertyByName("name",result
);
84 static TAIType
nodeType(const IPrimitive
*prim
)
87 prim
->getPropertyByName("ai_type",result
);
88 return getType
<TAIType
>(result
.c_str());
91 static TAITypeSpec
nodeTypeSpec(const IPrimitive
*prim
)
94 prim
->getPropertyByName("ai_type",result
);
95 return getType
<TAITypeSpec
>(result
.c_str());
98 static std::string
nodeClass(const IPrimitive
*prim
)
101 prim
->getPropertyByName("class",result
);
105 std::map
<const IPrimitive
*,uint32
> MapPrimToAlias
;
106 std::map
<uint32
,const IPrimitive
*> MapAliasToPrim
;
108 uint32
nodeAlias(const IPrimitive
*prim
, bool canFail
= false)
111 // see if we've already got an alias for this prim node
112 if (MapPrimToAlias
.find(prim
)!=MapPrimToAlias
.end())
114 alias
=MapPrimToAlias
[prim
];
118 TPrimitiveClassPredicate
pred("alias");
119 IPrimitive
*aliasNode
= getPrimitiveChild(const_cast<IPrimitive
*>(prim
), pred
);
122 CPrimAlias
*pa
= dynamic_cast<CPrimAlias
*>(aliasNode
);
123 alias
= pa
->getFullAlias();
127 nlassertex(alias
!= 0, ("in primitive '%s'", buildPrimPath(prim
).c_str()));
131 // prim->getPropertyByName("alias",s);
134 // nlassert(!s.empty());
137 // // for legacy reasons the field may be called 'unique_id' instead of 'alias'
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")
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);
156 // if we haven a valid alias, ask one to the container
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
170 // uint32 oldAlias=alias;
171 // while (MapAliasToPrim.find(alias)!=MapAliasToPrim.end())
174 // nlwarning("Alias %u not unique - remaping to %u",oldAlias,alias);
178 // add alias to maps...
179 MapAliasToPrim
[alias
]=prim
;
180 MapPrimToAlias
[prim
]=alias
;
185 //---------------------------------------------------------------------------------------
186 // handy routine for reading vertical pos
187 //---------------------------------------------------------------------------------------
189 static bool parseVerticalPos(const IPrimitive
*prim
, uint32
&verticalPos
, const char *propertyName
= "vertical_pos")
193 if (prim
->getPropertyByName(propertyName
, s
))
195 verticalPos
= verticalPosFromString(s
);
200 verticalPos
= vp_auto
;
205 //---------------------------------------------------------------------------------------
206 // handy routine for reading the family flags
207 //---------------------------------------------------------------------------------------
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;
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)
225 // tribeNames.push_back(names[i].first);
232 // // read the family flags
233 // for (uint i=0; i<familyNames.size(); ++i)
235 // if (familyNames[i] == "tribe")
237 // // special case for tribe
238 // for (uint j=0; j<tribeNames.size(); ++j)
240 // string flagName = tribeNames[j];
242 // if (prim->getPropertyByName(flagName.c_str(), s) && s=="true")
243 // result.insert(flagName);
248 // // standard case for all other
250 // if (prim->getPropertyByName(familyNames[i].c_str(), s) && s=="true")
251 // result.insert(familyNames[i]);
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 //---------------------------------------------------------------------------------------
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
);
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());
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
);
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(),
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 //////////////////////////////////////////////////////////////////////////
416 //////////////////////////////////////////////////////////////////////////
418 //////////////////////////////////////////////////////////////////////////
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();
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
]));
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
);
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
))
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
537 case AITypeEventAction
:
539 CAIEventActionNode::TSmartPtr childAction
;
540 childAction
=parsePrimEventAction(treeNode
?nextTreeNode(treeNode
,child
):NULL
,child
);
542 result
->Children
.push_back(childAction
);
545 case AITypeActionZone
:
547 result
->_PropertyZones
.push_back(parseMachineStatePropertyZone(treeNode
?nextTreeNode(treeNode
,child
):NULL
,child
));
548 result
->_PropertyZones
.back()->Target
= CTmpPropertyZone::All
;
551 case AITypeFaunaActionZone
:
553 result
->_PropertyZones
.push_back(parseMachineStatePropertyZone(treeNode
?nextTreeNode(treeNode
,child
):NULL
,child
));
554 result
->_PropertyZones
.back()->Target
= CTmpPropertyZone::Fauna
;
557 case AITypeNpcActionZone
:
559 result
->_PropertyZones
.push_back(parseMachineStatePropertyZone(treeNode
?nextTreeNode(treeNode
,child
):treeNode
,child
));
560 result
->_PropertyZones
.back()->Target
= CTmpPropertyZone::Npc
;
565 // not handled there, but by caller
568 nlwarning("Don't know how to treat ai_type '%s'",getName(type
));
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"/>
582 <PARAMETER NAME="params" TYPE="string_array" VISIBLE="true" WIDGET_HEIGHT="100"/>
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
);
607 child
->getPropertyByName("family", familyTag
);
608 CAIActions::exec("GRPFAM", childTreeNode
, familyTag
, name
, logicActionAlias
);
609 TAIType type
= nodeType(child
);
612 case AITypeGroupFamily
:
614 nlwarning("Parsing a group_family, primitive is outdated. Please report to jvuarand.");
615 // parsePrimGroupFamily(nextTreeNode(aliasNode,child),child);
619 case AITypeGroupFamilyProfileFauna
:
620 parsePrimGroupFamilyProfileFaunaContent(childTreeNode
, child
);
621 // parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyFauna);
624 case AITypeGroupFamilyProfileTribe
:
625 parsePrimGroupFamilyProfileTribeContent(childTreeNode
, child
);
627 case AITypeGroupFamilyProfileNpc
:
628 parsePrimGroupFamilyProfileNpcContent(childTreeNode
, child
);
631 // case AITypeGroupFamilyProfileGeneric:
632 // parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyTribe);
635 CAIActions::end(childTreeNode
->getAlias());
644 // add group description to already parsed event actions
645 static void addGroupDescriptionToEventAction(const CAIAliasDescriptionNode
*treeNode
, const IPrimitive
*prim
, uint depth
)
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
))
656 const TAIType type
=nodeType(child
);
658 // it's one of ours! - so match against the types we recognise
661 case AITypeEventAction
:
663 addGroupDescriptionToEventAction(treeNode
?nextTreeNode(treeNode
,child
):NULL
,child
, depth
+ 1);
666 case AITypeActionZone
:
667 case AITypeFaunaActionZone
:
668 case AITypeNpcActionZone
:
669 // no-op, already parsed
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");
685 nlwarning("Don't know how to treat ai_type '%s'",getName(type
));
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
;
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():"");
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 //---------------------------------------------------------------------------------------
752 static void parsePrimBotKami(const CAIAliasDescriptionNode
*treeNode
,const IPrimitive
*prim
)
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());
767 // lookup the creature sheet name
769 if (!prim
->getPropertyByName("sheet",sheet
))
771 nlwarning("'sheet' property not found in kami record: %s",treeNode
->fullName().c_str());
776 const CPrimPoint
*point
=dynamic_cast<const CPrimPoint
*>(prim
);
779 nlwarning("Failed to cast to CPrimPoin kami: %s",name
.c_str());
780 CAIActions::end(treeNode
->getAlias());
783 sint x
=(uint32
)(point
->Point
.x
*1000);
784 sint y
=(uint32
)(point
->Point
.y
*1000);
785 float theta
=(float)point
->Angle
;
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();
822 // const CPrimVector *pointArray=prim->getPrimVector();
823 // for (uint i=0;i<numPoints;++i)
825 // points.push_back(CAIActions::CArg(pointArray[i].x));
826 // points.push_back(CAIActions::CArg(pointArray[i].y));
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
))
850 parsePrimBotKami(nextTreeNode(treeNode
,child
),child
);
856 nlwarning("Didn't found ai_type when expecting 'BOT_NPC' in parsePrimGrpKami");
863 CAIActions::end(treeNode
->getAlias());
868 //---------------------------------------------------------------------------------------
871 static void parsePrimBotKaravan(const CAIAliasDescriptionNode
*treeNode
,const IPrimitive
*prim
)
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());
886 // lookup the creature sheet name
888 if (!prim
->getPropertyByName("sheet",sheet
))
890 nlwarning("'sheet' property not found in karavan record: %s",treeNode
->fullName().c_str());
894 // add the bot to the current group
895 const CPrimPoint
*point
=dynamic_cast<const CPrimPoint
*>(prim
);
898 nlwarning("Failed to cast to CPrimPoin karavan: %s",name
.c_str());
899 CAIActions::end(treeNode
->getAlias());
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
);
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
);
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
);
951 parsePrimBotKaravan(nextTreeNode(treeNode
,child
),child
);
957 nlwarning("Unsupported ai_type in parsePrimGrpKaravan");
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());
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
);
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();
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
));
1002 LOG("State has no geometry: %s: %s",pointsType
,name
.c_str());
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
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);
1036 switch (nodeTypeSpec(child
))
1039 parsePrimGrpNpc(nextTreeNode(treeNode
,child
),child
,name
);
1041 case AITypeSpecFauna
:
1042 parsePrimGrpFauna(nextTreeNode(treeNode
,child
),child
);
1044 case AITypeSpecKami
: // a non-deposit kami group
1045 parsePrimGrpKami(nextTreeNode(treeNode
,child
),child
);
1047 case AITypeSpecKaravan
:
1048 parsePrimGrpKaravan(nextTreeNode(treeNode
,child
),child
);
1052 nlwarning("Don't know how to treat ai_group of type '%s' in primState",getName(nodeTypeSpec(child
)));
1059 parsePrimEvent(nextTreeNode(treeNode
,child
),child
);
1062 parsePrimState(nextTreeNode(treeNode
,child
),child
,"PATAT");
1068 nlwarning("Don't know how to treat ai_type '%s'",getName(nodeType(child
)));
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
);
1087 case AITypeNpcStateChat
:
1088 parsePrimStateChat(nextTreeNode(treeNode
,child
),child
);
1090 default: // we don't care unknown objets.
1097 CAIActions::end(treeNode
->getAlias());
1100 //////////////////////////////////////////////////////////////////////////
1101 // End States Methods
1102 //////////////////////////////////////////////////////////////////////////
1107 //---------------------------------------------------------------------------------------
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
)
1135 std::string radiusString
;
1136 child
->getPropertyByName("radius",radiusString
);
1138 NLMISC::fromString(radiusString
, radius
);
1141 nlwarning("Ignoring place '%s' because bad radius: '%s' (converted to int as %u)",
1143 radiusString
.c_str(),
1147 // if (radiusString!=toString(radius))
1149 // nlwarning("Ignoring place '%s' because bad radius: '%s'",placeName.c_str(),radiusString.c_str());
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());
1159 float x
=(float)(child
->getPrimVector()->x
);
1160 float y
=(float)(child
->getPrimVector()->y
);
1163 parseVerticalPos(child
, verticalPos
);
1165 if (type
== AITypePlaceFauna
)
1168 uint32 stayTimeMin
= 1000;
1169 uint32 stayTimeMax
= 1000;
1171 std::string indexNext
;
1172 bool flagSpawn
= false;
1173 bool flagFood
= false;
1174 bool flagRest
= false;
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)",
1219 child
->getPrimVector()->x
,
1220 child
->getPrimVector()->y
,
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
);
1235 LOG("Adding place (type XYR): %s at: (%.0f,%.0f) x %d (%s)",
1237 child
->getPrimVector()->x
,
1238 child
->getPrimVector()->y
,
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
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'"));
1283 if (prim
->getPropertyByName("creature_code", s
) && !s
.empty())
1284 sheet
= s
+".creature";
1287 NLMISC::fromString(countStr
, count
);
1290 throw parsePopException(std::string("FAUNA_SPAWN_ATOM property 'count' invalid: ")+countStr
);
1295 //---------------------------------------------------------------------------------------
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
1318 if (prim
->getPropertyByName("weight",s
))
1320 NLMISC::fromString(s
, weight
);
1321 if (toString(weight
)!=s
)
1323 nlwarning("weight invalid value: %s");
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
))
1337 // not interested to parse alias nodes !
1338 if (nodeClass(child
) == "alias")
1343 std::string theSheet
;
1345 parsePopulation (child
, theSheet
, count
);
1346 if (theSheet
.empty())
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
);
1366 nlwarning("FAUNA_SPAWN failed because population is empty, '%s'%s",
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());
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)
1402 // if (treeNode->getChild(i)->getType()==AITypePlace)
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();
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
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
);
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
);
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
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')
1442 float time1
=0, time2
=0, time3
=-1;
1443 sscanf(s
.c_str(),"%f %f %f",&time1
,&time2
,&time3
);
1445 CAIActions::exec("SPAWTIME",time1
,time2
);
1447 CAIActions::exec("SPAWTIME",time1
,time2
,time3
);
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
);
1458 std::string
cycles("");
1459 prim
->getPropertyByName("cycles",cycles
);
1460 CAIActions::exec("STCYCLES",cycles
);
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
))
1476 // try to get a type for the child
1477 TAIType type
=nodeType(child
);
1480 case AITypeGrpFaunaPop
:
1481 parsePrimGrpFaunaSpawn(nextTreeNode(nextTreeNode(treeNode
,prim
),prim
),child
);
1484 parsePrimEvent(nextTreeNode(treeNode
,child
),child
);
1491 if (type
!=AITypePlace
&& type
!=AITypePlaceFauna
)
1492 nlwarning("Don't know how to treat ai_type '%s'",getName(type
));
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
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
))
1521 // try to get a type for the child
1522 TAIType type
=nodeType(child
);
1527 parsePrimGrpFauna(nextTreeNode(treeNode
,child
),child
);
1530 parsePrimState(nextTreeNode(treeNode
,child
),child
,"PATAT");
1533 parsePrimEvent(nextTreeNode(treeNode
,child
),child
);
1535 // this isn't an ai block so check its children
1537 parsePrimMgrFauna(mapName
,nextTreeNode(treeNode
,child
),child
,folders
,filename
,false);
1542 nlwarning("Found ai_type: '%s' when expecting 'GROUP_FAUNA'",getName(type
));
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
);
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
);
1580 case AITypeNpcStateChat
:
1581 parsePrimStateChat(nextTreeNode(treeNode
,child
),child
);
1584 parsePrimEvent(nextTreeNode(treeNode
,child
),child
);
1589 default: // we don't care unknown objets.
1590 nlwarning("Don't know how to treat ai_type '%s'",getName(nodeType(child
)));
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
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
))
1621 // try to get a type for the child
1622 TAIType type
=nodeType(child
);
1626 case AITypeNpcStateRoute
:
1627 parsePrimState(nextTreeNode(treeNode
,child
),child
,"PATH");
1629 case AITypeNpcStateZone
:
1630 parsePrimState(nextTreeNode(treeNode
,child
),child
,"PATAT");
1632 case AITypePunctualState
:
1633 parsePrimNPCPunctualState(nextTreeNode(treeNode
,child
),child
);
1636 parsePrimEvent(nextTreeNode(treeNode
,child
),child
);
1639 case AITypeKamiDeposit
: // a deposit
1640 parsePrimState(nextTreeNode(treeNode
,child
),child
,"PATAT");
1644 parsePrimMgrKami(mapName
,nextTreeNode(treeNode
,child
),child
,folders
,filename
, false);
1649 nlwarning("Unsupported ai_type in parsePrimMgrKami");
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
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
);
1683 case AITypeKaravanState
:
1684 parsePrimState(nextTreeNode(treeNode
,child
),child
,"");
1687 parsePrimMgrKaravan(mapName
,nextTreeNode(treeNode
,child
),child
,folders
,filename
, false);
1692 nlwarning("Unsupported ai_type in parsePrimMgrKaravan");
1700 CAIActions::end(treeNode
->getAlias());
1703 //---------------------------------------------------------------------------------------
1707 void mergeEquipement(const std::vector
<std::string
> &grpEquip
, const std::vector
<std::string
> &botEquip
, std::vector
<std::string
> &result
)
1710 map
<string
, string
> equip
;
1713 for (i
=0; i
<grpEquip
.size(); ++i
)
1715 if (stringToKeywordAndTail(grpEquip
[i
], key
, tail
))
1718 for (i
=0; i
<botEquip
.size(); ++i
)
1720 if (stringToKeywordAndTail(botEquip
[i
], key
, tail
))
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
;
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
);
1779 nlwarning("Failed to cast to CPrimPoin bot: %s",name
.c_str());
1782 sint x
=(uint32
)(point
->Point
.x
*1000);
1783 sint y
=(uint32
)(point
->Point
.y
*1000);
1784 float theta
=(float)point
->Angle
;
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());
1833 const std::vector
<std::string
> *keywords
=&EmptyStringVector
;
1834 prim
->getPropertyByName("grp_keywords",keywords
);
1835 CAIActions::execute("KEYWORDS",*keywords
);
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
)
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
);
1889 prim
->getPropertyByName("count",s
);
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
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());
1907 if (!DefaultBotLook
.empty())
1909 nlwarning("No bots found in NPC group: %s",treeNode
->fullName().c_str());
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
);
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
))
1943 parsePrimBotNpc(nextTreeNode(treeNode
,child
),child
);
1946 parsePrimEvent(nextTreeNode(treeNode
,child
),child
);
1950 // case AITypeGrpParameters:
1953 nlwarning("Don't know how to treat ai_type '%s'",getName(nodeType(child
)));
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);
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);
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
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");
2030 case AITypeNpcStateZone
:
2031 parsePrimState(nextTreeNode(treeNode
,child
),child
,"PATAT");
2034 parsePrimState(nextTreeNode(treeNode
,child
),child
,"PATAT");
2036 case AITypePunctualState
:
2037 parsePrimNPCPunctualState(nextTreeNode(treeNode
,child
),child
);
2040 parsePrimEvent(nextTreeNode(treeNode
,child
),child
);
2043 parsePrimGrpNpc(nextTreeNode(treeNode
,child
),child
,std::string());
2045 // uinknown so pass it..
2047 if (nodeClass(child
) != "alias")
2048 parsePrimMgrNpc(mapName
,nextTreeNode(treeNode
,child
),child
,folders
,filename
, false);
2053 nlwarning("unrecognised ai_type in NPC manager %s: '%s'",treeNode
->fullName().c_str(),getName(nodeType(child
)));
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);
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
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");
2097 case AITypeNpcStateZone
:
2098 parsePrimState(nextTreeNode(treeNode
,child
),child
,"PATAT");
2101 parsePrimState(nextTreeNode(treeNode
,child
),child
,"PATAT");
2103 case AITypePunctualState
:
2104 parsePrimNPCPunctualState(nextTreeNode(treeNode
,child
),child
);
2107 parsePrimEvent(nextTreeNode(treeNode
,child
),child
);
2110 parsePrimGrpNpc(nextTreeNode(treeNode
,child
),child
,std::string());
2112 // uinknown so pass it..
2114 if (nodeClass(child
) != "alias")
2115 parsePrimMgrOutpost(mapName
, nextTreeNode(treeNode
, child
), child
, folders
, filename
, false);
2120 nlwarning("unrecognised ai_type in outpost manager %s: '%s'",treeNode
->fullName().c_str(),getName(nodeType(child
)));
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);
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());
2159 // TAITypeSpec typeSpec;
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());
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
);
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 //---------------------------------------------------------------------------------------
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
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))
2225 parsePrimEvent(nextTreeNode(treeNode, child), child);
2228 nlwarning("unrecognised ai_type in NPC manager %s: '%s'",treeNode->fullName().c_str(),getName(nodeType(child)));
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
);
2248 nlwarning("Failed to cast spire to CPrimPoint: %s", name
.c_str());
2251 sint x
= (uint32
)(point
->Point
.x
*1000);
2252 sint y
= (uint32
)(point
->Point
.y
*1000);
2253 float theta
= (float)point
->Angle
;
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())
2261 // nlwarning("No effect defined in spire %s", name.c_str());
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
))
2309 parsePrimEvent(NULL
, child
);
2312 nlwarning("unrecognised ai_type in spire %s: '%s'", name
.c_str(), getName(nodeType(child
)));
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
)
2331 x
= prim
->getPrimVector()->x
;
2332 y
= prim
->getPrimVector()->y
;
2334 prim
->getPropertyByName("radius", s
);
2335 NLMISC::fromString(s
, r
);
2337 vector
<string
> *params
= &EmptyStringVector
;
2338 prim
->getPropertyByName("properties", params
);
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
)
2360 x
= prim
->getPrimVector()->x
;
2361 y
= prim
->getPrimVector()->y
;
2363 prim
->getPropertyByName("radius", s
);
2364 NLMISC::fromString(s
, r
);
2366 vector
<string
> *params
=&EmptyStringVector
;
2367 prim
->getPropertyByName("properties", params
);
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
)
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();
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
));
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
;
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
);
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
);
2470 prim
->getPropertyByName("difficulty", s
);
2472 NLMISC::fromString(s
, difficulty
);
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
);
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
);
2528 case AITypeDynNpcZonePlace
:
2529 parsePrimDynNpcZonePlace(nextTreeNode(aliasNode
,child
),child
);
2531 case AITypeDynNpcZoneShape
:
2532 parsePrimDynNpcZoneShape(nextTreeNode(aliasNode
,child
),child
);
2535 parsePrimDynRoad(nextTreeNode(aliasNode
,child
),child
);
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
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
))
2625 parsePrimCell(nextTreeNode(aliasNode
,child
),child
);
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
);
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
);
2669 vector
<string
> *botEquip
= &EmptyStringVector
;
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
);
2684 prim
->getPropertyByName("level_delta", s
);
2685 NLMISC::fromString(s
, levelDelta
);
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";
2697 // read the old think
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
2723 vector
<string
> *botEquip
= &EmptyStringVector
;
2726 vector
<string
> *grpParam
= &EmptyStringVector
;
2727 bool countMultipliedBySheet
;
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
);
2753 prim
->getPropertyByName("level_delta", s
);
2754 NLMISC::fromString(s
, levelDelta
);
2758 prim
->getPropertyByName("creature_code", lookSheet
); //caracSheet);
2759 if (!lookSheet
.empty())
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()));
2795 prim
->getPropertyByName("spawn_type",s
);
2797 getType(st
, s
.c_str());
2798 uint32 spawnType
= st
;
2800 CAIActions::begin(aliasNode
->getAlias());
2801 CAIActions::exec("GRPTMPL", aliasNode
,
2804 countMultipliedBySheet
,
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
);
2843 case AITypeFaunaSpawnAtom
:
2848 std::string theSheet
;
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());
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
);
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");
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
);
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
);
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");
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
);
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");
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
);
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
);
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);
3053 case AITypeGroupFamilyProfileFauna
:
3054 parsePrimGroupFamilyProfileFauna(nextTreeNode(aliasNode
,child
),child
);
3055 // parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyFauna);
3058 case AITypeGroupFamilyProfileTribe
:
3059 parsePrimGroupFamilyProfileTribe(nextTreeNode(aliasNode
,child
),child
);
3062 case AITypeGroupFamilyProfileNpc
:
3063 parsePrimGroupFamilyProfileNpc(nextTreeNode(aliasNode
,child
),child
);
3066 // case AITypeGroupFamilyProfileGeneric:
3067 // parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyTribe);
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);
3131 // string civilisation;
3132 // const vector<string> *params = &EmptyStringVector;
3134 // prim->getPropertyByName("civilisation", civilisation);
3135 // prim->getPropertyByName("parameters", params);
3137 // CAIActions::begin(aliasNode->getAlias());
3138 // CAIActions::exec("SQUADFAM", aliasNode);
3139 //// CAIActions::exec("IDTREE",aliasNode);
3142 // CAIActions::execute("CHGPARM", *params);
3145 // for (uint i=0;i<prim->getNumChildren();++i)
3147 // // get a pointer to the child and make sure its valid
3148 // const IPrimitive *child;
3149 // if (prim->getChild(child, i))
3151 // switch(nodeType(child))
3153 // case AITypeGroupTemplate:
3154 // case AITypeGroupTemplateMultiLevel:
3155 // parsePrimGroupTemplate(nextTreeNode(aliasNode,child),child,"O");
3163 // CAIActions::end(aliasNode->getAlias());
3166 static void parsePrimOutpostSpawnZone(const CAIAliasDescriptionNode
*aliasNode
, const IPrimitive
*prim
)
3169 x
= prim
->getPrimVector()->x
;
3170 y
= prim
->getPrimVector()->y
;
3172 prim
->getPropertyByName("radius", s
);
3173 NLMISC::fromString(s
, r
);
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
);
3188 const CPrimPoint
*point
=dynamic_cast<CPrimPoint
const*>(prim
);
3191 nlwarning("Failed to cast to CPrimPoin bot: %s",name
.c_str());
3196 theta
= point
->Angle
;
3197 // x = prim->getPrimVector()->x;
3198 // y = prim->getPrimVector()->y;
3200 // prim->getPropertyByName("radius", s);
3201 // r = float(atof(s.c_str()));
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
);
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
);
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
);
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
);
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);
3328 case AITypeOutpostSpawnZone
:
3329 parsePrimOutpostSpawnZone(nextTreeNode(aliasNode
,child
), child
);
3331 case AITypeOutpostBuilding
:
3332 parsePrimOutpostBuilding(nextTreeNode(aliasNode
,child
), child
);
3335 parsePrimMgr(child
, mapName
, filename
);
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
);
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
);
3378 parsePrimOutpost(child
, mapName
, filename
);
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
);
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
);
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
)
3442 const std::vector
<std::string
>* pcode
= NULL
;
3443 prim
->getPropertyByName("name", primName
);
3444 prim
->getPropertyByName("code", pcode
);
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();
3452 for(; it
!=itEnd
; ++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
))
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
)
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());
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
,
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());
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
));
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
))
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
)
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());
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
,
3659 AITYPES::TAIType type
= nodeType(prim
);
3660 if (type
== AITypeCustomLootTables
)
3662 uint size
= prim
->getNumChildren();
3666 nlinfo("<ParsePrimCustomLootTable> Custom loot tables folder declared but empty in primitive '%s'", filename
.c_str());
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
);
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
);
3704 // we're clear to parse so go ahead!
3705 parsePrimMgr(prim
, mapName
, filename
);
3708 case AITypeDynamicSystem
:
3710 // we're clear to parse so go ahead!
3711 parsePrimDynSystem(prim
, mapName
, filename
);
3714 case AITypeSquadTemplate
:
3716 parsePrimSquadTemplate(prim
, mapName
, filename
);
3719 case AITypeNogoPointList
:
3721 parsePrimNogoPointList(prim
, mapName
, filename
);
3724 case AITypeSafeZone
:
3726 parsePrimSafeZone(prim
, mapName
, filename
);
3731 parsePrimScript(prim
, mapName
, filename
);
3736 parsePrimSpire(prim
, mapName
, filename
);
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
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)
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)
3778 // fi.MapName = *first;
3779 // fi.FileName = *first2;
3780 // vect.push_back(fi);
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" );
3802 CPrimitives
* primDoc
= new CPrimitives();
3807 H_AUTO( streamToPrimDoc
);
3808 CPrimitiveContext::instance().CurrentPrimitive
= primDoc
;
3809 primDoc
->serial(stream
);
3810 CPrimitiveContext::instance().CurrentPrimitive
= NULL
;
3815 nlwarning("stream error");
3819 parsePrimNoStream( primDoc
, streamName
);
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");
3841 nlassert (LigoConfig
!= NULL
);
3843 CPrimitiveContext::instance().CurrentPrimitive
= primDoc
;
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
))),
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
))),
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());
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())
3896 // read the file into memory and parse to generate 'prims' data tree
3902 if (fileIn
.open (filename
))
3904 nlinfo("Opening %s in %s", filename
.c_str(), CPath::getCurrentPath().c_str());
3905 sFilename
= filename
;
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(),
3920 // Test if binary caching is wanted
3921 bool cachePrims
= true;
3922 CConfigFile::CVar
*cachePrimsVar
= IService::getInstance()->ConfigFile
.getVarPtr("CachePrims");
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;
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";
3940 && CFile::fileExists(binFileName
)
3941 && CFile::getFileModificationDate(binFileName
) > CFile::getFileModificationDate(sFilename
))
3945 // ok, the cache is here and up to date !
3946 nlinfo("Loading '%s' from binary file '%s'",
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 !
3966 xmlIn
.init (fileIn
);
3968 // set the primitive context
3969 CPrimitiveContext::instance().CurrentPrimitive
= &prims
;
3971 if (!prims
.read (xmlIn
.getRootNode (), sFilename
.c_str(), *LigoConfig
))
3973 nlwarning ("Error reading file %s", sFilename
.c_str());
3976 // clean the context
3977 CPrimitiveContext::instance().CurrentPrimitive
= NULL
;
3981 // save a binary version
3982 CFile::createDirectory(IService::getInstance()->WriteFilesDirectory
.toString()+"primitive_cache");
3983 COFile
saveBin(binFileName
);
3984 prims
.serial(saveBin
);
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());
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
))),
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
))),
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>")
4034 AI_SHARE::CAIActionsDataRecord pdr
;
4035 pdr
.readFile(args
[0]);
4036 CAIActions::IExecutor
* executer
;
4037 executer
= CAIActions::getExecuter();
4040 nlwarning("no executer");
4043 pdr
.applyToExecutor(*executer
);
4049 NLMISC_COMMAND(loadPrimitiveFile
,"load a primitive file. don't forget to call BuildPrimitiveDependencies","<file name>")
4054 if (NLMISC::CFile::getExtension(args
[0]).empty())
4055 parsePrimFile(args
[0]+".primitive");
4057 parsePrimFile(args
[0]);
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>")
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");
4092 const std::string filename
= CPath::lookup(prims
[j
], false);
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'",
4101 nameFilter
.c_str());
4111 // ensure that each primitive file is only loaded once at AIS startup
4112 if (loadedPrimitives
.find(prims
[j
])!=loadedPrimitives
.end())
4114 loadedPrimitives
.insert(prims
[j
]);
4116 // this one can be loaded
4117 ICommand::execute(toString("loadPrimitiveFile %s", prims
[j
].c_str()), log
);
4126 typedef map
<string
,set
<string
> > TLoadedPrimitiveMapSet
;
4127 static TLoadedPrimitiveMapSet loadedPrimitives
;
4129 NLMISC_COMMAND(loadMap
,"load a complete set of primitive files","<map name>")
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");
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'",
4167 // check primitive already loaded
4168 if (filename
.empty())
4171 TLoadedPrimitiveMapSet::iterator it
=loadedPrimitives
.find(continentName
);
4172 if ( it
!=loadedPrimitives
.end()
4173 && it
->second
.find(filename
)!=it
->second
.end())
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",
4184 continentName
.c_str());
4188 ICommand::execute(toString("createStaticAIInstance %s", continentName
.c_str()), log
);
4190 loadedPrimitives
[continentName
].insert(filename
);
4191 parsePrimFile(filename
);
4197 NLMISC_COMMAND(unloadMap
,"unload a complete set of primitive files","<map name>")
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())
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",
4224 continentName
.c_str());
4227 ICommand::execute(toString("unloadPrimitiveFile %s", filename
.c_str()), log
);
4231 log
.displayNL("unloadMap failed : no map named %s found", args
[0].c_str());
4234 loadedPrimitives
.erase (continentName
);
4239 NLMISC_COMMAND(verbosePrimitiveParserLog
,"Turn on or off or check the state of verbose .primitive parser logging","")
4245 StrToBool (VerboseLog
, args
[0]);
4247 nlinfo("verbose Logging is %s",VerboseLog
?"ON":"OFF");
4251 } // end of namespace