mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-12-23 01:18:46 +00:00
4222 lines
129 KiB
C++
4222 lines
129 KiB
C++
|
// 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
|
||
|
char* props[] = { "tribe_squads", "tribe_squads2", "default_squads", "buyable_squads" };
|
||
|
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
|
||
|
|