1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-15 20:03:15 +02:00

NKAI: fix retreat logic

This commit is contained in:
Andrii Danylchenko
2022-10-15 15:05:20 +03:00
parent 153cccdf46
commit e9c725181c
6 changed files with 26 additions and 9 deletions

View File

@@ -735,7 +735,7 @@ boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
bs.canSurrender = cb->battleCanSurrender(playerID); bs.canSurrender = cb->battleCanSurrender(playerID);
bs.ourSide = cb->battleGetMySide(); bs.ourSide = cb->battleGetMySide();
bs.ourHero = cb->battleGetMyHero(); bs.ourHero = cb->battleGetMyHero();
bs.enemyHero = cb->battleGetFightingHero(!bs.ourSide); bs.enemyHero = nullptr;
for(auto stack : cb->battleGetAllStacks(false)) for(auto stack : cb->battleGetAllStacks(false))
{ {
@@ -744,7 +744,10 @@ boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
if(stack->side == bs.ourSide) if(stack->side == bs.ourSide)
bs.ourStacks.push_back(stack); bs.ourStacks.push_back(stack);
else else
{
bs.enemyStacks.push_back(stack); bs.enemyStacks.push_back(stack);
bs.enemyHero = cb->battleGetOwnerHero(stack);
}
} }
} }

View File

@@ -497,7 +497,8 @@ boost::optional<BattleAction> AIGateway::makeSurrenderRetreatDecision(
double fightRatio = battleState.getOurStrength() / (double)battleState.getEnemyStrength(); double fightRatio = battleState.getOurStrength() / (double)battleState.getEnemyStrength();
if(fightRatio < 0.3 && battleState.canFlee) // if we have no towns - things are already bad, so retreat is not an option.
if(cb->getTownsInfo().size() && fightRatio < 0.3 && battleState.canFlee)
{ {
return BattleAction::makeRetreat(battleState.ourSide); return BattleAction::makeRetreat(battleState.ourSide);
} }
@@ -1035,8 +1036,10 @@ bool AIGateway::canRecruitAnyHero(const CGTownInstance * t) const
//TODO: make gathering gold, building tavern or conquering town (?) possible subgoals //TODO: make gathering gold, building tavern or conquering town (?) possible subgoals
if(!t) if(!t)
t = findTownWithTavern(); t = findTownWithTavern();
if(!t)
if(!t || !townHasFreeTavern(t))
return false; return false;
if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
return false; return false;
if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES) if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES)
@@ -1401,7 +1404,7 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade
const CGTownInstance * AIGateway::findTownWithTavern() const const CGTownInstance * AIGateway::findTownWithTavern() const
{ {
for(const CGTownInstance * t : cb->getTownsInfo()) for(const CGTownInstance * t : cb->getTownsInfo())
if(t->hasBuilt(BuildingID::TAVERN) && (!t->visitingHero || !t->garrisonHero)) if(townHasFreeTavern(t))
return t; return t;
return nullptr; return nullptr;

View File

@@ -450,4 +450,14 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
return true; return true;
} }
bool townHasFreeTavern(const CGTownInstance * town)
{
if(!town->hasBuilt(BuildingID::TAVERN)) return false;
if(!town->visitingHero) return true;
bool canMoveVisitingHeroToGarnison = !town->getUpperArmy()->stacksCount();
return canMoveVisitingHeroToGarnison;
}
} }

View File

@@ -238,6 +238,7 @@ bool isSafeToVisit(HeroPtr h, const CCreatureSet *, uint64_t dangerStrength);
bool compareHeroStrength(HeroPtr h1, HeroPtr h2); bool compareHeroStrength(HeroPtr h1, HeroPtr h2);
bool compareArmyStrength(const CArmedInstance * a1, const CArmedInstance * a2); bool compareArmyStrength(const CArmedInstance * a1, const CArmedInstance * a2);
bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2); bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2);
bool townHasFreeTavern(const CGTownInstance * town);
uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock> start); uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock> start);

View File

@@ -53,7 +53,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const
for(auto town : towns) for(auto town : towns)
{ {
if((!town->garrisonHero || !town->visitingHero) && ai->canRecruitAnyHero(town)) if(ai->canRecruitAnyHero(town))
{ {
auto availableHeroes = cb->getAvailableHeroes(town); auto availableHeroes = cb->getAvailableHeroes(town);

View File

@@ -65,12 +65,12 @@ void RecruitHero::accept(AIGateway * ai)
if(t->visitingHero) if(t->visitingHero)
{ {
if(t->garrisonHero)
throw cannotFulfillGoalException("Town " + t->nodeName() + " is occupied. Cannot recruit hero!");
cb->swapGarrisonHero(t); cb->swapGarrisonHero(t);
} }
if(t->visitingHero)
throw cannotFulfillGoalException("Town " + t->nodeName() + " is occupied. Cannot recruit hero!");
cb->recruitHero(t, heroToHire); cb->recruitHero(t, heroToHire);
ai->nullkiller->heroManager->update(); ai->nullkiller->heroManager->update();