2010-05-06 00:08:41 +00:00
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "stdpch.h"
# include <errno.h>
# include "nel/misc/config_file.h"
# include "nel/misc/command.h"
# include "nel/misc/file.h"
# include "nel/misc/path.h"
# include "nel/misc/i_xml.h"
# include "nel/ligo/primitive.h"
# include "nel/ligo/primitive_utils.h"
# include "nel/ligo/ligo_config.h"
# include "nel/net/service.h"
# include "ai_types.h"
# include "ai_actions.h"
# include "ai_actions_dr.h"
# include "ai_alias_description_node.h"
# include "ai_share.h"
# include "../server_share/primitive_cfg.h"
# include "../server_share/used_continent.h"
using namespace NLMISC ;
using namespace NLNET ;
using namespace NLLIGO ;
using namespace std ;
using namespace AITYPES ;
namespace AI_SHARE
{
// debug
static bool s_WriteScenarioDebugDataToFile = false ;
static void parsePrimGroupFamilyProfileFaunaContent ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim ) ;
static void parsePrimGroupFamilyProfileTribeContent ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim ) ;
static void parsePrimGroupFamilyProfileNpcContent ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim ) ;
//---------------------------------------------------------------------------------------
// THIS LINE EXISTS TO MAKE SURE THE LINKER DOESN'T THROW OUT THIS MODULE AT LINK TIME!!!
bool LinkWithPrimitiveParser = false ;
// The ligo config, if NULL, you don't have called AI_SHARE::init()
NLLIGO : : CLigoConfig * LigoConfig = NULL ;
//---------------------------------------------------------------------------------------
// Stuff used for management of log messages
static bool VerboseLog = false ;
# define LOG if (!VerboseLog) {} else nlinfo
//---------------------------------------------------------------------------------------
// some handy utilities for extracting common fields from prims
//---------------------------------------------------------------------------------------
static std : : string nodeName ( const IPrimitive * prim )
{
std : : string result ;
prim - > getPropertyByName ( " name " , result ) ;
return result ;
}
static TAIType nodeType ( const IPrimitive * prim )
{
std : : string result ;
prim - > getPropertyByName ( " ai_type " , result ) ;
return getType < TAIType > ( result . c_str ( ) ) ;
}
static TAITypeSpec nodeTypeSpec ( const IPrimitive * prim )
{
std : : string result ;
prim - > getPropertyByName ( " ai_type " , result ) ;
return getType < TAITypeSpec > ( result . c_str ( ) ) ;
}
static std : : string nodeClass ( const IPrimitive * prim )
{
std : : string result ;
prim - > getPropertyByName ( " class " , result ) ;
return result ;
}
std : : map < const IPrimitive * , uint32 > MapPrimToAlias ;
std : : map < uint32 , const IPrimitive * > MapAliasToPrim ;
uint32 nodeAlias ( const IPrimitive * prim , bool canFail = false )
{
uint32 alias = 0 ;
// see if we've already got an alias for this prim node
if ( MapPrimToAlias . find ( prim ) ! = MapPrimToAlias . end ( ) )
{
alias = MapPrimToAlias [ prim ] ;
return alias ;
}
TPrimitiveClassPredicate pred ( " alias " ) ;
IPrimitive * aliasNode = getPrimitiveChild ( const_cast < IPrimitive * > ( prim ) , pred ) ;
if ( aliasNode )
{
CPrimAlias * pa = dynamic_cast < CPrimAlias * > ( aliasNode ) ;
alias = pa - > getFullAlias ( ) ;
}
if ( ! canFail )
nlassertex ( alias ! = 0 , ( " in primitive '%s' " , buildPrimPath ( prim ) . c_str ( ) ) ) ;
// std::string s;
// prim->getPropertyByName("alias",s);
# ifdef NL_DEBUG
// nlassert(!s.empty());
# endif
// // for legacy reasons the field may be called 'unique_id' instead of 'alias'
// if (s.empty())
// prim->getPropertyByName("unique_id",s);
// alias=atoi(s.c_str());
// // if we haven't found a sensible alias value use the prim node address
// if (alias==0 && s!="0")
// {
// alias=(sint32)prim;
// if( nodeType(prim)!=AITypeBadType
// && nodeType(prim)!=AITypeEventAction
// && nodeType(prim)!=AITypeActionZone
// && nodeType(prim)!=AITypeFaunaSpawnAtom) // legacy reasons .. again (bad).
// nlwarning("Failed to find alias for prim node: '%s': '%s' (using generated alias: %u)",
// buildPrimPath(prim).c_str(),
//// getName(nodeType(prim)),
// nodeName(prim).c_str(),alias);
// }
// if we haven a valid alias, ask one to the container
if ( alias = = 0 )
{
CPrimitiveContext & ctx = CPrimitiveContext : : instance ( ) ;
nlassert ( ctx . CurrentPrimitive ) ;
alias = ctx . CurrentPrimitive - > genAlias ( const_cast < IPrimitive * > ( prim ) , 0 ) ;
alias = ctx . CurrentPrimitive - > buildFullAlias ( alias ) ;
}
// make sure the alias is unique
if ( MapAliasToPrim . find ( alias ) ! = MapAliasToPrim . end ( ) )
// && nodeClass(prim) != "npc_group_parameters" ) // <= for legacy reason
{
nlassert ( false ) ;
// uint32 oldAlias=alias;
// while (MapAliasToPrim.find(alias)!=MapAliasToPrim.end())
// ++alias;
//#if !FINAL_VERSION
// nlwarning("Alias %u not unique - remaping to %u",oldAlias,alias);
//#endif
}
// add alias to maps...
MapAliasToPrim [ alias ] = prim ;
MapPrimToAlias [ prim ] = alias ;
return alias ;
}
//---------------------------------------------------------------------------------------
// handy routine for reading vertical pos
//---------------------------------------------------------------------------------------
static bool parseVerticalPos ( const IPrimitive * prim , uint32 & verticalPos , const char * propertyName = " vertical_pos " )
{
string s ;
if ( prim - > getPropertyByName ( propertyName , s ) )
{
verticalPos = verticalPosFromString ( s ) ;
return true ;
}
else
{
verticalPos = vp_auto ;
return false ;
}
}
//---------------------------------------------------------------------------------------
// handy routine for reading the family flags
//---------------------------------------------------------------------------------------
// TODO
//static void parseFamilyFlag(const IPrimitive *prim, set<string> &result)
//{
// static bool inited; // todo, change this as we can need to reload definitions .. (like new tribes or other ..)
// static vector<string> familyNames;
// static vector<string> tribeNames;
//
// if (!inited)
// {
// // build the list of family and tribes
// TPopulationFamily::getFamilyNames(familyNames);
// const std::vector<std::pair<std::string, NLMISC::TStringId> > &names = TPopulationFamily::getTribesNames();
//
// for (uint i=0; i<names.size(); ++i)
// {
// tribeNames.push_back(names[i].first);
// }
//
// inited = true;
// }
//
// result.clear();
// // read the family flags
// for (uint i=0; i<familyNames.size(); ++i)
// {
// if (familyNames[i] == "tribe")
// {
// // special case for tribe
// for (uint j=0; j<tribeNames.size(); ++j)
// {
// string flagName = tribeNames[j];
// string s;
// if (prim->getPropertyByName(flagName.c_str(), s) && s=="true")
// result.insert(flagName);
// }
// }
// else
// {
// // standard case for all other
// string s;
// if (prim->getPropertyByName(familyNames[i].c_str(), s) && s=="true")
// result.insert(familyNames[i]);
// }
//
// }
//
//}
//---------------------------------------------------------------------------------------
// handy routine for scanning a node for mission sub-nodes
//---------------------------------------------------------------------------------------
static void lookForMissions ( const IPrimitive * prim , std : : vector < int > & missions , std : : vector < std : : string > & missionsNames )
{
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
if ( NLMISC : : nlstricmp ( nodeClass ( child ) , " mission " ) = = 0 )
{
LOG ( " Found mission: %s: %s " ,
LigoConfig - > aliasToString ( nodeAlias ( child ) ) . c_str ( ) ,
nodeName ( child ) . c_str ( ) ) ;
missions . push_back ( nodeAlias ( child ) ) ;
missionsNames . push_back ( nodeName ( child ) ) ;
}
}
}
}
//---------------------------------------------------------------------------------------
// handy structures for dealing with folders and their sub-trees
//---------------------------------------------------------------------------------------
struct SFolderRef
{
SFolderRef ( ) { }
SFolderRef ( const CAIAliasDescriptionNode * node , const IPrimitive * prim ) : Prim ( prim ) , Node ( node ) { }
const IPrimitive * Prim ;
NLMISC : : CSmartPtr < const CAIAliasDescriptionNode > Node ;
} ;
// the following variables are setup by parsePrimGrpNpc() and referenced by parsePrimNpcBot
//oldlevel static std::string DefaultBotLevel;
static std : : string DefaultBotLook ;
static uint32 DefaultBotVerticalPos = vp_auto ;
//static std::string DefaultBotStats;
static std : : vector < std : : string > EmptyStringVector ;
static const std : : vector < std : : string > * DefaultBotKeywords = & EmptyStringVector ;
static const std : : vector < std : : string > * DefaultBotEquipment = & EmptyStringVector ;
static const std : : vector < std : : string > * DefaultBotChat = & EmptyStringVector ;
static std : : vector < std : : string > DefaultMissionNames ;
static std : : vector < int > DefaultMissions ;
static const std : : vector < std : : string > * DefaultGrpParameters = & EmptyStringVector ;
static string CurrentGroupFamily ;
//---------------------------------------------------------------------------------------
// some handy utilities for manageing the treeNode trees
//---------------------------------------------------------------------------------------
// the following routine looks though the children of treeNode for one that matches prim
// if no child is found then treeNode is returned
static const CAIAliasDescriptionNode * nextTreeNode ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// get hold of the node name, type and alias
std : : string name = nodeName ( prim ) ;
TAIType type = nodeType ( prim ) ;
uint32 uniqueId = 0 ;
if ( type ! = AITYPES : : AITypeBadType )
uniqueId = nodeAlias ( prim ) ;
// see if one of the children of treeNode corresponds to the primitive
for ( uint i = 0 ; i < treeNode - > getChildCount ( ) ; + + i )
{
CAIAliasDescriptionNode * childNode = treeNode - > getChild ( i ) ;
if ( childNode - > getAlias ( ) = = uniqueId )
{
if ( childNode - > getType ( ) ! = type
| | childNode - > getName ( ) ! = name )
{
nlwarning ( " nextTreeNode(): Unique ID conflict in node: (%s, %u, %s): looking for (%s, %u, %s) but found (%s, %u, %s) " ,
getName ( treeNode - > getType ( ) ) , treeNode - > getAlias ( ) , treeNode - > fullName ( ) . c_str ( ) ,
getName ( childNode - > getType ( ) ) , childNode - > getAlias ( ) , childNode - > fullName ( ) . c_str ( ) ,
getName ( type ) , uniqueId , name . c_str ( ) ) ;
continue ;
}
return childNode ;
}
}
return treeNode ;
}
// the following routine recursively scans 'prim' and its children, constructing a CAIAliasDescriptionNode tree
// to represent ai type tree entries
static void buildAliasTree ( CAIAliasDescriptionNode * treeNode , CAIAliasDescriptionNode * rootNode , const IPrimitive * prim , std : : vector < SFolderRef > & folders )
{
// run through the node children looking for nodes with types that we recognize
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
// try to get a type, alias and name for the child
TAIType type = nodeType ( child ) ;
if ( type = = AITypeBadType )
{
buildAliasTree ( treeNode , rootNode , child , folders ) ;
continue ;
}
// CAIAliasDescriptionNode *parentNode= (type==AITypeFolder)? rootNode: treeNode;
CAIAliasDescriptionNode * parentNode = treeNode ;
uint32 uniqueId = nodeAlias ( child , true ) ;
std : : string name = nodeName ( child ) ;
// make sure the name is unique
if ( parentNode - > findNodeChildByNameAndType ( name , type ) ! = NULL )
{
LOG ( " Name not unique: %s: '%s:%s' @ '%s' " ,
getName ( type ) , parentNode - > fullName ( ) . c_str ( ) ,
name . c_str ( ) ,
treeNode - > fullName ( ) . c_str ( ) ) ;
}
// make sure the unique id is unique (SLOW!, must be replace with a fast hash_map access!)
if ( rootNode - > lookupAlias ( uniqueId ) ! = NULL )
{
nlwarning ( " WARNING - Alias clash for '%s'%s and '%s:%s' @ '%s' " ,
rootNode - > lookupAlias ( uniqueId ) - > fullName ( ) . c_str ( ) ,
LigoConfig - > aliasToString ( uniqueId ) . c_str ( ) ,
parentNode - > fullName ( ) . c_str ( ) , name . c_str ( ) ,
treeNode - > fullName ( ) . c_str ( ) ) ;
}
// create a new tree node as a child of treeNode
NLMISC : : CSmartPtr < CAIAliasDescriptionNode > node = new CAIAliasDescriptionNode ( name , uniqueId , type , parentNode ) ;
// parse this branch as a sub-tree of our new node
buildAliasTree ( node , rootNode , child , folders ) ;
// if this was a folder then add to the folder vector
if ( type = = AITypeFolder )
folders . push_back ( SFolderRef ( node , child ) ) ;
}
}
}
//---------------------------------------------------------------------------------------
// routines used by the primitive file parser
//---------------------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// States Methods
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// predecl.
static void parsePrimGrpNpc ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim , const std : : string initialState ) ;
static void parsePrimGrpFauna ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim ) ;
static void parsePrimStateChat ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// read the main body of the parameters
const std : : vector < std : : string > * botKeywords = & EmptyStringVector ;
const std : : vector < std : : string > * botNames = & EmptyStringVector ;
const std : : vector < std : : string > * chat = & EmptyStringVector ;
prim - > getPropertyByName ( " bot_keyword_filter " , botKeywords ) ;
prim - > getPropertyByName ( " bots_by_name " , botNames ) ;
prim - > getPropertyByName ( " chat_parameters " , chat ) ;
// register the profile
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " CHAT " , treeNode - > getAlias ( ) ) ;
if ( ! botKeywords - > empty ( ) ) CAIActions : : execute ( " BOTKEYS " , * botKeywords ) ;
if ( ! botNames - > empty ( ) ) CAIActions : : execute ( " BOTNAMES " , * botNames ) ;
if ( ! chat - > empty ( ) ) CAIActions : : execute ( " CHAT " , * chat ) ;
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimStateProfile ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// read the main body of the parameters
string movingProfile ;
string activityProfile ;
vector < string > * profileParams = & EmptyStringVector ;
const std : : vector < std : : string > * grpKeywords = & EmptyStringVector ;
const std : : vector < std : : string > * grpNames = & EmptyStringVector ;
prim - > getPropertyByName ( " ai_movement " , movingProfile ) ;
prim - > getPropertyByName ( " ai_activity " , activityProfile ) ;
prim - > getPropertyByName ( " ai_profile_params " , profileParams ) ;
prim - > getPropertyByName ( " grp_keyword_filter " , grpKeywords ) ;
prim - > getPropertyByName ( " grps_by_name " , grpNames ) ;
// register the profile
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " PROFILE " , treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " MOVEPROF " , movingProfile ) ;
CAIActions : : exec ( " ACTPROF " , activityProfile ) ;
CAIActions : : execute ( " PROFPARM " , * profileParams ) ;
if ( ! grpKeywords - > empty ( ) ) CAIActions : : execute ( " GRPKEYS " , * grpKeywords ) ;
if ( ! grpNames - > empty ( ) ) CAIActions : : execute ( " GRPNAMES " , * grpNames ) ;
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static CTmpPropertyZone : : TSmartPtr parseMachineStatePropertyZone ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
CTmpPropertyZone : : TSmartPtr propertyZone = new CTmpPropertyZone ( ) ;
// void setPatat (AITYPES::TVerticalPos verticalPos, const std::vector <CAIVector> &points)
uint numPoints = prim - > getNumVector ( ) ;
if ( numPoints ! = 0 )
{
const CPrimVector * const pointArray = prim - > getPrimVector ( ) ;
for ( uint i = 0 ; i < numPoints ; + + i )
{
propertyZone - > points . push_back ( CAIVector ( pointArray [ i ] . x , pointArray [ i ] . y ) ) ;
}
}
vector < string > * params = & EmptyStringVector ;
prim - > getPropertyByName ( " params " , params ) ;
for ( uint i = 0 ; i < params - > size ( ) ; i + + )
{
// const string str=(*params)[i];
// CPropertyId activity=CPropertyId::create(str);
// propertyZone->properties.addActivity(activity);
propertyZone - > properties . addProperty ( CPropertyId : : create ( ( * params ) [ i ] ) ) ;
}
return propertyZone ;
}
static CAIEventActionNode : : TSmartPtr parsePrimEventAction ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
CAIEventActionNode : : TSmartPtr result = new CAIEventActionNode ;
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = 0 ;
result - > Alias = treeNode ? treeNode - > getAlias ( ) : uniqueId ;
LOG ( " Parsing npc event action: %s " , name . c_str ( ) ) ;
// read the main body of the parameters
std : : string weightStr ;
const std : : vector < std : : string > * parameters = & EmptyStringVector ;
prim - > getPropertyByName ( " action " , result - > Action ) ;
prim - > getPropertyByName ( " weight " , weightStr ) ;
prim - > getPropertyByName ( " parameters " , parameters ) ;
result - > Weight = atoi ( weightStr . c_str ( ) ) ;
result - > Args = * parameters ;
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( ! prim - > getChild ( child , i ) )
continue ;
// try to get a type for the child
const TAIType type = nodeType ( child ) ;
// it's one of ours! - so match against the types we recognise
switch ( type )
{
case AITypeEventAction :
{
CAIEventActionNode : : TSmartPtr childAction ;
childAction = parsePrimEventAction ( treeNode ? nextTreeNode ( treeNode , child ) : NULL , child ) ;
if ( childAction )
result - > Children . push_back ( childAction ) ;
}
break ;
case AITypeActionZone :
{
result - > _PropertyZones . push_back ( parseMachineStatePropertyZone ( treeNode ? nextTreeNode ( treeNode , child ) : NULL , child ) ) ;
result - > _PropertyZones . back ( ) - > Target = CTmpPropertyZone : : All ;
}
break ;
case AITypeFaunaActionZone :
{
result - > _PropertyZones . push_back ( parseMachineStatePropertyZone ( treeNode ? nextTreeNode ( treeNode , child ) : NULL , child ) ) ;
result - > _PropertyZones . back ( ) - > Target = CTmpPropertyZone : : Fauna ;
}
break ;
case AITypeNpcActionZone :
{
result - > _PropertyZones . push_back ( parseMachineStatePropertyZone ( treeNode ? nextTreeNode ( treeNode , child ) : treeNode , child ) ) ;
result - > _PropertyZones . back ( ) - > Target = CTmpPropertyZone : : Npc ;
}
break ;
case AITypeBadType :
case AITypeFolder :
// not handled there, but by caller
break ;
default :
nlwarning ( " Don't know how to treat ai_type '%s' " , getName ( type ) ) ;
break ;
}
}
return result ;
}
/*
< PRIMITIVE CLASS_NAME = " fauna_action_zone " TYPE = " zone " R = " 128 " G = " 128 " B = " 128 " A = " 128 " AUTO_INIT = " true " DELETABLE = " true " NUMBERIZE = " false " >
< PARAMETER NAME = " name " TYPE = " string " VISIBLE = " true " / >
< PARAMETER NAME = " ai_type " TYPE = " string " VISIBLE = " false " >
< DEFAULT_VALUE VALUE = " FAUNA_ACTION_ZONE " / >
< / PARAMETER >
< PARAMETER NAME = " params " TYPE = " string_array " VISIBLE = " true " WIDGET_HEIGHT = " 100 " / >
< / PRIMITIVE >
*/
static void parsePrimGroupDescriptionsForAction ( const CAIAliasDescriptionNode * aliasNode ,
const IPrimitive * prim ,
uint32 logicActionAlias
)
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
if ( nodeType ( child ) = = AITypeBadType ) continue ; // skip alias node
const CAIAliasDescriptionNode * childTreeNode = nextTreeNode ( aliasNode , child ) ;
string familyTag ;
child - > getPropertyByName ( " family " , familyTag ) ;
CAIActions : : exec ( " GRPFAM " , childTreeNode , familyTag , name , logicActionAlias ) ;
TAIType type = nodeType ( child ) ;
switch ( type )
{
case AITypeGroupFamily :
{
nlwarning ( " Parsing a group_family, primitive is outdated. Please report to jvuarand. " ) ;
// parsePrimGroupFamily(nextTreeNode(aliasNode,child),child);
}
break ;
case AITypeGroupFamilyProfileFauna :
parsePrimGroupFamilyProfileFaunaContent ( childTreeNode , child ) ;
// parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyFauna);
break ;
case AITypeGroupFamilyProfileTribe :
parsePrimGroupFamilyProfileTribeContent ( childTreeNode , child ) ;
break ;
case AITypeGroupFamilyProfileNpc :
parsePrimGroupFamilyProfileNpcContent ( childTreeNode , child ) ;
break ;
// case AITypeGroupFamilyProfileGeneric:
// parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyTribe);
// break;
default :
CAIActions : : end ( childTreeNode - > getAlias ( ) ) ;
break ;
}
}
}
}
// add group description to already parsed event actions
static void addGroupDescriptionToEventAction ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim , uint depth )
{
uint32 uniqueId = 0 ;
CAIActions : : begin ( treeNode ? treeNode - > getAlias ( ) : uniqueId ) ;
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure it's valid
const IPrimitive * child ;
if ( ! prim - > getChild ( child , i ) )
continue ;
//
const TAIType type = nodeType ( child ) ;
// it's one of ours! - so match against the types we recognise
switch ( type )
{
case AITypeEventAction :
{
addGroupDescriptionToEventAction ( treeNode ? nextTreeNode ( treeNode , child ) : NULL , child , depth + 1 ) ;
}
break ;
case AITypeActionZone :
case AITypeFaunaActionZone :
case AITypeNpcActionZone :
// no-op, already parsed
break ;
case AITypeFolder :
{
string cname = nodeClass ( child ) ;
// parse optionnal group descriptions
if ( cname = = " group_descriptions " )
{
CAIActions : : exec ( " SETACTN " , treeNode ? treeNode - > getAlias ( ) : uniqueId ) ;
parsePrimGroupDescriptionsForAction ( treeNode ? nextTreeNode ( treeNode , child ) : NULL , child , treeNode ? treeNode - > getAlias ( ) : uniqueId ) ;
CAIActions : : exec ( " CLRACTN " ) ;
}
}
break ;
case AITypeBadType :
default :
nlwarning ( " Don't know how to treat ai_type '%s' " , getName ( type ) ) ;
break ;
}
}
CAIActions : : end ( treeNode ? treeNode - > getAlias ( ) : uniqueId ) ;
}
static void parsePrimEvent ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
CAIEventDescription : : TSmartPtr result = new CAIEventDescription ;
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing npc event: %s " , name . c_str ( ) ) ;
// read the main body of the parameters
const std : : vector < std : : string > * stateKeywords = & EmptyStringVector ;
const std : : vector < std : : string > * namedStates = & EmptyStringVector ;
const std : : vector < std : : string > * groupKeywords = & EmptyStringVector ;
const std : : vector < std : : string > * namedGroups = & EmptyStringVector ;
prim - > getPropertyByName ( " event " , result - > EventType ) ;
// the event should have two children, the alias and the action
const IPrimitive * child ;
std : : string type ;
if ( prim - > getNumChildren ( ) ! = 2
| | ! prim - > getChild ( child , 1 )
| | ! child - > getPropertyByName ( " ai_type " , type )
| | getType < TAIType > ( type . c_str ( ) ) ! = AITypeEventAction )
{
nlwarning ( " Failed to find the action associated with event: %s (in %s) " , name . c_str ( ) , treeNode ? treeNode - > fullName ( ) . c_str ( ) : " " ) ;
return ;
}
result - > Action = parsePrimEventAction ( treeNode ? nextTreeNode ( treeNode , child ) : NULL , child ) ;
prim - > getPropertyByName ( " state_keyword_filter " , stateKeywords ) ;
prim - > getPropertyByName ( " states_by_name " , namedStates ) ;
prim - > getPropertyByName ( " group_keyword_filter " , groupKeywords ) ;
prim - > getPropertyByName ( " groups_by_name " , namedGroups ) ;
result - > StateKeywords = * stateKeywords ;
result - > NamedStates = * namedStates ;
result - > GroupKeywords = * groupKeywords ;
result - > NamedGroups = * namedGroups ;
// register the event and call the parser for the associated action
CAIActions : : begin ( treeNode ? treeNode - > getAlias ( ) : uniqueId ) ;
CAIActions : : exec ( " EVENT " , uniqueId , result ) ;
CAIActions : : end ( treeNode ? treeNode - > getAlias ( ) : uniqueId ) ;
// Each 'event actions' may have a group description attached to it,
// parse it here, because we don't want to embed those descriptions in the
// CAIEventDescription class
addGroupDescriptionToEventAction ( treeNode ? nextTreeNode ( treeNode , child ) : NULL , child , 1 ) ;
CAIActions : : exec ( " ENDEVENT " ) ; // this will clear the logic actions map
}
//---------------------------------------------------------------------------------------
// kami routines
static void parsePrimBotKami ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
nlassert ( false ) ;
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// lookup the kami type
std : : string kamiType ;
if ( ! prim - > getPropertyByName ( " ai_kami_type " , kamiType ) | | ( kamiType ! = " PREACHER " & & kamiType ! = " GUARDIAN " ) )
{
nlwarning ( " ai_kami_type property not found in kami record: %s " , treeNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
// lookup the creature sheet name
std : : string sheet ;
if ( ! prim - > getPropertyByName ( " sheet " , sheet ) )
{
nlwarning ( " 'sheet' property not found in kami record: %s " , treeNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
// lookup x,y,theta
const CPrimPoint * point = dynamic_cast < const CPrimPoint * > ( prim ) ;
if ( point = = NULL )
{
nlwarning ( " Failed to cast to CPrimPoin kami: %s " , name . c_str ( ) ) ;
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
return ;
}
sint x = ( uint32 ) ( point - > Point . x * 1000 ) ;
sint y = ( uint32 ) ( point - > Point . y * 1000 ) ;
float theta = ( float ) point - > Angle ;
// do the business
LOG ( " Adding kami npc bot: %s: %s pos: (%d,%d) orientation: %.2f " , kamiType . c_str ( ) , name . c_str ( ) , x , y , theta ) ;
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " BOTNPC " , treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " LOOK " , sheet ) ;
CAIActions : : exec ( " STATS " , 25 ) ;
CAIActions : : exec ( " KEYWORDS " , kamiType ) ;
CAIActions : : exec ( " STARTPOS " , x , y , theta ) ;
if ( kamiType = = " PREACHER " )
{
// todo: get rid of this code :o)
// add teleport stuff to the Kami ... this is temporary
std : : vector < std : : string > chat ;
chat . push_back ( std : : string ( " shop: KAMI_TP_FOREST " ) ) ;
CAIActions : : execute ( " CHAT " , chat ) ;
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimGrpKami ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing group kami: %s " , name . c_str ( ) ) ;
// extract x and y coords of points from patat (if there is one)
// std::vector <CAIActions::CArg> points;
// uint numPoints=prim->getNumVector();
// if (numPoints!=0)
// {
// const CPrimVector *pointArray=prim->getPrimVector();
// for (uint i=0;i<numPoints;++i)
// {
// points.push_back(CAIActions::CArg(pointArray[i].x));
// points.push_back(CAIActions::CArg(pointArray[i].y));
// }
// }
// setup the grp context
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " GRPNPC " , uniqueId ) ;
// commit the zone points
// if (!points.empty())
// CAIActions::execute("PATAT",points);
// run through the group children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
// try to get a type for the child
// it's one of ours! - so match against the types we recognise
switch ( nodeType ( child ) )
{
case AITypeBot :
parsePrimBotKami ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeBadType :
case AITypeFolder :
break ;
default :
nlwarning ( " Didn't found ai_type when expecting 'BOT_NPC' in parsePrimGrpKami " ) ;
break ;
}
}
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
//---------------------------------------------------------------------------------------
// karavan routines
static void parsePrimBotKaravan ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
nlassert ( false ) ;
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// lookup the karavan type
std : : string karavanType ;
if ( ! prim - > getPropertyByName ( " ai_karavan_type " , karavanType ) )
{
nlwarning ( " ai_karavan_type property not found in karavan record: %s " , treeNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
// lookup the creature sheet name
std : : string sheet ;
if ( ! prim - > getPropertyByName ( " sheet " , sheet ) )
{
nlwarning ( " 'sheet' property not found in karavan record: %s " , treeNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
// add the bot to the current group
const CPrimPoint * point = dynamic_cast < const CPrimPoint * > ( prim ) ;
if ( ! point )
{
nlwarning ( " Failed to cast to CPrimPoin karavan: %s " , name . c_str ( ) ) ;
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
return ;
}
sint x = ( uint32 ) ( point - > Point . x * 1000 ) ;
sint y = ( uint32 ) ( point - > Point . y * 1000 ) ;
float theta = ( float ) point - > Angle ;
LOG ( " Adding karavan npc bot: %s: %s pos: (%d,%d) orientation: %.2f " , karavanType . c_str ( ) , name . c_str ( ) , x , y , theta ) ;
// do the business
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " BOTNPC " , treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " LOOK " , sheet ) ;
CAIActions : : exec ( " STATS " , 25 ) ;
CAIActions : : exec ( " KEYWORDS " , karavanType ) ;
CAIActions : : exec ( " STARTPOS " , x , y , theta ) ;
// if (kamiType=="")
{
// todo: get rid of this code :o)
// add teleport stuff to the Kami ... this is temporary
std : : vector < std : : string > chat ;
chat . push_back ( std : : string ( " shop: KARAVAN_TP_FOREST " ) ) ;
CAIActions : : execute ( " CHAT " , chat ) ;
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimGrpKaravan ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing group karavan: %s " , name . c_str ( ) ) ;
// setup the grp context
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " GRPNPC " , treeNode - > getAlias ( ) ) ;
// run through the group children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
TAIType type = nodeType ( child ) ;
switch ( type )
{
case AITypeBot :
parsePrimBotKaravan ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeFolder :
case AITypeBadType :
break ;
default :
nlwarning ( " Unsupported ai_type in parsePrimGrpKaravan " ) ;
break ;
}
}
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimState ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim , const char * pointsType )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing npc state with %s: %s " , pointsType , name . c_str ( ) ) ;
// look for keywords
std : : string moveProfile ;
std : : string activityProfile ;
vector < string > * profileParams = & EmptyStringVector ;
const std : : vector < std : : string > * keywords = & EmptyStringVector ;
prim - > getPropertyByName ( " grp_keywords " , keywords ) ;
prim - > getPropertyByName ( " ai_movement " , moveProfile ) ;
prim - > getPropertyByName ( " ai_activity " , activityProfile ) ;
prim - > getPropertyByName ( " ai_profile_params " , profileParams ) ;
uint32 verticalPos ;
parseVerticalPos ( prim , verticalPos ) ;
// extract x and y coords of points from spline or patat
std : : vector < CAIActions : : CArg > points ;
uint numPoints = prim - > getNumVector ( ) ;
if ( numPoints ! = 0 )
{
const CPrimVector * pointArray = prim - > getPrimVector ( ) ;
for ( uint i = 0 ; i < numPoints ; + + i )
{
points . push_back ( CAIActions : : CArg ( pointArray [ i ] . x ) ) ;
points . push_back ( CAIActions : : CArg ( pointArray [ i ] . y ) ) ;
}
}
else
LOG ( " State has no geometry: %s: %s " , pointsType , name . c_str ( ) ) ;
// create the state
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " STATE " , uniqueId ) ;
CAIActions : : exec ( " MOVEPROF " , moveProfile ) ;
CAIActions : : exec ( " ACTPROF " , activityProfile ) ;
CAIActions : : execute ( " PROFPARM " , * profileParams ) ;
CAIActions : : exec ( " VERTPOS " , verticalPos ) ;
if ( ! keywords - > empty ( ) )
CAIActions : : execute ( " KEYWORDS " , * keywords ) ;
if ( ! points . empty ( ) )
CAIActions : : execute ( pointsType , points ) ;
// run through the group children looking for nodes with types that we recognise
uint j ;
for ( j = 0 ; j < prim - > getNumChildren ( ) ; + + j )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , j ) )
{
// try to get a type for the child
switch ( nodeType ( child ) )
{
case AITypeNpcStateProfile :
case AITypeNpcStateChat :
// this kind of node is read in the next loop
// this is because any mission in a group MUST be read before
// the parsing of the state profile/
// parsePrimStateProfile(nextTreeNode(treeNode,child),child);
break ;
case AITypeGrp :
{
switch ( nodeTypeSpec ( child ) )
{
case AITypeSpecNpc :
parsePrimGrpNpc ( nextTreeNode ( treeNode , child ) , child , name ) ;
break ;
case AITypeSpecFauna :
parsePrimGrpFauna ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeSpecKami : // a non-deposit kami group
parsePrimGrpKami ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeSpecKaravan :
parsePrimGrpKaravan ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
default :
nlwarning ( " Don't know how to treat ai_group of type '%s' in primState " , getName ( nodeTypeSpec ( child ) ) ) ;
break ;
}
}
break ;
case AITypeEvent :
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeState :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATAT " ) ;
break ;
case AITypeBadType :
case AITypeFolder :
break ;
default :
nlwarning ( " Don't know how to treat ai_type '%s' " , getName ( nodeType ( child ) ) ) ;
break ;
}
}
}
// a second loop for state profile node.
for ( j = 0 ; j < prim - > getNumChildren ( ) ; + + j )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , j ) )
{
switch ( nodeType ( child ) )
{
case AITypeNpcStateProfile :
parsePrimStateProfile ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeNpcStateChat :
parsePrimStateChat ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
default : // we don't care unknown objets.
break ;
}
}
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
//////////////////////////////////////////////////////////////////////////
// End States Methods
//////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------------------------------------
// shared routines
static void parsePrimPlaces ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// run through the group children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
// hack because the place type
std : : string placeName ;
child - > getPropertyByName ( " ai_place_type " , placeName ) ;
// try to get a type for the child
TAIType type = nodeType ( child ) ;
if ( type ! = AITypeBadType
& & type ! = AITypeFolder )
{
// get hold of the unique id
uint32 uniqueId = nodeAlias ( child ) ;
// it's one of ours! - so match against the types we recognise
if ( type = = AITypePlace | | type = = AITypeOutpost | | type = = AITypePlaceFauna )
{
// read the radius
std : : string radiusString ;
child - > getPropertyByName ( " radius " , radiusString ) ;
uint radius = atoi ( radiusString . c_str ( ) ) ;
if ( radius = = 0 )
{
nlwarning ( " Ignoring place '%s' because bad radius: '%s' (converted to int as %u) " ,
placeName . c_str ( ) ,
radiusString . c_str ( ) ,
radius ) ;
continue ;
}
// if (radiusString!=toString(radius))
// {
// nlwarning("Ignoring place '%s' because bad radius: '%s'",placeName.c_str(),radiusString.c_str());
// continue;
// }
//
// read the xy coordinates
if ( child - > getNumVector ( ) ! = 1 )
{
nlwarning ( " Ignoring place '%s' because num points not 1 (%d) " , placeName . c_str ( ) , child - > getNumVector ( ) ) ;
continue ;
}
float x = ( float ) ( child - > getPrimVector ( ) - > x ) ;
float y = ( float ) ( child - > getPrimVector ( ) - > y ) ;
uint32 verticalPos ;
parseVerticalPos ( child , verticalPos ) ;
if ( type = = AITypePlaceFauna )
{
std : : string tmpStr ;
uint32 stayTimeMin = 1000 ;
uint32 stayTimeMax = 1000 ;
uint32 index = 0 ;
std : : string indexNext ;
bool flagSpawn = false ;
bool flagFood = false ;
bool flagRest = false ;
//
bool active = true ;
bool timeDriven = false ;
std : : string timeInterval ;
std : : string dayInterval ;
//
if ( child - > getPropertyByName ( " visit_time_min " , tmpStr ) )
{
stayTimeMin = atoi ( tmpStr . c_str ( ) ) ;
}
if ( child - > getPropertyByName ( " visit_time_max " , tmpStr ) )
{
stayTimeMax = atoi ( tmpStr . c_str ( ) ) ;
}
if ( child - > getPropertyByName ( " index " , tmpStr ) )
{
index = atoi ( tmpStr . c_str ( ) ) ;
}
child - > getPropertyByName ( " index_next " , indexNext ) ;
if ( child - > getPropertyByName ( " flag_spawn " , tmpStr ) )
{
flagSpawn = nlstricmp ( tmpStr , " true " ) = = 0 ;
}
if ( child - > getPropertyByName ( " flag_rest " , tmpStr ) )
{
flagRest = nlstricmp ( tmpStr , " true " ) = = 0 ;
}
if ( child - > getPropertyByName ( " flag_food " , tmpStr ) )
{
flagFood = nlstricmp ( tmpStr , " true " ) = = 0 ;
}
if ( child - > getPropertyByName ( " active " , tmpStr ) )
{
active = nlstricmp ( tmpStr , " true " ) = = 0 ;
}
if ( child - > getPropertyByName ( " time_driven " , tmpStr ) )
{
timeDriven = nlstricmp ( tmpStr , " true " ) = = 0 ;
}
child - > getPropertyByName ( " time_interval " , timeInterval ) ;
child - > getPropertyByName ( " day_interval " , dayInterval ) ;
LOG ( " Adding place (type XYRFauna): %s at: (%.0f,%.0f) x %d (%s) " ,
placeName . c_str ( ) ,
child - > getPrimVector ( ) - > x ,
child - > getPrimVector ( ) - > y ,
radius ,
verticalPosToString ( ( TVerticalPos ) verticalPos ) . c_str ( ) ) ;
// add the place to the current context
CAIActions : : begin ( uniqueId ) ;
CAIActions : : exec ( " PLACEXYR " , uniqueId , x , y , radius * 1000 , verticalPos ) ;
CAIActions : : exec ( " PLXYRFAF " , uniqueId , flagSpawn , flagRest , flagFood ) ; // set flags
CAIActions : : exec ( " PLXYRFAS " , uniqueId , stayTimeMin , stayTimeMax ) ; // set stay times
CAIActions : : exec ( " PLXYRFAI " , uniqueId , index , indexNext ) ; // set indices
CAIActions : : exec ( " PLXYRFAA " , uniqueId , active , timeDriven , timeInterval , dayInterval ) ; // set indices
CAIActions : : end ( uniqueId ) ;
}
else
{
LOG ( " Adding place (type XYR): %s at: (%.0f,%.0f) x %d (%s) " ,
placeName . c_str ( ) ,
child - > getPrimVector ( ) - > x ,
child - > getPrimVector ( ) - > y ,
radius ,
verticalPosToString ( ( TVerticalPos ) verticalPos ) . c_str ( ) ) ;
// add the place to the current context
CAIActions : : begin ( uniqueId ) ;
CAIActions : : exec ( " PLACEXYR " , uniqueId , x , y , radius * 1000 , verticalPos ) ;
CAIActions : : end ( uniqueId ) ;
}
}
}
}
}
}
struct parsePopException : public Exception
{
parsePopException ( const std : : string & Reason ) : Exception ( Reason )
{ }
} ;
static void parsePopulation ( const IPrimitive * prim , std : : string & sheet , uint & count )
{
// try to get a type for the child
std : : string type ;
if ( ! prim - > getPropertyByName ( " ai_type " , type ) )
{
throw parsePopException ( std : : string ( " ai_type not found " ) ) ;
}
// it's one of ours! - so match against the types we recognise
if ( NLMISC : : nlstricmp ( type , " FAUNA_SPAWN_ATOM " ) ! = 0 )
{
throw parsePopException ( std : : string ( " Expected ai_type FAUNA_SPAWN_ATOM but found " ) + type ) ;
}
std : : string countStr ;
if ( ! prim - > getPropertyByName ( " count " , countStr ) )
{
throw parsePopException ( std : : string ( " FAUNA_SPAWN_ATOM failed to find property ''count' " ) ) ;
}
{
string s ;
if ( prim - > getPropertyByName ( " creature_code " , s ) & & ! s . empty ( ) )
sheet = s + " .creature " ;
}
count = atoi ( countStr . c_str ( ) ) ;
if ( count < = 0 )
{
throw parsePopException ( std : : string ( " FAUNA_SPAWN_ATOM property 'count' invalid: " ) + countStr ) ;
}
}
//---------------------------------------------------------------------------------------
// fauna routines
static void parsePrimGrpFaunaSpawn ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing group fauna spawn: %s " , name . c_str ( ) ) ;
// we need a vector of arguments for the call to execute() at the end
std : : vector < CAIActions : : CArg > executeArgs ;
executeArgs . push_back ( CAIActions : : CArg ( uniqueId ) ) ;
// lookup the spawn type for the manager
std : : string spawnType ( " ALWAYS " ) ;
prim - > getPropertyByName ( " spawn_type " , spawnType ) ;
executeArgs . push_back ( CAIActions : : CArg ( spawnType ) ) ;
// deal with the weight
std : : string s ;
uint32 weight ;
if ( prim - > getPropertyByName ( " weight " , s ) )
{
weight = atoi ( s . c_str ( ) ) ;
if ( toString ( weight ) ! = s )
{
nlwarning ( " weight invalid value: %s " ) ;
weight = 100 ;
}
}
executeArgs . push_back ( CAIActions : : CArg ( weight ) ) ;
// run through the group children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( ! prim - > getChild ( child , i ) )
continue ;
// not interested to parse alias nodes !
if ( nodeClass ( child ) = = " alias " )
continue ;
try
{
std : : string theSheet ;
uint count ;
parsePopulation ( child , theSheet , count ) ;
if ( theSheet . empty ( ) )
continue ;
executeArgs . push_back ( CAIActions : : CArg ( theSheet ) ) ;
executeArgs . push_back ( count ) ;
}
catch ( parsePopException e )
{
nlwarning ( " FaunaGroup: %s of %s : %s " , nodeName ( child ) . c_str ( ) , treeNode - > fullName ( ) . c_str ( ) , e . what ( ) ) ;
}
}
// open the parse context
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
// call the 'execution' system
if ( ! executeArgs . empty ( )
& & executeArgs . size ( ) > = 5 )
CAIActions : : execute ( " POPVER " , executeArgs ) ;
else
nlwarning ( " FAUNA_SPAWN failed because population is empty, '%s'%s " ,
name . c_str ( ) ,
LigoConfig - > aliasToString ( uniqueId ) . c_str ( ) ) ;
// close the parse context
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimGrpFauna ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// lookup the fauna type for the manager
/* std::string faunaTypeStr;
prim - > getPropertyByName ( " fauna_type " , faunaTypeStr ) ;
if ( getType < TFaunaType > ( faunaTypeStr . c_str ( ) ) = = FaunaTypeBadType )
{
nlwarning ( " Ignoring group %s due to unknown type: '%s' " , name . c_str ( ) , faunaTypeStr . c_str ( ) ) ;
return ;
}
*/
// open the parse context
LOG ( " Parsing group fauna: %s " , name . c_str ( ) ) ;
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
// Don't know what for .. ???
// // get hold of the ids of the places
// uint32 feedPlace=~0u, restPlace=~0u, spawnPlace=~0u;
// for (uint i=0;i<treeNode->getChildCount();++i)
// {
// if (treeNode->getChild(i)->getType()==AITypePlace)
// {
// if (name=="FAUNA_FOOD") feedPlace=treeNode->getChild(i)->getAlias();
// if (name=="FAUNA_REST") restPlace=treeNode->getChild(i)->getAlias();
// if (name=="FAUNA_SPAWN") spawnPlace=treeNode->getChild(i)->getAlias();
// }
//
// }
// setup the grp context
CAIActions : : exec ( " GRPFAUNA " , uniqueId /*,faunaTypeStr*/ ) ;
// create any places that we're going to reffer to later
parsePrimPlaces ( nextTreeNode ( treeNode , prim ) , prim ) ;
// time variables used for determining time spent eating, rate of progress of hunger, etc
std : : string s ;
if ( prim - > getPropertyByName ( " times " , s ) & & ! s . empty ( ) )
{
float time1 = 0 , time2 = 0 ;
sscanf ( s . c_str ( ) , " %f %f " , & time1 , & time2 ) ;
CAIActions : : exec ( " SETTIMES " , time1 , time2 ) ;
}
else
{
LOG ( " No 'times' record found: using default value: 10 10 " ) ;
float time1 = 30.0f , time2 = 120.0f ;
CAIActions : : exec ( " SETTIMES " , time1 , time2 ) ;
}
s . clear ( ) ;
prim - > getPropertyByName ( " autoSpawn " , s ) ;
CAIActions : : exec ( " AUTOSPWN " , uint32 ( nlstricmp ( s . c_str ( ) , " false " ) ! = 0 ) ) ;
// time variables used for determining time corpses stay on ground and time before creatures respawn
s . clear ( ) ;
prim - > getPropertyByName ( " spawn_times " , s ) ; // This code is a nasty hack to provide legacy support
if ( s . empty ( ) ) // for .primitive files generated with a defective
prim - > getPropertyByName ( " Spawn_times " , s ) ; // world_editor.xml (case problem in 'spawn_times')
if ( ! s . empty ( ) )
{
float time1 = 0 , time2 = 0 , time3 = - 1 ;
sscanf ( s . c_str ( ) , " %f %f %f " , & time1 , & time2 , & time3 ) ;
if ( time3 = = - 1 )
CAIActions : : exec ( " SPAWTIME " , time1 , time2 ) ;
else
CAIActions : : exec ( " SPAWTIME " , time1 , time2 , time3 ) ;
}
else
{
LOG ( " No 'spawn times' record found: using default value: 30 120 " ) ;
float time1 = 30.0f , time2 = 120.0f ;
CAIActions : : exec ( " SPAWTIME " , time1 , time2 ) ;
}
// ring cycles.
{
std : : string cycles ( " " ) ;
prim - > getPropertyByName ( " cycles " , cycles ) ;
CAIActions : : exec ( " STCYCLES " , cycles ) ;
}
// solidarity used
s . clear ( ) ;
prim - > getPropertyByName ( " solidarity " , s ) ;
CAIActions : : exec ( " ASSIST " , uint32 ( nlstricmp ( s . c_str ( ) , " disabled " ) ! = 0 ) ) ;
// run through the group children looking for nodes with types that we recognise
for ( uint j = 0 ; j < prim - > getNumChildren ( ) ; + + j )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( ! prim - > getChild ( child , j ) )
continue ;
// try to get a type for the child
TAIType type = nodeType ( child ) ;
switch ( type )
{
case AITypeGrpFaunaPop :
parsePrimGrpFaunaSpawn ( nextTreeNode ( nextTreeNode ( treeNode , prim ) , prim ) , child ) ;
break ;
case AITypeEvent :
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeBadType :
case AITypeFolder :
break ;
default :
if ( type ! = AITypePlace & & type ! = AITypePlaceFauna )
nlwarning ( " Don't know how to treat ai_type '%s' " , getName ( type ) ) ;
break ;
}
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimMgrFauna ( const std : : string & mapName , const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim , std : : vector < SFolderRef > & folders , const std : : string & filename , bool firstTime = true )
{
// get hold of the unique id
uint32 uniqueId = nodeAlias ( prim , true ) ;
// setup the mgr context
if ( firstTime )
{
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " MGRFAUNA " , treeNode - > getAlias ( ) , treeNode - > getName ( ) , mapName , filename ) ;
CAIActions : : exec ( " IDTREE " , treeNode ) ;
}
// run through the mgr children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( ! prim - > getChild ( child , i ) )
continue ;
// try to get a type for the child
TAIType type = nodeType ( child ) ;
switch ( type )
{
case AITypeGrp :
parsePrimGrpFauna ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeState :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATAT " ) ;
break ;
case AITypeEvent :
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
// this isn't an ai block so check its children
case AITypeBadType :
parsePrimMgrFauna ( mapName , nextTreeNode ( treeNode , child ) , child , folders , filename , false ) ;
break ;
case AITypeFolder :
break ;
default :
nlwarning ( " Found ai_type: '%s' when expecting 'GROUP_FAUNA' " , getName ( type ) ) ;
break ;
}
}
if ( firstTime )
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimNPCPunctualState ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing npc punctual state: %s " , name . c_str ( ) ) ;
// look for keywords
const std : : vector < std : : string > * keywords = & EmptyStringVector ;
prim - > getPropertyByName ( " grp_keywords " , keywords ) ;
// create the state
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " PUNCTUAL " , uniqueId ) ;
if ( ! keywords - > empty ( ) ) CAIActions : : execute ( " KEYWORDS " , * keywords ) ;
// run through the group children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeNpcStateProfile :
parsePrimStateProfile ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeNpcStateChat :
parsePrimStateChat ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeEvent :
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeBadType :
case AITypeFolder :
break ;
default : // we don't care unknown objets.
nlwarning ( " Don't know how to treat ai_type '%s' " , getName ( nodeType ( child ) ) ) ;
break ;
}
}
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimMgrKami ( const std : : string & mapName , const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim , std : : vector < SFolderRef > & folders , const std : : string & filename , bool firstTime = true )
{
// get hold of the unique id
uint32 uniqueId = nodeAlias ( prim ) ;
// setup the mgr context
if ( firstTime )
{
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " MGRNPC " , treeNode - > getAlias ( ) , treeNode - > getName ( ) , mapName , filename ) ;
CAIActions : : exec ( " IDTREE " , treeNode ) ;
}
// run through the mgr children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( ! prim - > getChild ( child , i ) )
continue ;
// try to get a type for the child
TAIType type = nodeType ( child ) ;
switch ( type )
{
case AITypeNpcStateRoute :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATH " ) ;
break ;
case AITypeNpcStateZone :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATAT " ) ;
break ;
case AITypePunctualState :
parsePrimNPCPunctualState ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeEvent :
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeKamiDeposit : // a deposit
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATAT " ) ;
break ;
case AITypeBadType :
parsePrimMgrKami ( mapName , nextTreeNode ( treeNode , child ) , child , folders , filename , false ) ;
break ;
case AITypeFolder :
break ;
default :
nlwarning ( " Unsupported ai_type in parsePrimMgrKami " ) ;
break ;
}
}
if ( firstTime )
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimMgrKaravan ( const std : : string & mapName , const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim , std : : vector < SFolderRef > & folders , const std : : string & filename , bool firstTime = true )
{
// get hold of the unique id
uint32 uniqueId = nodeAlias ( prim ) ;
// setup the mgr context
if ( firstTime )
{
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " MGRNPC " , treeNode - > getAlias ( ) , treeNode - > getName ( ) , mapName , filename ) ;
CAIActions : : exec ( " IDTREE " , treeNode ) ;
}
// run through the mgr children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
// try to get a type for the child
TAIType type = nodeType ( child ) ;
switch ( type )
{
case AITypeKaravanState :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " " ) ;
break ;
case AITypeBadType :
parsePrimMgrKaravan ( mapName , nextTreeNode ( treeNode , child ) , child , folders , filename , false ) ;
break ;
case AITypeFolder :
break ;
default :
nlwarning ( " Unsupported ai_type in parsePrimMgrKaravan " ) ;
break ;
}
}
}
if ( firstTime )
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
//---------------------------------------------------------------------------------------
// npc routines
void mergeEquipement ( const std : : vector < std : : string > & grpEquip , const std : : vector < std : : string > & botEquip , std : : vector < std : : string > & result )
{
uint i ;
map < string , string > equip ;
string key , tail ;
for ( i = 0 ; i < grpEquip . size ( ) ; + + i )
{
if ( stringToKeywordAndTail ( grpEquip [ i ] , key , tail ) )
equip [ key ] = tail ;
}
for ( i = 0 ; i < botEquip . size ( ) ; + + i )
{
if ( stringToKeywordAndTail ( botEquip [ i ] , key , tail ) )
equip [ key ] = tail ;
}
result . clear ( ) ;
// rebuild the final equipement
map < string , string > : : iterator first ( equip . begin ( ) ) , last ( equip . end ( ) ) ;
for ( ; first ! = last ; + + first )
{
result . push_back ( first - > first + " : " + first - > second ) ;
}
}
static void parsePrimBotNpc ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// setup the set of parameters that are initialised by default in parsePrimGrpNpc()
//oldlevel std::string levelStr; /* = DefaultBotLevel; */
std : : string look ; // = DefaultBotLook;
// std::string fight;
// std::string stats; // = DefaultBotStats;
const std : : vector < std : : string > * keywords = NULL ; //DefaultBotKeywords;
const std : : vector < std : : string > * equipment = NULL ; //&EmptyStringVector;// = DefaultBotEquipment;
const std : : vector < std : : string > * chat = NULL ; //DefaultBotChat;
static std : : vector < int > missions ;
static std : : vector < std : : string > missionsNames ;
missions = DefaultMissions ;
missionsNames = DefaultMissionNames ;
std : : string isStuck ;
uint32 verticalPos ;
// try to read the above parameters from prim (on failure default value persists)
//oldlevel if (!prim->getPropertyByName("level", levelStr) || levelStr.empty())
//oldlevel levelStr = DefaultBotLevel;
if ( ! prim - > getPropertyByName ( " keywords " , keywords ) | | keywords = = NULL )
keywords = DefaultBotKeywords ;
if ( ! prim - > getPropertyByName ( " equipment " , equipment ) | | equipment = = NULL )
equipment = & EmptyStringVector ;
if ( ! prim - > getPropertyByName ( " chat_parameters " , chat ) | | chat = = NULL )
chat = DefaultBotChat ;
if ( ! prim - > getPropertyByName ( " sheet_client " , look ) | | look . empty ( ) )
look = DefaultBotLook ;
prim - > getPropertyByName ( " is_stuck " , isStuck ) ;
lookForMissions ( prim , missions , missionsNames ) ;
if ( ! parseVerticalPos ( prim , verticalPos ) )
verticalPos = DefaultBotVerticalPos ;
// build the equipement
std : : vector < std : : string > equipmentMerged ;
mergeEquipement ( * DefaultBotEquipment , * equipment , equipmentMerged ) ;
// lookup coordinate and orientation for the bot
const CPrimPoint * point = dynamic_cast < const CPrimPoint * > ( prim ) ;
if ( point = = NULL )
{
nlwarning ( " Failed to cast to CPrimPoin bot: %s " , name . c_str ( ) ) ;
return ;
}
sint x = ( uint32 ) ( point - > Point . x * 1000 ) ;
sint y = ( uint32 ) ( point - > Point . y * 1000 ) ;
float theta = ( float ) point - > Angle ;
// setup the bots
LOG ( " Adding npc bot: %s pos: (%d,%d) orientation: %.2f " , name . c_str ( ) , x , y , theta ) ;
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " BOTNPC " , uniqueId ) ;
CAIActions : : exec ( " STARTPOS " , x , y , theta , verticalPos ) ;
CAIActions : : exec ( " LOOK " , look ) ;
// CAIActions::exec("STATS",stats+NLMISC::toString("_lvl_%02d",level),level);
CAIActions : : exec ( " STATS " ) ; //,level);
CAIActions : : exec ( " ISSTUCK " , uint32 ( nlstricmp ( isStuck . c_str ( ) , " true " ) = = 0 ) ) ;
CAIActions : : exec ( " BLDNGBOT " , uint32 ( false ) ) ;
// if ( !fight.empty() )
// CAIActions::exec("FIGHTBRK",fight);
CAIActions : : execute ( " CHAT " , * chat ) ;
CAIActions : : execute ( " EQUIP " , equipmentMerged ) ;
CAIActions : : execute ( " KEYWORDS " , * keywords ) ;
for ( uint i = 0 ; i < missions . size ( ) ; + + i )
CAIActions : : exec ( " MISSIONS " , missions [ i ] , missionsNames [ i ] ) ;
// CAIActions::execute("MISSIONS", missions, missionsNames);
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
static void parsePrimGrpParameters ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim )
{
vector < string > * profileParams = & EmptyStringVector ;
DefaultGrpParameters = & EmptyStringVector ;
prim - > getPropertyByName ( " grp_parameters " , DefaultGrpParameters ) ;
prim - > getPropertyByName ( " ai_profile_params " , profileParams ) ;
CAIActions : : execute ( " PARAMETR " , * DefaultGrpParameters ) ;
CAIActions : : execute ( " PROFPARM " , * profileParams ) ;
}
static void parsePrimGrpNpc ( const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim , const std : : string initialState )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing npc group: %s " , name . c_str ( ) ) ;
// setup the grp context
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " GRPNPC " , treeNode - > getAlias ( ) ) ;
// group parameters
const std : : vector < std : : string > * keywords = & EmptyStringVector ;
prim - > getPropertyByName ( " grp_keywords " , keywords ) ;
CAIActions : : execute ( " KEYWORDS " , * keywords ) ;
string s ;
prim - > getPropertyByName ( " autoSpawn " , s ) ;
CAIActions : : exec ( " AUTOSPWN " , uint32 ( nlstricmp ( s . c_str ( ) , " false " ) ! = 0 ) ) ;
// bot groups contain a set of default parameters for their bot children
//oldlevel DefaultBotLevel.clear(); prim->getPropertyByName("bot_level",DefaultBotLevel);
DefaultBotLook . clear ( ) ; prim - > getPropertyByName ( " bot_sheet_client " , DefaultBotLook ) ;
// DefaultBotStats.clear(); prim->getPropertyByName("bot_sheet_server",DefaultBotStats);
DefaultBotKeywords = & EmptyStringVector ; prim - > getPropertyByName ( " bot_keywords " , DefaultBotKeywords ) ;
DefaultBotEquipment = & EmptyStringVector ; prim - > getPropertyByName ( " bot_equipment " , DefaultBotEquipment ) ;
DefaultBotChat = & EmptyStringVector ; prim - > getPropertyByName ( " bot_chat_parameters " , DefaultBotChat ) ;
DefaultMissionNames . clear ( ) ;
DefaultMissions . clear ( ) ; lookForMissions ( prim , DefaultMissions , DefaultMissionNames ) ;
parseVerticalPos ( prim , DefaultBotVerticalPos , " bot_vertical_pos " ) ;
DefaultGrpParameters = & EmptyStringVector ;
CAIActions : : execute ( " PARAMETR " , * DefaultGrpParameters ) ;
// count the number of bots so that we can allocate the correct space for them
bool foundBots = false ;
for ( uint j = 0 ; ! foundBots & & j < prim - > getNumChildren ( ) ; + + j )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , j ) )
{
// try to get a type for the child - we're looking for children of type 'NPC_BOT'
TAIType type = nodeType ( child ) ;
if ( type ! = AITypeBadType
& & type = = AITypeBot )
foundBots = true ;
}
}
// parse the group parameter
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
if ( nodeClass ( child ) = = " npc_group_parameters " )
{
parsePrimGrpParameters ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
}
}
}
prim - > getPropertyByName ( " count " , s ) ;
uint botCount = atoi ( s . c_str ( ) ) ;
if ( foundBots & & botCount ! = 0 )
{
nlwarning ( " Mixing of automatic and explicit bot is not supported, only explicit bot will be spawned ! (in '%s') " , treeNode - > fullName ( ) . c_str ( ) ) ;
}
// if we didn't find any explicit bots then generate a set of 'default' bots
if ( ! foundBots )
{
if ( botCount > 200 | | s ! = NLMISC : : toString ( botCount ) )
{
nlwarning ( " Invalid 'count' (value: '%s') parameter in NPC bot group: %s " , s . c_str ( ) , treeNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
if ( botCount = = 0 )
{
if ( ! DefaultBotLook . empty ( ) )
{
nlwarning ( " No bots found in NPC group: %s " , treeNode - > fullName ( ) . c_str ( ) ) ;
return ;
}
}
CAIActions : : exec ( " BOTCOUNT " , botCount ) ;
for ( uint i = 0 ; i < botCount ; + + i )
{
CAIActions : : begin ( i ) ;
CAIActions : : exec ( " BOTNPC " , i ) ;
CAIActions : : exec ( " STARTPOS " , 0 , 0 , 0.0f , DefaultBotVerticalPos ) ;
CAIActions : : exec ( " LOOK " , DefaultBotLook ) ;
CAIActions : : exec ( " STATS " ) ; //, level ); // +NLMISC::toString("_lvl_%02d",level)
CAIActions : : execute ( " CHAT " , * DefaultBotChat ) ;
CAIActions : : execute ( " EQUIP " , * DefaultBotEquipment ) ;
CAIActions : : execute ( " KEYWORDS " , * DefaultBotKeywords ) ;
CAIActions : : end ( i ) ;
}
}
else
CAIActions : : exec ( " BOTCOUNT " , 0 ) ; // tell the system that we are not using auto generated bots but named bots
// run through the group children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
// try to get a type for the child
// it's one of ours! - so match against the types we recognise
switch ( nodeType ( child ) )
{
case AITypeBot :
parsePrimBotNpc ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeEvent :
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeBadType :
case AITypeFolder :
// case AITypeGrpParameters:
break ;
default :
nlwarning ( " Don't know how to treat ai_type '%s' " , getName ( nodeType ( child ) ) ) ;
break ;
}
}
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
/*static void parsePrimNPCPunctualState(const CAIAliasDescriptionNode *treeNode,const IPrimitive *prim)
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing npc punctual state: %s " , name . c_str ( ) ) ;
// look for keywords
const std : : vector < std : : string > * keywords = & EmptyStringVector ;
prim - > getPropertyByName ( " grp_keywords " , keywords ) ;
// create the state
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " PUNCTUAL " , uniqueId ) ;
if ( ! keywords - > empty ( ) ) CAIActions : : execute ( " KEYWORDS " , * keywords ) ;
// run through the group children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
// try to get a type for the child
TAIType type = nodeType ( child ) ;
if ( type ! = AITypeBadType
& & type ! = AITypeFolder )
{
if ( type = = AITypeNpcStateProfile )
parsePrimStateProfile ( nextTreeNode ( treeNode , child ) , child ) ;
else if ( type = = AITypeEvent )
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
else
nlwarning ( " Don't know how to treat ai_type '%s' " , getName ( type ) ) ;
}
}
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
*/
static void parsePrimMgrNpc ( const std : : string & mapName , const CAIAliasDescriptionNode * treeNode , const IPrimitive * prim , std : : vector < SFolderRef > & folders , const std : : string & filename , bool firstTime = true )
{
// get hold of the unique id
uint32 uniqueId = nodeAlias ( prim ) ;
// setup the mgr context
if ( firstTime )
{
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " MGRNPC " , treeNode - > getAlias ( ) , treeNode - > getName ( ) , mapName , filename ) ;
CAIActions : : exec ( " IDTREE " , treeNode ) ;
}
// run through the mgr children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeNpcStateRoute :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATH " ) ;
break ;
case AITypeNpcStateZone :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATAT " ) ;
break ;
case AITypeState :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATAT " ) ;
break ;
case AITypePunctualState :
parsePrimNPCPunctualState ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeEvent :
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeGrp :
parsePrimGrpNpc ( nextTreeNode ( treeNode , child ) , child , std : : string ( ) ) ;
break ;
// uinknown so pass it..
case AITypeBadType :
if ( nodeClass ( child ) ! = " alias " )
parsePrimMgrNpc ( mapName , nextTreeNode ( treeNode , child ) , child , folders , filename , false ) ;
break ;
case AITypeFolder :
break ;
default :
nlwarning ( " unrecognised ai_type in NPC manager %s: '%s' " , treeNode - > fullName ( ) . c_str ( ) , getName ( nodeType ( child ) ) ) ;
break ;
}
}
}
if ( firstTime )
{
// now add the folders to the manager
for ( uint i = 0 ; i < folders . size ( ) ; + + i )
parsePrimMgrNpc ( mapName , folders [ i ] . Node , folders [ i ] . Prim , folders , filename , false ) ;
// close the manger
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
}
static void parsePrimMgrOutpost ( std : : string const & mapName , CAIAliasDescriptionNode const * treeNode , IPrimitive const * prim , std : : vector < SFolderRef > & folders , std : : string const & filename , bool firstTime = true )
{
// get hold of the unique id
uint32 uniqueId = nodeAlias ( prim ) ;
// setup the mgr context
if ( firstTime )
{
std : : string str ;
prim - > getPropertyByName ( " manual_spawn " , str ) ;
bool manualSpawn = ( str = = " true " ) ;
CAIActions : : begin ( treeNode - > getAlias ( ) ) ;
CAIActions : : exec ( " MGROUTPO " , treeNode - > getAlias ( ) , treeNode - > getName ( ) , mapName , filename , manualSpawn ) ;
CAIActions : : exec ( " IDTREE " , treeNode ) ;
}
// run through the mgr children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeNpcStateRoute :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATH " ) ;
break ;
case AITypeNpcStateZone :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATAT " ) ;
break ;
case AITypeState :
parsePrimState ( nextTreeNode ( treeNode , child ) , child , " PATAT " ) ;
break ;
case AITypePunctualState :
parsePrimNPCPunctualState ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeEvent :
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
case AITypeGrp :
parsePrimGrpNpc ( nextTreeNode ( treeNode , child ) , child , std : : string ( ) ) ;
break ;
// uinknown so pass it..
case AITypeBadType :
if ( nodeClass ( child ) ! = " alias " )
parsePrimMgrOutpost ( mapName , nextTreeNode ( treeNode , child ) , child , folders , filename , false ) ;
break ;
case AITypeFolder :
break ;
default :
nlwarning ( " unrecognised ai_type in outpost manager %s: '%s' " , treeNode - > fullName ( ) . c_str ( ) , getName ( nodeType ( child ) ) ) ;
break ;
}
}
}
if ( firstTime )
{
// now add the folders to the manager
for ( uint i = 0 ; i < folders . size ( ) ; + + i )
parsePrimMgrOutpost ( mapName , folders [ i ] . Node , folders [ i ] . Prim , folders , filename , false ) ;
// close the manger
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
}
//---------------------------------------------------------------------------------------
// parsing route nodes for managers (of all types)
static void parsePrimMgr ( const IPrimitive * prim , const std : : string & mapName , const std : : string & filename )
{
H_AUTO ( parsePrim_Mgr ) ;
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing manager: %s " , name . c_str ( ) ) ;
// make sure the manager type is specified and is one of ours
std : : string mgrTypeName ;
TMgrType mgrType = MgrTypeBadType ;
prim - > getPropertyByName ( " ai_manager_type " , mgrTypeName ) ;
mgrType = getTypeAs ( mgrType , mgrTypeName . c_str ( ) ) ;
if ( mgrType = = MgrTypeBadType )
{
nlwarning ( " Ignoring manager due to unknown type: '%s' " , mgrTypeName . c_str ( ) ) ;
return ;
}
// TAITypeSpec typeSpec;
// switch (mgrType)
// {
// case MgrTypeFauna: typeSpec = AITypeSpecFauna; break;
// case MgrTypeKaravan: typeSpec = AITypeSpecKaravan; break;
// case MgrTypeKami: typeSpec = AITypeSpecKami; break;
//// case MgrTypeTribe: typeSpec = AITypeSpecTribe; break;
// case MgrTypeNpc: typeSpec = AITypeSpecNpc; break;
//
// // TODO: case MgrTypePet:
// // TODO: case MgrTypeGuildNpc:
//
// default: nlwarning("Unhandled ai manager type: '%s'",mgrTypeName.c_str());
// }
// build the tree of aliases and the vector of folders
std : : vector < SFolderRef > folders ;
NLMISC : : CSmartPtr < CAIAliasDescriptionNode > aliasTree ;
{
H_AUTO ( parsePrim_aliasTree ) ;
aliasTree = new CAIAliasDescriptionNode ( name , uniqueId , AITypeManager , NULL ) ;
buildAliasTree ( aliasTree , aliasTree , prim , folders ) ;
}
switch ( mgrType )
{
case MgrTypeFauna : parsePrimMgrFauna ( mapName , aliasTree , prim , folders , filename ) ; break ;
case MgrTypeKaravan : parsePrimMgrKaravan ( mapName , aliasTree , prim , folders , filename ) ; break ;
case MgrTypeKami : parsePrimMgrKami ( mapName , aliasTree , prim , folders , filename ) ; break ;
// case MgrTypeTribe: parsePrimMgrTribe(mapName,aliasTree,prim,folders); break;
case MgrTypeNpc : parsePrimMgrNpc ( mapName , aliasTree , prim , folders , filename ) ; break ;
case MgrTypeOutpost : parsePrimMgrOutpost ( mapName , aliasTree , prim , folders , filename ) ; break ;
// TODO: case MgrTypePet:
// TODO: case MgrTypeGuildNpc:
default : nlwarning ( " Unhandled ai manager type: '%s' " , mgrTypeName . c_str ( ) ) ;
}
CAIAliasDescriptionNode : : flushUnusedAliasDescription ( ) ;
}
//---------------------------------------------------------------------------------------
// parsing spires
/*
static void parsePrimMgrSpire ( std : : string const & mapName , CAIAliasDescriptionNode const * treeNode , IPrimitive const * prim , std : : vector < SFolderRef > & folders , std : : string const & filename , bool firstTime = true )
{
uint32 uniqueId = nodeAlias ( prim ) ;
// setup the mgr context
if ( firstTime )
{
}
parsePrimGrpSpire ( treeNode , prim , " " ) ;
// run through the mgr children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
IPrimitive const * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeEvent :
parsePrimEvent ( nextTreeNode ( treeNode , child ) , child ) ;
break ;
default :
nlwarning ( " unrecognised ai_type in NPC manager %s: '%s' " , treeNode - > fullName ( ) . c_str ( ) , getName ( nodeType ( child ) ) ) ;
break ;
}
}
}
CAIActions : : end ( treeNode - > getAlias ( ) ) ;
}
*/
static void parsePrimSpire ( IPrimitive const * prim , std : : string const & mapName , std : : string const & filename )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
LOG ( " Parsing spire: %s " , name . c_str ( ) ) ;
CPrimPoint const * point = dynamic_cast < CPrimPoint const * > ( prim ) ;
if ( ! point )
{
nlwarning ( " Failed to cast spire to CPrimPoint: %s " , name . c_str ( ) ) ;
return ;
}
sint x = ( uint32 ) ( point - > Point . x * 1000 ) ;
sint y = ( uint32 ) ( point - > Point . y * 1000 ) ;
float theta = ( float ) point - > Angle ;
uint32 verticalPos ;
if ( ! parseVerticalPos ( prim , verticalPos ) )
verticalPos = DefaultBotVerticalPos ;
std : : string effect , sheet_socle ;
std : : vector < std : : string > * sheet_spire ;
// if (!prim->getPropertyByName("effect", effect) || effect.empty())
// {
// nlwarning("No effect defined in spire %s", name.c_str());
// return;
// }
if ( ! prim - > getPropertyByName ( " sheet_socle " , sheet_socle ) | | sheet_socle . empty ( ) )
sheet_socle = DefaultBotLook ;
if ( ! prim - > getPropertyByName ( " sheet_spire " , sheet_spire ) | | ! sheet_spire | | sheet_spire - > empty ( ) )
sheet_spire = & EmptyStringVector ;
vector < string > sheets ;
sheets . insert ( sheets . end ( ) , " socle: " + sheet_socle ) ;
sheets . insert ( sheets . end ( ) , sheet_spire - > begin ( ) , sheet_spire - > end ( ) ) ;
uint32 mgrAlias = 0 ;
uint32 stateAlias = 0 ;
uint32 grpAlias = uniqueId ;
uint32 botAlias = 0 ;
// build the tree of aliases and the vector of folders
std : : vector < SFolderRef > folders ;
NLMISC : : CSmartPtr < CAIAliasDescriptionNode > aliasTree = new CAIAliasDescriptionNode ( name , uniqueId , AITypeManager , NULL ) ;
buildAliasTree ( aliasTree , aliasTree , prim , folders ) ;
CAIActions : : begin ( mgrAlias ) ; // mgr
CAIActions : : exec ( " SPIREMGR " , mgrAlias , name , mapName , filename ) ;
CAIActions : : exec ( " IDTREE " , aliasTree ) ;
CAIActions : : begin ( stateAlias ) ;
CAIActions : : exec ( " SPIRSTAT " , stateAlias , name ) ;
CAIActions : : begin ( grpAlias ) ; // grp
CAIActions : : exec ( " SPIREGRP " , grpAlias , name ) ;
CAIActions : : begin ( botAlias ) ; // bot
CAIActions : : exec ( " SPIREBOT " , botAlias , name ) ;
CAIActions : : exec ( " LOOK " , sheet_socle ) ;
CAIActions : : execute ( " SPIRSHTS " , sheets ) ;
CAIActions : : exec ( " STARTPOS " , x , y , theta , verticalPos ) ;
CAIActions : : end ( botAlias ) ; // bot
// run through the mgr children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
IPrimitive const * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeEvent :
parsePrimEvent ( NULL , child ) ;
break ;
default :
nlwarning ( " unrecognised ai_type in spire %s: '%s' " , name . c_str ( ) , getName ( nodeType ( child ) ) ) ;
break ;
}
}
}
CAIActions : : end ( grpAlias ) ; // grp
CAIActions : : end ( stateAlias ) ; // state
CAIActions : : end ( mgrAlias ) ; // mgr
CAIAliasDescriptionNode : : flushUnusedAliasDescription ( ) ;
}
/////////////////////////////////////////////////////////
/////////////////// Dynamic system parsing //////////////
/////////////////////////////////////////////////////////
static void parsePrimDynFaunaZone ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
float x , y , r ;
x = prim - > getPrimVector ( ) - > x ;
y = prim - > getPrimVector ( ) - > y ;
string s ;
prim - > getPropertyByName ( " radius " , s ) ;
r = float ( atof ( s . c_str ( ) ) ) ;
vector < string > * params = & EmptyStringVector ;
prim - > getPropertyByName ( " properties " , params ) ;
uint32 verticalPos ;
parseVerticalPos ( prim , verticalPos ) ;
std : : string concatStr ;
for ( uint i = 0 ; i < params - > size ( ) ; + + i )
{
concatStr + = ( * params ) [ i ] + " " ;
}
//nlinfo("creating cell zone with flags : %s", concatStr.c_str());
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " DYNFZ " , aliasNode , x , y , r , /*activities,*/ verticalPos ) ;
CAIActions : : execute ( " ACT_PARM " , * params ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimDynNpcZonePlace ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
float x , y , r ;
x = prim - > getPrimVector ( ) - > x ;
y = prim - > getPrimVector ( ) - > y ;
string s ;
prim - > getPropertyByName ( " radius " , s ) ;
r = float ( atof ( s . c_str ( ) ) ) ;
vector < string > * params = & EmptyStringVector ;
prim - > getPropertyByName ( " properties " , params ) ;
uint32 verticalPos ;
parseVerticalPos ( prim , verticalPos ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " DYNNZ " , aliasNode , x , y , r , verticalPos ) ;
CAIActions : : execute ( " DYNNZPRM " , * params ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimDynNpcZoneShape ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
uint32 verticalPos ;
parseVerticalPos ( prim , verticalPos ) ;
// extract x and y coords of points from patate
std : : vector < CAIActions : : CArg > args ;
args . push_back ( aliasNode ) ;
args . push_back ( verticalPos ) ;
uint numPoints = prim - > getNumVector ( ) ;
if ( numPoints ! = 0 )
{
const CPrimVector * pointArray = prim - > getPrimVector ( ) ;
for ( uint i = 0 ; i < numPoints ; + + i )
{
args . push_back ( CAIActions : : CArg ( pointArray [ i ] . x ) ) ;
args . push_back ( CAIActions : : CArg ( pointArray [ i ] . y ) ) ;
}
}
else
LOG ( " Zone has no geometry " /*": %s: %s",pointsType,name.c_str()*/ ) ;
vector < string > * params = & EmptyStringVector ;
prim - > getPropertyByName ( " properties " , params ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : execute ( " DYNNZSHP " , args ) ;
CAIActions : : execute ( " DYNNZPRM " , * params ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimRoadTrigger ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
CPrimVector t1 , t2 , sp ;
float t1r , t2r , spr ;
string s ;
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
if ( nodeName ( child ) = = " trigger 1 " )
{
t1 = * child - > getPrimVector ( ) ;
child - > getPropertyByName ( " radius " , s ) ;
t1r = float ( atof ( s . c_str ( ) ) ) ;
}
else if ( nodeName ( child ) = = " trigger 2 " )
{
t2 = * child - > getPrimVector ( ) ;
child - > getPropertyByName ( " radius " , s ) ;
t2r = float ( atof ( s . c_str ( ) ) ) ;
}
else if ( nodeName ( child ) = = " spawn " )
{
sp = * child - > getPrimVector ( ) ;
child - > getPropertyByName ( " radius " , s ) ;
spr = float ( atof ( s . c_str ( ) ) ) ;
}
}
}
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " TRIGGER " , aliasNode ) ;
CAIActions : : exec ( " TRIGT1 " , t1 . x , t1 . y , t1r ) ;
CAIActions : : exec ( " TRIGT2 " , t2 . x , t2 . y , t2r ) ;
CAIActions : : exec ( " TRIGSP " , sp . x , sp . y , spr ) ;
// TODO
// set<string> flags;
// parseFamilyFlag(prim, flags);
// vector<string> v(flags.begin(), flags.end());
// CAIActions::execute("TRIGFLG", v);
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimDynRoad ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// road dificulty
string s ;
prim - > getPropertyByName ( " difficulty " , s ) ;
float difficulty = float ( atof ( s . c_str ( ) ) ) ;
uint32 verticalPos ;
parseVerticalPos ( prim , verticalPos ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " DYNROAD " , aliasNode , difficulty , verticalPos ) ;
// build polygon data
vector < double > poly ;
const CPrimVector * v = prim - > getPrimVector ( ) ;
for ( uint i = 0 ; i < prim - > getNumVector ( ) ; + + i )
{
poly . push_back ( v [ i ] . x ) ;
poly . push_back ( v [ i ] . y ) ;
}
CAIActions : : execute ( " ROADGEO " , poly ) ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeRoadTrigger :
parsePrimRoadTrigger ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
}
}
}
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimGeomItems ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeDynFaunaZone :
parsePrimDynFaunaZone ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
case AITypeDynNpcZonePlace :
parsePrimDynNpcZonePlace ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
case AITypeDynNpcZoneShape :
parsePrimDynNpcZoneShape ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
case AITypeDynRoad :
parsePrimDynRoad ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
}
}
}
}
static void parsePrimCell ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// set<string> flags;
// read the family flags
// TODO
// parseFamilyFlag(prim, flags);
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " CELL " , aliasNode ) ;
// build the resulting vector of family/tribe string/
// vector<string> vs(flags.begin(), flags.end());
// CAIActions::execute("CELLFLG", vs);
// build polygon data
vector < double > poly ;
const CPrimVector * v = prim - > getPrimVector ( ) ;
for ( uint i = 0 ; i < prim - > getNumVector ( ) ; + + i )
{
poly . push_back ( v [ i ] . x ) ;
poly . push_back ( v [ i ] . y ) ;
}
CAIActions : : execute ( " CELLGEO " , poly ) ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
string cname = nodeClass ( child ) ;
if ( cname = = " geom_items " )
parsePrimGeomItems ( nextTreeNode ( aliasNode , child ) , child ) ;
}
}
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
//void parsePrimCellZoneEnergy(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
//{
// std::string family;
// std::string energy;
// std::string energy2;
// std::string energy3;
// std::string energy4;
// prim->getPropertyByName("name", family);
// prim->getPropertyByName("energy_0_25", energy);
// prim->getPropertyByName("energy_25_50", energy2);
// prim->getPropertyByName("energy_50_75", energy3);
// prim->getPropertyByName("energy_75_100", energy4);
// CAIActions::exec("CZ_NRJ", family, energy, energy2, energy3, energy4);
//}
static void parsePrimCellZone ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " CELLZNE " , aliasNode ) ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeCell :
parsePrimCell ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
default :
break ;
}
}
}
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimCellZones ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeCellZone :
parsePrimCellZone ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
}
}
}
}
static void parsePrimBotTemplate ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim , std : : string const & familyType )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
string s ;
vector < string > * botEquip = & EmptyStringVector ;
string lookSheet ;
bool multiLevel = false ;
sint32 levelDelta = 0 ;
if ( nodeClass ( prim ) = = " bot_template_npc " )
{
prim - > getPropertyByName ( " equipment " , botEquip ) ;
prim - > getPropertyByName ( " sheet_look " , lookSheet ) ;
}
else if ( nodeClass ( prim ) = = " bot_template_npc_ml " )
{
prim - > getPropertyByName ( " equipment " , botEquip ) ;
prim - > getPropertyByName ( " sheet_look " , lookSheet ) ;
multiLevel = true ;
prim - > getPropertyByName ( " level_delta " , s ) ;
levelDelta = atoi ( s . c_str ( ) ) ;
}
else
{
prim - > getPropertyByName ( " creature_code " , lookSheet ) ;
if ( ! lookSheet . empty ( ) )
{
// the new code system replace the old sheet_carac or creature_type
// lookSheet = lookSheet+".creature";
}
else
{
// read the old think
# ifdef NL_DEBUG
nlassert ( false ) ;
# endif
prim - > getPropertyByName ( " creature_type " , lookSheet ) ;
//oldlevel lookSheet = lookSheet+"_lvl_"+toString("%02u", level)+".creature";
}
}
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " BOTTMPL " + familyType , aliasNode , lookSheet , multiLevel ) ; //, caracSheet);
CAIActions : : execute ( " BT_EQUI " + familyType , * botEquip ) ;
CAIActions : : exec ( " BT_LVLD " + familyType , levelDelta ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimGroupTemplate ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim , std : : string const & familyType )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// read template parameters
string s ;
uint32 botCount ;
vector < string > * botEquip = & EmptyStringVector ;
string lookSheet ;
string caracSheet ;
vector < string > * grpParam = & EmptyStringVector ;
bool countMultipliedBySheet ;
bool seasons [ 4 ] ;
uint32 weights [ 4 ] ;
uint32 grpEnergyValue ;
bool multiLevel = false ;
sint32 levelDelta = 0 ;
prim - > getPropertyByName ( " count " , s ) ;
botCount = atoi ( s . c_str ( ) ) ;
prim - > getPropertyByName ( " count_multiplied_by_sheet " , s ) ;
countMultipliedBySheet = ( s = = " true " ) ;
if ( nodeClass ( prim ) = = " group_template_npc " )
{
// properties only for npc bots
prim - > getPropertyByName ( " bot_equipment " , botEquip ) ;
prim - > getPropertyByName ( " bot_sheet_look " , lookSheet ) ;
}
else if ( nodeClass ( prim ) = = " group_template_npc_ml " )
{
// properties only for npc bots
prim - > getPropertyByName ( " bot_equipment " , botEquip ) ;
prim - > getPropertyByName ( " bot_sheet_look " , lookSheet ) ;
multiLevel = true ;
prim - > getPropertyByName ( " level_delta " , s ) ;
levelDelta = atoi ( s . c_str ( ) ) ;
}
else
{
prim - > getPropertyByName ( " creature_code " , lookSheet ) ; //caracSheet);
if ( ! lookSheet . empty ( ) )
{
}
else
{
// read the old think
prim - > getPropertyByName ( " creature_type " , lookSheet ) ;
}
}
prim - > getPropertyByName ( " grp_parameters " , grpParam ) ;
prim - > getPropertyByName ( " exist_in_spring " , s ) ;
seasons [ 0 ] = ( s = = " true " ) ;
prim - > getPropertyByName ( " exist_in_summer " , s ) ;
seasons [ 1 ] = ( s = = " true " ) ;
prim - > getPropertyByName ( " exist_in_autumn " , s ) ;
seasons [ 2 ] = ( s = = " true " ) ;
prim - > getPropertyByName ( " exist_in_winter " , s ) ;
seasons [ 3 ] = ( s = = " true " ) ;
prim - > getPropertyByName ( " weight_0_25 " , s ) ;
weights [ 0 ] = atoi ( s . c_str ( ) ) ;
prim - > getPropertyByName ( " weight_25_50 " , s ) ;
weights [ 1 ] = atoi ( s . c_str ( ) ) ;
prim - > getPropertyByName ( " weight_50_75 " , s ) ;
weights [ 2 ] = atoi ( s . c_str ( ) ) ;
prim - > getPropertyByName ( " weight_75_100 " , s ) ;
weights [ 3 ] = atoi ( s . c_str ( ) ) ;
vector < string > * actParams = & EmptyStringVector ;
prim - > getPropertyByName ( " properties " , actParams ) ;
prim - > getPropertyByName ( " total_energy_value " , s ) ;
grpEnergyValue = ( uint32 ) ( ENERGY_SCALE * atof ( s . c_str ( ) ) ) ;
s = " ALWAYS " ;
prim - > getPropertyByName ( " spawn_type " , s ) ;
TSpawnType st ;
getType ( st , s . c_str ( ) ) ;
uint32 spawnType = st ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " GRPTMPL " , aliasNode ,
CurrentGroupFamily ,
botCount ,
countMultipliedBySheet ,
multiLevel
) ;
if ( nodeClass ( prim ) = = " squad_template_variant " )
{
vector < string > * botSheets ;
if ( ! ( prim - > getPropertyByName ( " bot_sheets " , botSheets ) & & botSheets ) )
nlerror ( " Missing property bot_sheets in squad %s " , name . c_str ( ) ) ;
CAIActions : : execute ( " IDTREE_F " , * botSheets ) ; // create the bot descs as well (group descs created in exec("GRPTMPL"))
}
CAIActions : : exec ( " GT_SHEE " + familyType , lookSheet ) ;
CAIActions : : exec ( " GT_LVLD " + familyType , levelDelta ) ;
CAIActions : : exec ( " GT_SEAS " + familyType , seasons [ 0 ] , seasons [ 1 ] , seasons [ 2 ] , seasons [ 3 ] ) ;
CAIActions : : exec ( " GT_NRG " + familyType , weights [ 0 ] , weights [ 1 ] , weights [ 2 ] , weights [ 3 ] ) ;
if ( grpEnergyValue ! = 0 ) // means not initialized.
CAIActions : : exec ( " GT_GNRJ " + familyType , grpEnergyValue ) ;
CAIActions : : exec ( " GT_ACT " + familyType , /*activity,*/ spawnType ) ;
CAIActions : : execute ( " GT_APRM " + familyType , * actParams ) ;
CAIActions : : execute ( " GT_EQUI " + familyType , * botEquip ) ;
CAIActions : : execute ( " GT_GPRM " + familyType , * grpParam ) ;
std : : vector < CAIActions : : CArg > executeArgs ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeBotTemplate :
case AITypeBotTemplateMultiLevel :
parsePrimBotTemplate ( nextTreeNode ( aliasNode , child ) , child , familyType ) ;
break ;
case AITypeFaunaSpawnAtom :
{
try
{
std : : string theSheet ;
uint count ;
parsePopulation ( child , theSheet , count ) ;
executeArgs . push_back ( CAIActions : : CArg ( theSheet ) ) ;
executeArgs . push_back ( count ) ;
}
catch ( parsePopException e )
{
nlwarning ( " FaunaGroup: %s of %s : %s " , nodeName ( child ) . c_str ( ) , aliasNode - > fullName ( ) . c_str ( ) , e . what ( ) ) ;
}
}
break ;
}
}
}
if ( ! executeArgs . empty ( ) )
CAIActions : : execute ( " POPVER " + familyType , executeArgs ) ;
CAIActions : : execute ( " GT_END " + familyType ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimGroupFamilyProfileFaunaContent ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
CAIActions : : execute ( " TMPPRFF " ) ;
const vector < string > * foodParams = & EmptyStringVector ;
prim - > getPropertyByName ( " food " , foodParams ) ;
CAIActions : : execute ( " TMPPRFFF " , * foodParams ) ;
const vector < string > * restParams = & EmptyStringVector ;
prim - > getPropertyByName ( " rest " , restParams ) ;
CAIActions : : execute ( " TMPPRFFR " , * restParams ) ;
std : : string energy ;
std : : string energy2 ;
std : : string energy3 ;
std : : string energy4 ;
prim - > getPropertyByName ( " energy_0_25 " , energy ) ;
prim - > getPropertyByName ( " energy_25_50 " , energy2 ) ;
prim - > getPropertyByName ( " energy_50_75 " , energy3 ) ;
prim - > getPropertyByName ( " energy_75_100 " , energy4 ) ;
CAIActions : : exec ( " CZ_NRJ " , energy , energy2 , energy3 , energy4 ) ;
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeGroupTemplateFauna :
parsePrimGroupTemplate ( nextTreeNode ( aliasNode , child ) , child , " C " ) ;
break ;
}
}
}
}
static void parsePrimGroupFamilyProfileFauna ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
string familyTag ;
CAIActions : : exec ( " GRPFAM " , aliasNode , familyTag ) ;
parsePrimGroupFamilyProfileFaunaContent ( aliasNode , prim ) ;
}
static void parsePrimGroupFamilyProfileTribeContent ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
std : : string aggro_groups ;
prim - > getPropertyByName ( " aggro_groups " , aggro_groups ) ;
CAIActions : : exec ( " TMPPRFT " , aggro_groups ) ;
std : : string energy ;
std : : string energy2 ;
std : : string energy3 ;
std : : string energy4 ;
prim - > getPropertyByName ( " energy_0_25 " , energy ) ;
prim - > getPropertyByName ( " energy_25_50 " , energy2 ) ;
prim - > getPropertyByName ( " energy_50_75 " , energy3 ) ;
prim - > getPropertyByName ( " energy_75_100 " , energy4 ) ;
CAIActions : : exec ( " CZ_NRJ " , energy , energy2 , energy3 , energy4 ) ;
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeGroupTemplate :
case AITypeGroupTemplateMultiLevel :
parsePrimGroupTemplate ( nextTreeNode ( aliasNode , child ) , child , " C " ) ;
break ;
}
}
}
}
static void parsePrimGroupFamilyProfileNpcContent ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
CAIActions : : execute ( " TMPPRFN " ) ;
const vector < string > * flagList = & EmptyStringVector ;
prim - > getPropertyByName ( " flags " , flagList ) ;
CAIActions : : execute ( " TMPPRFNF " , * flagList ) ;
std : : string energy ;
std : : string energy2 ;
std : : string energy3 ;
std : : string energy4 ;
prim - > getPropertyByName ( " energy_0_25 " , energy ) ;
prim - > getPropertyByName ( " energy_25_50 " , energy2 ) ;
prim - > getPropertyByName ( " energy_50_75 " , energy3 ) ;
prim - > getPropertyByName ( " energy_75_100 " , energy4 ) ;
CAIActions : : exec ( " CZ_NRJ " , energy , energy2 , energy3 , energy4 ) ;
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeGroupTemplate :
case AITypeGroupTemplateMultiLevel :
parsePrimGroupTemplate ( nextTreeNode ( aliasNode , child ) , child , " C " ) ;
break ;
}
}
}
}
static void parsePrimGroupFamilyProfileTribe ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
string familyTag ;
prim - > getPropertyByName ( " family " , familyTag ) ;
CAIActions : : exec ( " GRPFAM " , aliasNode , familyTag ) ;
parsePrimGroupFamilyProfileTribeContent ( aliasNode , prim ) ;
}
static void parsePrimGroupFamilyProfileNpc ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
string familyTag ;
CAIActions : : exec ( " GRPFAM " , aliasNode , familyTag ) ;
parsePrimGroupFamilyProfileNpcContent ( aliasNode , prim ) ;
}
static void parsePrimGroupDescriptions ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeGroupFamily :
{
nlwarning ( " Parsing a group_family, primitive is outdated. Please report to jvuarand. " ) ;
// parsePrimGroupFamily(nextTreeNode(aliasNode,child),child);
}
break ;
case AITypeGroupFamilyProfileFauna :
parsePrimGroupFamilyProfileFauna ( nextTreeNode ( aliasNode , child ) , child ) ;
// parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyFauna);
break ;
case AITypeGroupFamilyProfileTribe :
parsePrimGroupFamilyProfileTribe ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
case AITypeGroupFamilyProfileNpc :
parsePrimGroupFamilyProfileNpc ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
// case AITypeGroupFamilyProfileGeneric:
// parsePrimGroupFamilyProfileGeneric(nextTreeNode(aliasNode,child),child, GroupFamilyTribe);
// break;
}
}
}
}
static void parsePrimDynRegion ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim , const std : : string & filename )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " DYNREG " , aliasNode , filename ) ;
CAIActions : : exec ( " IDTREE " , aliasNode ) ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
string cname = nodeClass ( child ) ;
if ( cname = = " cell_zones " )
parsePrimCellZones ( nextTreeNode ( aliasNode , child ) , child ) ;
else if ( cname = = " group_descriptions " )
parsePrimGroupDescriptions ( nextTreeNode ( aliasNode , child ) , child ) ;
}
}
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
/*
static void parsePrimOutpostCharge ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
string civilisation ;
const vector < string > * params = & EmptyStringVector ;
prim - > getPropertyByName ( " civilisation " , civilisation ) ;
prim - > getPropertyByName ( " parameters " , params ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " CHARGE " , aliasNode , civilisation ) ;
CAIActions : : execute ( " CHGPARM " , * params ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
*/
//static void parsePrimOutpostSquadFamily(const CAIAliasDescriptionNode *aliasNode, const IPrimitive *prim)
//{
// // get hold of the node name and unique id
// std::string name = nodeName(prim);
//// uint32 uniqueId = nodeAlias(prim);
// /*
// string civilisation;
// const vector<string> *params = &EmptyStringVector;
//
// prim->getPropertyByName("civilisation", civilisation);
// prim->getPropertyByName("parameters", params);
// */
// CAIActions::begin(aliasNode->getAlias());
// CAIActions::exec("SQUADFAM", aliasNode);
//// CAIActions::exec("IDTREE",aliasNode);
// /*
//
// CAIActions::execute("CHGPARM", *params);
//
// */
// for (uint i=0;i<prim->getNumChildren();++i)
// {
// // get a pointer to the child and make sure its valid
// const IPrimitive *child;
// if (prim->getChild(child, i))
// {
// switch(nodeType(child))
// {
// case AITypeGroupTemplate:
// case AITypeGroupTemplateMultiLevel:
// parsePrimGroupTemplate(nextTreeNode(aliasNode,child),child,"O");
// break;
// }
//
// }
//
// }
//
// CAIActions::end(aliasNode->getAlias());
//}
static void parsePrimOutpostSpawnZone ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim )
{
float x , y , r ;
x = prim - > getPrimVector ( ) - > x ;
y = prim - > getPrimVector ( ) - > y ;
string s ;
prim - > getPropertyByName ( " radius " , s ) ;
r = float ( atof ( s . c_str ( ) ) ) ;
uint32 verticalPos ;
parseVerticalPos ( prim , verticalPos ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " SPWNZONE " , aliasNode , x , y , r , verticalPos ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimOutpostBuilding ( CAIAliasDescriptionNode const * aliasNode , IPrimitive const * prim )
{
string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
float x , y , theta ;
const CPrimPoint * point = dynamic_cast < CPrimPoint const * > ( prim ) ;
if ( point = = NULL )
{
nlwarning ( " Failed to cast to CPrimPoin bot: %s " , name . c_str ( ) ) ;
return ;
}
x = point - > Point . x ;
y = point - > Point . y ;
theta = point - > Angle ;
// x = prim->getPrimVector()->x;
// y = prim->getPrimVector()->y;
// string s;
// prim->getPropertyByName("radius", s);
// r = float(atof(s.c_str()));
uint32 verticalPos ;
parseVerticalPos ( prim , verticalPos ) ;
bool isStuck = true ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " BUILDING " , uniqueId ) ;
CAIActions : : exec ( " STARTPOS " , ( sint32 ) ( x * 1000.f ) , ( sint32 ) ( y * 1000.f ) , theta , verticalPos ) ;
// CAIActions::exec("LOOK", "");
CAIActions : : exec ( " ISSTUCK " , uint32 ( isStuck ) ) ;
CAIActions : : exec ( " BLDNGBOT " , uint32 ( true ) ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimBotTemplate ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim , std : : string const & familyType ) ;
static void parsePrimSquadTemplateVariant ( const CAIAliasDescriptionNode * aliasNode , const IPrimitive * prim , const std : : string & templateName )
{
// get hold of the node name
std : : string name = nodeName ( prim ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " SQD_T_V " , templateName , name ) ;
parsePrimGroupTemplate ( aliasNode , prim , " O " ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimSquadTemplate ( const IPrimitive * prim , const std : : string & mapName , const std : : string & filename )
{
// get hold of the node name and unique id
string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
// build the tree of aliases and the vector of folders
std : : vector < SFolderRef > folders ;
NLMISC : : CSmartPtr < CAIAliasDescriptionNode > aliasNode = new CAIAliasDescriptionNode ( name , uniqueId , AITypeOutpost , NULL ) ;
buildAliasTree ( aliasNode , aliasNode , prim , folders ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " SQD_TMPL " , aliasNode , filename ) ;
// run through the children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeSquadTemplateVariant :
parsePrimSquadTemplateVariant ( nextTreeNode ( aliasNode , child ) , child , name ) ;
break ;
}
}
}
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimOutpost ( const IPrimitive * prim , const std : : string & mapName , const std : : string & filename )
{
// get hold of the node name and unique id
string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
string familyName ;
string continent , s ;
stringToKeywordAndTail ( mapName , continent , s ) ;
prim - > getPropertyByName ( " owner_tribe " , familyName ) ;
// build the tree of aliases and the vector of folders
std : : vector < SFolderRef > folders ;
NLMISC : : CSmartPtr < CAIAliasDescriptionNode > aliasNode = new CAIAliasDescriptionNode ( name , uniqueId , AITypeOutpost , NULL ) ;
buildAliasTree ( aliasNode , aliasNode , prim , folders ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
// outpost general properties
CAIActions : : exec ( " OUTPOST " , aliasNode , continent , filename , familyName ) ;
// link squads
2010-05-17 10:24:49 +00:00
const char * props [ ] = { " tribe_squads " , " tribe_squads2 " , " default_squads " , " buyable_squads " } ;
2010-05-06 00:08:41 +00:00
size_t nprops = sizeof ( props ) / sizeof ( props [ 0 ] ) ;
for ( size_t i = 0 ; i ! = nprops ; + + i )
{
vector < string > * propSquads ;
if ( prim - > getPropertyByName ( props [ i ] , propSquads ) & & propSquads )
{
vector < string > squadsToLink ;
// Insert default variant at beginning of vector
squadsToLink . push_back ( continent ) ;
squadsToLink . insert ( squadsToLink . end ( ) , ( * propSquads ) . begin ( ) , ( * propSquads ) . end ( ) ) ;
CAIActions : : execute ( " OUTP_SQD " , squadsToLink ) ;
}
else
nlerror ( " Missing property %s in %s in %s " , props [ i ] , name . c_str ( ) , filename . c_str ( ) ) ;
}
CAIActions : : exec ( " IDTREE " , aliasNode ) ;
// build polygon data
vector < double > poly ;
const CPrimVector * v = prim - > getPrimVector ( ) ;
for ( uint i = 0 ; i < prim - > getNumVector ( ) ; + + i )
{
poly . push_back ( v [ i ] . x ) ;
poly . push_back ( v [ i ] . y ) ;
}
CAIActions : : execute ( " OUTPOGEO " , poly ) ;
// run through the children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
// case AITypeOutpostSquadFamily:
// parsePrimOutpostSquadFamily(nextTreeNode(aliasNode,child), child);
// break;
case AITypeOutpostSpawnZone :
parsePrimOutpostSpawnZone ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
case AITypeOutpostBuilding :
parsePrimOutpostBuilding ( nextTreeNode ( aliasNode , child ) , child ) ;
break ;
case AITypeManager :
parsePrimMgr ( child , mapName , filename ) ;
break ;
}
}
}
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimDynSystem ( const IPrimitive * prim , const std : : string & mapName , const std : : string & filename )
{
// get hold of the node name and unique id
std : : string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
string contName ;
prim - > getPropertyByName ( " continent_name " , contName ) ;
nlassertex ( ! contName . empty ( ) , ( " Error while loading dynamic system from '%s', the continent name is empty ! " , filename . c_str ( ) ) ) ;
// build the tree of aliases and the vector of folders
std : : vector < SFolderRef > folders ;
NLMISC : : CSmartPtr < CAIAliasDescriptionNode > aliasNode = new CAIAliasDescriptionNode ( name , uniqueId , AITypeDynamicSystem , NULL ) ;
buildAliasTree ( aliasNode , aliasNode , prim , folders ) ;
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
CAIActions : : exec ( " DYNSYS " , contName , mapName ) ;
// run through the dynsystem children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeDynamicRegion :
parsePrimDynRegion ( nextTreeNode ( aliasNode , child ) , child , filename ) ;
break ;
case AITypeOutpost :
parsePrimOutpost ( child , mapName , filename ) ;
break ;
}
}
}
CAIActions : : exec ( " DYN_END " ) ;
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimNogoPointList ( const IPrimitive * prim , const std : : string & mapName , const std : : string & filename )
{
// get hold of the node name and unique id
string name = nodeName ( prim ) ;
uint32 uniqueId = nodeAlias ( prim ) ;
NLMISC : : CSmartPtr < CAIAliasDescriptionNode > aliasNode = new CAIAliasDescriptionNode ( name , uniqueId , AITypeOutpost , NULL ) ;
//
CAIActions : : begin ( aliasNode - > getAlias ( ) ) ;
// run through the charge children looking for nodes with types that we recognise
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
{
switch ( nodeType ( child ) )
{
case AITypeNogoPoint : // OutpostCharge:
{
float x = ( float ) ( child - > getPrimVector ( ) - > x ) ;
float y = ( float ) ( child - > getPrimVector ( ) - > y ) ;
CAIActions : : exec ( " SETNOGO " , x , y ) ;
}
break ;
}
}
}
CAIActions : : end ( aliasNode - > getAlias ( ) ) ;
}
static void parsePrimSafeZone ( const IPrimitive * prim , const std : : string & mapName , const std : : string & filename )
{
float x = ( float ) ( prim - > getPrimVector ( ) - > x ) ;
float y = ( float ) ( prim - > getPrimVector ( ) - > y ) ;
string radiusString ;
prim - > getPropertyByName ( " radius " , radiusString ) ;
float radius = ( float ) atof ( radiusString . c_str ( ) ) ;
CAIActions : : exec ( " SAFEZONE " , x , y , radius ) ;
}
static void parsePrimScript ( const IPrimitive * prim , const std : : string & mapName , const std : : string & filename )
{
string primName ;
const std : : vector < std : : string > * pcode = NULL ;
prim - > getPropertyByName ( " name " , primName ) ;
prim - > getPropertyByName ( " code " , pcode ) ;
std : : string code ;
// Concat the strings inside a single one...
if ( pcode ! = NULL & & ! pcode - > empty ( ) )
{
std : : vector < std : : string > : : const_iterator it = pcode - > begin ( ) , itEnd = pcode - > end ( ) ;
code = * it ;
+ + it ;
for ( ; it ! = itEnd ; + + it ) {
code + = " \n " ;
code + = * it ;
}
}
// ... coz CAIActions::exec cannot handle a vector<string>
CAIActions : : exec ( " SCRIPT " , primName , code ) ;
}
/**
* parse a user model
* a user model contains an id , a base SheetId ( used later to fill unmodified attributes of the dynamic sheet )
* and a script defining all attributes to be modified along with the new values
*/
static void parseUserModelListRec ( const IPrimitive * prim ,
const std : : string & mapName ,
const std : : string & filename ,
std : : vector < CAIActions : : CArg > & args )
{
AITYPES : : TAIType type = nodeType ( prim ) ;
if ( type = = AITypeUserModelList )
{
// run through the list of children
for ( uint j = 0 ; j < prim - > getNumChildren ( ) ; + + j )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( ! prim - > getChild ( child , j ) )
continue ;
// try to get a type for the child
TAIType type = nodeType ( child ) ;
if ( type = = AITypeUserModel )
{
std : : string userModelId ;
std : : string script = " " ;
std : : string baseSheet ;
const std : : vector < std : : string > * pcode = NULL ;
child - > getPropertyByName ( " name " , userModelId ) ;
child - > getPropertyByName ( " script " , pcode ) ;
child - > getPropertyByName ( " sheet_client " , baseSheet ) ;
if ( pcode ! = NULL & & ! pcode - > empty ( ) )
{
std : : vector < std : : string > : : const_iterator start = pcode - > begin ( ) ;
for ( std : : vector < std : : string > : : const_iterator it = start ; it ! = pcode - > end ( ) ; + + it )
{
if ( it ! = start )
{
script + = " \n " ;
}
script + = * it ;
}
}
args . push_back ( CAIActions : : CArg ( userModelId ) ) ;
args . push_back ( CAIActions : : CArg ( baseSheet ) ) ;
args . push_back ( CAIActions : : CArg ( script ) ) ;
nldebug ( " <ParsePrimUserModelList> Add user model '%s' " , userModelId . c_str ( ) ) ;
}
}
}
else
{
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
parseUserModelListRec ( child , mapName , filename , args ) ;
}
}
}
/**
* Parse method called on the main user model node , which is a list of user models
* builds a CArgs vector and executes an AiAction USR_MDL
* This aiAction is defined in the CAIUserModelManager class
*/
static void parsePrimUserModelList ( const IPrimitive * prim ,
const std : : string & mapName ,
const std : : string & filename ,
uint32 primAlias )
{
std : : vector < CAIActions : : CArg > args ;
args . push_back ( CAIActions : : CArg ( primAlias ) ) ;
parseUserModelListRec ( prim , mapName , filename , args ) ;
if ( args . size ( ) = = 0 )
{
nlinfo ( " <ParsePrimUserModelList> No User Model List found in primitive '%s' " , filename . c_str ( ) ) ;
return ;
}
CAIActions : : execute ( " USR_MDL " , args ) ;
}
/**
* Method called to parse a custom loot table .
* A custom loot table contains an id and money values , and a list of custom loot sets .
* A custom loot set contains a drop probability and a script defining what item it will drop
* ( item name , quantity , quality )
*/
static void parseCustomLootTableRec ( const IPrimitive * prim ,
const std : : string & mapName ,
const std : : string & filename ,
std : : vector < CAIActions : : CArg > & args )
{
AITYPES : : TAIType type = nodeType ( prim ) ;
if ( type = = AITypeCustomLootTable )
{
//first push number of loot sets in the current loot table
uint size = prim - > getNumChildren ( ) ;
args . push_back ( CAIActions : : CArg ( size ) ) ;
//then push loot table info
std : : string customTableId ;
std : : string strMoneyBase ;
std : : string strMoneyFactor ;
std : : string strMoneyProba ;
prim - > getPropertyByName ( " name " , customTableId ) ;
prim - > getPropertyByName ( " money_base " , strMoneyBase ) ;
prim - > getPropertyByName ( " money_factor " , strMoneyFactor ) ;
prim - > getPropertyByName ( " money_proba " , strMoneyProba ) ;
args . push_back ( CAIActions : : CArg ( customTableId ) ) ;
char * ptr = NULL ;
float moneyProba = static_cast < float > ( strtod ( strMoneyProba . c_str ( ) , & ptr ) ) ;
if ( ptr ! = NULL & & * ptr = = ' \0 ' & & errno ! = ERANGE )
{
args . push_back ( CAIActions : : CArg ( moneyProba ) ) ;
}
float moneyFactor = static_cast < float > ( strtod ( strMoneyFactor . c_str ( ) , & ptr ) ) ;
if ( ptr ! = NULL & & * ptr = = ' \0 ' & & errno ! = ERANGE )
{
args . push_back ( CAIActions : : CArg ( moneyFactor ) ) ;
}
uint32 moneyBase = static_cast < uint32 > ( strtol ( strMoneyBase . c_str ( ) , & ptr , 10 ) ) ;
if ( ptr ! = NULL & & * ptr = = ' \0 ' & & errno ! = ERANGE )
{
args . push_back ( CAIActions : : CArg ( moneyBase ) ) ;
}
// run through the list of children
for ( uint j = 0 ; j < prim - > getNumChildren ( ) ; + + j )
{
// get a pointer to the child and make sure its valid
const IPrimitive * child ;
if ( ! prim - > getChild ( child , j ) )
continue ;
// try to get a type for the child
TAIType type = nodeType ( child ) ;
if ( type = = AITypeCustomLootSet )
{
std : : string dropProba ;
std : : string script = " " ;
const std : : vector < std : : string > * pcode = NULL ;
child - > getPropertyByName ( " drop_proba " , dropProba ) ;
child - > getPropertyByName ( " script " , pcode ) ;
if ( pcode ! = NULL & & ! pcode - > empty ( ) )
{
std : : vector < std : : string > : : const_iterator start = pcode - > begin ( ) ;
for ( std : : vector < std : : string > : : const_iterator it = start ; it ! = pcode - > end ( ) ; + + it )
{
if ( it ! = start )
{
script + = " \n " ;
}
script + = * it ;
}
}
args . push_back ( CAIActions : : CArg ( dropProba ) ) ;
args . push_back ( CAIActions : : CArg ( script ) ) ;
}
}
nldebug ( " <ParseCustomLootTable> Add custom loot table'%s' " , customTableId . c_str ( ) ) ;
}
else
{
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
parseCustomLootTableRec ( child , mapName , filename , args ) ;
}
}
}
/**
* Main parsing method used to build the CArgs vector containing the custom loot tables data defined in the primitive .
* Called on the main node which is a list of custom loot tables
* Once the parsing is done and the CArgs vector is built , an AiAction CUSTOMLT ( CustomLootTables ) is executed .
* This aiAction is defined in the CAIUserModelManager class
*/
static void parsePrimCustomLootTable ( const IPrimitive * prim ,
const std : : string & mapName ,
const std : : string & filename ,
uint32 primAlias )
{
AITYPES : : TAIType type = nodeType ( prim ) ;
if ( type = = AITypeCustomLootTables )
{
uint size = prim - > getNumChildren ( ) ;
if ( size = = 0 )
{
nlinfo ( " <ParsePrimCustomLootTable> Custom loot tables folder declared but empty in primitive '%s' " , filename . c_str ( ) ) ;
return ;
}
std : : vector < CAIActions : : CArg > args ;
args . push_back ( CAIActions : : CArg ( size ) ) ;
args . push_back ( CAIActions : : CArg ( primAlias ) ) ;
//TODO: add the primitive aliasStaticPart in the vector in order to remove all userModels/custom loot table
//from AIS and EGS managers when a primitive is unloaded
//args.push_back(CAIActions::CArg(nodeAlias(prim)));
parseCustomLootTableRec ( prim , mapName , filename , args ) ;
CAIActions : : execute ( " CUSTOMLT " , args ) ;
}
else
{
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
parsePrimCustomLootTable ( child , mapName , filename , primAlias ) ;
}
}
}
static void parsePrim ( const IPrimitive * prim , const std : : string & mapName , const std : : string & filename )
{
AITYPES : : TAIType type = nodeType ( prim ) ;
switch ( type )
{
case AITypeManager :
{
// we're clear to parse so go ahead!
parsePrimMgr ( prim , mapName , filename ) ;
}
break ;
case AITypeDynamicSystem :
{
// we're clear to parse so go ahead!
parsePrimDynSystem ( prim , mapName , filename ) ;
}
break ;
case AITypeSquadTemplate :
{
parsePrimSquadTemplate ( prim , mapName , filename ) ;
}
break ;
case AITypeNogoPointList :
{
parsePrimNogoPointList ( prim , mapName , filename ) ;
}
break ;
case AITypeSafeZone :
{
parsePrimSafeZone ( prim , mapName , filename ) ;
}
break ;
case AITypeScript :
{
parsePrimScript ( prim , mapName , filename ) ;
}
break ;
case AITypeSpire :
{
parsePrimSpire ( prim , mapName , filename ) ;
}
break ;
default :
{
// this node's not a manager so checkout children
for ( uint i = 0 ; i < prim - > getNumChildren ( ) ; + + i )
{
const IPrimitive * child ;
if ( prim - > getChild ( child , i ) )
parsePrim ( child , mapName , filename ) ;
}
}
}
}
//---------------------------------------------------------------------------------------
// utility routines for primitive file list management
struct TFileInfo
{
std : : string FileName ;
std : : string MapName ;
// uint32 FirstSlot;
} ;
const uint32 HighestSlotId = 1023 ;
//void getFileSlotVector(std::vector <TFileInfo> &vect)
//{
// CPrimitiveCfg::readPrimitiveCfg();
//
// const std::vector<std::string> &mapNames = CPrimitiveCfg::getMapNames();
// std::vector<std::string>::const_iterator first(mapNames.begin()), last(mapNames.end());
// for (; first != last; ++first)
// {
// const std::vector<std::string> &primitives = CPrimitiveCfg::getMap(*first);
// std::vector<std::string>::const_iterator first2(primitives.begin()), last2(primitives.end());
// for (; first2 != last2; ++first2)
// {
// TFileInfo fi;
// fi.MapName = *first;
// fi.FileName = *first2;
// vect.push_back(fi);
// }
// }
//
//}
void parsePrimStream ( NLMISC : : IStream & stream , const std : : string & streamName )
{
H_AUTO ( parsePrimStream ) ;
std : : string filename = streamName ;
nlinfo ( " begin parsing prim stream: %s " , filename . c_str ( ) ) ;
// normalise the file name
// std::string fileName=lookupFileName(std::string(filename));
if ( filename . empty ( ) )
{
nlwarning ( " parse primitive stream called with empty name " ) ;
return ;
}
CPrimitives * primDoc = new CPrimitives ( ) ;
try
{
{
//stream to PrimDoc
H_AUTO ( streamToPrimDoc ) ;
CPrimitiveContext : : instance ( ) . CurrentPrimitive = primDoc ;
primDoc - > serial ( stream ) ;
CPrimitiveContext : : instance ( ) . CurrentPrimitive = NULL ;
}
}
catch ( . . . )
{
nlwarning ( " stream error " ) ;
return ;
}
parsePrimNoStream ( primDoc , streamName ) ;
delete primDoc ;
}
void parsePrimNoStream ( CPrimitives * primDoc , const std : : string & streamName )
{
H_AUTO ( parsePrimNoStream ) ;
using namespace AI_SHARE ;
using namespace NLMISC ;
// clear out the alias maps
MapPrimToAlias . clear ( ) ;
MapAliasToPrim . clear ( ) ;
if ( s_WriteScenarioDebugDataToFile ) // debug
{
nldebug ( " writing test2.primitive " ) ;
saveXmlPrimitiveFile ( * primDoc , " test2.primitive " ) ;
}
// Call init() !!
nlassert ( LigoConfig ! = NULL ) ;
CPrimitiveContext : : instance ( ) . CurrentPrimitive = primDoc ;
//prim to AIAction
// initialise the action executor
CAIActions : : openFile ( streamName ) ; // AJM: note this does not open a file or stream
// do the real parsing work
{
uint32 primAlias = primDoc - > getAliasStaticPart ( ) ;
H_AUTO ( parsePrimUserModelList ) ;
//first parse for user models
parsePrimUserModelList ( ( IPrimitive * ) primDoc - > RootNode ,
CPrimitiveCfg : : getContinentNameOf ( streamName ) + " : " + CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( streamName ) ) ,
CFile : : getFilename ( CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( streamName ) ) ) ,
primAlias ) ;
//then parse for custom loot table
H_AUTO ( parsePrimCustomLootTable ) ;
parsePrimCustomLootTable ( ( IPrimitive * ) primDoc - > RootNode ,
CPrimitiveCfg : : getContinentNameOf ( streamName ) + " : " + CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( streamName ) ) ,
CFile : : getFilename ( CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( streamName ) ) ) ,
primAlias ) ;
H_AUTO ( parsePrim ) ;
//then do the real parsing work
parsePrim ( ( IPrimitive * ) primDoc - > RootNode , CPrimitiveCfg : : getContinentNameOf ( streamName ) + " : " + CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( streamName ) ) , CFile : : getFilename ( CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( streamName ) ) ) ) ;
}
CPrimitiveContext : : instance ( ) . CurrentPrimitive = NULL ;
// allow for action executor housekeeping
CAIActions : : closeFile ( streamName ) ; // AJM: note this does not close a file or a stream
}
//---------------------------------------------------------------------------------------
// the main primitive file parser routine
void parsePrimFile ( const std : : string & filename )
{
H_AUTO ( parsePrimFile ) ;
nldebug ( " PARSING PRIM FILE %s " , filename . c_str ( ) ) ;
// Call init() !!
nlassert ( LigoConfig ! = NULL ) ;
// clear out the alias maps
MapPrimToAlias . clear ( ) ;
MapAliasToPrim . clear ( ) ;
// normalise the file name
// std::string fileName=lookupFileName(std::string(filename));
if ( filename . empty ( ) )
return ;
// read the file into memory and parse to generate 'prims' data tree
CPrimitives prims ;
string sFilename ;
bool opened ;
CIFile fileIn ;
if ( fileIn . open ( filename ) )
{
nlinfo ( " Opening %s in %s " , filename . c_str ( ) , CPath : : getCurrentPath ( ) . c_str ( ) ) ;
sFilename = filename ;
opened = true ;
}
else
{
// If file not found, search in path
sFilename = CPath : : lookup ( filename , false ) ;
nlinfo ( " Opening in %s " , filename . c_str ( ) ) ;
opened = ( fileIn . open ( sFilename . c_str ( ) ) ) ;
}
nlinfo ( " Load&parse primitive file '%s' (in '%s') " ,
CFile : : getFilename ( filename ) . c_str ( ) ,
sFilename . c_str ( ) ) ;
// Test if binary caching is wanted
bool cachePrims = true ;
CConfigFile : : CVar * cachePrimsVar = IService : : getInstance ( ) - > ConfigFile . getVarPtr ( " CachePrims " ) ;
if ( cachePrimsVar )
{
cachePrims = cachePrimsVar - > asInt ( ) ! = 0 ;
}
bool cachePrimsLog = false ;
CConfigFile : : CVar * cachePrimsLogVar = IService : : getInstance ( ) - > ConfigFile . getVarPtr ( " CachePrimsLog " ) ;
if ( cachePrimsLogVar )
{
cachePrimsLog = cachePrimsLogVar - > asInt ( ) ! = 0 ;
}
if ( opened )
{
// lookup in binary cache before reading in XML
bool readXml = true ;
string binFileName = NLNET : : IService : : getInstance ( ) - > WriteFilesDirectory . toString ( ) + " primitive_cache/ " + CFile : : getFilename ( filename ) + " .binprim " ;
if ( cachePrims
& & CFile : : fileExists ( binFileName )
& & CFile : : getFileModificationDate ( binFileName ) > CFile : : getFileModificationDate ( sFilename ) )
{
if ( cachePrimsLog )
{
// ok, the cache is here and up to date !
nlinfo ( " Loading '%s' from binary file '%s' " ,
sFilename . c_str ( ) ,
binFileName . c_str ( ) ) ;
}
try
{
CIFile binFile ( binFileName ) ;
CPrimitiveContext : : instance ( ) . CurrentPrimitive = & prims ;
prims . serial ( binFile ) ;
CPrimitiveContext : : instance ( ) . CurrentPrimitive = NULL ;
// ok, all was fine, don't read in xml !
readXml = false ;
}
catch ( . . . )
{ }
}
if ( readXml )
{
// Xml stream
CIXml xmlIn ;
xmlIn . init ( fileIn ) ;
// set the primitive context
CPrimitiveContext : : instance ( ) . CurrentPrimitive = & prims ;
// Read it
if ( ! prims . read ( xmlIn . getRootNode ( ) , sFilename . c_str ( ) , * LigoConfig ) )
{
nlwarning ( " Error reading file %s " , sFilename . c_str ( ) ) ;
return ;
}
// clean the context
CPrimitiveContext : : instance ( ) . CurrentPrimitive = NULL ;
if ( cachePrims )
{
// save a binary version
CFile : : createDirectory ( IService : : getInstance ( ) - > WriteFilesDirectory . toString ( ) + " primitive_cache " ) ;
COFile saveBin ( binFileName ) ;
prims . serial ( saveBin ) ;
}
}
}
else
{
// if file not found sFilename is the result of CPath::lookup so if not in path sFilename is an empty string
nlwarning ( " Failed to open file '%s' for reading. " , sFilename . empty ( ) ? filename . c_str ( ) : sFilename . c_str ( ) ) ;
return ;
}
// initialise the action executor
CAIActions : : openFile ( sFilename ) ;
CPrimitiveContext : : instance ( ) . CurrentPrimitive = & prims ;
// do the real parsing work
{
uint32 primAlias = prims . getAliasStaticPart ( ) ;
H_AUTO ( parsePrimUserModelList ) ;
//first parse for user models
parsePrimUserModelList ( ( IPrimitive * ) prims . RootNode ,
CPrimitiveCfg : : getContinentNameOf ( filename ) + " : " + CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( sFilename ) ) ,
CFile : : getFilename ( CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( sFilename ) ) ) ,
primAlias ) ;
//then parse for custom loot table
H_AUTO ( parsePrimCustomLootTable ) ;
parsePrimCustomLootTable ( ( IPrimitive * ) prims . RootNode ,
CPrimitiveCfg : : getContinentNameOf ( filename ) + " : " + CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( sFilename ) ) ,
CFile : : getFilename ( CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( sFilename ) ) ) ,
primAlias ) ;
H_AUTO ( parsePrim ) ;
parsePrim ( ( IPrimitive * ) prims . RootNode , CPrimitiveCfg : : getContinentNameOf ( filename ) + " : " + CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( sFilename ) ) , CFile : : getFilename ( CFile : : getFilenameWithoutExtension ( CFile : : getFilename ( sFilename ) ) ) ) ;
}
CPrimitiveContext : : instance ( ) . CurrentPrimitive = NULL ;
// allow for action executor housekeeping
CAIActions : : closeFile ( sFilename ) ;
}
//---------------------------------------------------------------------------------------
NLMISC_COMMAND ( loadPdrFile , " load a primitive file. don't forget to call BuildPrimitiveDependencies " , " <file name> " )
{
if ( args . size ( ) ! = 1 )
return false ;
AI_SHARE : : CAIActionsDataRecord pdr ;
pdr . readFile ( args [ 0 ] ) ;
CAIActions : : IExecutor * executer ;
executer = CAIActions : : getExecuter ( ) ;
if ( ! executer )
{
nlwarning ( " no executer " ) ;
return false ;
}
pdr . applyToExecutor ( * executer ) ;
return true ;
}
NLMISC_COMMAND ( loadPrimitiveFile , " load a primitive file. don't forget to call BuildPrimitiveDependencies " , " <file name> " )
{
if ( args . size ( ) ! = 1 )
return false ;
if ( NLMISC : : CFile : : getExtension ( args [ 0 ] ) . empty ( ) )
parsePrimFile ( args [ 0 ] + " .primitive " ) ;
else
parsePrimFile ( args [ 0 ] ) ;
return true ;
}
// have to do this on managers coz there no more implicit correspondence ..
NLMISC_COMMAND ( loadMapsFromCommon , " load all primitive defined in usedPrimitives in common.cfg for the given map " , " <map name> " )
{
if ( args . size ( ) ! = 1 )
return false ;
CPrimitiveCfg : : readPrimitiveCfg ( ) ;
// 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
static std : : set < std : : string > loadedPrimitives ;
std : : vector < std : : string > mapConfigNames ;
// load only active primitive maps...
{
CConfigFile : : CVar & usedPrimitives = IService : : getInstance ( ) - > ConfigFile . getVar ( " UsedPrimitives " ) ;
const vector < string > & basePrim = CPrimitiveCfg : : getMap ( args [ 0 ] ) ;
set < string > filter ( basePrim . begin ( ) , basePrim . end ( ) ) ;
for ( uint i = 0 ; ( sint ) i < usedPrimitives . size ( ) ; + + i )
{
const vector < string > & prims = CPrimitiveCfg : : getMap ( usedPrimitives . asString ( i ) ) ;
for ( uint j = 0 ; j < prims . size ( ) ; + + j )
{
if ( filter . find ( prims [ j ] ) ! = filter . end ( ) )
{
// check for primitive filter
CConfigFile : : CVar * pvar = IService : : getInstance ( ) - > ConfigFile . getVarPtr ( " PrimitiveFilter " ) ;
if ( pvar )
{
const std : : string filename = CPath : : lookup ( prims [ j ] , false ) ;
bool load = true ;
for ( uint k = 0 ; k < pvar - > size ( ) ; + + k )
{
string nameFilter = pvar - > asString ( k ) ;
if ( filename . find ( nameFilter ) ! = string : : npos )
{
log . displayNL ( " loadMap : loading of primitive '%s' canceled by PrimitiveFilter '%s' " ,
filename . c_str ( ) ,
nameFilter . c_str ( ) ) ;
load = false ;
break ;
}
}
if ( ! load )
continue ;
}
// ensure that each primitive file is only loaded once at AIS startup
if ( loadedPrimitives . find ( prims [ j ] ) ! = loadedPrimitives . end ( ) )
continue ;
loadedPrimitives . insert ( prims [ j ] ) ;
// this one can be loaded
ICommand : : execute ( toString ( " loadPrimitiveFile %s " , prims [ j ] . c_str ( ) ) , log ) ;
}
}
}
}
return true ;
}
typedef map < string , set < string > > TLoadedPrimitiveMapSet ;
static TLoadedPrimitiveMapSet loadedPrimitives ;
NLMISC_COMMAND ( loadMap , " load a complete set of primitive files " , " <map name> " )
{
if ( args . size ( ) ! = 1 )
return false ;
CPrimitiveCfg : : readPrimitiveCfg ( ) ;
const vector < string > & map = CPrimitiveCfg : : getMap ( args [ 0 ] ) ;
const string continentName = CPrimitiveCfg : : getContinentNameOf ( args [ 0 ] ) ;
nlassert ( continentName . size ( ) > 0 ) ;
vector < string > : : const_iterator first ( map . begin ( ) ) , last ( map . end ( ) ) ;
for ( ; first ! = last ; + + first )
{
const std : : string filename = CPath : : lookup ( * first , false ) ;
// check for primitive filter
CConfigFile : : CVar * pvar = IService : : getInstance ( ) - > ConfigFile . getVarPtr ( " PrimitiveFilter " ) ;
if ( pvar )
{
bool load = true ;
for ( uint i = 0 ; i < pvar - > size ( ) ; + + i )
{
string filter = pvar - > asString ( i ) ;
if ( filename . find ( filter ) ! = string : : npos )
{
log . displayNL ( " loadMap : loading of primitive '%s' canceled by PrimitiveFilter '%s' " ,
filename . c_str ( ) ,
filter . c_str ( ) ) ;
load = false ;
break ;
}
}
if ( ! load )
continue ;
}
// check primitive already loaded
if ( filename . empty ( ) )
continue ;
TLoadedPrimitiveMapSet : : iterator it = loadedPrimitives . find ( continentName ) ;
if ( it ! = loadedPrimitives . end ( )
& & it - > second . find ( filename ) ! = it - > second . end ( ) )
continue ;
// check that the continent is active
CUsedContinent & uc = CUsedContinent : : instance ( ) ;
uint32 in = uc . getInstanceForContinent ( continentName ) ;
if ( in = = ~ 0 )
{
log . displayNL ( " loadMap : while loading map '%s', can't load primitive '%s' coz continent '%s' is not active " ,
args [ 0 ] . c_str ( ) ,
filename . c_str ( ) ,
continentName . c_str ( ) ) ;
}
else
{
ICommand : : execute ( toString ( " createStaticAIInstance %s " , continentName . c_str ( ) ) , log ) ;
loadedPrimitives [ continentName ] . insert ( filename ) ;
parsePrimFile ( filename ) ;
}
}
return true ;
}
NLMISC_COMMAND ( unloadMap , " unload a complete set of primitive files " , " <map name> " )
{
if ( args . size ( ) ! = 1 )
return false ;
CPrimitiveCfg : : readPrimitiveCfg ( ) ;
const vector < string > & map = CPrimitiveCfg : : getMap ( args [ 0 ] ) ;
const string continentName = CPrimitiveCfg : : getContinentNameOf ( args [ 0 ] ) ;
if ( ! continentName . empty ( ) )
{
vector < string > : : const_iterator first ( map . begin ( ) ) , last ( map . end ( ) ) ;
for ( ; first ! = last ; + + first )
{
const std : : string filename = CPath : : lookup ( * first , false ) ;
if ( filename . empty ( ) )
continue ;
// check that the continent is active
CUsedContinent & uc = CUsedContinent : : instance ( ) ;
uint32 in = uc . getInstanceForContinent ( continentName ) ;
if ( in = = ~ 0 )
{
log . displayNL ( " unloadMap : while loading map '%s', can't load primitive '%s' coz continent '%s' is not active " ,
args [ 0 ] . c_str ( ) ,
filename . c_str ( ) ,
continentName . c_str ( ) ) ;
}
else
ICommand : : execute ( toString ( " unloadPrimitiveFile %s " , filename . c_str ( ) ) , log ) ;
}
}
else
log . displayNL ( " unloadMap failed : no map named %s found " , args [ 0 ] . c_str ( ) ) ;
// Remove this file
loadedPrimitives . erase ( continentName ) ;
return true ;
}
NLMISC_COMMAND ( verbosePrimitiveParserLog , " Turn on or off or check the state of verbose .primitive parser logging " , " " )
{
if ( args . size ( ) > 1 )
return false ;
if ( args . size ( ) = = 1 )
StrToBool ( VerboseLog , args [ 0 ] ) ;
nlinfo ( " verbose Logging is %s " , VerboseLog ? " ON " : " OFF " ) ;
return true ;
}
} // end of namespace