From 9012560e38934191fb9d64398c94432f1f013c71 Mon Sep 17 00:00:00 2001 From: Xilmi Date: Mon, 16 Dec 2024 17:19:07 +0100 Subject: [PATCH 1/4] Fix for AI not recognizing 2nd T7-building of Factory as dwelling This lead to it being built dead-last in the build-order instead of the AI trying to go for it quite early. --- AI/Nullkiller/Analyzers/BuildAnalyzer.cpp | 6 +++--- lib/constants/EntityIdentifiers.h | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp b/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp index 01dfa0a82..4310e31af 100644 --- a/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp +++ b/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp @@ -212,7 +212,7 @@ BuildingInfo BuildAnalyzer::getBuildingOrPrerequisite( int creatureLevel = -1; int creatureUpgrade = 0; - if(BuildingID::DWELL_FIRST <= toBuild && toBuild <= BuildingID::DWELL_UP_LAST) + if(toBuild.IsDwelling()) { creatureLevel = BuildingID::getLevelFromDwelling(toBuild); creatureUpgrade = BuildingID::getUpgradedFromDwelling(toBuild); @@ -271,7 +271,7 @@ BuildingInfo BuildAnalyzer::getBuildingOrPrerequisite( auto otherDwelling = [](const BuildingID & id) -> bool { - return BuildingID::DWELL_FIRST <= id && id <= BuildingID::DWELL_UP_LAST; + return id.IsDwelling(); }; if(vstd::contains_if(missingBuildings, otherDwelling)) @@ -420,7 +420,7 @@ BuildingInfo::BuildingInfo( } else { - if(BuildingID::DWELL_FIRST <= id && id <= BuildingID::DWELL_UP_LAST) + if(id.IsDwelling()) { creatureGrows = creature->getGrowth(); diff --git a/lib/constants/EntityIdentifiers.h b/lib/constants/EntityIdentifiers.h index 3bc547247..8637d9182 100644 --- a/lib/constants/EntityIdentifiers.h +++ b/lib/constants/EntityIdentifiers.h @@ -366,6 +366,11 @@ public: dwelling.advance(GameConstants::CREATURES_PER_TOWN - 1); } + bool IsDwelling() const + { + return (DWELL_FIRST <= num && num <= DWELL_UP_LAST) || (DWELL_LVL_8 <= num && num <= DWELL_LVL_8_UP) || num == DWELL_UP2_FIRST; + } + bool IsSpecialOrGrail() const { return num == SPECIAL_1 || num == SPECIAL_2 || num == SPECIAL_3 || num == SPECIAL_4 || num == GRAIL; From 99fcf136ec2b2fbf50b5de2686df7b84b817acd0 Mon Sep 17 00:00:00 2001 From: Xilmi Date: Mon, 16 Dec 2024 23:45:21 +0100 Subject: [PATCH 2/4] Nullkiller AI is now also capable of upgrading dwellings a second time if that's possible --- AI/Nullkiller/Analyzers/BuildAnalyzer.cpp | 2 +- lib/constants/EntityIdentifiers.h | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp b/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp index 4310e31af..062744bd5 100644 --- a/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp +++ b/AI/Nullkiller/Analyzers/BuildAnalyzer.cpp @@ -36,7 +36,7 @@ void BuildAnalyzer::updateTownDwellings(TownDevelopmentInfo & developmentInfo) logAi->trace("Checking dwelling level %d", level); BuildingInfo nextToBuild = BuildingInfo(); - for(int upgradeIndex : {1, 0}) + for(int upgradeIndex : {2, 1, 0}) { BuildingID building = BuildingID(BuildingID::getDwellingFromLevel(level, upgradeIndex)); if(!vstd::contains(buildings, building)) diff --git a/lib/constants/EntityIdentifiers.h b/lib/constants/EntityIdentifiers.h index 8637d9182..171613a19 100644 --- a/lib/constants/EntityIdentifiers.h +++ b/lib/constants/EntityIdentifiers.h @@ -306,6 +306,7 @@ public: DWELL_LVL_7_UP = DWELL_UP_LAST, DWELL_UP2_FIRST = DWELL_LVL_7_UP + 1, + DWELL_LVL_1_UP2 = DWELL_UP2_FIRST, DWELL_LVL_2_UP2, DWELL_LVL_3_UP2, DWELL_LVL_4_UP2, DWELL_LVL_5_UP2, DWELL_LVL_6_UP2, DWELL_LVL_7_UP2, DWELL_LVL_8_UP2, // //Special buildings for towns. CASTLE_GATE = SPECIAL_3, //Inferno @@ -319,7 +320,8 @@ private: { std::vector dwellings = { DWELL_LVL_1, DWELL_LVL_2, DWELL_LVL_3, DWELL_LVL_4, DWELL_LVL_5, DWELL_LVL_6, DWELL_LVL_7, DWELL_LVL_8 }; std::vector dwellingsUp = { DWELL_LVL_1_UP, DWELL_LVL_2_UP, DWELL_LVL_3_UP, DWELL_LVL_4_UP, DWELL_LVL_5_UP, DWELL_LVL_6_UP, DWELL_LVL_7_UP, DWELL_LVL_8_UP }; - return {dwellings, dwellingsUp}; + std::vector dwellingsUp2 = { DWELL_UP2_FIRST, DWELL_LVL_2_UP2, DWELL_LVL_3_UP2, DWELL_LVL_4_UP2, DWELL_LVL_5_UP2 , DWELL_LVL_6_UP2 , DWELL_LVL_7_UP2, DWELL_LVL_8_UP2 }; + return {dwellings, dwellingsUp, dwellingsUp2 }; } public: @@ -339,6 +341,8 @@ public: } if(dwelling >= BuildingIDBase::DWELL_LVL_8 && dwelling < BuildingIDBase::DWELL_LVL_8 + 5) return 7; + else if (dwelling >= BuildingIDBase::DWELL_UP2_FIRST) + return (dwelling - DWELL_UP2_FIRST) % (GameConstants::CREATURES_PER_TOWN - 1); else return (dwelling - DWELL_FIRST) % (GameConstants::CREATURES_PER_TOWN - 1); } @@ -354,6 +358,8 @@ public: } if(dwelling >= BuildingIDBase::DWELL_LVL_8 && dwelling < BuildingIDBase::DWELL_LVL_8 + 5) return dwelling - BuildingIDBase::DWELL_LVL_8; + else if (dwelling >= BuildingIDBase::DWELL_UP2_FIRST) + return (dwelling - DWELL_UP2_FIRST) / (GameConstants::CREATURES_PER_TOWN - 1); else return (dwelling - DWELL_FIRST) / (GameConstants::CREATURES_PER_TOWN - 1); } @@ -368,7 +374,7 @@ public: bool IsDwelling() const { - return (DWELL_FIRST <= num && num <= DWELL_UP_LAST) || (DWELL_LVL_8 <= num && num <= DWELL_LVL_8_UP) || num == DWELL_UP2_FIRST; + return (DWELL_FIRST <= num && num <= DWELL_UP_LAST) || (DWELL_LVL_8 <= num && num <= DWELL_LVL_8_UP) || (num >= DWELL_UP2_FIRST && num < DWELL_LVL_8); } bool IsSpecialOrGrail() const From aff73b6e65f5808cebba7ce7f5d6518c1030c94b Mon Sep 17 00:00:00 2001 From: Xilmi Date: Tue, 17 Dec 2024 12:02:58 +0100 Subject: [PATCH 3/4] Be less wasteful with hiring heroes When an enemy is near our city that currently has a hero hiding in it, we don't buy a hero without army as that one would be forced to wait outside and likely be killed. --- AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp b/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp index fd87347a6..ef4811ab7 100644 --- a/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp +++ b/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp @@ -97,6 +97,10 @@ Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * ai) const for(auto hero : availableHeroes) { + if ((town->visitingHero || town->garrisonHero) + && closestThreat < 0 + && hero->getArmyCost() < GameConstants::HERO_GOLD_COST / 3.0) + continue; auto score = ai->heroManager->evaluateHero(hero); if(score > minScoreToHireMain) { From 64ad060846388b9959b1edbbe85f8728fcb1067b Mon Sep 17 00:00:00 2001 From: Xilmi Date: Tue, 17 Dec 2024 12:03:46 +0100 Subject: [PATCH 4/4] Update RecruitHeroBehavior.cpp closestThreat was supposed to be < 1, not < 0 --- AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp b/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp index ef4811ab7..f6c01ef4c 100644 --- a/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp +++ b/AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp @@ -98,7 +98,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * ai) const for(auto hero : availableHeroes) { if ((town->visitingHero || town->garrisonHero) - && closestThreat < 0 + && closestThreat < 1 && hero->getArmyCost() < GameConstants::HERO_GOLD_COST / 3.0) continue; auto score = ai->heroManager->evaluateHero(hero);