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:
@@ -734,8 +734,8 @@ boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
|
|||||||
bs.canFlee = cb->battleCanFlee();
|
bs.canFlee = cb->battleCanFlee();
|
||||||
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
@@ -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();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user