mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-23 12:08:45 +02:00
Nullkiller AI: basic hill fort support and hero chain reworked to start from stronger army
This commit is contained in:
parent
400967904b
commit
a39fa51e14
@ -213,6 +213,14 @@ std::vector<creInfo> AIhelper::getArmyAvailableToBuy(const CCreatureSet * hero,
|
|||||||
return armyManager->getArmyAvailableToBuy(hero, dwelling);
|
return armyManager->getArmyAvailableToBuy(hero, dwelling);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArmyUpgradeInfo AIhelper::calculateCreateresUpgrade(
|
||||||
|
const CCreatureSet * army,
|
||||||
|
const CGObjectInstance * upgrader,
|
||||||
|
const TResources & availableResources) const
|
||||||
|
{
|
||||||
|
return armyManager->calculateCreateresUpgrade(army, upgrader, availableResources);
|
||||||
|
}
|
||||||
|
|
||||||
int AIhelper::selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const
|
int AIhelper::selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const
|
||||||
{
|
{
|
||||||
return heroManager->selectBestSkill(hero, skills);
|
return heroManager->selectBestSkill(hero, skills);
|
||||||
|
@ -82,6 +82,10 @@ public:
|
|||||||
std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const override;
|
std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const override;
|
||||||
uint64_t evaluateStackPower(const CCreature * creature, int count) const override;
|
uint64_t evaluateStackPower(const CCreature * creature, int count) const override;
|
||||||
SlotInfo getTotalCreaturesAvailable(CreatureID creatureID) const override;
|
SlotInfo getTotalCreaturesAvailable(CreatureID creatureID) const override;
|
||||||
|
ArmyUpgradeInfo calculateCreateresUpgrade(
|
||||||
|
const CCreatureSet * army,
|
||||||
|
const CGObjectInstance * upgrader,
|
||||||
|
const TResources & availableResources) const override;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -208,3 +208,143 @@ void ArmyManager::update()
|
|||||||
army.second.power = evaluateStackPower(army.second.creature, army.second.count);
|
army.second.power = evaluateStackPower(army.second.creature, army.second.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UpgradeInfo
|
||||||
|
{
|
||||||
|
const CCreature * initialCreature;
|
||||||
|
const CCreature * upgradedCreature;
|
||||||
|
TResources cost;
|
||||||
|
int count;
|
||||||
|
uint64_t upgradeValue;
|
||||||
|
|
||||||
|
UpgradeInfo(CreatureID initial, CreatureID upgraded, int count)
|
||||||
|
:initialCreature(initial.toCreature()), upgradedCreature(upgraded.toCreature()), count(count)
|
||||||
|
{
|
||||||
|
cost = (upgradedCreature->cost - initialCreature->cost) * count;
|
||||||
|
upgradeValue = (upgradedCreature->AIValue - initialCreature->AIValue) * count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<SlotInfo> ArmyManager::convertToSlots(const CCreatureSet * army) const
|
||||||
|
{
|
||||||
|
std::vector<SlotInfo> result;
|
||||||
|
|
||||||
|
for(auto slot : army->Slots())
|
||||||
|
{
|
||||||
|
SlotInfo slotInfo;
|
||||||
|
|
||||||
|
slotInfo.creature = slot.second->getCreatureID().toCreature();
|
||||||
|
slotInfo.count = slot.second->count;
|
||||||
|
slotInfo.power = evaluateStackPower(slotInfo.creature, slotInfo.count);
|
||||||
|
|
||||||
|
result.push_back(slotInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<UpgradeInfo> ArmyManager::getHillFortUpgrades(const CCreatureSet * army) const
|
||||||
|
{
|
||||||
|
std::vector<UpgradeInfo> upgrades;
|
||||||
|
|
||||||
|
for(auto creature : army->Slots())
|
||||||
|
{
|
||||||
|
CreatureID initial = creature.second->getCreatureID();
|
||||||
|
auto possibleUpgrades = initial.toCreature()->upgrades;
|
||||||
|
|
||||||
|
if(possibleUpgrades.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CreatureID strongestUpgrade = *vstd::minElementByFun(possibleUpgrades, [](CreatureID cre) -> uint64_t
|
||||||
|
{
|
||||||
|
return cre.toCreature()->AIValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
UpgradeInfo upgrade = UpgradeInfo(initial, strongestUpgrade, creature.second->count);
|
||||||
|
|
||||||
|
if(initial.toCreature()->level == 1)
|
||||||
|
upgrade.cost = TResources();
|
||||||
|
|
||||||
|
upgrades.push_back(upgrade);
|
||||||
|
}
|
||||||
|
|
||||||
|
return upgrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<UpgradeInfo> ArmyManager::getDwellingUpgrades(const CCreatureSet * army, const CGDwelling * dwelling) const
|
||||||
|
{
|
||||||
|
std::vector<UpgradeInfo> upgrades;
|
||||||
|
|
||||||
|
return upgrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<UpgradeInfo> ArmyManager::getPossibleUpgrades(const CCreatureSet * army, const CGObjectInstance * upgrader) const
|
||||||
|
{
|
||||||
|
std::vector<UpgradeInfo> upgrades;
|
||||||
|
|
||||||
|
if(upgrader->ID == Obj::HILL_FORT)
|
||||||
|
{
|
||||||
|
upgrades = getHillFortUpgrades(army);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto dwelling = dynamic_cast<const CGDwelling *>(upgrader);
|
||||||
|
|
||||||
|
if(dwelling)
|
||||||
|
{
|
||||||
|
upgrades = getDwellingUpgrades(army, dwelling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return upgrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArmyUpgradeInfo ArmyManager::calculateCreateresUpgrade(
|
||||||
|
const CCreatureSet * army,
|
||||||
|
const CGObjectInstance * upgrader,
|
||||||
|
const TResources & availableResources) const
|
||||||
|
{
|
||||||
|
std::vector<UpgradeInfo> upgrades = getPossibleUpgrades(army, upgrader);
|
||||||
|
|
||||||
|
vstd::erase_if(upgrades, [&](const UpgradeInfo & u) -> bool
|
||||||
|
{
|
||||||
|
return !availableResources.canAfford(u.cost);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(upgrades.empty())
|
||||||
|
return ArmyUpgradeInfo();
|
||||||
|
|
||||||
|
std::sort(upgrades.begin(), upgrades.end(), [](const UpgradeInfo & u1, const UpgradeInfo & u2) -> bool
|
||||||
|
{
|
||||||
|
return u1.upgradeValue > u2.upgradeValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
TResources resourcesLeft = availableResources;
|
||||||
|
ArmyUpgradeInfo result;
|
||||||
|
|
||||||
|
result.resultingArmy = convertToSlots(army);
|
||||||
|
|
||||||
|
for(auto upgrade : upgrades)
|
||||||
|
{
|
||||||
|
if(resourcesLeft.canAfford(upgrade.cost))
|
||||||
|
{
|
||||||
|
SlotInfo upgradedArmy;
|
||||||
|
|
||||||
|
upgradedArmy.creature = upgrade.upgradedCreature;
|
||||||
|
upgradedArmy.count = upgrade.count;
|
||||||
|
upgradedArmy.power = evaluateStackPower(upgradedArmy.creature, upgradedArmy.count);
|
||||||
|
|
||||||
|
auto slotToReplace = std::find_if(result.resultingArmy.begin(), result.resultingArmy.end(), [&](const SlotInfo & slot) -> bool {
|
||||||
|
return slot.count == upgradedArmy.count && slot.creature == upgrade.initialCreature;
|
||||||
|
});
|
||||||
|
|
||||||
|
resourcesLeft -= upgrade.cost;
|
||||||
|
result.upgradeCost += upgrade.cost;
|
||||||
|
result.upgradeValue += upgrade.upgradeValue;
|
||||||
|
|
||||||
|
*slotToReplace = upgradedArmy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
@ -25,6 +25,18 @@ struct SlotInfo
|
|||||||
uint64_t power;
|
uint64_t power;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ArmyUpgradeInfo
|
||||||
|
{
|
||||||
|
std::vector<SlotInfo> resultingArmy;
|
||||||
|
uint64_t upgradeValue;
|
||||||
|
TResources upgradeCost;
|
||||||
|
|
||||||
|
ArmyUpgradeInfo()
|
||||||
|
: resultingArmy(), upgradeValue(0), upgradeCost()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class DLL_EXPORT IArmyManager //: public: IAbstractManager
|
class DLL_EXPORT IArmyManager //: public: IAbstractManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -40,8 +52,14 @@ public:
|
|||||||
virtual std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const = 0;
|
virtual std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const = 0;
|
||||||
virtual uint64_t evaluateStackPower(const CCreature * creature, int count) const = 0;
|
virtual uint64_t evaluateStackPower(const CCreature * creature, int count) const = 0;
|
||||||
virtual SlotInfo getTotalCreaturesAvailable(CreatureID creatureID) const = 0;
|
virtual SlotInfo getTotalCreaturesAvailable(CreatureID creatureID) const = 0;
|
||||||
|
virtual ArmyUpgradeInfo calculateCreateresUpgrade(
|
||||||
|
const CCreatureSet * army,
|
||||||
|
const CGObjectInstance * upgrader,
|
||||||
|
const TResources & availableResources) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UpgradeInfo;
|
||||||
|
|
||||||
class DLL_EXPORT ArmyManager : public IArmyManager
|
class DLL_EXPORT ArmyManager : public IArmyManager
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -63,4 +81,14 @@ public:
|
|||||||
std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const override;
|
std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const override;
|
||||||
uint64_t evaluateStackPower(const CCreature * creature, int count) const override;
|
uint64_t evaluateStackPower(const CCreature * creature, int count) const override;
|
||||||
SlotInfo getTotalCreaturesAvailable(CreatureID creatureID) const override;
|
SlotInfo getTotalCreaturesAvailable(CreatureID creatureID) const override;
|
||||||
|
ArmyUpgradeInfo calculateCreateresUpgrade(
|
||||||
|
const CCreatureSet * army,
|
||||||
|
const CGObjectInstance * upgrader,
|
||||||
|
const TResources & availableResources) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<SlotInfo> convertToSlots(const CCreatureSet * army) const;
|
||||||
|
std::vector<UpgradeInfo> getPossibleUpgrades(const CCreatureSet * army, const CGObjectInstance * upgrader) const;
|
||||||
|
std::vector<UpgradeInfo> getHillFortUpgrades(const CCreatureSet * army) const;
|
||||||
|
std::vector<UpgradeInfo> getDwellingUpgrades(const CCreatureSet * army, const CGDwelling * dwelling) const;
|
||||||
};
|
};
|
||||||
|
@ -172,10 +172,15 @@ Goals::TGoalVec StartupBehavior::getTasks()
|
|||||||
{
|
{
|
||||||
for(const CGTownInstance * town : towns)
|
for(const CGTownInstance * town : towns)
|
||||||
{
|
{
|
||||||
if(town->garrisonHero && town->garrisonHero->movement && ai->nullkiller->getHeroLockedReason(town->garrisonHero) != HeroLockedReason::DEFENCE)
|
if(town->garrisonHero
|
||||||
|
&& town->garrisonHero->movement
|
||||||
|
&& !town->visitingHero
|
||||||
|
&& ai->nullkiller->getHeroLockedReason(town->garrisonHero) != HeroLockedReason::DEFENCE)
|
||||||
|
{
|
||||||
tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(town, nullptr).setpriority(0.0001f)));
|
tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(town, nullptr).setpriority(0.0001f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "../VCAI.h"
|
#include "../VCAI.h"
|
||||||
#include "../AIhelper.h"
|
#include "../AIhelper.h"
|
||||||
#include "../Engine/Nullkiller.h"
|
#include "../Engine/Nullkiller.h"
|
||||||
|
#include "../Goals/ExecuteHeroChain.h"
|
||||||
|
|
||||||
#define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
|
#define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
|
||||||
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
|
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
|
||||||
@ -153,7 +154,7 @@ uint64_t evaluateArtifactArmyValue(CArtifactInstance * art)
|
|||||||
return statsValue > classValue ? statsValue : classValue;
|
return statsValue > classValue ? statsValue : classValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t getArmyReward(const CGObjectInstance * target, const CGHeroInstance * hero, bool checkGold)
|
uint64_t getArmyReward(const CGObjectInstance * target, const CGHeroInstance * hero, const CCreatureSet * army, bool checkGold)
|
||||||
{
|
{
|
||||||
const float enemyArmyEliminationRewardRatio = 0.5f;
|
const float enemyArmyEliminationRewardRatio = 0.5f;
|
||||||
|
|
||||||
@ -164,6 +165,8 @@ uint64_t getArmyReward(const CGObjectInstance * target, const CGHeroInstance * h
|
|||||||
{
|
{
|
||||||
case Obj::TOWN:
|
case Obj::TOWN:
|
||||||
return target->tempOwner == PlayerColor::NEUTRAL ? 1000 : 10000;
|
return target->tempOwner == PlayerColor::NEUTRAL ? 1000 : 10000;
|
||||||
|
case Obj::HILL_FORT:
|
||||||
|
return ai->ah->calculateCreateresUpgrade(army, target, cb->getResourceAmount()).upgradeValue;
|
||||||
case Obj::CREATURE_BANK:
|
case Obj::CREATURE_BANK:
|
||||||
return getCreatureBankArmyReward(target, hero);
|
return getCreatureBankArmyReward(target, hero);
|
||||||
case Obj::CREATURE_GENERATOR1:
|
case Obj::CREATURE_GENERATOR1:
|
||||||
@ -377,15 +380,11 @@ class ExecuteHeroChainEvaluationContextBuilder : public IEvaluationContextBuilde
|
|||||||
public:
|
public:
|
||||||
virtual Goals::EvaluationContext buildEvaluationContext(Goals::TSubgoal task) const override
|
virtual Goals::EvaluationContext buildEvaluationContext(Goals::TSubgoal task) const override
|
||||||
{
|
{
|
||||||
|
Goals::ExecuteHeroChain & chain = dynamic_cast<Goals::ExecuteHeroChain &>(*task);
|
||||||
auto evaluationContext = task->evaluationContext;
|
auto evaluationContext = task->evaluationContext;
|
||||||
|
|
||||||
int objId = task->objid;
|
|
||||||
|
|
||||||
if(task->parent)
|
|
||||||
objId = task->parent->objid;
|
|
||||||
|
|
||||||
auto heroPtr = task->hero;
|
auto heroPtr = task->hero;
|
||||||
const CGObjectInstance * target = cb->getObj((ObjectInstanceID)objId, false);
|
const CGObjectInstance * target = cb->getObj((ObjectInstanceID)task->objid, false);
|
||||||
auto day = cb->getDate(Date::DAY);
|
auto day = cb->getDate(Date::DAY);
|
||||||
auto hero = heroPtr.get();
|
auto hero = heroPtr.get();
|
||||||
bool checkGold = evaluationContext.danger == 0;
|
bool checkGold = evaluationContext.danger == 0;
|
||||||
@ -393,7 +392,7 @@ public:
|
|||||||
evaluationContext.armyLossPersentage = task->evaluationContext.armyLoss / (double)task->evaluationContext.heroStrength;
|
evaluationContext.armyLossPersentage = task->evaluationContext.armyLoss / (double)task->evaluationContext.heroStrength;
|
||||||
evaluationContext.heroRole = ai->ah->getHeroRole(heroPtr);
|
evaluationContext.heroRole = ai->ah->getHeroRole(heroPtr);
|
||||||
evaluationContext.goldReward = getGoldReward(target, hero);
|
evaluationContext.goldReward = getGoldReward(target, hero);
|
||||||
evaluationContext.armyReward = getArmyReward(target, hero, checkGold);
|
evaluationContext.armyReward = getArmyReward(target, hero, chain.getPath().heroArmy, checkGold);
|
||||||
evaluationContext.skillReward = getSkillReward(target, hero, evaluationContext.heroRole);
|
evaluationContext.skillReward = getSkillReward(target, hero, evaluationContext.heroRole);
|
||||||
evaluationContext.strategicalValue = getStrategicalValue(target);
|
evaluationContext.strategicalValue = getStrategicalValue(target);
|
||||||
|
|
||||||
|
@ -281,32 +281,17 @@ ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj, const VCAI * ai)
|
|||||||
|
|
||||||
switch(obj->ID)
|
switch(obj->ID)
|
||||||
{
|
{
|
||||||
case Obj::HERO:
|
|
||||||
{
|
|
||||||
InfoAboutHero iah;
|
|
||||||
cb->getHeroInfo(obj, iah);
|
|
||||||
return iah.army.getStrength();
|
|
||||||
}
|
|
||||||
case Obj::TOWN:
|
case Obj::TOWN:
|
||||||
case Obj::GARRISON:
|
|
||||||
case Obj::GARRISON2:
|
|
||||||
{
|
{
|
||||||
InfoAboutTown iat;
|
const CGTownInstance * cre = dynamic_cast<const CGTownInstance *>(obj);
|
||||||
cb->getTownInfo(obj, iat);
|
return cre->getUpperArmy()->getArmyStrength();
|
||||||
return iat.army.getStrength();
|
|
||||||
}
|
}
|
||||||
case Obj::MONSTER:
|
case Obj::MONSTER:
|
||||||
{
|
case Obj::HERO:
|
||||||
//TODO!!!!!!!!
|
case Obj::GARRISON:
|
||||||
const CGCreature * cre = dynamic_cast<const CGCreature *>(obj);
|
case Obj::GARRISON2:
|
||||||
return cre->getArmyStrength();
|
|
||||||
}
|
|
||||||
case Obj::CREATURE_GENERATOR1:
|
case Obj::CREATURE_GENERATOR1:
|
||||||
case Obj::CREATURE_GENERATOR4:
|
case Obj::CREATURE_GENERATOR4:
|
||||||
{
|
|
||||||
const CGDwelling * d = dynamic_cast<const CGDwelling *>(obj);
|
|
||||||
return d->getArmyStrength();
|
|
||||||
}
|
|
||||||
case Obj::MINE:
|
case Obj::MINE:
|
||||||
case Obj::ABANDONED_MINE:
|
case Obj::ABANDONED_MINE:
|
||||||
{
|
{
|
||||||
|
@ -279,7 +279,8 @@ bool AINodeStorage::calculateHeroChainFinal()
|
|||||||
{
|
{
|
||||||
if(node.turns > heroChainTurn
|
if(node.turns > heroChainTurn
|
||||||
&& node.action != CGPathNode::ENodeAction::UNKNOWN
|
&& node.action != CGPathNode::ENodeAction::UNKNOWN
|
||||||
&& node.actor->actorExchangeCount > 1)
|
&& node.actor->actorExchangeCount > 1
|
||||||
|
&& !hasBetterChain(&node, &node, chains))
|
||||||
{
|
{
|
||||||
heroChain.push_back(&node);
|
heroChain.push_back(&node);
|
||||||
}
|
}
|
||||||
@ -332,6 +333,55 @@ bool AINodeStorage::calculateHeroChain()
|
|||||||
return heroChain.size();
|
return heroChain.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AINodeStorage::selectFirstActor()
|
||||||
|
{
|
||||||
|
if(!actors.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto strongest = *vstd::maxElementByFun(actors, [](std::shared_ptr<ChainActor> actor) -> uint64_t
|
||||||
|
{
|
||||||
|
return actor->armyValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
chainMask = strongest->chainMask;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AINodeStorage::selectNextActor()
|
||||||
|
{
|
||||||
|
auto currentActor = std::find_if(actors.begin(), actors.end(), [&](std::shared_ptr<ChainActor> actor)-> bool
|
||||||
|
{
|
||||||
|
return actor->chainMask == chainMask;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto nextActor = actors.end();
|
||||||
|
|
||||||
|
for(auto actor = actors.begin(); actor != actors.end(); actor++)
|
||||||
|
{
|
||||||
|
if(actor->get()->armyValue > currentActor->get()->armyValue
|
||||||
|
|| actor->get()->armyValue == currentActor->get()->armyValue && actor <= currentActor)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nextActor == actors.end()
|
||||||
|
|| actor->get()->armyValue > nextActor->get()->armyValue)
|
||||||
|
{
|
||||||
|
nextActor = actor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nextActor != actors.end())
|
||||||
|
{
|
||||||
|
chainMask = nextActor->get()->chainMask;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void AINodeStorage::cleanupInefectiveChains(std::vector<ExchangeCandidate> & result) const
|
void AINodeStorage::cleanupInefectiveChains(std::vector<ExchangeCandidate> & result) const
|
||||||
{
|
{
|
||||||
vstd::erase_if(result, [&](const ExchangeCandidate & chainInfo) -> bool
|
vstd::erase_if(result, [&](const ExchangeCandidate & chainInfo) -> bool
|
||||||
@ -354,6 +404,9 @@ void AINodeStorage::calculateHeroChain(
|
|||||||
if(node == srcNode || !node->actor)
|
if(node == srcNode || !node->actor)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if((node->actor->chainMask & chainMask) == 0 && (srcNode->actor->chainMask & chainMask) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
if(node->turns > heroChainTurn
|
if(node->turns > heroChainTurn
|
||||||
|| (node->action == CGPathNode::ENodeAction::UNKNOWN && node->actor->hero)
|
|| (node->action == CGPathNode::ENodeAction::UNKNOWN && node->actor->hero)
|
||||||
|| (node->actor->chainMask & srcNode->actor->chainMask) != 0)
|
|| (node->actor->chainMask & srcNode->actor->chainMask) != 0)
|
||||||
|
@ -112,6 +112,7 @@ private:
|
|||||||
std::vector<std::shared_ptr<ChainActor>> actors;
|
std::vector<std::shared_ptr<ChainActor>> actors;
|
||||||
std::vector<CGPathNode *> heroChain;
|
std::vector<CGPathNode *> heroChain;
|
||||||
EHeroChainPass heroChainPass; // true if we need to calculate hero chain
|
EHeroChainPass heroChainPass; // true if we need to calculate hero chain
|
||||||
|
uint64_t chainMask;
|
||||||
int heroChainTurn;
|
int heroChainTurn;
|
||||||
int heroChainMaxTurns;
|
int heroChainMaxTurns;
|
||||||
PlayerColor playerID;
|
PlayerColor playerID;
|
||||||
@ -126,6 +127,8 @@ public:
|
|||||||
void initialize(const PathfinderOptions & options, const CGameState * gs) override;
|
void initialize(const PathfinderOptions & options, const CGameState * gs) override;
|
||||||
|
|
||||||
bool increaseHeroChainTurnLimit();
|
bool increaseHeroChainTurnLimit();
|
||||||
|
bool selectFirstActor();
|
||||||
|
bool selectNextActor();
|
||||||
|
|
||||||
virtual std::vector<CGPathNode *> getInitialNodes() override;
|
virtual std::vector<CGPathNode *> getInitialNodes() override;
|
||||||
|
|
||||||
|
@ -62,25 +62,32 @@ void AIPathfinder::updatePaths(std::vector<HeroPtr> heroes, bool useHeroChain)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto config = std::make_shared<AIPathfinding::AIPathfinderConfig>(cb, ai, storage);
|
auto config = std::make_shared<AIPathfinding::AIPathfinderConfig>(cb, ai, storage);
|
||||||
bool continueCalculation = false;
|
|
||||||
|
logAi->trace("Recalculate paths pass %d", pass++);
|
||||||
|
cb->calculatePaths(config);
|
||||||
|
|
||||||
|
if(!useHeroChain)
|
||||||
|
return;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
storage->selectFirstActor();
|
||||||
|
|
||||||
do
|
do
|
||||||
|
{
|
||||||
|
while(storage->calculateHeroChain())
|
||||||
{
|
{
|
||||||
logAi->trace("Recalculate paths pass %d", pass++);
|
logAi->trace("Recalculate paths pass %d", pass++);
|
||||||
cb->calculatePaths(config);
|
cb->calculatePaths(config);
|
||||||
} while(useHeroChain && storage->calculateHeroChain());
|
}
|
||||||
|
|
||||||
if(!useHeroChain)
|
logAi->trace("Select next actor");
|
||||||
break;
|
} while(storage->selectNextActor());
|
||||||
|
|
||||||
if(storage->calculateHeroChainFinal())
|
if(storage->calculateHeroChainFinal())
|
||||||
{
|
{
|
||||||
logAi->trace("Recalculate paths pass final");
|
logAi->trace("Recalculate paths pass final");
|
||||||
cb->calculatePaths(config);
|
cb->calculatePaths(config);
|
||||||
}
|
}
|
||||||
|
} while(storage->increaseHeroChainTurnLimit());
|
||||||
continueCalculation = storage->increaseHeroChainTurnLimit() && storage->calculateHeroChain();
|
|
||||||
} while(continueCalculation);
|
|
||||||
}
|
}
|
||||||
|
@ -456,11 +456,6 @@ void VCAI::showHillFortWindow(const CGObjectInstance * object, const CGHeroInsta
|
|||||||
{
|
{
|
||||||
LOG_TRACE(logAi);
|
LOG_TRACE(logAi);
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
|
|
||||||
requestActionASAP([=]()
|
|
||||||
{
|
|
||||||
makePossibleUpgrades(visitor);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VCAI::playerBonusChanged(const Bonus & bonus, bool gain)
|
void VCAI::playerBonusChanged(const Bonus & bonus, bool gain)
|
||||||
@ -781,6 +776,7 @@ void makePossibleUpgrades(const CArmedInstance * obj)
|
|||||||
if(ui.oldID >= 0 && cb->getResourceAmount().canAfford(ui.cost[0] * s->count))
|
if(ui.oldID >= 0 && cb->getResourceAmount().canAfford(ui.cost[0] * s->count))
|
||||||
{
|
{
|
||||||
cb->upgradeCreature(obj, SlotID(i), ui.newID[0]);
|
cb->upgradeCreature(obj, SlotID(i), ui.newID[0]);
|
||||||
|
logAi->debug("Upgraded %d %s to %s", s->count, ui.oldID.toCreature()->namePl, ui.newID[0].toCreature()->namePl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1092,6 +1088,9 @@ void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Obj::HILL_FORT:
|
||||||
|
makePossibleUpgrades(h.get());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
completeGoal(sptr(Goals::VisitObj(obj->id.getNum()).sethero(h)));
|
completeGoal(sptr(Goals::VisitObj(obj->id.getNum()).sethero(h)));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user