diff --git a/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp b/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp index 3e422a376..1d1fdafe9 100644 --- a/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp +++ b/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp @@ -283,6 +283,17 @@ void BuildAnalyzer::updateDailyIncome() } } +bool BuildAnalyzer::hasAnyBuilding(int32_t alignment, BuildingID bid) const +{ + for(auto tdi : developmentInfos) + { + if(tdi.town->alignment == alignment && tdi.town->hasBuilt(bid)) + return true; + } + + return false; +} + void TownDevelopmentInfo::addExistingDwelling(const BuildingInfo & existingDwelling) { existingDwellings.push_back(existingDwelling); diff --git a/AI/Nullkiller/Analyzers/BuildAnalyzer.h b/AI/Nullkiller/Analyzers/BuildAnalyzer.h index c15c8d9cd..1b028a319 100644 --- a/AI/Nullkiller/Analyzers/BuildAnalyzer.h +++ b/AI/Nullkiller/Analyzers/BuildAnalyzer.h @@ -81,6 +81,7 @@ public: const std::vector & getDevelopmentInfo() const { return developmentInfos; } TResources getDailyIncome() const { return dailyIncome; } float getGoldPreasure() const { return goldPreasure; } + bool hasAnyBuilding(int32_t alignment, BuildingID bid) const; private: BuildingInfo getBuildingOrPrerequisite( diff --git a/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp b/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp index 5171ca342..5259acc9b 100644 --- a/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp +++ b/AI/Nullkiller/Analyzers/ObjectClusterizer.cpp @@ -72,6 +72,11 @@ std::vector ObjectClusterizer::getNearbyObjects() cons return nearObjects.getObjects(); } +std::vector ObjectClusterizer::getFarObjects() const +{ + return farObjects.getObjects(); +} + std::vector> ObjectClusterizer::getLockedClusters() const { std::vector> result; diff --git a/AI/Nullkiller/Analyzers/ObjectClusterizer.h b/AI/Nullkiller/Analyzers/ObjectClusterizer.h index 951310deb..a602f3a44 100644 --- a/AI/Nullkiller/Analyzers/ObjectClusterizer.h +++ b/AI/Nullkiller/Analyzers/ObjectClusterizer.h @@ -55,6 +55,7 @@ private: public: void clusterize(); std::vector getNearbyObjects() const; + std::vector getFarObjects() const; std::vector> getLockedClusters() const; const CGObjectInstance * getBlocker(const AIPath & path) const; diff --git a/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp b/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp index 389035de2..b788c4d1d 100644 --- a/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp +++ b/AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp @@ -178,6 +178,11 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const #endif vstd::concatenate(tasks, getVisitGoals(paths, objToVisit)); } + + vstd::erase_if(tasks, [](TSubgoal task) -> bool + { + return task->invalid(); + }); }; if(specificObjects) @@ -187,12 +192,10 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const else { captureObjects(ai->nullkiller->objectClusterizer->getNearbyObjects()); - } - vstd::erase_if(tasks, [](TSubgoal task) -> bool - { - return task->invalid(); - }); + if(tasks.empty()) + captureObjects(ai->nullkiller->objectClusterizer->getFarObjects()); + } return tasks; } diff --git a/AI/Nullkiller/Behaviors/StartupBehavior.cpp b/AI/Nullkiller/Behaviors/StartupBehavior.cpp index a0b4ca4e0..898ebf5dc 100644 --- a/AI/Nullkiller/Behaviors/StartupBehavior.cpp +++ b/AI/Nullkiller/Behaviors/StartupBehavior.cpp @@ -73,7 +73,9 @@ bool needToRecruitHero(const CGTownInstance * startupTown) auto heroToCheck = startupTown->garrisonHero ? startupTown->garrisonHero.get() : startupTown->visitingHero.get(); auto paths = cb->getPathsInfo(heroToCheck); - for(auto obj : ai->visitableObjs) + int treasureSourcesCount = 0; + + for(auto obj : ai->nullkiller->objectClusterizer->getNearbyObjects()) { if(obj->ID == Obj::RESOURCE && obj->subID == Res::GOLD || obj->ID == Obj::TREASURE_CHEST @@ -84,12 +86,15 @@ bool needToRecruitHero(const CGTownInstance * startupTown) if((path->accessible == CGPathNode::BLOCKVIS || path->accessible == CGPathNode::VISIT) && path->reachable()) { - return true; + treasureSourcesCount++; } } } - return false; + auto basicCount = cb->getTownsInfo().size() + 2; + auto boost = (int)std::floor(std::pow(treasureSourcesCount / 3.0, 2)); + + return cb->getHeroCount(ai->playerID, true) < basicCount + boost; } Goals::TGoalVec StartupBehavior::decompose() const diff --git a/AI/Nullkiller/Engine/PriorityEvaluator.cpp b/AI/Nullkiller/Engine/PriorityEvaluator.cpp index 12a7cee98..4663775c1 100644 --- a/AI/Nullkiller/Engine/PriorityEvaluator.cpp +++ b/AI/Nullkiller/Engine/PriorityEvaluator.cpp @@ -530,6 +530,8 @@ public: evaluationContext.movementCostByRole[role] += objInfo.second.movementCost / boost; evaluationContext.movementCost += objInfo.second.movementCost / boost; + vstd::amax(evaluationContext.turn, objInfo.second.turn / boost); + boost <<= 1; if(boost > 8) @@ -538,7 +540,6 @@ public: const AIPath & pathToCenter = clusterGoal.getPathToCenter(); - vstd::amax(evaluationContext.turn, pathToCenter.turn()); } }; @@ -561,10 +562,9 @@ public: if(bi.creatureID != CreatureID::NONE) { - evaluationContext.strategicalValue += (0.5f + 0.1f * bi.creatureLevel) / (float)bi.prerequisitesCount; - if(bi.baseCreatureID == bi.creatureID) { + evaluationContext.strategicalValue += 0.5f + 0.1f * bi.creatureLevel / (float)bi.prerequisitesCount; evaluationContext.armyReward += ai->ah->evaluateStackPower(bi.creatureID.toCreature(), bi.creatureGrows); } else @@ -572,7 +572,10 @@ public: auto creaturesToUpgrade = ai->ah->getTotalCreaturesAvailable(bi.baseCreatureID); auto upgradedPower = ai->ah->evaluateStackPower(bi.creatureID.toCreature(), creaturesToUpgrade.count); - evaluationContext.armyReward += upgradedPower - creaturesToUpgrade.power; + evaluationContext.strategicalValue += 0.05f * bi.creatureLevel / (float)bi.prerequisitesCount; + + if(!ai->nullkiller->buildAnalyzer->hasAnyBuilding(buildThis.town->alignment, bi.id)) + evaluationContext.armyReward += upgradedPower - creaturesToUpgrade.power; } } else diff --git a/AI/Nullkiller/Pathfinding/AINodeStorage.h b/AI/Nullkiller/Pathfinding/AINodeStorage.h index 9c9266e6f..de33caa7f 100644 --- a/AI/Nullkiller/Pathfinding/AINodeStorage.h +++ b/AI/Nullkiller/Pathfinding/AINodeStorage.h @@ -11,7 +11,7 @@ #pragma once #define PATHFINDER_TRACE_LEVEL 0 -#define AI_TRACE_LEVEL 1 +#define AI_TRACE_LEVEL 1 #include "../../../lib/CPathfinder.h" #include "../../../lib/mapObjects/CGHeroInstance.h"