浏览代码

#3824 - fix empty army with only commander issues

Andrii Danylchenko 1 年之前
父节点
当前提交
6e641dbdea

+ 3 - 0
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);

+ 12 - 0
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;
+}
+
 }

+ 2 - 0
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<std::chrono::high_resolution_clock> start);
 
 // todo: move to obj manager

+ 9 - 0
AI/Nullkiller/Analyzers/ArmyManager.cpp

@@ -136,6 +136,10 @@ public:
 std::vector<SlotInfo> 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<FactionID, uint64_t> alignmentMap;
 
 	for(auto & slot : sortedSlots)
@@ -348,6 +352,11 @@ std::vector<creInfo> 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();

+ 6 - 1
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<const CGHeroInstance *>(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:

+ 7 - 2
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -1354,7 +1354,12 @@ void AINodeStorage::calculateChainInfo(std::vector<AIPath> & 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

+ 2 - 2
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)