From 8729c32b68f30f75afdf246f9ff23aa1c3fbad43 Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Tue, 4 Oct 2011 06:49:44 +0000 Subject: [PATCH] - bugfix AI, no longer try to build a farm type unit if the faction does not have a unit that is able to build it yet - new optional feature added to tell each faction some basic info regarding which units should take priority when building,producing and morphing --- source/glest_game/ai/ai_rule.cpp | 112 ++++++++++++++++--- source/glest_game/type_instances/faction.cpp | 56 ++++++++++ source/glest_game/type_instances/faction.h | 2 + source/glest_game/types/faction_type.cpp | 53 +++++++++ source/glest_game/types/faction_type.h | 14 ++- 5 files changed, 220 insertions(+), 17 deletions(-) diff --git a/source/glest_game/ai/ai_rule.cpp b/source/glest_game/ai/ai_rule.cpp index 10d983c8..de91de82 100644 --- a/source/glest_game/ai/ai_rule.cpp +++ b/source/glest_game/ai/ai_rule.cpp @@ -536,11 +536,14 @@ bool AiRuleBuildOneFarm::test(){ const Resource *r= producedType->getCost(k); //find a food producer in the farm produced units - if(r->getAmount()<0 && r->getType()->getClass()==rcConsumable && ai->getCountOfType(ut)==0){ - farm= ut; + if(r->getAmount() < 0 && r->getType()->getClass() == rcConsumable && ai->getCountOfType(ut) == 0) { + if(aiInterface->reqsOk(ct) && aiInterface->getMyFaction()->canCreateUnit(ut, true, true, true) == true) { + farm= ut; + //printf("AiRuleBuildOneFarm returning true, RULE Name[%s] ut [%s] producedType [%s]\n",this->getName().c_str(),ut->getName().c_str(),producedType->getName().c_str()); - if(ai->outputAIBehaviourToConsole()) printf("AiRuleBuildOneFarm returning true, RULE Name[%s]\n",this->getName().c_str()); - return true; + if(ai->outputAIBehaviourToConsole()) printf("AiRuleBuildOneFarm returning true, RULE Name[%s]\n",this->getName().c_str()); + return true; + } } } } @@ -652,21 +655,67 @@ void AiRuleProduce::execute(){ } } -void AiRuleProduce::produceGeneric(const ProduceTask *pt){ +void AiRuleProduce::produceGeneric(const ProduceTask *pt) { typedef vector UnitTypes; UnitTypes ableUnits; AiInterface *aiInterface= ai->getAiInterface(); + if(pt->getResourceType() != NULL) { + if(aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcResourceProducerUnits).size() > 0) { + const std::vector &unitList = aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcResourceProducerUnits); + for(unsigned int i = 0; i < unitList.size(); ++i) { + const FactionType::PairPUnitTypeInt &priorityUnit = unitList[i]; + if(ai->getCountOfType(priorityUnit.first) < priorityUnit.second && + aiInterface->getMyFaction()->canCreateUnit(priorityUnit.first, false, true, true) == true) { + //if(ai->getRandom()->randRange(0, 1)==0) { + ai->addTask(new ProduceTask(priorityUnit.first)); + return; + //} + } + } + } + } + else if(pt->getUnitClass() == ucWorker) { + if(aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcWorkerUnits).size() > 0) { + const std::vector &unitList = aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcWorkerUnits); + for(unsigned int i = 0; i < unitList.size(); ++i) { + const FactionType::PairPUnitTypeInt &priorityUnit = unitList[i]; + if(ai->getCountOfType(priorityUnit.first) < priorityUnit.second && + aiInterface->getMyFaction()->canCreateUnit(priorityUnit.first, false, true, true) == true) { + //if(ai->getRandom()->randRange(0, 1)==0) { + ai->addTask(new ProduceTask(priorityUnit.first)); + return; + //} + } + } + } + } + else if(pt->getUnitClass() == ucWarrior) { + if(aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcWarriorUnits).size() > 0) { + const std::vector &unitList = aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcWarriorUnits); + for(unsigned int i = 0; i < unitList.size(); ++i) { + const FactionType::PairPUnitTypeInt &priorityUnit = unitList[i]; + if(ai->getCountOfType(priorityUnit.first) < priorityUnit.second && + aiInterface->getMyFaction()->canCreateUnit(priorityUnit.first, false, true, true) == true) { + //if(ai->getRandom()->randRange(0, 1)==0) { + ai->addTask(new ProduceTask(priorityUnit.first)); + return; + //} + } + } + } + } + //for each unit, produce it if possible - for(int i=0; igetMyUnitCount(); ++i){ + for(int i = 0; i < aiInterface->getMyUnitCount(); ++i) { //for each command const UnitType *ut= aiInterface->getMyUnit(i)->getType(); - for(int j=0; jgetCommandTypeCount(); ++j){ + for(int j = 0; j < ut->getCommandTypeCount(); ++j) { const CommandType *ct= ut->getCommandType(j); //if the command is produce - if(ct->getClass()==ccProduce || ct->getClass()==ccMorph){ + if(ct->getClass() == ccProduce || ct->getClass()==ccMorph) { const UnitType *producedUnit= static_cast(ct->getProduced()); bool produceIt= false; @@ -674,19 +723,19 @@ void AiRuleProduce::produceGeneric(const ProduceTask *pt){ if(ai->outputAIBehaviourToConsole()) printf("produceGeneric [%p] Testing AI RULE Name[%s]\n",pt->getResourceType(), this->getName().c_str()); //if the unit produces the resource - if(pt->getResourceType()!=NULL){ + if(pt->getResourceType() != NULL) { const Resource *r= producedUnit->getCost(pt->getResourceType()); if(r != NULL) { if(ai->outputAIBehaviourToConsole()) printf("produceGeneric r = [%s][%d] Testing AI RULE Name[%s]\n",r->getDescription().c_str(),r->getAmount(), this->getName().c_str()); } - if(r!=NULL && r->getAmount()<0){ + if(r != NULL && r->getAmount() < 0) { produceIt= true; } } - else{ + else { //if the unit is from the right class if(ai->outputAIBehaviourToConsole()) printf("produceGeneric right class = [%d] Testing AI RULE Name[%s]\n",producedUnit->isOfClass(pt->getUnitClass()), this->getName().c_str()); @@ -697,7 +746,7 @@ void AiRuleProduce::produceGeneric(const ProduceTask *pt){ } } - if(produceIt){ + if(produceIt) { //if the unit is not already on the list if(find(ableUnits.begin(), ableUnits.end(), producedUnit)==ableUnits.end()){ ableUnits.push_back(producedUnit); @@ -708,13 +757,13 @@ void AiRuleProduce::produceGeneric(const ProduceTask *pt){ } //add specific produce task - if(!ableUnits.empty()){ + if(ableUnits.empty() == false) { if(ai->outputAIBehaviourToConsole()) printf("produceGeneric !ableUnits.empty(), ableUnits.size() = [%d] Testing AI RULE Name[%s]\n",(int)ableUnits.size(), this->getName().c_str()); //priority for non produced units - for(unsigned int i=0; igetCountOfType(ableUnits[i])==0){ + for(unsigned int i=0; i < ableUnits.size(); ++i) { + if(ai->getCountOfType(ableUnits[i]) == 0) { if(ai->getRandom()->randRange(0, 1)==0){ ai->addTask(new ProduceTask(ableUnits[i])); return; @@ -1023,13 +1072,44 @@ void AiRuleBuild::execute() { } } -void AiRuleBuild::buildGeneric(const BuildTask *bt){ +void AiRuleBuild::buildGeneric(const BuildTask *bt) { //find buildings that can be built AiInterface *aiInterface= ai->getAiInterface(); typedef vector UnitTypes; UnitTypes buildings; + if(bt->getResourceType() != NULL) { + if(aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcResourceProducerUnits).size() > 0) { + const std::vector &unitList = aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcResourceProducerUnits); + for(unsigned int i = 0; i < unitList.size(); ++i) { + const FactionType::PairPUnitTypeInt &priorityUnit = unitList[i]; + if(ai->getCountOfType(priorityUnit.first) < priorityUnit.second && + aiInterface->getMyFaction()->canCreateUnit(priorityUnit.first, true, false, false) == true) { + //if(ai->getRandom()->randRange(0, 1)==0) { + ai->addTask(new BuildTask(priorityUnit.first)); + return; + //} + } + } + } + } + else { + if(aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcBuildingUnits).size() > 0) { + const std::vector &unitList = aiInterface->getMyFactionType()->getAIBehaviorUnits(aibcBuildingUnits); + for(unsigned int i = 0; i < unitList.size(); ++i) { + const FactionType::PairPUnitTypeInt &priorityUnit = unitList[i]; + if(ai->getCountOfType(priorityUnit.first) < priorityUnit.second && + aiInterface->getMyFaction()->canCreateUnit(priorityUnit.first, true, false, false) == true) { + //if(ai->getRandom()->randRange(0, 1)==0) { + ai->addTask(new BuildTask(priorityUnit.first)); + return; + //} + } + } + } + } + //for each unit for(int i=0; igetMyUnitCount(); ++i){ diff --git a/source/glest_game/type_instances/faction.cpp b/source/glest_game/type_instances/faction.cpp index 95b7ee35..0652606f 100644 --- a/source/glest_game/type_instances/faction.cpp +++ b/source/glest_game/type_instances/faction.cpp @@ -1588,6 +1588,62 @@ void Faction::setSwitchTeamVote(SwitchTeamVote &vote) { switchTeamVotes[vote.factionIndex] = vote; } +bool Faction::canCreateUnit(const UnitType *ut, bool checkBuild, bool checkProduce, bool checkMorph) const { + // Now check that at least 1 other unit can produce, build or morph this unit + bool foundUnit = false; + for(int l = 0; l < this->getUnitCount() && foundUnit == false; ++l) { + const UnitType *unitType2 = this->getUnit(l)->getType(); + + for(int j = 0; j < unitType2->getCommandTypeCount() && foundUnit == false; ++j) { + const CommandType *cmdType = unitType2->getCommandType(j); + if(cmdType != NULL) { + // Check if this is a produce command + if(checkProduce == true && cmdType->getClass() == ccProduce) { + const ProduceCommandType *produce = dynamic_cast(cmdType); + if(produce != NULL) { + const UnitType *produceUnit = produce->getProducedUnit(); + + if( produceUnit != NULL && + ut->getId() != unitType2->getId() && + ut->getName() == produceUnit->getName()) { + foundUnit = true; + break; + } + } + } + // Check if this is a build command + else if(checkBuild == true && cmdType->getClass() == ccBuild) { + const BuildCommandType *build = dynamic_cast(cmdType); + for(int k = 0; k < build->getBuildingCount() && foundUnit == false; ++k) { + const UnitType *buildUnit = build->getBuilding(k); + + if( buildUnit != NULL && + ut->getId() != unitType2->getId() && + ut->getName() == buildUnit->getName()) { + foundUnit = true; + break; + } + } + } + // Check if this is a morph command + else if(checkMorph == true && cmdType->getClass() == ccMorph) { + const MorphCommandType *morph = dynamic_cast(cmdType); + const UnitType *morphUnit = morph->getMorphUnit(); + + if( morphUnit != NULL && + ut->getId() != unitType2->getId() && + ut->getName() == morphUnit->getName()) { + foundUnit = true; + break; + } + } + } + } + } + + return foundUnit; +} + std::string Faction::toString() const { std::string result = ""; diff --git a/source/glest_game/type_instances/faction.h b/source/glest_game/type_instances/faction.h index b476e12c..4af5c966 100644 --- a/source/glest_game/type_instances/faction.h +++ b/source/glest_game/type_instances/faction.h @@ -248,6 +248,8 @@ public: void sortUnitsByCommandGroups(); + bool canCreateUnit(const UnitType *ut, bool checkBuild, bool checkProduce, bool checkMorph) const; + std::string toString() const; private: diff --git a/source/glest_game/types/faction_type.cpp b/source/glest_game/types/faction_type.cpp index 9323a249..6a33ce56 100644 --- a/source/glest_game/types/faction_type.cpp +++ b/source/glest_game/types/faction_type.cpp @@ -163,10 +163,63 @@ void FactionType::load(const string &dir, const TechTree *techTree, Checksum* ch music->open(musicNode->getAttribute("path")->getRestrictedValue(currentPath)); loadedFileList[musicNode->getAttribute("path")->getRestrictedValue(currentPath)].push_back(make_pair(path,musicNode->getAttribute("path")->getRestrictedValue())); } + + //read ai behavior + if(factionNode->hasChild("ai-behavior") == true) { + const XmlNode *aiNode= factionNode->getChild("ai-behavior"); + if(aiNode->hasChild("worker-units") == true) { + const XmlNode *aiNodeUnits= aiNode->getChild("worker-units"); + for(int i = 0; i < aiNodeUnits->getChildCount(); ++i) { + const XmlNode *unitNode= aiNodeUnits->getChild("unit", i); + string name= unitNode->getAttribute("name")->getRestrictedValue(); + int minimum= unitNode->getAttribute("minimum")->getIntValue(); + + mapAIBehaviorUnitCategories[aibcWorkerUnits].push_back(PairPUnitTypeInt(getUnitType(name), minimum)); + } + } + if(aiNode->hasChild("warrior-units") == true) { + const XmlNode *aiNodeUnits= aiNode->getChild("warrior-units"); + for(int i = 0; i < aiNodeUnits->getChildCount(); ++i) { + const XmlNode *unitNode= aiNodeUnits->getChild("unit", i); + string name= unitNode->getAttribute("name")->getRestrictedValue(); + int minimum= unitNode->getAttribute("minimum")->getIntValue(); + + mapAIBehaviorUnitCategories[aibcWarriorUnits].push_back(PairPUnitTypeInt(getUnitType(name), minimum)); + } + } + if(aiNode->hasChild("resource-producer-units") == true) { + const XmlNode *aiNodeUnits= aiNode->getChild("resource-producer-units"); + for(int i = 0; i < aiNodeUnits->getChildCount(); ++i) { + const XmlNode *unitNode= aiNodeUnits->getChild("unit", i); + string name= unitNode->getAttribute("name")->getRestrictedValue(); + int minimum= unitNode->getAttribute("minimum")->getIntValue(); + + mapAIBehaviorUnitCategories[aibcResourceProducerUnits].push_back(PairPUnitTypeInt(getUnitType(name), minimum)); + } + } + if(aiNode->hasChild("building-units") == true) { + const XmlNode *aiNodeUnits= aiNode->getChild("building-units"); + for(int i = 0; i < aiNodeUnits->getChildCount(); ++i) { + const XmlNode *unitNode= aiNodeUnits->getChild("unit", i); + string name= unitNode->getAttribute("name")->getRestrictedValue(); + int minimum= unitNode->getAttribute("minimum")->getIntValue(); + + mapAIBehaviorUnitCategories[aibcBuildingUnits].push_back(PairPUnitTypeInt(getUnitType(name), minimum)); + } + } + } } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } +const std::vector FactionType::getAIBehaviorUnits(AIBehaviorUnitCategory category) const { + std::map >::const_iterator iterFind = mapAIBehaviorUnitCategories.find(category); + if(iterFind != mapAIBehaviorUnitCategories.end()) { + return iterFind->second; + } + return std::vector(); +} + FactionType::~FactionType(){ delete music; music = NULL; diff --git a/source/glest_game/types/faction_type.h b/source/glest_game/types/faction_type.h index d6d33495..5fbbce0b 100644 --- a/source/glest_game/types/faction_type.h +++ b/source/glest_game/types/faction_type.h @@ -27,8 +27,16 @@ namespace Glest{ namespace Game{ /// Each of the possible factions the user can select // ===================================================== +enum AIBehaviorUnitCategory { + aibcWorkerUnits, + aibcWarriorUnits, + aibcResourceProducerUnits, + aibcBuildingUnits +}; + + class FactionType { -private: +public: typedef pair PairPUnitTypeInt; typedef vector UnitTypes; typedef vector UpgradeTypes; @@ -44,6 +52,8 @@ private: StrSound *music; FactionPersonalityType personalityType; + std::map > mapAIBehaviorUnitCategories; + public: //init FactionType(); @@ -51,6 +61,8 @@ public: Checksum *techtreeChecksum, std::map > > &loadedFileList); ~FactionType(); + const std::vector getAIBehaviorUnits(AIBehaviorUnitCategory category) const; + //get int getUnitTypeCount() const {return unitTypes.size();} int getUpgradeTypeCount() const {return upgradeTypes.size();}