1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Fix hero count calculation for resourceful ai mod

This commit is contained in:
Andrii Danylchenko
2023-04-22 14:47:02 +03:00
parent a553a4aa66
commit d347db4c16
8 changed files with 57 additions and 51 deletions

View File

@@ -1058,27 +1058,6 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re
} }
} }
bool AIGateway::canRecruitAnyHero(const CGTownInstance * t) const
{
//TODO: make gathering gold, building tavern or conquering town (?) possible subgoals
if(!t)
t = findTownWithTavern();
if(!t || !townHasFreeTavern(t))
return false;
if(cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
return false;
if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES)
return false;
if(cb->getHeroesInfo().size() >= VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
return false;
if(!cb->getAvailableHeroes(t).size())
return false;
return true;
}
void AIGateway::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side) void AIGateway::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side)
{ {
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
@@ -1160,16 +1139,6 @@ void AIGateway::addVisitableObj(const CGObjectInstance * obj)
} }
} }
HeroPtr AIGateway::getHeroWithGrail() const
{
for(const CGHeroInstance * h : cb->getHeroesInfo())
{
if(h->hasArt(ArtifactID::GRAIL))
return h;
}
return nullptr;
}
bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h) bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
{ {
if(h->inTownGarrison && h->visitedTown) if(h->inTownGarrison && h->visitedTown)
@@ -1437,15 +1406,6 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade
} }
} }
const CGTownInstance * AIGateway::findTownWithTavern() const
{
for(const CGTownInstance * t : cb->getTownsInfo())
if(townHasFreeTavern(t))
return t;
return nullptr;
}
void AIGateway::endTurn() void AIGateway::endTurn()
{ {
logAi->info("Player %d (%s) ends turn", playerID, playerID.getStr()); logAi->info("Player %d (%s) ends turn", playerID, playerID.getStr());

View File

@@ -198,11 +198,6 @@ public:
void retrieveVisitableObjs(); void retrieveVisitableObjs();
virtual std::vector<const CGObjectInstance *> getFlaggedObjects() const; virtual std::vector<const CGObjectInstance *> getFlaggedObjects() const;
HeroPtr getHeroWithGrail() const;
const CGTownInstance * findTownWithTavern() const;
bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;
void requestSent(const CPackForServer * pack, int requestID) override; void requestSent(const CPackForServer * pack, int requestID) override;
void answerQuery(QueryID queryID, int selection); void answerQuery(QueryID queryID, int selection);
//special function that can be called ONLY from game events handling thread and will send request ASAP //special function that can be called ONLY from game events handling thread and will send request ASAP

View File

@@ -12,6 +12,8 @@
#include "../Engine/Nullkiller.h" #include "../Engine/Nullkiller.h"
#include "../../../lib/mapObjects/MapObjects.h" #include "../../../lib/mapObjects/MapObjects.h"
#include "../../../lib/CHeroHandler.h" #include "../../../lib/CHeroHandler.h"
#include "../../../lib/GameSettings.h"
#include "../../../lib/CGameState.h"
namespace NKAI namespace NKAI
{ {
@@ -179,6 +181,51 @@ float HeroManager::evaluateHero(const CGHeroInstance * hero) const
return evaluateFightingStrength(hero); return evaluateFightingStrength(hero);
} }
bool HeroManager::canRecruitHero(const CGTownInstance * town) const
{
if(!town)
town = findTownWithTavern();
if(!town || !townHasFreeTavern(town))
return false;
if(cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST)
return false;
const bool includeGarnisoned = true;
int heroCount = cb->getHeroCount(ai->playerID, includeGarnisoned);
if(heroCount >= ALLOWED_ROAMING_HEROES)
return false;
if(heroCount >= VLC->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
return false;
if(!cb->getAvailableHeroes(town).size())
return false;
return true;
}
const CGTownInstance * HeroManager::findTownWithTavern() const
{
for(const CGTownInstance * t : cb->getTownsInfo())
if(townHasFreeTavern(t))
return t;
return nullptr;
}
const CGHeroInstance * HeroManager::findHeroWithGrail() const
{
for(const CGHeroInstance * h : cb->getHeroesInfo())
{
if(h->hasArt(ArtifactID::GRAIL))
return h;
}
return nullptr;
}
SecondarySkillScoreMap::SecondarySkillScoreMap(std::map<SecondarySkill, float> scoreMap) SecondarySkillScoreMap::SecondarySkillScoreMap(std::map<SecondarySkill, float> scoreMap)
:scoreMap(scoreMap) :scoreMap(scoreMap)
{ {

View File

@@ -30,6 +30,8 @@ public:
virtual void update() = 0; virtual void update() = 0;
virtual float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const = 0; virtual float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const = 0;
virtual float evaluateHero(const CGHeroInstance * hero) const = 0; virtual float evaluateHero(const CGHeroInstance * hero) const = 0;
virtual bool canRecruitHero(const CGTownInstance * t = nullptr) const = 0;
virtual const CGHeroInstance * findHeroWithGrail() const = 0;
}; };
class DLL_EXPORT ISecondarySkillRule class DLL_EXPORT ISecondarySkillRule
@@ -57,20 +59,24 @@ private:
static SecondarySkillEvaluator scountSkillsScores; static SecondarySkillEvaluator scountSkillsScores;
CCallback * cb; //this is enough, but we downcast from CCallback CCallback * cb; //this is enough, but we downcast from CCallback
const Nullkiller * ai;
std::map<HeroPtr, HeroRole> heroRoles; std::map<HeroPtr, HeroRole> heroRoles;
public: public:
HeroManager(CCallback * CB, const Nullkiller * ai) : cb(CB) {} HeroManager(CCallback * CB, const Nullkiller * ai) : cb(CB), ai(ai) {}
const std::map<HeroPtr, HeroRole> & getHeroRoles() const override; const std::map<HeroPtr, HeroRole> & getHeroRoles() const override;
HeroRole getHeroRole(const HeroPtr & hero) const override; HeroRole getHeroRole(const HeroPtr & hero) const override;
int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const override; int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const override;
void update() override; void update() override;
float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const override; float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const override;
float evaluateHero(const CGHeroInstance * hero) const override; float evaluateHero(const CGHeroInstance * hero) const override;
bool canRecruitHero(const CGTownInstance * t = nullptr) const override;
const CGHeroInstance * findHeroWithGrail() const override;
private: private:
float evaluateFightingStrength(const CGHeroInstance * hero) const; float evaluateFightingStrength(const CGHeroInstance * hero) const;
float evaluateSpeciality(const CGHeroInstance * hero) const; float evaluateSpeciality(const CGHeroInstance * hero) const;
const CGTownInstance * findTownWithTavern() const;
}; };
// basic skill scores. missing skills will have score of 0 // basic skill scores. missing skills will have score of 0

View File

@@ -53,7 +53,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose() const
for(auto town : towns) for(auto town : towns)
{ {
if(ai->canRecruitAnyHero(town)) if(ai->nullkiller->heroManager->canRecruitHero(town))
{ {
auto availableHeroes = cb->getAvailableHeroes(town); auto availableHeroes = cb->getAvailableHeroes(town);

View File

@@ -66,7 +66,7 @@ const CGHeroInstance * getNearestHero(const CGTownInstance * town)
bool needToRecruitHero(const CGTownInstance * startupTown) bool needToRecruitHero(const CGTownInstance * startupTown)
{ {
if(!ai->canRecruitAnyHero(startupTown)) if(!ai->nullkiller->heroManager->canRecruitHero(startupTown))
return false; return false;
if(!startupTown->garrisonHero && !startupTown->visitingHero) if(!startupTown->garrisonHero && !startupTown->visitingHero)

View File

@@ -33,8 +33,6 @@ void RecruitHero::accept(AIGateway * ai)
{ {
auto t = town; auto t = town;
if(!t) t = ai->findTownWithTavern();
if(!t) if(!t)
{ {
throw cannotFulfillGoalException("No town to recruit hero!"); throw cannotFulfillGoalException("No town to recruit hero!");

View File

@@ -1093,7 +1093,7 @@ void AINodeStorage::calculateTownPortal(
if(nodeOptional) if(nodeOptional)
{ {
#if NKAI_PATHFINDER_TRACE_LEVEL >= 1 #if NKAI_PATHFINDER_TRACE_LEVEL >= 1
logAi->trace("Adding town portal node at %s", targetTown->name); logAi->trace("Adding town portal node at %s", targetTown->getObjectName());
#endif #endif
output.push_back(nodeOptional.value()); output.push_back(nodeOptional.value());
} }