mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
nkai: fix freezes
This commit is contained in:
@@ -229,6 +229,31 @@ const CGHeroInstance * HeroManager::findHeroWithGrail() const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CGHeroInstance * HeroManager::findWeakHeroToDismiss(uint64_t armyLimit) const
|
||||||
|
{
|
||||||
|
const CGHeroInstance * weakestHero = nullptr;
|
||||||
|
auto myHeroes = ai->cb->getHeroesInfo();
|
||||||
|
|
||||||
|
for(auto existingHero : myHeroes)
|
||||||
|
{
|
||||||
|
if(ai->isHeroLocked(existingHero)
|
||||||
|
|| existingHero->getArmyStrength() >armyLimit
|
||||||
|
|| getHeroRole(existingHero) == HeroRole::MAIN
|
||||||
|
|| existingHero->movementPointsRemaining()
|
||||||
|
|| existingHero->artifactsWorn.size() > (existingHero->hasSpellbook() ? 2 : 1))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!weakestHero || weakestHero->getFightingStrength() > existingHero->getFightingStrength())
|
||||||
|
{
|
||||||
|
weakestHero = existingHero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return weakestHero;
|
||||||
|
}
|
||||||
|
|
||||||
SecondarySkillScoreMap::SecondarySkillScoreMap(std::map<SecondarySkill, float> scoreMap)
|
SecondarySkillScoreMap::SecondarySkillScoreMap(std::map<SecondarySkill, float> scoreMap)
|
||||||
:scoreMap(scoreMap)
|
:scoreMap(scoreMap)
|
||||||
{
|
{
|
||||||
|
@@ -33,6 +33,7 @@ public:
|
|||||||
virtual bool canRecruitHero(const CGTownInstance * t = nullptr) const = 0;
|
virtual bool canRecruitHero(const CGTownInstance * t = nullptr) const = 0;
|
||||||
virtual bool heroCapReached() const = 0;
|
virtual bool heroCapReached() const = 0;
|
||||||
virtual const CGHeroInstance * findHeroWithGrail() const = 0;
|
virtual const CGHeroInstance * findHeroWithGrail() const = 0;
|
||||||
|
virtual const CGHeroInstance * findWeakHeroToDismiss(uint64_t armyLimit) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT ISecondarySkillRule
|
class DLL_EXPORT ISecondarySkillRule
|
||||||
@@ -74,6 +75,7 @@ public:
|
|||||||
bool canRecruitHero(const CGTownInstance * t = nullptr) const override;
|
bool canRecruitHero(const CGTownInstance * t = nullptr) const override;
|
||||||
bool heroCapReached() const override;
|
bool heroCapReached() const override;
|
||||||
const CGHeroInstance * findHeroWithGrail() const override;
|
const CGHeroInstance * findHeroWithGrail() const override;
|
||||||
|
const CGHeroInstance * findWeakHeroToDismiss(uint64_t armyLimit) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float evaluateFightingStrength(const CGHeroInstance * hero) const;
|
float evaluateFightingStrength(const CGHeroInstance * hero) const;
|
||||||
|
@@ -121,16 +121,31 @@ bool handleGarrisonHeroFromPreviousTurn(const CGTownInstance * town, Goals::TGoa
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!town->visitingHero && cb->getHeroCount(ai->playerID, false) < GameConstants::MAX_HEROES_PER_PLAYER)
|
if(!town->visitingHero)
|
||||||
{
|
{
|
||||||
logAi->trace(
|
if(cb->getHeroCount(ai->playerID, false) < GameConstants::MAX_HEROES_PER_PLAYER)
|
||||||
"Extracting hero %s from garrison of town %s",
|
{
|
||||||
town->garrisonHero->getNameTranslated(),
|
logAi->trace(
|
||||||
town->getNameTranslated());
|
"Extracting hero %s from garrison of town %s",
|
||||||
|
town->garrisonHero->getNameTranslated(),
|
||||||
|
town->getNameTranslated());
|
||||||
|
|
||||||
tasks.push_back(Goals::sptr(Goals::ExchangeSwapTownHeroes(town, nullptr).setpriority(5)));
|
tasks.push_back(Goals::sptr(Goals::ExchangeSwapTownHeroes(town, nullptr).setpriority(5)));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
else if(ai->nullkiller->heroManager->getHeroRole(town->garrisonHero.get()) == HeroRole::MAIN)
|
||||||
|
{
|
||||||
|
auto armyDismissLimit = 1000;
|
||||||
|
auto heroToDismiss = ai->nullkiller->heroManager->findWeakHeroToDismiss(armyDismissLimit);
|
||||||
|
|
||||||
|
if(heroToDismiss)
|
||||||
|
{
|
||||||
|
tasks.push_back(Goals::sptr(Goals::DismissHero(heroToDismiss).setpriority(5)));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -141,14 +156,6 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
logAi->trace("Evaluating defence for %s", town->getNameTranslated());
|
logAi->trace("Evaluating defence for %s", town->getNameTranslated());
|
||||||
|
|
||||||
auto treatNode = ai->nullkiller->dangerHitMap->getObjectTreat(town);
|
auto treatNode = ai->nullkiller->dangerHitMap->getObjectTreat(town);
|
||||||
|
|
||||||
if(!treatNode.fastestDanger.hero)
|
|
||||||
{
|
|
||||||
logAi->trace("No treat found for town %s", town->getNameTranslated());
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<HitMapInfo> treats = ai->nullkiller->dangerHitMap->getTownTreats(town);
|
std::vector<HitMapInfo> treats = ai->nullkiller->dangerHitMap->getTownTreats(town);
|
||||||
|
|
||||||
treats.push_back(treatNode.fastestDanger); // no guarantee that fastest danger will be there
|
treats.push_back(treatNode.fastestDanger); // no guarantee that fastest danger will be there
|
||||||
@@ -158,6 +165,13 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!treatNode.fastestDanger.hero)
|
||||||
|
{
|
||||||
|
logAi->trace("No treat found for town %s", town->getNameTranslated());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t reinforcement = ai->nullkiller->armyManager->howManyReinforcementsCanBuy(town->getUpperArmy(), town);
|
uint64_t reinforcement = ai->nullkiller->armyManager->howManyReinforcementsCanBuy(town->getUpperArmy(), town);
|
||||||
|
|
||||||
if(reinforcement)
|
if(reinforcement)
|
||||||
@@ -224,11 +238,6 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
if(path.getHeroStrength() < townDefenseStrength)
|
if(path.getHeroStrength() < townDefenseStrength)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if(town->visitingHero)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(path.turn() <= treat.turn - 2)
|
if(path.turn() <= treat.turn - 2)
|
||||||
{
|
{
|
||||||
@@ -440,27 +449,10 @@ void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitM
|
|||||||
}
|
}
|
||||||
else if(ai->nullkiller->heroManager->heroCapReached())
|
else if(ai->nullkiller->heroManager->heroCapReached())
|
||||||
{
|
{
|
||||||
const CGHeroInstance * weakestHero = nullptr;
|
heroToDismiss = ai->nullkiller->heroManager->findWeakHeroToDismiss(hero->getArmyStrength());
|
||||||
|
|
||||||
for(auto existingHero : myHeroes)
|
if(!heroToDismiss)
|
||||||
{
|
|
||||||
if(ai->nullkiller->isHeroLocked(existingHero)
|
|
||||||
|| existingHero->getArmyStrength() > hero->getArmyStrength()
|
|
||||||
|| ai->nullkiller->heroManager->getHeroRole(existingHero) == HeroRole::MAIN
|
|
||||||
|| existingHero->movementPointsRemaining()
|
|
||||||
|| existingHero->artifactsWorn.size() > (existingHero->hasSpellbook() ? 2 : 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(!weakestHero || weakestHero->getFightingStrength() > existingHero->getFightingStrength())
|
|
||||||
{
|
|
||||||
weakestHero = existingHero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!weakestHero)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
heroToDismiss = weakestHero;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TGoalVec sequence;
|
TGoalVec sequence;
|
||||||
|
@@ -592,7 +592,6 @@ int32_t getArmyCost(const CArmedInstance * army)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets aproximated reward in gold. Daily income is multiplied by 5
|
|
||||||
int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CGHeroInstance * hero) const
|
int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
if(!target)
|
if(!target)
|
||||||
@@ -713,9 +712,6 @@ public:
|
|||||||
|
|
||||||
auto strategicalValue = evaluationContext.evaluator.getStrategicalValue(town);
|
auto strategicalValue = evaluationContext.evaluator.getStrategicalValue(town);
|
||||||
|
|
||||||
if(evaluationContext.evaluator.ai->buildAnalyzer->getDevelopmentInfo().size() == 1)
|
|
||||||
vstd::amax(evaluationContext.strategicalValue, 10.0);
|
|
||||||
|
|
||||||
float multiplier = 1;
|
float multiplier = 1;
|
||||||
|
|
||||||
if(treat.turn < defendTown.getTurn())
|
if(treat.turn < defendTown.getTurn())
|
||||||
@@ -736,7 +732,12 @@ public:
|
|||||||
|
|
||||||
evaluationContext.armyGrowth += armyGrowth * multiplier;
|
evaluationContext.armyGrowth += armyGrowth * multiplier;
|
||||||
evaluationContext.goldReward += dailyIncome * 5 * multiplier;
|
evaluationContext.goldReward += dailyIncome * 5 * multiplier;
|
||||||
evaluationContext.addNonCriticalStrategicalValue(1.7f * multiplier * strategicalValue);
|
|
||||||
|
if(evaluationContext.evaluator.ai->buildAnalyzer->getDevelopmentInfo().size() == 1)
|
||||||
|
vstd::amax(evaluationContext.strategicalValue, 2.5f * multiplier * strategicalValue);
|
||||||
|
else
|
||||||
|
evaluationContext.addNonCriticalStrategicalValue(1.7f * multiplier * strategicalValue);
|
||||||
|
|
||||||
vstd::amax(evaluationContext.danger, defendTown.getTreat().danger);
|
vstd::amax(evaluationContext.danger, defendTown.getTreat().danger);
|
||||||
addTileDanger(evaluationContext, town->visitablePos(), defendTown.getTurn(), defendTown.getDefenceStrength());
|
addTileDanger(evaluationContext, town->visitablePos(), defendTown.getTurn(), defendTown.getDefenceStrength());
|
||||||
}
|
}
|
||||||
|
@@ -171,6 +171,10 @@ RuleBlock: basic
|
|||||||
rule: if heroRole is SCOUT and turn is NEXT and mainTurnDistance is LONG then Value is BAD
|
rule: if heroRole is SCOUT and turn is NEXT and mainTurnDistance is LONG then Value is BAD
|
||||||
rule: if heroRole is SCOUT and turn is NOW and scoutTurnDistance is LONG then Value is BAD
|
rule: if heroRole is SCOUT and turn is NOW and scoutTurnDistance is LONG then Value is BAD
|
||||||
rule: if heroRole is SCOUT and turn is NOW and scoutTurnDistance is MEDIUM then Value is BAD with 0.3
|
rule: if heroRole is SCOUT and turn is NOW and scoutTurnDistance is MEDIUM then Value is BAD with 0.3
|
||||||
|
rule: if heroRole is SCOUT and fear is HIGH then Value is BAD with 0.8
|
||||||
|
rule: if heroRole is SCOUT and fear is MEDIUM then Value is BAD with 0.5
|
||||||
|
rule: if heroRole is MAIN and fear is HIGH then Value is BAD with 0.5
|
||||||
|
rule: if heroRole is MAIN and fear is MEDIUM then Value is BAD with 0.2
|
||||||
RuleBlock: strategicalValue
|
RuleBlock: strategicalValue
|
||||||
enabled: true
|
enabled: true
|
||||||
conjunction: AlgebraicProduct
|
conjunction: AlgebraicProduct
|
||||||
@@ -205,7 +209,8 @@ RuleBlock: strategicalValue
|
|||||||
rule: if heroRole is SCOUT and strategicalValue is LOW and danger is NONE and scoutTurnDistance is MEDIUM and fear is not HIGH then Value is SMALL
|
rule: if heroRole is SCOUT and strategicalValue is LOW and danger is NONE and scoutTurnDistance is MEDIUM and fear is not HIGH then Value is SMALL
|
||||||
rule: if armyLoss is HIGH and strategicalValue is LOW then Value is BAD
|
rule: if armyLoss is HIGH and strategicalValue is LOW then Value is BAD
|
||||||
rule: if armyLoss is HIGH and strategicalValue is MEDIUM then Value is BAD with 0.7
|
rule: if armyLoss is HIGH and strategicalValue is MEDIUM then Value is BAD with 0.7
|
||||||
rule: if strategicalValue is CRITICAL then Value is CRITICAL
|
rule: if strategicalValue is CRITICAL and heroRole is MAIN then Value is CRITICAL
|
||||||
|
rule: if strategicalValue is CRITICAL and heroRole is SCOUT then Value is CRITICAL with 0.7
|
||||||
RuleBlock: armyReward
|
RuleBlock: armyReward
|
||||||
enabled: true
|
enabled: true
|
||||||
conjunction: AlgebraicProduct
|
conjunction: AlgebraicProduct
|
||||||
@@ -220,6 +225,14 @@ RuleBlock: armyReward
|
|||||||
rule: if heroRole is MAIN and armyReward is MEDIUM and mainTurnDistance is LONG and fear is not HIGH then Value is MEDIUM
|
rule: if heroRole is MAIN and armyReward is MEDIUM and mainTurnDistance is LONG and fear is not HIGH then Value is MEDIUM
|
||||||
rule: if heroRole is MAIN and armyReward is LOW and mainTurnDistance is LOW and fear is not HIGH then Value is MEDIUM
|
rule: if heroRole is MAIN and armyReward is LOW and mainTurnDistance is LOW and fear is not HIGH then Value is MEDIUM
|
||||||
rule: if heroRole is MAIN and armyReward is LOW and mainTurnDistance is MEDIUM and fear is not HIGH then Value is SMALL
|
rule: if heroRole is MAIN and armyReward is LOW and mainTurnDistance is MEDIUM and fear is not HIGH then Value is SMALL
|
||||||
|
rule: if heroRole is SCOUT and armyReward is HIGH and danger is NONE and scoutTurnDistance is LOW and fear is not HIGH then Value is HIGH
|
||||||
|
rule: if heroRole is SCOUT and armyReward is HIGH and danger is NONE and scoutTurnDistance is MEDIUM and fear is not HIGH then Value is HIGH with 0.7
|
||||||
|
rule: if heroRole is SCOUT and armyReward is HIGH and danger is NONE and scoutTurnDistance is LONG and fear is not HIGH then Value is BITHIGH
|
||||||
|
rule: if heroRole is SCOUT and armyReward is MEDIUM and danger is NONE and scoutTurnDistance is LOW then Value is HIGH with 0.7
|
||||||
|
rule: if heroRole is SCOUT and armyReward is MEDIUM and danger is NONE and scoutTurnDistance is MEDIUM and fear is not HIGH then Value is BITHIGH
|
||||||
|
rule: if heroRole is SCOUT and armyReward is MEDIUM and danger is NONE and scoutTurnDistance is LONG and fear is not HIGH then Value is MEDIUM
|
||||||
|
rule: if heroRole is SCOUT and armyReward is LOW and danger is NONE and scoutTurnDistance is LOW and fear is not HIGH then Value is MEDIUM
|
||||||
|
rule: if heroRole is SCOUT and armyReward is LOW and danger is NONE and scoutTurnDistance is MEDIUM and fear is not HIGH then Value is SMALL
|
||||||
RuleBlock: gold
|
RuleBlock: gold
|
||||||
enabled: true
|
enabled: true
|
||||||
conjunction: AlgebraicProduct
|
conjunction: AlgebraicProduct
|
||||||
|
Reference in New Issue
Block a user