mirror of
https://github.com/vcmi/vcmi.git
synced 2025-02-09 13:14:02 +02:00
Nullkiller: stabilization+clasterization improvements+fuzzy fear
This commit is contained in:
parent
75b8ee74fa
commit
32fb465823
@ -99,6 +99,12 @@ uint64_t DangerHitMapAnalyzer::enemyCanKillOurHeroesAlongThePath(const AIPath &
|
|||||||
const HitMapNode & DangerHitMapAnalyzer::getObjectTreat(const CGObjectInstance * obj) const
|
const HitMapNode & DangerHitMapAnalyzer::getObjectTreat(const CGObjectInstance * obj) const
|
||||||
{
|
{
|
||||||
auto tile = obj->visitablePos();
|
auto tile = obj->visitablePos();
|
||||||
|
|
||||||
|
return getTileTreat(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
const HitMapNode & DangerHitMapAnalyzer::getTileTreat(const int3 & tile) const
|
||||||
|
{
|
||||||
const HitMapNode & info = hitMap[tile.x][tile.y][tile.z];
|
const HitMapNode & info = hitMap[tile.x][tile.y][tile.z];
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
@ -51,6 +51,7 @@ public:
|
|||||||
void updateHitMap();
|
void updateHitMap();
|
||||||
uint64_t enemyCanKillOurHeroesAlongThePath(const AIPath & path) const;
|
uint64_t enemyCanKillOurHeroesAlongThePath(const AIPath & path) const;
|
||||||
const HitMapNode & getObjectTreat(const CGObjectInstance * obj) const;
|
const HitMapNode & getObjectTreat(const CGObjectInstance * obj) const;
|
||||||
|
const HitMapNode & getTileTreat(const int3 & tile) const;
|
||||||
const std::set<const CGObjectInstance *> & getOneTurnAccessibleObjects(const CGHeroInstance * enemy) const;
|
const std::set<const CGObjectInstance *> & getOneTurnAccessibleObjects(const CGHeroInstance * enemy) const;
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
|
@ -92,7 +92,7 @@ const CGObjectInstance * ObjectClusterizer::getBlocker(const AIPath & path) cons
|
|||||||
{
|
{
|
||||||
auto guardPos = ai->cb->getGuardingCreaturePosition(node->coord);
|
auto guardPos = ai->cb->getGuardingCreaturePosition(node->coord);
|
||||||
auto blockers = ai->cb->getVisitableObjs(node->coord);
|
auto blockers = ai->cb->getVisitableObjs(node->coord);
|
||||||
|
|
||||||
if(guardPos.valid())
|
if(guardPos.valid())
|
||||||
{
|
{
|
||||||
auto guard = ai->cb->getTopObj(ai->cb->getGuardingCreaturePosition(node->coord));
|
auto guard = ai->cb->getTopObj(ai->cb->getGuardingCreaturePosition(node->coord));
|
||||||
@ -103,6 +103,16 @@ const CGObjectInstance * ObjectClusterizer::getBlocker(const AIPath & path) cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(node->specialAction && node->actionIsBlocked)
|
||||||
|
{
|
||||||
|
auto blockerObject = node->specialAction->targetObject();
|
||||||
|
|
||||||
|
if(blockerObject)
|
||||||
|
{
|
||||||
|
blockers.push_back(blockerObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(blockers.empty())
|
if(blockers.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -113,7 +123,8 @@ const CGObjectInstance * ObjectClusterizer::getBlocker(const AIPath & path) cons
|
|||||||
|| blocker->ID == Obj::GARRISON2
|
|| blocker->ID == Obj::GARRISON2
|
||||||
|| blocker->ID == Obj::BORDERGUARD
|
|| blocker->ID == Obj::BORDERGUARD
|
||||||
|| blocker->ID == Obj::QUEST_GUARD
|
|| blocker->ID == Obj::QUEST_GUARD
|
||||||
|| blocker->ID == Obj::BORDER_GATE)
|
|| blocker->ID == Obj::BORDER_GATE
|
||||||
|
|| blocker->ID == Obj::SHIPYARD)
|
||||||
{
|
{
|
||||||
if(!isObjectPassable(blocker))
|
if(!isObjectPassable(blocker))
|
||||||
return blocker;
|
return blocker;
|
||||||
@ -201,9 +212,15 @@ void ObjectClusterizer::clusterize()
|
|||||||
|
|
||||||
bool added = false;
|
bool added = false;
|
||||||
bool directlyAccessible = false;
|
bool directlyAccessible = false;
|
||||||
|
std::set<const CGHeroInstance *> heroesProcessed;
|
||||||
|
|
||||||
for(auto & path : paths)
|
for(auto & path : paths)
|
||||||
{
|
{
|
||||||
|
if(vstd::contains(heroesProcessed, path.targetHero))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
heroesProcessed.insert(path.targetHero);
|
||||||
|
|
||||||
if(path.nodes.size() > 1)
|
if(path.nodes.size() > 1)
|
||||||
{
|
{
|
||||||
auto blocker = getBlocker(path);
|
auto blocker = getBlocker(path);
|
||||||
@ -236,10 +253,13 @@ void ObjectClusterizer::clusterize()
|
|||||||
|
|
||||||
if(!added || directlyAccessible)
|
if(!added || directlyAccessible)
|
||||||
{
|
{
|
||||||
if(paths.front().turn() <= 2)
|
AIPath & shortestPath = paths.front();
|
||||||
nearObjects.addObject(obj, paths.front(), 0);
|
float priority = ai->priorityEvaluator->evaluate(Goals::sptr(Goals::ExecuteHeroChain(shortestPath, obj)));
|
||||||
|
|
||||||
|
if(shortestPath.turn() <= 2 || priority > 0.6f)
|
||||||
|
nearObjects.addObject(obj, shortestPath, 0);
|
||||||
else
|
else
|
||||||
farObjects.addObject(obj, paths.front(), 0);
|
farObjects.addObject(obj, shortestPath, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ uint64_t townArmyIncome(const CGTownInstance * town)
|
|||||||
|
|
||||||
void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town) const
|
void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town) const
|
||||||
{
|
{
|
||||||
auto basicPriority = 0.3f + std::sqrt(townArmyIncome(town) / 20000.0f)
|
auto basicPriority = 0.3f + std::sqrt(townArmyIncome(town) / 40000.0f)
|
||||||
+ town->dailyIncome()[Res::GOLD] / 10000.0f;
|
+ town->dailyIncome()[Res::GOLD] / 10000.0f;
|
||||||
|
|
||||||
logAi->debug("Evaluating defence for %s, basic priority %f", town->name, basicPriority);
|
logAi->debug("Evaluating defence for %s, basic priority %f", town->name, basicPriority);
|
||||||
@ -124,7 +124,8 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
{
|
{
|
||||||
if(path.turn() <= treat.turn && dayOfWeek + treat.turn < 6 && isSafeToVisit(path.targetHero, path.heroArmy, treat.danger)
|
if(path.turn() <= treat.turn && dayOfWeek + treat.turn < 6 && isSafeToVisit(path.targetHero, path.heroArmy, treat.danger)
|
||||||
|| path.exchangeCount == 1 && path.turn() < treat.turn
|
|| path.exchangeCount == 1 && path.turn() < treat.turn
|
||||||
|| path.turn() < treat.turn - 1)
|
|| path.turn() < treat.turn - 1
|
||||||
|
|| path.turn() < treat.turn && treat.turn >= 2)
|
||||||
{
|
{
|
||||||
logAi->debug(
|
logAi->debug(
|
||||||
"Hero %s can eliminate danger for town %s using path %s.",
|
"Hero %s can eliminate danger for town %s using path %s.",
|
||||||
@ -194,6 +195,9 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Goals::ExecuteHeroChain> pathsToDefend;
|
||||||
|
std::map<const CGHeroInstance *, std::vector<AIPath>> defferedPaths;
|
||||||
|
|
||||||
for(AIPath & path : paths)
|
for(AIPath & path : paths)
|
||||||
{
|
{
|
||||||
#if AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
@ -211,11 +215,16 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
town->name,
|
town->name,
|
||||||
path.targetHero->name);
|
path.targetHero->name);
|
||||||
|
|
||||||
|
defferedPaths[path.targetHero].push_back(path);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float priority = basicPriority
|
float priority = basicPriority * std::min(SAFE_ATTACK_CONSTANT, (float)path.getHeroStrength() / treat.danger)
|
||||||
+ std::min(SAFE_ATTACK_CONSTANT, (float)path.getHeroStrength() / treat.danger) / (treat.turn + 1);
|
- treat.turn * 0.2f;
|
||||||
|
|
||||||
|
if(treat.turn < path.turn())
|
||||||
|
priority /= (path.turn() - treat.turn) * 2;
|
||||||
|
|
||||||
if(path.targetHero == town->visitingHero && path.exchangeCount == 1)
|
if(path.targetHero == town->visitingHero && path.exchangeCount == 1)
|
||||||
{
|
{
|
||||||
@ -231,7 +240,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(path.turn() <= treat.turn && path.getHeroStrength() * SAFE_ATTACK_CONSTANT >= treat.danger)
|
if(treat.turn == 0 || path.turn() <= treat.turn && path.getHeroStrength() * SAFE_ATTACK_CONSTANT >= treat.danger)
|
||||||
{
|
{
|
||||||
if(ai->nullkiller->arePathHeroesLocked(path))
|
if(ai->nullkiller->arePathHeroesLocked(path))
|
||||||
{
|
{
|
||||||
@ -245,27 +254,33 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathsToDefend.push_back(Goals::ExecuteHeroChain(path, town).setpriority(priority));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Goals::ExecuteHeroChain & chain : pathsToDefend)
|
||||||
|
{
|
||||||
|
auto path = chain.getPath();
|
||||||
|
|
||||||
|
for(AIPath & defferedPath : defferedPaths[path.targetHero])
|
||||||
|
{
|
||||||
|
if(defferedPath.getHeroStrength() >= path.getHeroStrength()
|
||||||
|
&& defferedPath.turn() <= path.turn())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if AI_TRACE_LEVEL >= 1
|
#if AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Move %s to defend town %s with priority %f",
|
logAi->trace("Move %s to defend town %s with priority %f",
|
||||||
path.targetHero->name,
|
path.targetHero->name,
|
||||||
town->name,
|
town->name,
|
||||||
priority);
|
chain.priority);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tasks.push_back(Goals::sptr(Goals::ExecuteHeroChain(path, town).setpriority(priority)));
|
tasks.push_back(Goals::sptr(chain));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logAi->debug("Found %d tasks", tasks.size());
|
logAi->debug("Found %d tasks", tasks.size());
|
||||||
|
|
||||||
/*for(auto & treat : treats)
|
|
||||||
{
|
|
||||||
auto paths = ai->nullkiller->pathfinder->getPathInfo(treat.hero->visitablePos());
|
|
||||||
|
|
||||||
for(AIPath & path : paths)
|
|
||||||
{
|
|
||||||
tasks.push_back(Goals::sptr(Goals::ExecuteHeroChain(path)));
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
@ -90,7 +90,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
|
|||||||
if(path.getFirstBlockedAction())
|
if(path.getFirstBlockedAction())
|
||||||
{
|
{
|
||||||
#if AI_TRACE_LEVEL >= 2
|
#if AI_TRACE_LEVEL >= 2
|
||||||
// TODO: decomposition?
|
// TODO: decomposition
|
||||||
logAi->trace("Ignore path. Action is blocked.");
|
logAi->trace("Ignore path. Action is blocked.");
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "StartupBehavior.h"
|
#include "StartupBehavior.h"
|
||||||
#include "../VCAI.h"
|
#include "../VCAI.h"
|
||||||
#include "../AIUtility.h"
|
#include "../AIUtility.h"
|
||||||
|
#include "../Goals/BuildThis.h"
|
||||||
#include "../Goals/RecruitHero.h"
|
#include "../Goals/RecruitHero.h"
|
||||||
#include "../Goals/ExecuteHeroChain.h"
|
#include "../Goals/ExecuteHeroChain.h"
|
||||||
#include "../Goals/ExchangeSwapTownHeroes.h"
|
#include "../Goals/ExchangeSwapTownHeroes.h"
|
||||||
@ -123,6 +124,14 @@ Goals::TGoalVec StartupBehavior::decompose() const
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!startupTown->hasBuilt(BuildingID::TAVERN)
|
||||||
|
&& cb->canBuildStructure(startupTown, BuildingID::TAVERN) == EBuildingState::ALLOWED)
|
||||||
|
{
|
||||||
|
tasks.push_back(Goals::sptr(Goals::BuildThis(BuildingID::TAVERN, startupTown).setpriority(100)));
|
||||||
|
|
||||||
|
return tasks;
|
||||||
|
}
|
||||||
|
|
||||||
bool canRecruitHero = needToRecruitHero(startupTown);
|
bool canRecruitHero = needToRecruitHero(startupTown);
|
||||||
auto closestHero = getNearestHero(startupTown);
|
auto closestHero = getNearestHero(startupTown);
|
||||||
|
|
||||||
|
@ -43,7 +43,8 @@ EvaluationContext::EvaluationContext(const Nullkiller * ai)
|
|||||||
heroRole(HeroRole::SCOUT),
|
heroRole(HeroRole::SCOUT),
|
||||||
turn(0),
|
turn(0),
|
||||||
strategicalValue(0),
|
strategicalValue(0),
|
||||||
evaluator(ai)
|
evaluator(ai),
|
||||||
|
enemyHeroDangerRatio(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +72,7 @@ void PriorityEvaluator::initVisitTile()
|
|||||||
strategicalValueVariable = engine->getInputVariable("strategicalValue");
|
strategicalValueVariable = engine->getInputVariable("strategicalValue");
|
||||||
goldPreasureVariable = engine->getInputVariable("goldPreasure");
|
goldPreasureVariable = engine->getInputVariable("goldPreasure");
|
||||||
goldCostVariable = engine->getInputVariable("goldCost");
|
goldCostVariable = engine->getInputVariable("goldCost");
|
||||||
|
fearVariable = engine->getInputVariable("fear");
|
||||||
value = engine->getOutputVariable("Value");
|
value = engine->getOutputVariable("Value");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,6 +383,19 @@ float RewardEvaluator::getSkillReward(const CGObjectInstance * target, const CGH
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t RewardEvaluator::getEnemyHeroDanger(const AIPath & path) const
|
||||||
|
{
|
||||||
|
auto & treatNode = ai->dangerHitMap->getTileTreat(path.targetTile());
|
||||||
|
|
||||||
|
if(treatNode.maximumDanger.danger == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(treatNode.maximumDanger.turn <= path.turn())
|
||||||
|
return treatNode.maximumDanger.danger;
|
||||||
|
|
||||||
|
return treatNode.fastestDanger.turn <= path.turn() ? treatNode.fastestDanger.danger : 0;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t getArmyCost(const CArmedInstance * army)
|
int32_t getArmyCost(const CArmedInstance * army)
|
||||||
{
|
{
|
||||||
int32_t value = 0;
|
int32_t value = 0;
|
||||||
@ -485,6 +500,7 @@ public:
|
|||||||
evaluationContext.skillReward += evaluationContext.evaluator.getSkillReward(target, hero, evaluationContext.heroRole);
|
evaluationContext.skillReward += evaluationContext.evaluator.getSkillReward(target, hero, evaluationContext.heroRole);
|
||||||
evaluationContext.strategicalValue += evaluationContext.evaluator.getStrategicalValue(target);
|
evaluationContext.strategicalValue += evaluationContext.evaluator.getStrategicalValue(target);
|
||||||
evaluationContext.goldCost += evaluationContext.evaluator.getGoldCost(target, hero, army);
|
evaluationContext.goldCost += evaluationContext.evaluator.getGoldCost(target, hero, army);
|
||||||
|
vstd::amax(evaluationContext.enemyHeroDangerRatio, evaluationContext.evaluator.getEnemyHeroDanger(path) / (double)path.getHeroStrength());
|
||||||
vstd::amax(evaluationContext.turn, path.turn());
|
vstd::amax(evaluationContext.turn, path.turn());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -659,6 +675,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
|||||||
goldPreasureVariable->setValue(ai->buildAnalyzer->getGoldPreasure());
|
goldPreasureVariable->setValue(ai->buildAnalyzer->getGoldPreasure());
|
||||||
goldCostVariable->setValue(evaluationContext.goldCost / ((float)cb->getResourceAmount(Res::GOLD) + (float)ai->buildAnalyzer->getDailyIncome()[Res::GOLD] + 1.0f));
|
goldCostVariable->setValue(evaluationContext.goldCost / ((float)cb->getResourceAmount(Res::GOLD) + (float)ai->buildAnalyzer->getDailyIncome()[Res::GOLD] + 1.0f));
|
||||||
turnVariable->setValue(evaluationContext.turn);
|
turnVariable->setValue(evaluationContext.turn);
|
||||||
|
fearVariable->setValue(evaluationContext.enemyHeroDangerRatio);
|
||||||
|
|
||||||
engine->process();
|
engine->process();
|
||||||
//engine.process(VISIT_TILE); //TODO: Process only Visit_Tile
|
//engine.process(VISIT_TILE); //TODO: Process only Visit_Tile
|
||||||
@ -671,7 +688,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
|||||||
assert(result >= 0);
|
assert(result >= 0);
|
||||||
|
|
||||||
#ifdef AI_TRACE_LEVEL >= 1
|
#ifdef AI_TRACE_LEVEL >= 1
|
||||||
logAi->trace("Evaluated %s, loss: %f, turn: %d, turns main: %f, scout: %f, gold: %d, cost: %d, army gain: %d, danger: %d, role: %s, strategical value: %f, cwr: %f, result %f",
|
logAi->trace("Evaluated %s, loss: %f, turn: %d, turns main: %f, scout: %f, gold: %d, cost: %d, army gain: %d, danger: %d, role: %s, strategical value: %f, cwr: %f, fear: %f, result %f",
|
||||||
task->toString(),
|
task->toString(),
|
||||||
evaluationContext.armyLossPersentage,
|
evaluationContext.armyLossPersentage,
|
||||||
(int)evaluationContext.turn,
|
(int)evaluationContext.turn,
|
||||||
@ -684,6 +701,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task)
|
|||||||
evaluationContext.heroRole == HeroRole::MAIN ? "main" : "scout",
|
evaluationContext.heroRole == HeroRole::MAIN ? "main" : "scout",
|
||||||
evaluationContext.strategicalValue,
|
evaluationContext.strategicalValue,
|
||||||
evaluationContext.closestWayRatio,
|
evaluationContext.closestWayRatio,
|
||||||
|
evaluationContext.enemyHeroDangerRatio,
|
||||||
result);
|
result);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ public:
|
|||||||
float getSkillReward(const CGObjectInstance * target, const CGHeroInstance * hero, HeroRole role) const;
|
float getSkillReward(const CGObjectInstance * target, const CGHeroInstance * hero, HeroRole role) const;
|
||||||
int32_t getGoldReward(const CGObjectInstance * target, const CGHeroInstance * hero) const;
|
int32_t getGoldReward(const CGObjectInstance * target, const CGHeroInstance * hero) const;
|
||||||
uint64_t getUpgradeArmyReward(const CGTownInstance * town, const BuildingInfo & bi) const;
|
uint64_t getUpgradeArmyReward(const CGTownInstance * town, const BuildingInfo & bi) const;
|
||||||
|
uint64_t getEnemyHeroDanger(const AIPath & path) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DLL_EXPORT EvaluationContext
|
struct DLL_EXPORT EvaluationContext
|
||||||
@ -48,6 +49,7 @@ struct DLL_EXPORT EvaluationContext
|
|||||||
HeroRole heroRole;
|
HeroRole heroRole;
|
||||||
uint8_t turn;
|
uint8_t turn;
|
||||||
RewardEvaluator evaluator;
|
RewardEvaluator evaluator;
|
||||||
|
float enemyHeroDangerRatio;
|
||||||
|
|
||||||
EvaluationContext(const Nullkiller * ai);
|
EvaluationContext(const Nullkiller * ai);
|
||||||
};
|
};
|
||||||
@ -87,6 +89,7 @@ private:
|
|||||||
fl::InputVariable * closestHeroRatioVariable;
|
fl::InputVariable * closestHeroRatioVariable;
|
||||||
fl::InputVariable * goldPreasureVariable;
|
fl::InputVariable * goldPreasureVariable;
|
||||||
fl::InputVariable * goldCostVariable;
|
fl::InputVariable * goldCostVariable;
|
||||||
|
fl::InputVariable * fearVariable;
|
||||||
fl::OutputVariable * value;
|
fl::OutputVariable * value;
|
||||||
std::vector<std::shared_ptr<IEvaluationContextBuilder>> evaluationContextBuilders;
|
std::vector<std::shared_ptr<IEvaluationContextBuilder>> evaluationContextBuilders;
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ void ExecuteHeroChain::accept(VCAI * ai)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node.turns == 0 && node.coord != hero->visitablePos())
|
if(node.turns == 0 && node.coord != hero->visitablePos())
|
||||||
{
|
{
|
||||||
auto targetNode = cb->getPathsInfo(hero)->getPathInfo(node.coord);
|
auto targetNode = cb->getPathsInfo(hero)->getPathInfo(node.coord);
|
||||||
|
|
||||||
|
@ -36,32 +36,6 @@ namespace AIPathfinding
|
|||||||
return sptr(Goals::Invalid());
|
return sptr(Goals::Invalid());
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChainActor * BuildBoatAction::getActor(const ChainActor * sourceActor) const
|
|
||||||
{
|
|
||||||
return sourceActor->resourceActor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SummonBoatAction::execute(const CGHeroInstance * hero) const
|
|
||||||
{
|
|
||||||
Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT).accept(ai.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
const ChainActor * SummonBoatAction::getActor(const ChainActor * sourceActor) const
|
|
||||||
{
|
|
||||||
return sourceActor->castActor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SummonBoatAction::applyOnDestination(
|
|
||||||
const CGHeroInstance * hero,
|
|
||||||
CDestinationNodeInfo & destination,
|
|
||||||
const PathNodeInfo & source,
|
|
||||||
AIPathNode * dstMode,
|
|
||||||
const AIPathNode * srcNode) const
|
|
||||||
{
|
|
||||||
dstMode->manaCost = srcNode->manaCost + getManaCost(hero);
|
|
||||||
dstMode->theNodeBefore = source.node;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BuildBoatAction::canAct(const AIPathNode * source) const
|
bool BuildBoatAction::canAct(const AIPathNode * source) const
|
||||||
{
|
{
|
||||||
auto hero = source->actor->hero;
|
auto hero = source->actor->hero;
|
||||||
@ -90,6 +64,37 @@ namespace AIPathfinding
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CGObjectInstance * BuildBoatAction::targetObject() const
|
||||||
|
{
|
||||||
|
return shipyard->o;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChainActor * BuildBoatAction::getActor(const ChainActor * sourceActor) const
|
||||||
|
{
|
||||||
|
return sourceActor->resourceActor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonBoatAction::execute(const CGHeroInstance * hero) const
|
||||||
|
{
|
||||||
|
Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT).accept(ai.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChainActor * SummonBoatAction::getActor(const ChainActor * sourceActor) const
|
||||||
|
{
|
||||||
|
return sourceActor->castActor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonBoatAction::applyOnDestination(
|
||||||
|
const CGHeroInstance * hero,
|
||||||
|
CDestinationNodeInfo & destination,
|
||||||
|
const PathNodeInfo & source,
|
||||||
|
AIPathNode * dstMode,
|
||||||
|
const AIPathNode * srcNode) const
|
||||||
|
{
|
||||||
|
dstMode->manaCost = srcNode->manaCost + getManaCost(hero);
|
||||||
|
dstMode->theNodeBefore = source.node;
|
||||||
|
}
|
||||||
|
|
||||||
std::string BuildBoatAction::toString() const
|
std::string BuildBoatAction::toString() const
|
||||||
{
|
{
|
||||||
return "Build Boat at " + shipyard->o->getObjectName();
|
return "Build Boat at " + shipyard->o->getObjectName();
|
||||||
|
@ -67,5 +67,7 @@ namespace AIPathfinding
|
|||||||
virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
|
virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
|
||||||
|
|
||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
|
|
||||||
|
virtual const CGObjectInstance * targetObject() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -37,4 +37,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual std::string toString() const = 0;
|
virtual std::string toString() const = 0;
|
||||||
|
|
||||||
|
virtual const CGObjectInstance * targetObject() const { return nullptr; }
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user