From 030582c1efae71db58e0c2d97083f081c79c8cde Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Sat, 31 Mar 2012 05:54:24 +0000 Subject: [PATCH] - added a new EnumParser class to convert enum to string and vice versa - factions can now customize some more of the AI behavior --- source/glest_game/ai/ai.cpp | 98 +++++++++++++++++++- source/glest_game/ai/ai.h | 44 ++++++--- source/glest_game/ai/ai_rule.cpp | 6 +- source/glest_game/game/game_constants.h | 35 +++++++ source/glest_game/type_instances/faction.cpp | 5 + source/glest_game/type_instances/faction.h | 3 + source/glest_game/types/faction_type.cpp | 38 +++++++- source/glest_game/types/faction_type.h | 37 +++++++- source/shared_lib/include/util/util.h | 1 - 9 files changed, 238 insertions(+), 29 deletions(-) diff --git a/source/glest_game/ai/ai.cpp b/source/glest_game/ai/ai.cpp index c2326bde..5218532f 100644 --- a/source/glest_game/ai/ai.cpp +++ b/source/glest_game/ai/ai.cpp @@ -15,6 +15,7 @@ #include "unit_type.h" #include "unit.h" #include "map.h" +#include "faction_type.h" #include "leak_dumper.h" using namespace Shared::Graphics; @@ -234,6 +235,53 @@ UpgradeTask * UpgradeTask::loadGame(const XmlNode *rootNode, Faction *faction) { void Ai::init(AiInterface *aiInterface, int useStartLocation) { this->aiInterface= aiInterface; + + Faction *faction = this->aiInterface->getMyFaction(); + if(faction->getAIBehaviorStaticOverideValue(aibsvcMaxBuildRadius) != INT_MAX) { + maxBuildRadius = faction->getAIBehaviorStaticOverideValue(aibsvcMaxBuildRadius); + //printf("Discovered overriden static value for AI, maxBuildRadius = %d\n",maxBuildRadius); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriors) != INT_MAX) { + minMinWarriors = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriors); + //printf("Discovered overriden static value for AI, minMinWarriors = %d\n",minMinWarriors); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuEasy) != INT_MAX) { + minMinWarriorsExpandCpuEasy = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuEasy); + //printf("Discovered overriden static value for AI, minMinWarriorsExpandCpuEasy = %d\n",minMinWarriorsExpandCpuEasy); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuMega) != INT_MAX) { + minMinWarriorsExpandCpuMega = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuMega); + //printf("Discovered overriden static value for AI, minMinWarriorsExpandCpuMega = %d\n",minMinWarriorsExpandCpuMega); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuUltra) != INT_MAX) { + minMinWarriorsExpandCpuUltra = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuUltra); + //printf("Discovered overriden static value for AI, minMinWarriorsExpandCpuUltra = %d\n",minMinWarriorsExpandCpuUltra); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuNormal) != INT_MAX) { + minMinWarriorsExpandCpuNormal = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuNormal); + //printf("Discovered overriden static value for AI, minMinWarriorsExpandCpuNormal = %d\n",minMinWarriorsExpandCpuNormal); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcMaxMinWarriors) != INT_MAX) { + maxMinWarriors = faction->getAIBehaviorStaticOverideValue(aibsvcMaxMinWarriors); + //printf("Discovered overriden static value for AI, maxMinWarriors = %d\n",maxMinWarriors); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcMaxExpansions) != INT_MAX) { + maxExpansions = faction->getAIBehaviorStaticOverideValue(aibsvcMaxExpansions); + //printf("Discovered overriden static value for AI, maxExpansions = %d\n",maxExpansions); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcVillageRadius) != INT_MAX) { + villageRadius = faction->getAIBehaviorStaticOverideValue(aibsvcVillageRadius); + //printf("Discovered overriden static value for AI, villageRadius = %d\n",villageRadius); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcScoutResourceRange) != INT_MAX) { + scoutResourceRange = faction->getAIBehaviorStaticOverideValue(aibsvcScoutResourceRange); + //printf("Discovered overriden static value for AI, scoutResourceRange = %d\n",scoutResourceRange); + } + if(faction->getAIBehaviorStaticOverideValue(aibsvcMinWorkerAttackersHarvesting) != INT_MAX) { + minWorkerAttackersHarvesting = faction->getAIBehaviorStaticOverideValue(aibsvcMinWorkerAttackersHarvesting); + //printf("Discovered overriden static value for AI, scoutResourceRange = %d\n",scoutResourceRange); + } + if(useStartLocation == -1) { startLoc = random.randRange(0, aiInterface->getMapMaxPlayers()-1); } @@ -709,7 +757,7 @@ void Ai::sendScoutPatrol(){ //printf("is inside map\n"); // find first resource in this area Vec2i resPos; - if(aiInterface->isResourceInRegion(pos, rt, resPos, 20)){ + if(aiInterface->isResourceInRegion(pos, rt, resPos, scoutResourceRange)){ // found a possible target. pos= resPos; //printf("lets try the new target\n"); @@ -738,8 +786,6 @@ void Ai::sendScoutPatrol(){ } void Ai::massiveAttack(const Vec2i &pos, Field field, bool ultraAttack){ - const int minWorkerAttackersHarvesting = 3; - int producerWarriorCount=0; int maxProducerWarriors=random.randRange(1,11); int unitCount = aiInterface->getMyUnitCount(); @@ -1126,6 +1172,29 @@ void Ai::saveGame(XmlNode *rootNode) const { // RandomGen random; aiNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements); // std::map factionSwitchTeamRequestCount; + +// int maxBuildRadius; + aiNode->addAttribute("maxBuildRadius",intToStr(maxBuildRadius), mapTagReplacements); +// int minMinWarriors; + aiNode->addAttribute("minMinWarriors",intToStr(minMinWarriors), mapTagReplacements); +// int minMinWarriorsExpandCpuEasy; + aiNode->addAttribute("minMinWarriorsExpandCpuEasy",intToStr(minMinWarriorsExpandCpuEasy), mapTagReplacements); +// int minMinWarriorsExpandCpuMega; + aiNode->addAttribute("minMinWarriorsExpandCpuMega",intToStr(minMinWarriorsExpandCpuMega), mapTagReplacements); +// int minMinWarriorsExpandCpuUltra; + aiNode->addAttribute("minMinWarriorsExpandCpuUltra",intToStr(minMinWarriorsExpandCpuUltra), mapTagReplacements); +// int minMinWarriorsExpandCpuNormal; + aiNode->addAttribute("minMinWarriorsExpandCpuNormal",intToStr(minMinWarriorsExpandCpuNormal), mapTagReplacements); +// int maxMinWarriors; + aiNode->addAttribute("maxMinWarriors",intToStr(maxMinWarriors), mapTagReplacements); +// int maxExpansions; + aiNode->addAttribute("maxExpansions",intToStr(maxExpansions), mapTagReplacements); +// int villageRadius; + aiNode->addAttribute("villageRadius",intToStr(villageRadius), mapTagReplacements); +// int scoutResourceRange; + aiNode->addAttribute("scoutResourceRange",intToStr(scoutResourceRange), mapTagReplacements); +// int minWorkerAttackersHarvesting; + aiNode->addAttribute("minWorkerAttackersHarvesting",intToStr(minWorkerAttackersHarvesting), mapTagReplacements); } void Ai::loadGame(const XmlNode *rootNode, Faction *faction) { @@ -1170,6 +1239,29 @@ void Ai::loadGame(const XmlNode *rootNode, Faction *faction) { // RandomGen random; random.setLastNumber(aiNode->getAttribute("random")->getIntValue()); // std::map factionSwitchTeamRequestCount; + + // int maxBuildRadius; + maxBuildRadius = aiNode->getAttribute("maxBuildRadius")->getIntValue(); + // int minMinWarriors; + minMinWarriors = aiNode->getAttribute("minMinWarriors")->getIntValue(); + // int minMinWarriorsExpandCpuEasy; + minMinWarriorsExpandCpuEasy = aiNode->getAttribute("minMinWarriorsExpandCpuEasy")->getIntValue(); + // int minMinWarriorsExpandCpuMega; + minMinWarriorsExpandCpuMega = aiNode->getAttribute("minMinWarriorsExpandCpuMega")->getIntValue(); + // int minMinWarriorsExpandCpuUltra; + minMinWarriorsExpandCpuUltra = aiNode->getAttribute("minMinWarriorsExpandCpuUltra")->getIntValue(); + // int minMinWarriorsExpandCpuNormal; + minMinWarriorsExpandCpuNormal = aiNode->getAttribute("minMinWarriorsExpandCpuNormal")->getIntValue(); + // int maxMinWarriors; + maxMinWarriors = aiNode->getAttribute("maxMinWarriors")->getIntValue(); + // int maxExpansions; + maxExpansions = aiNode->getAttribute("maxExpansions")->getIntValue(); + // int villageRadius; + villageRadius = aiNode->getAttribute("villageRadius")->getIntValue(); + // int scoutResourceRange; + scoutResourceRange = aiNode->getAttribute("scoutResourceRange")->getIntValue(); + // int minWorkerAttackersHarvesting; + minWorkerAttackersHarvesting = aiNode->getAttribute("minWorkerAttackersHarvesting")->getIntValue(); } }}//end namespace diff --git a/source/glest_game/ai/ai.h b/source/glest_game/ai/ai.h index b5a2f368..8c1c08b0 100644 --- a/source/glest_game/ai/ai.h +++ b/source/glest_game/ai/ai.h @@ -129,17 +129,19 @@ public: class Ai { private: - static const int maxBuildRadius= 40; + int maxBuildRadius; - static const int minMinWarriors= 7; - static const int minMinWarriorsExpandCpuEasy= 1; - static const int minMinWarriorsExpandCpuMega= 3; - static const int minMinWarriorsExpandCpuUltra= 3; - static const int minMinWarriorsExpandCpuNormal= 3; - static const int maxMinWarriors= 20; + int minMinWarriors; + int minMinWarriorsExpandCpuEasy; + int minMinWarriorsExpandCpuMega; + int minMinWarriorsExpandCpuUltra; + int minMinWarriorsExpandCpuNormal; + int maxMinWarriors; - static const int maxExpansions= 2; - static const int villageRadius= 15; + int maxExpansions; + int villageRadius; + int scoutResourceRange; + int minWorkerAttackersHarvesting; public: enum ResourceUsage { @@ -163,20 +165,32 @@ private: Positions expansionPositions; RandomGen random; std::map factionSwitchTeamRequestCount; + int minWarriors; bool getAdjacentUnits(std::map > &signalAdjacentUnits, const Unit *unit); public: Ai() { - aiInterface = NULL; - startLoc = -1; + // Defaults that used to be static which can now be overriden + maxBuildRadius = 40; + minMinWarriors = 7; + minMinWarriorsExpandCpuEasy = 1; + minMinWarriorsExpandCpuMega = 3; + minMinWarriorsExpandCpuUltra = 3; + minMinWarriorsExpandCpuNormal = 3; + maxMinWarriors = 20; + maxExpansions = 2; + villageRadius = 15; + scoutResourceRange = 20; + minWorkerAttackersHarvesting = 3; + + aiInterface = NULL; + startLoc = -1; randomMinWarriorsReached = false; - minWarriors = 0; + minWarriors = 0; } ~Ai(); - int minWarriors; - void init(AiInterface *aiInterface,int useStartLocation=-1); void update(); @@ -185,6 +199,8 @@ public: RandomGen* getRandom() {return &random;} int getCountOfType(const UnitType *ut); + int getMinWarriors() const { return minWarriors; } + int getCountOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount=NULL); float getRatioOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount=NULL); diff --git a/source/glest_game/ai/ai_rule.cpp b/source/glest_game/ai/ai_rule.cpp index c7a908f2..489f06c5 100644 --- a/source/glest_game/ai/ai_rule.cpp +++ b/source/glest_game/ai/ai_rule.cpp @@ -430,7 +430,7 @@ void AiRuleAddTasks::execute(){ if(warriorRatio<0.30) ai->addTask(new ProduceTask(ucWarrior)); if(workerCount>=10) ai->addTask(new ProduceTask(ucWarrior)); if(workerCount>=15) ai->addTask(new ProduceTask(ucWarrior)); - if(warriorCountminWarriors+2) + if(warriorCount < ai->getMinWarriors() + 2) { ai->addTask(new ProduceTask(ucWarrior)); if( buildingCount>9 ) @@ -603,8 +603,8 @@ bool AiRuleProduceResourceProducer::test(){ } int targetStaticResourceCount = minStaticResources; - if(aiInterface->getMyFactionType()->getAIBehaviorMinStaticResourceCount() != INT_MAX) { - targetStaticResourceCount = aiInterface->getMyFactionType()->getAIBehaviorMinStaticResourceCount(); + if(aiInterface->getMyFactionType()->getAIBehaviorStaticOverideValue(aibsvcMinStaticResourceCount) != INT_MAX) { + targetStaticResourceCount = aiInterface->getMyFactionType()->getAIBehaviorStaticOverideValue(aibsvcMinStaticResourceCount); } //statics second diff --git a/source/glest_game/game/game_constants.h b/source/glest_game/game/game_constants.h index bf868a36..383e89d1 100644 --- a/source/glest_game/game/game_constants.h +++ b/source/glest_game/game/game_constants.h @@ -4,6 +4,9 @@ #include #include #include "vec.h" +#include +#include +#include // ============================================================== // This file is part of Glest (www.glest.org) @@ -17,9 +20,41 @@ // ============================================================== using namespace Shared::Graphics; +using namespace std; namespace Glest{ namespace Game{ +template +class EnumParser { +private: + typedef map enumMapType; + typedef typename enumMapType::const_iterator enumMapTypeIter; + EnumParser(); + + enumMapType enumMap; + +public: + + static T getEnum(const string &value) { + static EnumParser parser; + enumMapTypeIter iValue = parser.enumMap.find(value); + if(iValue == parser.enumMap.end()) { + throw std::runtime_error("unknown enum lookup [" + value + "]"); + } + return iValue->second; + } + static string getString(const T &value) { + static EnumParser parser; + for(enumMapTypeIter iValue = parser.enumMap.first(); + iValue != parser.enumMap.end(); ++iValue) { + if(iValue->second == value) { + return iValue->first; + } + } + throw std::runtime_error("unknown enum lookup [" + intToStr(value) + "]"); + } +}; + // ===================================================== // class GameConstants // ===================================================== diff --git a/source/glest_game/type_instances/faction.cpp b/source/glest_game/type_instances/faction.cpp index b5e52439..c643790e 100644 --- a/source/glest_game/type_instances/faction.cpp +++ b/source/glest_game/type_instances/faction.cpp @@ -452,6 +452,11 @@ FactionPersonalityType Faction::getPersonalityType() const { return factionType->getPersonalityType(); } +int Faction::getAIBehaviorStaticOverideValue(AIBehaviorStaticValueCategory type) const { + return factionType->getAIBehaviorStaticOverideValue(type); +} + + Unit * Faction::getUnit(int i) const { Unit *result = units[i]; return result; diff --git a/source/glest_game/type_instances/faction.h b/source/glest_game/type_instances/faction.h index 2d8acee8..17c0eb35 100644 --- a/source/glest_game/type_instances/faction.h +++ b/source/glest_game/type_instances/faction.h @@ -22,6 +22,7 @@ #include "command_type.h" #include "base_thread.h" #include +#include "faction_type.h" #include "leak_dumper.h" using std::map; @@ -186,8 +187,10 @@ public: bool getCpuUltraControl() const {return control==ctCpuUltra;} bool getCpuMegaControl() const {return control==ctCpuMega;} ControlType getControlType() const {return control;} + FactionPersonalityType getPersonalityType() const; void setPersonalityType(FactionPersonalityType pType) { overridePersonalityType=pType; } + int getAIBehaviorStaticOverideValue(AIBehaviorStaticValueCategory type) const; Unit *getUnit(int i) const; int getUnitCount() const; diff --git a/source/glest_game/types/faction_type.cpp b/source/glest_game/types/faction_type.cpp index c9398016..bc08f6f8 100644 --- a/source/glest_game/types/faction_type.cpp +++ b/source/glest_game/types/faction_type.cpp @@ -33,7 +33,6 @@ namespace Glest{ namespace Game{ FactionType::FactionType() { music = NULL; personalityType = fpt_Normal; - aIBehavior_minStaticResourceCount = INT_MAX; } //load a faction, given a directory @@ -42,8 +41,6 @@ void FactionType::load(const string &factionName, const TechTree *techTree, Chec if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - aIBehavior_minStaticResourceCount = INT_MAX; - string techTreePath = techTree->getPath(); string techTreeName=techTree->getName(); string currentPath = ""; @@ -221,9 +218,30 @@ void FactionType::load(const string &factionName, const TechTree *techTree, Chec if(factionNode->hasChild("ai-behavior") == true) { const XmlNode *aiNode= factionNode->getChild("ai-behavior"); if(aiNode->hasAttribute("min-static-resource-count") == true) { - aIBehavior_minStaticResourceCount = aiNode->getAttribute("min-static-resource-count")->getIntValue(); - //printf("aIBehavior_minStaticResourceCount = %d\n",aIBehavior_minStaticResourceCount); + mapAIBehaviorStaticOverrideValues[aibsvcMinStaticResourceCount] = aiNode->getAttribute("min-static-resource-count")->getIntValue(); } + + if(aiNode->hasChild("static-values") == true) { + const XmlNode *aiNodeUnits= aiNode->getChild("static-values"); + for(int i = 0; i < aiNodeUnits->getChildCount(); ++i) { + const XmlNode *unitNode= aiNodeUnits->getChild("static", i); + AIBehaviorStaticValueCategory type = aibsvcMaxBuildRadius; + if(unitNode->hasAttribute("type") == true) { + type = static_cast( + unitNode->getAttribute("type")->getIntValue()); + } + else { + type = EnumParser::getEnum( + unitNode->getAttribute("type-name")->getValue()); + //printf("Discovered overriden static value for AI, type = %d, value = %d\n",type,value); + } + + int value = unitNode->getAttribute("value")->getIntValue(); + mapAIBehaviorStaticOverrideValues[type]=value; + //printf("Discovered overriden static value for AI, type = %d, value = %d\n",type,value); + } + } + if(aiNode->hasChild("worker-units") == true) { const XmlNode *aiNodeUnits= aiNode->getChild("worker-units"); for(int i = 0; i < aiNodeUnits->getChildCount(); ++i) { @@ -279,6 +297,16 @@ void FactionType::load(const string &factionName, const TechTree *techTree, Chec if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } +int FactionType::getAIBehaviorStaticOverideValue(AIBehaviorStaticValueCategory type) const { + int result = INT_MAX; + std::map::const_iterator iterFind = + mapAIBehaviorStaticOverrideValues.find(type); + if(iterFind != mapAIBehaviorStaticOverrideValues.end()) { + result = iterFind->second; + } + return result; +} + const std::vector FactionType::getAIBehaviorUnits(AIBehaviorUnitCategory category) const { std::map >::const_iterator iterFind = mapAIBehaviorUnitCategories.find(category); if(iterFind != mapAIBehaviorUnitCategories.end()) { diff --git a/source/glest_game/types/faction_type.h b/source/glest_game/types/faction_type.h index 7ca8eb45..296cdcf8 100644 --- a/source/glest_game/types/faction_type.h +++ b/source/glest_game/types/faction_type.h @@ -15,12 +15,14 @@ #include "unit_type.h" #include "upgrade_type.h" #include "sound.h" +#include +#include +#include "util.h" #include "leak_dumper.h" using Shared::Sound::StrSound; namespace Glest{ namespace Game{ - // ===================================================== // class FactionType // @@ -34,6 +36,35 @@ enum AIBehaviorUnitCategory { aibcBuildingUnits }; +enum AIBehaviorStaticValueCategory { + aibsvcMaxBuildRadius, + aibsvcMinMinWarriors, + aibsvcMinMinWarriorsExpandCpuEasy, + aibsvcMinMinWarriorsExpandCpuMega, + aibsvcMinMinWarriorsExpandCpuUltra, + aibsvcMinMinWarriorsExpandCpuNormal, + aibsvcMaxMinWarriors, + aibsvcMaxExpansions, + aibsvcVillageRadius, + aibsvcMinStaticResourceCount, + aibsvcScoutResourceRange, + aibsvcMinWorkerAttackersHarvesting +}; +template <> +inline EnumParser::EnumParser() { + enumMap["MaxBuildRadius"] = aibsvcMaxBuildRadius; + enumMap["MinMinWarriors"] = aibsvcMinMinWarriors; + enumMap["MinMinWarriorsExpandCpuEasy"] = aibsvcMinMinWarriorsExpandCpuEasy; + enumMap["MinMinWarriorsExpandCpuMega"] = aibsvcMinMinWarriorsExpandCpuMega; + enumMap["MinMinWarriorsExpandCpuUltra"] = aibsvcMinMinWarriorsExpandCpuUltra; + enumMap["MinMinWarriorsExpandCpuNormal"]= aibsvcMinMinWarriorsExpandCpuNormal; + enumMap["MaxMinWarriors"] = aibsvcMaxMinWarriors; + enumMap["MaxExpansions"] = aibsvcMaxExpansions; + enumMap["VillageRadius"] = aibsvcVillageRadius; + enumMap["MinStaticResourceCount"] = aibsvcMinStaticResourceCount; + enumMap["ScoutResourceRange"] = aibsvcScoutResourceRange; + enumMap["MinWorkerAttackersHarvesting"] = aibsvcMinWorkerAttackersHarvesting; +} class FactionType { public: @@ -54,7 +85,7 @@ private: std::map > mapAIBehaviorUnitCategories; std::vector vctAIBehaviorUpgrades; - int aIBehavior_minStaticResourceCount; + std::map mapAIBehaviorStaticOverrideValues; public: //init @@ -65,7 +96,7 @@ public: const std::vector getAIBehaviorUnits(AIBehaviorUnitCategory category) const; const std::vector getAIBehaviorUpgrades() const { return vctAIBehaviorUpgrades; }; - int getAIBehaviorMinStaticResourceCount() const { return aIBehavior_minStaticResourceCount; } + int getAIBehaviorStaticOverideValue(AIBehaviorStaticValueCategory type) const; //get int getUnitTypeCount() const {return unitTypes.size();} diff --git a/source/shared_lib/include/util/util.h b/source/shared_lib/include/util/util.h index a3813cf2..408e9137 100644 --- a/source/shared_lib/include/util/util.h +++ b/source/shared_lib/include/util/util.h @@ -244,7 +244,6 @@ public: } }; - }}//end namespace #endif