diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index d2bc2fabb..55a5029a3 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -911,6 +911,9 @@ void AIGateway::moveCreaturesToHero(const CGTownInstance * t) void AIGateway::pickBestCreatures(const CArmedInstance * destinationArmy, const CArmedInstance * source) { + if(source->stacksCount() == 0) + return; + const CArmedInstance * armies[] = {destinationArmy, source}; auto bestArmy = nullkiller->armyManager->getBestArmy(destinationArmy, destinationArmy, source); diff --git a/AI/Nullkiller/AIUtility.cpp b/AI/Nullkiller/AIUtility.cpp index 8e5ae878d..462c56112 100644 --- a/AI/Nullkiller/AIUtility.cpp +++ b/AI/Nullkiller/AIUtility.cpp @@ -439,4 +439,16 @@ bool townHasFreeTavern(const CGTownInstance * town) return canMoveVisitingHeroToGarnison; } +uint64_t getHeroArmyStrengthWithCommander(const CGHeroInstance * hero, const CCreatureSet * heroArmy) +{ + auto armyStrength = heroArmy->getArmyStrength(); + + if(hero && hero->commander && hero->commander->alive) + { + armyStrength += 100 * hero->commander->level; + } + + return armyStrength; +} + } diff --git a/AI/Nullkiller/AIUtility.h b/AI/Nullkiller/AIUtility.h index 787913a43..ceba7909e 100644 --- a/AI/Nullkiller/AIUtility.h +++ b/AI/Nullkiller/AIUtility.h @@ -238,6 +238,8 @@ bool compareArmyStrength(const CArmedInstance * a1, const CArmedInstance * a2); bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2); bool townHasFreeTavern(const CGTownInstance * town); +uint64_t getHeroArmyStrengthWithCommander(const CGHeroInstance * hero, const CCreatureSet * heroArmy); + uint64_t timeElapsed(std::chrono::time_point start); // todo: move to obj manager diff --git a/AI/Nullkiller/Analyzers/ArmyManager.cpp b/AI/Nullkiller/Analyzers/ArmyManager.cpp index c1827547f..5c2a7f4a8 100644 --- a/AI/Nullkiller/Analyzers/ArmyManager.cpp +++ b/AI/Nullkiller/Analyzers/ArmyManager.cpp @@ -136,6 +136,10 @@ public: std::vector ArmyManager::getBestArmy(const IBonusBearer * armyCarrier, const CCreatureSet * target, const CCreatureSet * source) const { auto sortedSlots = getSortedSlots(target, source); + + if(source->stacksCount() == 0) + return sortedSlots; + std::map alignmentMap; for(auto & slot : sortedSlots) @@ -348,6 +352,11 @@ std::vector ArmyManager::getArmyAvailableToBuy( ui64 ArmyManager::howManyReinforcementsCanGet(const IBonusBearer * armyCarrier, const CCreatureSet * target, const CCreatureSet * source) const { + if(source->stacksCount() == 0) + { + return 0; + } + auto bestArmy = getBestArmy(armyCarrier, target, source); uint64_t newArmy = 0; uint64_t oldArmy = target->getArmyStrength(); diff --git a/AI/Nullkiller/Engine/FuzzyHelper.cpp b/AI/Nullkiller/Engine/FuzzyHelper.cpp index 6b7acbc67..ed7abb7c1 100644 --- a/AI/Nullkiller/Engine/FuzzyHelper.cpp +++ b/AI/Nullkiller/Engine/FuzzyHelper.cpp @@ -145,6 +145,12 @@ ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj) return danger; } + case Obj::HERO: + { + const CGHeroInstance * hero = dynamic_cast(obj); + return getHeroArmyStrengthWithCommander(hero, hero); + } + case Obj::ARTIFACT: case Obj::RESOURCE: { @@ -153,7 +159,6 @@ ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj) [[fallthrough]]; } case Obj::MONSTER: - case Obj::HERO: case Obj::GARRISON: case Obj::GARRISON2: case Obj::CREATURE_GENERATOR1: diff --git a/AI/Nullkiller/Pathfinding/AINodeStorage.cpp b/AI/Nullkiller/Pathfinding/AINodeStorage.cpp index 8c2b6f01b..5940d83ec 100644 --- a/AI/Nullkiller/Pathfinding/AINodeStorage.cpp +++ b/AI/Nullkiller/Pathfinding/AINodeStorage.cpp @@ -1354,7 +1354,12 @@ void AINodeStorage::calculateChainInfo(std::vector & paths, const int3 & path.heroArmy = node.actor->creatureSet; path.armyLoss = node.armyLoss; path.targetObjectDanger = evaluateDanger(pos, path.targetHero, !node.actor->allowBattle); - path.targetObjectArmyLoss = evaluateArmyLoss(path.targetHero, path.heroArmy->getArmyStrength(), path.targetObjectDanger); + + path.targetObjectArmyLoss = evaluateArmyLoss( + path.targetHero, + getHeroArmyStrengthWithCommander(path.targetHero, path.heroArmy), + path.targetObjectDanger); + path.chainMask = node.actor->chainMask; path.exchangeCount = node.actor->actorExchangeCount; @@ -1473,7 +1478,7 @@ uint8_t AIPath::turn() const uint64_t AIPath::getHeroStrength() const { - return targetHero->getFightingStrength() * heroArmy->getArmyStrength(); + return targetHero->getFightingStrength() * getHeroArmyStrengthWithCommander(targetHero, heroArmy); } uint64_t AIPath::getTotalDanger() const diff --git a/AI/Nullkiller/Pathfinding/Actors.cpp b/AI/Nullkiller/Pathfinding/Actors.cpp index 71259fa05..cccd55a57 100644 --- a/AI/Nullkiller/Pathfinding/Actors.cpp +++ b/AI/Nullkiller/Pathfinding/Actors.cpp @@ -45,7 +45,7 @@ ChainActor::ChainActor(const CGHeroInstance * hero, HeroRole heroRole, uint64_t layer = hero->boat ? hero->boat->layer : EPathfindingLayer::LAND; initialMovement = hero->movementPointsRemaining(); initialTurn = 0; - armyValue = hero->getArmyStrength(); + armyValue = getHeroArmyStrengthWithCommander(hero, hero); heroFightingStrength = hero->getFightingStrength(); tiCache.reset(new TurnInfo(hero)); } @@ -55,7 +55,7 @@ ChainActor::ChainActor(const ChainActor * carrier, const ChainActor * other, con baseActor(this), carrierParent(carrier), otherParent(other), heroFightingStrength(carrier->heroFightingStrength), actorExchangeCount(carrier->actorExchangeCount + other->actorExchangeCount), armyCost(carrier->armyCost + other->armyCost), actorAction() { - armyValue = heroArmy->getArmyStrength(); + armyValue = getHeroArmyStrengthWithCommander(hero, heroArmy); } ChainActor::ChainActor(const CGObjectInstance * obj, const CCreatureSet * creatureSet, uint64_t chainMask, int initialTurn)