// Ryzom - MMORPG Framework // 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 . #include "stdpch.h" // Net #include "nel/net/service.h" // Georges #include "nel/georges/u_form.h" #include "nel/georges/u_form_elm.h" #include "nel/georges/u_form_loader.h" #include "nel/georges/load_form.h" #include "sheets.h" #include "nel/misc/o_xml.h" using namespace MULTI_LINE_FORMATER; /////////// // USING // /////////// using namespace NLGEORGES; using namespace NLMISC; using namespace NLNET; using namespace std; using namespace AITYPES; ////////////////////////////////////////////////////////////////////////////// // Constants // ////////////////////////////////////////////////////////////////////////////// #ifdef NL_DEBUG CVariable debugSheet("ai", "debugSheet", "The sheet to break onto", "", 0, true); #endif char const* AISPackedSheetsFilename="ais.packed_sheets"; char const* AISPackedFightConfigSheetsFilename="ais_fight_config.packed_sheets"; char const* AISPackedActionSheetsFilename="ais_action.packed_sheets"; char const* AISPackedRaceStatsSheetsFilename="ais_race_stats.packed_sheets"; static AISHEETS::CCreature EmptySheet; sint32 AISHEETS::ICreature::InvalidFameForGuardAttack = 0x7FFFFFFF; ////////////////////////////////////////////////////////////////////////////// // CAIAction // ////////////////////////////////////////////////////////////////////////////// AISHEETS::CAIAction::CAIAction() : _SelfAction(false) { } void AISHEETS::CAIAction::readGeorges(NLMISC::CSmartPtr const& form, NLMISC::CSheetId const& sheetId) { NLGEORGES::UFormElm const& item = form->getRootNode(); // the form was found so read the true values from George _SheetId = sheetId; item.getValueByName(_SelfAction, "SelfAction"); } uint AISHEETS::CAIAction::getVersion() { return 2; } void AISHEETS::CAIAction::serial(NLMISC::IStream& s) { s.serial(_SheetId); s.serial(_SelfAction); } std::vector AISHEETS::CAIAction::getMultiLineInfoString() const { std::vector container; pushTitle(container, "AISHEETS::CAIAction"); pushEntry(container, "ai_action sheet"); pushFooter(container); return container; } ////////////////////////////////////////////////////////////////////////////// // CActionList // ////////////////////////////////////////////////////////////////////////////// void AISHEETS::CActionList::computeAbilities() { _HasNormalAction = false; _HasSelfAction = false; FOREACH(itAction, std::vector, _Actions) { IAIActionCPtr const& action = *itAction; if (!action.isNull() && action->SelfAction()) _HasSelfAction = true; else _HasNormalAction = true; } } void AISHEETS::CActionList::readGeorges(NLMISC::CSmartPtr const& form, NLMISC::CSheetId const& sheetId) { NLGEORGES::UFormElm const& item = form->getRootNode(); // the form was found so read the true values from George _SheetId = sheetId; { NLGEORGES::UFormElm const* actionListNode = NULL; item.getNodeByName(&actionListNode, "actions"); if (actionListNode) { uint arraySize = 0; actionListNode->getArraySize(arraySize); for (uint i=0; igetArrayValue(action, i); if (!action.empty()) { addAction(NLMISC::CSheetId(action), action); } } } } computeAbilities(); } uint AISHEETS::CActionList::getVersion() { return 4; } void AISHEETS::CActionList::serial(NLMISC::IStream& s) { s.serial(_SheetId); if (s.isReading()) { uint32 nbSheet; s.serial(nbSheet); for (uint32 i=0; iSheetId(); s.serial(sheetId); } } computeAbilities(); } void AISHEETS::CActionList::addAction(NLMISC::CSheetId const& sheetId, std::string const& actionName) { IAIActionCPtr action = CSheets::getInstance()->lookupAction(sheetId); if (!action.isNull()) { _Actions.push_back(action); } else { if (!actionName.empty()) nlwarning("action %s doesnt exist", actionName.c_str()); } } std::vector AISHEETS::CActionList::getMultiLineInfoString() const { std::vector container; pushTitle(container, "AISHEETS::CActionList"); pushEntry(container, "action_list sheet"); pushFooter(container); return container; } ////////////////////////////////////////////////////////////////////////////// // CGroupProperties // ////////////////////////////////////////////////////////////////////////////// AISHEETS::CGroupProperties::CGroupProperties() : _Assist(false) , _Attack(false) { } ////////////////////////////////////////////////////////////////////////////// // CCreature // ////////////////////////////////////////////////////////////////////////////// AISHEETS::CCreature::CCreature() : _Level(1) , _Radius(0.5f), _Height(2.0f), _Width(1.0f), _Length(1.0f) , _BoundingRadius(0.5) , _BonusAggroHungry(0.0), _BonusAggroVeryHungry(0.0) , _AssistDist(10) , _MinFightDist(0) , _FactionIndex(CStaticFames::INVALID_FACTION_INDEX) , _FameForGuardAttack(ICreature::InvalidFameForGuardAttack) , _GroupPropertiesIndex(0) , _DynamicGroupCountMultiplier(1) { } void AISHEETS::CCreature::calcFightAndVisualValues(std::string* left, std::string* right) { CVisualSlotManager* visualSlotManager = CVisualSlotManager::getInstance(); #ifdef NL_DEBUG nlassert(visualSlotManager); #endif uint32 leftAsInt = visualSlotManager->leftItem2Index(LeftItem()); uint32 rightAsInt = visualSlotManager->rightItem2Index(RightItem()); if (LeftItem()!=NLMISC::CSheetId::Unknown && leftAsInt==0 && left!=NULL) { if (left->size() < 3 || left->at(3) != 'p') nlwarning("Left item '%s' not allowed, if ammo, this is normal", left->c_str()); } if (RightItem()!=NLMISC::CSheetId::Unknown && rightAsInt==0 && right!=NULL) { if (right->size() < 3 || right->at(3) != 'p') nlwarning("Right item '%s' not allowed, if ammo, this is normal", right->c_str()); } _MinFightDist = (!FightConfig(FIGHTCFG_RANGE).isNULL()||!FightConfig(FIGHTCFG_NUKE).isNULL())?20:0; } void AISHEETS::CCreature::parseFightConfig(NLGEORGES::UForm const* form, std::string const& fightConfigString, uint32 actionListIndex, NLMISC::CDbgPtr& fightConfig) { NLGEORGES::UFormElm const* actionListNode = NULL; const_cast(form->getRootNode()).getNodeByName(&actionListNode, fightConfigString.c_str()); if (actionListNode) { uint arraySize = 0; actionListNode->getArraySize(arraySize); if (actionListIndexgetArrayValue(actionListFileName,actionListIndex); addActionConfig (actionListFileName, fightConfig); } } } void AISHEETS::CCreature::readFightConfig(NLMISC::IStream& s, NLMISC::CDbgPtr& fightConfig) { NLMISC::CSheetId sheetId; s.serial(sheetId); if (sheetId!=NLMISC::CSheetId::Unknown) addActionConfig(sheetId, fightConfig); } void AISHEETS::CCreature::saveFightConfig(NLMISC::IStream& s, NLMISC::CDbgPtr& fightConfig) { if (!fightConfig.isNULL()) { s.serial(fightConfig->_SheetId); } else { NLMISC::CSheetId id; s.serial(id); } } bool AISHEETS::CCreature::mustAssist(CCreature const& creature) const { return getPropertiesCst(creature.GroupPropertiesIndex()).assist(); } void AISHEETS::CCreature::setAssisGroupIndexs() { _GroupPropertiesIndex = CSheets::getInstance()->getGroupPropertiesIndex(GroupIndexStr()); if (_GroupPropertiesIndex==std::numeric_limits::max()) return; std::vector groupList; getGroupStr(groupList, AssistGroupIndexStr()); FOREACH(it, std::vector, groupList) getProperties(*it).setAssist(true); } void AISHEETS::CCreature::setAttackGroupIndexs() { _GroupPropertiesIndex = CSheets::getInstance()->getGroupPropertiesIndex(GroupIndexStr()); if (_GroupPropertiesIndex==std::numeric_limits::max()) return; std::vector groupList; getGroupStr(groupList, AttackGroupIndexStr()); FOREACH(it, std::vector, groupList) getProperties(*it).setAttack(true); } void AISHEETS::CCreature::addActionConfig(std::string const& sheetIdName, NLMISC::CDbgPtr& actionConfigList) { if (sheetIdName.empty()) { nlwarning("sheetIdName is empty"); return; } if (!addActionConfig(NLMISC::CSheetId(sheetIdName), actionConfigList)) { #ifdef NL_DEBUG nlwarning("Error in actionConfig Reference for %s", sheetIdName.c_str()); #endif } } bool AISHEETS::CCreature::addActionConfig(NLMISC::CSheetId const& sheetId, NLMISC::CDbgPtr& actionConfigList) { CActionList const* actionConfig = CSheets::getInstance()->lookupActionList(sheetId); if (actionConfig) { actionConfigList = actionConfig; // fightConfigList.push_back(actionConfig); return true; } return false; } AISHEETS::CGroupProperties& AISHEETS::CCreature::getProperties(uint32 groupIndex) { #if !FINAL_VERSION nlassert(groupIndex!=std::numeric_limits::max()); #endif if (_GroupPropertiesTbl.size()<=groupIndex && groupIndex!=std::numeric_limits::max()) { uint32 const resizeSize = std::max((uint32)CSheets::getInstance()->_NameToGroupIndex.size(), (uint32)(groupIndex+1)); _GroupPropertiesTbl.resize(resizeSize); } return _GroupPropertiesTbl[groupIndex]; } AISHEETS::CGroupProperties const& AISHEETS::CCreature::getPropertiesCst(uint32 groupIndex) const { if (groupIndex<_GroupPropertiesTbl.size()) return _GroupPropertiesTbl[groupIndex]; else return CSheets::getInstance()->_DefaultGroupProp; } std::vector AISHEETS::CCreature::getMultiLineInfoString() const { std::vector container; pushTitle(container, "AISHEETS::CCreature"); pushEntry(container, "sheet=" + SheetId().toString()); pushEntry(container, "level=" + toString("%d", Level())); container.back() += "radii=" + toString("%4.1f,%4.1f", Radius(), BoundingRadius()); container.back() += "height=" + toString("%4.1f", Height()); pushFooter(container); return container; } void AISHEETS::CCreature::readGeorges(NLMISC::CSmartPtr const& form, NLMISC::CSheetId const& sheetId) { NLGEORGES::UFormElm const& item = form->getRootNode(); // the form was found so read the true values from George _SheetId = sheetId; #ifdef NL_DEBUG nlassert(debugSheet.get().empty() || _SheetId!=NLMISC::CSheetId(debugSheet)); #endif item.getValueByName(_Level,"Basics.Level"); if (!item.getValueByName(_DynamicGroupCountMultiplier, "Basics.Characteristics.DynGroupCountMultiplier")) _DynamicGroupCountMultiplier = 1; item.getValueByName(_ColorHead,"Basics.Equipment.Head.Color"); item.getValueByName(_ColorArms,"Basics.Equipment.Arms.Color"); item.getValueByName(_ColorHands,"Basics.Equipment.Hands.Color"); item.getValueByName(_ColorBody,"Basics.Equipment.Body.Color"); item.getValueByName(_ColorLegs,"Basics.Equipment.Legs.Color"); item.getValueByName(_ColorFeets,"Basics.Equipment.Feet.Color"); item.getValueByName(_Radius,"Collision.CollisionRadius"); item.getValueByName(_Height,"Collision.Height"); item.getValueByName(_Width,"Collision.Width"); item.getValueByName(_Length,"Collision.Length"); item.getValueByName(_BoundingRadius,"Collision.BoundingRadius"); item.getValueByName(_NotTraversable, "Collision.NotTraversable"); item.getValueByName(_BonusAggroHungry,"Combat.BonusAggroHungry"); item.getValueByName(_BonusAggroVeryHungry,"Combat.BonusAggroVeryHungry"); item.getValueByName(_AggroRadiusNotHungry,"Combat.AggroRadiusNotHungry"); item.getValueByName(_AggroRadiusHungry,"Combat.AggroRadiusHungry"); item.getValueByName(_AggroRadiusHunting,"Combat.AggroRadiusHunting"); if (!item.getValueByName(_AggroReturnDistCheck,"Combat.AggroReturnDistCheck")) _AggroReturnDistCheck = -1.f; if (!item.getValueByName(_AggroRadiusD1,"Combat.AggroRadiusD1")) _AggroRadiusD1 = -1.f; if (!item.getValueByName(_AggroRadiusD2,"Combat.AggroRadiusD2")) _AggroRadiusD2 = -1.f; if (!item.getValueByName(_AggroPrimaryGroupDist,"Combat.AggroPrimaryGroupDist")) _AggroPrimaryGroupDist = -1.f; if (!item.getValueByName(_AggroPrimaryGroupCoef,"Combat.AggroPrimaryGroupCoef")) _AggroPrimaryGroupCoef = -1.f; if (!item.getValueByName(_AggroSecondaryGroupDist,"Combat.AggroSecondaryGroupDist")) _AggroSecondaryGroupDist = -1.f; if (!item.getValueByName(_AggroSecondaryGroupCoef,"Combat.AggroSecondaryGroupCoef")) _AggroSecondaryGroupCoef = -1.f; if (!item.getValueByName(_AggroPropagationRadius,"Combat.AggroPropagationRadius")) _AggroPropagationRadius = -1.f; item.getValueByName(_AssistDist,"Combat.AssistDist"); item.getValueByName(_Scale, "3d data.Scale"); { std::string faunaTypeStr; item.getValueByName(faunaTypeStr, "Basics.type"); _FaunaType = getType(faunaTypeStr.c_str()); } item.getValueByName(_ForceDisplayCreatureName, "3d data.ForceDisplayCreatureName"); // Get the dist fromm Bip to Mid float tmpBip01ToMid; if (!item.getValueByName(tmpBip01ToMid, "Collision.Dist Bip01 to mid")) tmpBip01ToMid = 0.f; // Get the distance from the bip01 to the front. if (!item.getValueByName(_DistToFront, "Collision.Dist Bip01 to front")) _DistToFront = 1.f; // Get the distance from the bip01 to the front. if (!item.getValueByName(_DistToBack, "Collision.Dist Bip01 to back")) _DistToBack = 1.f; // Get the creature Width. if (!item.getValueByName(_DistToSide, "Collision.Width")) _DistToSide = 1.f; _DistToFront = _DistToFront-tmpBip01ToMid; _DistToBack = tmpBip01ToMid-_DistToBack; _DistToSide = _DistToSide/2.f; _DistToFront *= _Scale; _DistToBack *= _Scale; _DistToSide *= _Scale; if (!item.getValueByName(_DistModulator, "Combat.DistModulator")) _DistModulator = 0.5f; // (0) - (1) - (n). if (!item.getValueByName(_TargetModulator, "Combat.TargetModulator")) _TargetModulator = 1.f; // (0) - (1). if (!item.getValueByName(_ScoreModulator, "Combat.ScoreModulator")) _ScoreModulator = 0.01f; // (0) - (1). if (!item.getValueByName(_FearModulator, "Combat.FearModulator")) _FearModulator = 0.01f; // (0) - (1). if (!item.getValueByName(_LifeLevelModulator, "Combat.LifeLevelModulator")) _LifeLevelModulator = 0.5f; // (0) - (1). if (!item.getValueByName(_CourageModulator, "Combat.CourageModulator")) _CourageModulator = 2.f; // (-n) - (0) - (+n). if (!item.getValueByName(_GroupCohesionModulator, "Combat.GroupCohesionModulator")) _GroupCohesionModulator = 0.5f; // (0) - (1) if (!item.getValueByName(_GroupDispersion, "Basics.MovementSpeeds.GroupDispersion")) _GroupDispersion = 0.5f; // (0) - (1). if (!item.getValueByName(_XPLevel, "Basics.XPLevel")) _XPLevel = 1; if (!item.getValueByName(_NbPlayers, "Basics.NbPlayers")) _NbPlayers = 1; nlassert(_DistModulator>=0); nlassert(_TargetModulator>=0); nlassert(_ScoreModulator>=0 && _ScoreModulator<=1); nlassert(_FearModulator>=0 && _FearModulator<=1); nlassert(_LifeLevelModulator>=0 && _LifeLevelModulator<=1); nlassert(_GroupCohesionModulator>=0 && _GroupCohesionModulator<=1); nlassert(_GroupDispersion>=0 && _GroupDispersion<=1); _EnergyValue = uint32(0.01f * ENERGY_SCALE); float v; if (item.getValueByName(v, "Basics.Characteristics.DynamicEnergyValue") && v!=0) _EnergyValue = uint32(v * ENERGY_SCALE); if (!item.getValueByName(_CanTurn, "Properties.Turn")) _CanTurn = true; uint32 meleeConfigChoice = 0; uint32 rangeConfigChoice = 0; uint32 nukeConfigChoice = 0; uint32 healConfigChoice = 0; breakable { std::string actionConfigStr; item.getValueByName(actionConfigStr, "action_cfg"); if (actionConfigStr.length()!=5) // 4numbers + "f". break; char a[2] = "0"; a[0] = actionConfigStr[0]; meleeConfigChoice = atol(a); a[0] = actionConfigStr[1]; rangeConfigChoice = atol(a); a[0] = actionConfigStr[2]; nukeConfigChoice = atol(a); a[0] = actionConfigStr[3]; healConfigChoice = atol(a); } static std::string meleeFightConfigString("melee_cfg"); static std::string rangeFightConfigString("range_cfg"); static std::string nukeFightConfigString("nuke_cfg"); static std::string healFightConfigString("heal_cfg"); if (meleeConfigChoice>0) parseFightConfig(form, meleeFightConfigString, meleeConfigChoice-1, _FightConfig[FIGHTCFG_MELEE]); if (rangeConfigChoice>0) parseFightConfig(form, rangeFightConfigString, rangeConfigChoice-1, _FightConfig[FIGHTCFG_RANGE]); if (nukeConfigChoice>0) parseFightConfig(form, nukeFightConfigString, nukeConfigChoice-1, _FightConfig[FIGHTCFG_NUKE]); if (healConfigChoice>0) parseFightConfig(form, healFightConfigString, healConfigChoice-1, _FightConfig[FIGHTCFG_HEAL]); // reads left & right item. { std::string left; item.getValueByName(left, "item_left"); if (!left.empty()) _LeftItem = NLMISC::CSheetId(left); std::string right; item.getValueByName(right, "item_right"); if (!right.empty()) _RightItem = NLMISC::CSheetId(right); calcFightAndVisualValues(&left, &right); } std::string s; if (item.getValueByName(s, "Basics.Fame")) { _FactionIndex = CStaticFames::getInstance().getFactionIndex(s); } if (item.getValueByName(s, "Basics.FameForGuardAttack") && !s.empty()) { float tmp; sscanf(s.c_str(), "%f", &tmp); _FameForGuardAttack = (sint32)tmp; } else _FameForGuardAttack = ICreature::InvalidFameForGuardAttack; // Assist Group Indexs. { item.getValueByName(_GroupIndexStr,"group_id"); if (_GroupIndexStr.empty()) { std::string cat; std::string raceCode; if (item.getValueByName(cat, "category") && item.getValueByName(raceCode, "race_code")) _GroupIndexStr = cat + raceCode; } item.getValueByName(_AssistGroupIndexStr, "group_assist"); setAssisGroupIndexs(); item.getValueByName(_AttackGroupIndexStr, "group_attack"); setAttackGroupIndexs(); } // Bot name item.getValueByName(_BotName, "Basics.BotName"); ////////////////////////////////////////////////////////////////////////// // Reads Script Comps. breakable { NLGEORGES::UFormElm const* scriptCompNode = NULL; const_cast(form->getRootNode()).getNodeByName(&scriptCompNode, "special_comp"); if (!scriptCompNode) break; uint arraySize = 0; scriptCompNode->getArraySize(arraySize); for (uint arrayIndex=0; arrayIndexgetArrayValue(scriptCompStr, arrayIndex); #ifndef NO_AI_COMP CFightScriptComp* scriptComp; try { scriptComp = CFightScriptCompReader::createScriptComp(scriptCompStr); registerScriptComp(scriptComp); } catch (const ReadFightActionException& ex) { nlwarning("script read error (ignored): %s", ex.what()); } #endif } } // Creature race breakable { string raceStr; if(item.getValueByName(raceStr, "Basics.Race") && !raceStr.empty()) _Race = EGSPD::CPeople::fromString(raceStr); else _Race = EGSPD::CPeople::Unknown; } } void AISHEETS::CCreature::registerScriptComp(CFightScriptComp* scriptComp) { _ScriptCompList.push_back(scriptComp); CFightSelectFilter* filter = dynamic_cast(scriptComp); if (!filter) return; std::string const& param = filter->getParam(); if (param=="ON_UPDATE") _UpdateScriptList.push_back(scriptComp); if (param=="ON_DEATH") _DeathScriptList.push_back(scriptComp); if (param=="ON_BIRTH") _BirthScriptList.push_back(scriptComp); } uint AISHEETS::CCreature::getVersion() { return 45; } void AISHEETS::CCreature::serial(NLMISC::IStream &s) { s.serial(_SheetId, _Level); #ifdef NL_DEBUG nlassert(debugSheet.get().empty() || _SheetId!=NLMISC::CSheetId(debugSheet)); #endif s.serial(_DynamicGroupCountMultiplier); s.serial(_ColorHead, _ColorArms, _ColorHands), s.serial(_ColorBody, _ColorLegs, _ColorFeets); s.serial(_Radius, _Height, _Width, _Length); s.serial(_BoundingRadius); s.serial(_BonusAggroHungry, _BonusAggroVeryHungry); s.serial(_AggroRadiusNotHungry, _AggroRadiusHungry, _AggroRadiusHunting); s.serial(_AggroReturnDistCheck); s.serial(_AggroRadiusD1, _AggroRadiusD2); s.serial(_AggroPrimaryGroupDist); s.serial(_AggroPrimaryGroupCoef); s.serial(_AggroSecondaryGroupDist); s.serial(_AggroSecondaryGroupCoef); s.serial(_AggroPropagationRadius); s.serial(_Scale); s.serial(_ForceDisplayCreatureName); s.serialEnum(_FaunaType); s.serial(_DistToFront); s.serial(_DistToBack); s.serial(_DistToSide); s.serial(_DistModulator); s.serial(_TargetModulator); s.serial(_ScoreModulator); s.serial(_FearModulator); s.serial(_LifeLevelModulator); s.serial(_CourageModulator); s.serial(_GroupCohesionModulator); s.serial(_GroupDispersion); s.serial(_XPLevel); s.serial(_NbPlayers); s.serial(_EnergyValue); s.serial(_CanTurn); if (s.isReading()) { readFightConfig(s, _FightConfig[FIGHTCFG_MELEE]); readFightConfig(s, _FightConfig[FIGHTCFG_RANGE]); readFightConfig(s, _FightConfig[FIGHTCFG_NUKE]); readFightConfig(s, _FightConfig[FIGHTCFG_HEAL]); } else { saveFightConfig(s, _FightConfig[FIGHTCFG_MELEE]); saveFightConfig(s, _FightConfig[FIGHTCFG_RANGE]); saveFightConfig(s, _FightConfig[FIGHTCFG_NUKE]); saveFightConfig(s, _FightConfig[FIGHTCFG_HEAL]); } s.serial(_AssistDist); // serialize left & right item. s.serial(_LeftItem, _RightItem); s.serial(_FactionIndex); s.serial(_FameForGuardAttack); s.serial(_GroupIndexStr); s.serial(_AssistGroupIndexStr); s.serial(_AttackGroupIndexStr); s.serial(_BotName); s.serialEnum(_Race); if (s.isReading()) { setAssisGroupIndexs(); setAttackGroupIndexs(); } if (s.isReading()) { uint32 nbScript; s.serial(nbScript); for (uint32 index=0; indextoString(); s.serial(str); } } calcFightAndVisualValues(); } void AISHEETS::CCreature::getGroupStr(std::vector& groupIndexStrList, std::string const& groupIndexStr) { if (groupIndexStr.empty()) return; size_t firstIndex = 0; size_t lastIndex = firstIndex - 1; do { firstIndex = lastIndex + 1; lastIndex = groupIndexStr.find_first_of(',',firstIndex); std::string str; if (lastIndex==std::string::npos) str = groupIndexStr.substr(firstIndex, groupIndexStr.size()-firstIndex); else str = groupIndexStr.substr(firstIndex, lastIndex-firstIndex); uint32 const otherGroupIndex = CSheets::getInstance()->getGroupPropertiesIndex(str); if (otherGroupIndex!=std::numeric_limits::max()) groupIndexStrList.push_back(otherGroupIndex); } while (lastIndex!=std::string::npos); } ////////////////////////////////////////////////////////////////////////////// // CRaceStats // ////////////////////////////////////////////////////////////////////////////// void AISHEETS::CRaceStats::readGeorges(NLMISC::CSmartPtr const& form, NLMISC::CSheetId const& sheetId) { NLGEORGES::UFormElm const& item = form->getRootNode(); // the form was found so read the true values from George _SheetId = sheetId; #ifdef NL_DEBUG nlassert(debugSheet.get().empty() || _SheetId!=NLMISC::CSheetId(debugSheet)); #endif item.getValueByName(_Race, "Race"); } uint AISHEETS::CRaceStats::getVersion() { return 1; } void AISHEETS::CRaceStats::serial(NLMISC::IStream &s) { s.serial(_SheetId); #ifdef NL_DEBUG nlassert(debugSheet.get().empty() || _SheetId!=NLMISC::CSheetId(debugSheet)); #endif s.serial(_SheetId); s.serial(_Race); } ////////////////////////////////////////////////////////////////////////////// // CSheets // ////////////////////////////////////////////////////////////////////////////// AISHEETS::CSheets* AISHEETS::CSheets::_Instance = NULL; AISHEETS::CSheets* AISHEETS::CSheets::getInstance() { if (!_Instance) _Instance = new AISHEETS::CSheets; return _Instance; } void AISHEETS::CSheets::destroyInstance() { delete _Instance; _Instance = NULL; } AISHEETS::CSheets::CSheets() : _Initialised(false) { } void AISHEETS::CSheets::init() { if (_Initialised) return; _PlayerGroupIndex=getGroupPropertiesIndex("zp"); #if !FINAL_VERSION nlassert(_PlayerGroupIndex!=std::numeric_limits::max()); #endif packSheets(IService::getInstance()->WriteFilesDirectory.toString()); _Initialised=true; } void AISHEETS::CSheets::packSheets(const std::string &writeFilesDirectoryName) { CConfigFile::CVar *varPtr = IService::isServiceInitialized() ? IService::getInstance()->ConfigFile.getVarPtr(std::string("GeorgePaths")) : NULL; // if config file variable 'GeorgePaths' exists then only do a minimal loadForms otherwise do the full works if (varPtr!=NULL) { bool addSearchPath=false; loadForm2("aiaction", writeFilesDirectoryName+AISPackedActionSheetsFilename, _ActionSheets, false, false); if (_ActionSheets.empty()) { if (!addSearchPath) { addSearchPath=true; for (uint32 i=0;isize();++i) CPath::addSearchPath(varPtr->asString(i).c_str(), true, false); } loadForm2("aiaction", writeFilesDirectoryName+AISPackedActionSheetsFilename, _ActionSheets, true); } loadForm("actionlist", writeFilesDirectoryName+AISPackedFightConfigSheetsFilename, _ActionListSheets, false, false); if (_ActionListSheets.empty()) { if (!addSearchPath) { addSearchPath=true; for (uint32 i=0;isize();++i) CPath::addSearchPath(varPtr->asString(i).c_str(), true, false); } loadForm("actionlist", writeFilesDirectoryName+AISPackedFightConfigSheetsFilename, _ActionListSheets, true); } loadForm2("creature", writeFilesDirectoryName+AISPackedSheetsFilename, _Sheets, false, false); if (_Sheets.empty()) { if (!addSearchPath) { addSearchPath=true; for (uint32 i=0;isize();++i) CPath::addSearchPath(varPtr->asString(i).c_str(), true, false); } loadForm2("creature", writeFilesDirectoryName+AISPackedSheetsFilename, _Sheets, true); } loadForm2("race_stats", writeFilesDirectoryName+AISPackedRaceStatsSheetsFilename, _RaceStatsSheets, false, false); if (_RaceStatsSheets.empty()) { if (!addSearchPath) { addSearchPath=true; for (uint32 i=0;isize();++i) CPath::addSearchPath(varPtr->asString(i).c_str(), true, false); } loadForm2("race_stats", writeFilesDirectoryName+AISPackedRaceStatsSheetsFilename, _RaceStatsSheets, true); } } else { loadForm2("aiaction", writeFilesDirectoryName+AISPackedActionSheetsFilename, _ActionSheets, true); loadForm("actionlist", writeFilesDirectoryName+AISPackedFightConfigSheetsFilename, _ActionListSheets, true); loadForm2("creature", writeFilesDirectoryName+AISPackedSheetsFilename, _Sheets, true); loadForm2("race_stats", writeFilesDirectoryName+AISPackedRaceStatsSheetsFilename, _RaceStatsSheets, true); } } void AISHEETS::CSheets::release() { _Sheets.clear(); _ActionListSheets.clear(); _ActionSheets.clear(); _RaceStatsSheets.clear(); } uint32 AISHEETS::CSheets::getGroupPropertiesIndex(const std::string &groupIndexName) { if (groupIndexName.empty()) return std::numeric_limits::max(); std::map::iterator it = _NameToGroupIndex.find(NLMISC::toUpper(groupIndexName)); if (it==_NameToGroupIndex.end()) { uint32 groupIndex = (uint32)_NameToGroupIndex.size(); _NameToGroupIndex.insert(make_pair(groupIndexName, groupIndex)); #if !FINAL_VERSION nldebug("GroupIndex Entry: %s %d", groupIndexName.c_str(), groupIndex); #endif it = _NameToGroupIndex.find(groupIndexName); #ifdef NL_DEBUG nlassert(it!=_NameToGroupIndex.end()); #endif // Resize other group table. Better imp should be done with listeners. } return it->second; } void AISHEETS::CSheets::display(CSmartPtr stringWriter, uint infoSelect) { nlassert(_Initialised); std::map::iterator it; for(it=_Sheets.begin(); it!=_Sheets.end(); ++it) { std::vector strings; strings = it->second->getMultiLineInfoString(); FOREACHC(itString, std::vector, strings) stringWriter->append(toString("%04x", it->second->SheetId().asInt()) + " " + *itString); } } AISHEETS::ICreatureCPtr AISHEETS::CSheets::lookup(CSheetId const& id) { // setup an iterator and lookup the sheet id in the map std::map::iterator it=_Sheets.find(id); // if we found a valid entry return a pointer to the creature record otherwise 0 if (it!=_Sheets.end()) return (AISHEETS::CCreature*)it->second; else { nlwarning("Unknow creature sheet '%s'", id.toString().c_str()); return NULL; } } AISHEETS::IAIActionCPtr AISHEETS::CSheets::lookupAction(CSheetId const& id) { // setup an iterator and lookup the sheet id in the map std::map::iterator it = _ActionSheets.find(id); // if we found a valid entry return a pointer to the creature record otherwise 0 if (it!=_ActionSheets.end()) return (AISHEETS::CAIAction*)it->second; else return NULL; } AISHEETS::CActionList const* AISHEETS::CSheets::lookupActionList(CSheetId const& id) { // setup an iterator and lookup the sheet id in the map std::map::iterator it=_ActionListSheets.find(id); // if we found a valid entry return a pointer to the creature record otherwise 0 if (it!=_ActionListSheets.end()) return &((*it).second); else return NULL; } AISHEETS::IRaceStatsCPtr AISHEETS::CSheets::lookupRaceStats(CSheetId const& id) { // setup an iterator and lookup the sheet id in the map std::map::iterator it=_RaceStatsSheets.find(id); if (it!=_RaceStatsSheets.end()) return (AISHEETS::CRaceStats*)it->second; else { nlwarning("Unknow race_stats sheet '%s'", id.toString().c_str()); return NULL; } } ////////////////////////////////////////////////////////////////////////////// // Console commands // ////////////////////////////////////////////////////////////////////////////// NLMISC_COMMAND(displaySheetNames,"display sheet data for all sheets","") { if(args.size() !=0) return false; AISHEETS::CSheets::getInstance()->display(new CLogStringWriter(&log),0); return true; } NLMISC_COMMAND(displaySheetBasics,"display sheet data for all sheets","") { if(args.size() !=0) return false; AISHEETS::CSheets::getInstance()->display(new CLogStringWriter(&log),1); return true; } NLMISC_COMMAND(displaySheetCombat,"display sheet data for all sheets","") { if(args.size() !=0) return false; AISHEETS::CSheets::getInstance()->display(new CLogStringWriter(&log),2); return true; } NLMISC_COMMAND(displaySheetByName,"display sheet data for given sheets"," [...]") { if (args.size() <1) return false; for (uint i=0;ilookup(NLMISC::CSheetId(args[i])); if (!sheet) { log.displayNL("Failed to find sheet: %s",args[0].c_str()); continue; } std::vector strings = sheet->getMultiLineInfoString(); FOREACHC(it, std::vector, strings) log.displayNL("%s", it->c_str()); } return true; } /* NLMISC_COMMAND(setSheetProperty,"change a value read from a sheet"," level|walk|run|radius|bounding|height|aggro|attack|danger|flight|survive|initSurv|crit ") { if (args.size() !=3) return false; // lookup the sheet id AISHEETS::CCreature* sheet = const_cast(dynamic_cast(AISHEETS::CSheets::getInstance()->lookup(NLMISC::CSheetId(args[0])))); if (!sheet) { log.displayNL("Failed to find sheet: %s",args[0].c_str()); return false; } // get the value float val = (float)atof(args[2].c_str()); if (val==0 && args[2]!="0" && args[2]!="0.0") { log.displayNL("'%s' is not a valid value",args[2].c_str()); return false; } breakable { if (nlstricmp(args[1].c_str(),"level")==0) { sheet->_Level=(uint32)val; break; } if (nlstricmp(args[1].c_str(),"radius")==0) { sheet->_Radius=val; break; } if (nlstricmp(args[1].c_str(),"bounding")==0) { sheet->_BoundingRadius=val; break; } if (nlstricmp(args[1].c_str(),"height")==0) { sheet->_Height=val; break; } log.displayNL("variable name not recognised: %s", args[1].c_str()); return false; } std::vector strings = sheet->getMultiLineInfoString(); FOREACHC(it, std::vector, strings) log.displayNL("%s", it->c_str()); return true; } */