1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

NKAI: hire retreated hero

This commit is contained in:
Andrii Danylchenko 2022-10-14 11:24:43 +03:00
parent 82a9f82e1c
commit 153cccdf46
4 changed files with 71 additions and 39 deletions

View File

@ -1401,7 +1401,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)
if(t->hasBuilt(BuildingID::TAVERN) && (!t->visitingHero || !t->garrisonHero))
return t;
return nullptr;
@ -1432,34 +1432,6 @@ void AIGateway::buildArmyIn(const CGTownInstance * t)
moveCreaturesToHero(t);
}
void AIGateway::recruitHero(const CGTownInstance * t, bool throwing)
{
logAi->debug("Trying to recruit a hero in %s at %s", t->name, t->visitablePos().toString());
auto heroes = cb->getAvailableHeroes(t);
if(heroes.size())
{
auto hero = heroes[0];
if(heroes.size() >= 2) //makes sense to recruit two heroes with starting amries in first week
{
if(heroes[1]->getTotalStrength() > hero->getTotalStrength())
hero = heroes[1];
}
cb->recruitHero(t, hero);
nullkiller->heroManager->update();
if(t->visitingHero)
moveHeroToTile(t->visitablePos(), t->visitingHero.get());
throw goalFulfilledException(sptr(Goals::RecruitHero(t)));
}
else if(throwing)
{
throw cannotFulfillGoalException("No available heroes in tavern in " + t->nodeName());
}
}
void AIGateway::finish()
{
//we want to lock to avoid multiple threads from calling makingTurn->join() at same time

View File

@ -177,7 +177,6 @@ public:
void endTurn();
// TODO: all the routines like recruiting hero or building army should be removed from here and extracted to elementar goals or whatever
void recruitHero(const CGTownInstance * t, bool throwing = false);
void recruitCreatures(const CGDwelling * d, const CArmedInstance * recruiter);
void pickBestCreatures(const CArmedInstance * army, const CArmedInstance * source); //called when we can't find a slot for new stack
void pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * other = nullptr);

View File

@ -34,10 +34,40 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const
Goals::TGoalVec tasks;
auto towns = cb->getTownsInfo();
auto ourHeroes = ai->nullkiller->heroManager->getHeroRoles();
auto minScoreToHireMain = std::numeric_limits<float>::max();
for(auto hero : ourHeroes)
{
if(hero.second != HeroRole::MAIN)
continue;
auto newScore = ai->nullkiller->heroManager->evaluateHero(hero.first.get());
if(minScoreToHireMain > newScore)
{
// weakest main hero score
minScoreToHireMain = newScore;
}
}
for(auto town : towns)
{
if(!town->garrisonHero && !town->visitingHero && ai->canRecruitAnyHero(town))
if((!town->garrisonHero || !town->visitingHero) && ai->canRecruitAnyHero(town))
{
auto availableHeroes = cb->getAvailableHeroes(town);
for(auto hero : availableHeroes)
{
auto score = ai->nullkiller->heroManager->evaluateHero(hero);
if(score > minScoreToHireMain)
{
tasks.push_back(Goals::sptr(Goals::RecruitHero(town, hero).setpriority(200)));
break;
}
}
if(cb->getHeroesInfo().size() < cb->getTownsInfo().size() + 1
|| (ai->nullkiller->getFreeResources()[Res::GOLD] > 10000
&& ai->nullkiller->buildAnalyzer->getGoldPreasure() < MAX_GOLD_PEASURE))

View File

@ -35,16 +35,47 @@ void RecruitHero::accept(AIGateway * ai)
if(!t) t = ai->findTownWithTavern();
if(t)
{
ai->recruitHero(t, true);
//TODO try to free way to blocked town
//TODO: adventure map tavern or prison?
}
else
if(!t)
{
throw cannotFulfillGoalException("No town to recruit hero!");
}
logAi->debug("Trying to recruit a hero in %s at %s", t->name, t->visitablePos().toString());
auto heroes = cb->getAvailableHeroes(t);
if(!heroes.size())
{
throw cannotFulfillGoalException("No available heroes in tavern in " + t->nodeName());
}
auto heroToHire = heroes[0];
for(auto hero : heroes)
{
if(objid == hero->id.getNum())
{
heroToHire = hero;
break;
}
if(hero->getTotalStrength() > heroToHire->getTotalStrength())
heroToHire = hero;
}
if(t->visitingHero)
{
if(t->garrisonHero)
throw cannotFulfillGoalException("Town " + t->nodeName() + " is occupied. Cannot recruit hero!");
cb->swapGarrisonHero(t);
}
cb->recruitHero(t, heroToHire);
ai->nullkiller->heroManager->update();
if(t->visitingHero)
ai->moveHeroToTile(t->visitablePos(), t->visitingHero.get());
}
}