1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +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

@@ -734,8 +734,8 @@ boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
bs.canFlee = cb->battleCanFlee();
bs.canSurrender = cb->battleCanSurrender(playerID);
bs.ourSide = cb->battleGetMySide();
bs.ourHero = cb->battleGetMyHero();
bs.enemyHero = cb->battleGetFightingHero(!bs.ourSide);
bs.ourHero = cb->battleGetMyHero();
bs.enemyHero = nullptr;
for(auto stack : cb->battleGetAllStacks(false))
{
@@ -744,7 +744,10 @@ boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
if(stack->side == bs.ourSide)
bs.ourStacks.push_back(stack);
else
{
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();
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);
}
@@ -1035,8 +1036,10 @@ bool AIGateway::canRecruitAnyHero(const CGTownInstance * t) const
//TODO: make gathering gold, building tavern or conquering town (?) possible subgoals
if(!t)
t = findTownWithTavern();
if(!t)
if(!t || !townHasFreeTavern(t))
return false;
if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
return false;
if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES)
@@ -1401,7 +1404,7 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade
const CGTownInstance * AIGateway::findTownWithTavern() const
{
for(const CGTownInstance * t : cb->getTownsInfo())
if(t->hasBuilt(BuildingID::TAVERN) && (!t->visitingHero || !t->garrisonHero))
if(townHasFreeTavern(t))
return t;
return nullptr;

View File

@@ -450,4 +450,14 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
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 compareArmyStrength(const CArmedInstance * a1, const CArmedInstance * 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);

View File

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

View File

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