mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-24 03:47:18 +02:00
Merge pull request #546 from nullkiller/ai-pathfinding-update-paths
AI pathfinding const api and updatePaths
This commit is contained in:
commit
6165954e40
@ -194,150 +194,15 @@ bool CDistanceSorter::operator()(const CGObjectInstance * lhs, const CGObjectIns
|
||||
return ln->cost < rn->cost;
|
||||
}
|
||||
|
||||
ui64 evaluateDanger(crint3 tile)
|
||||
{
|
||||
const TerrainTile * t = cb->getTile(tile, false);
|
||||
if(!t) //we can know about guard but can't check its tile (the edge of fow)
|
||||
return 190000000; //MUCH
|
||||
|
||||
ui64 objectDanger = 0;
|
||||
ui64 guardDanger = 0;
|
||||
|
||||
auto visObjs = cb->getVisitableObjs(tile);
|
||||
if(visObjs.size())
|
||||
objectDanger = evaluateDanger(visObjs.back());
|
||||
|
||||
int3 guardPos = cb->getGuardingCreaturePosition(tile);
|
||||
if(guardPos.x >= 0 && guardPos != tile)
|
||||
guardDanger = evaluateDanger(guardPos);
|
||||
|
||||
//TODO mozna odwiedzic blockvis nie ruszajac straznika
|
||||
return std::max(objectDanger, guardDanger);
|
||||
}
|
||||
|
||||
ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor)
|
||||
{
|
||||
const TerrainTile * t = cb->getTile(tile, false);
|
||||
if(!t) //we can know about guard but can't check its tile (the edge of fow)
|
||||
return 190000000; //MUCH
|
||||
|
||||
ui64 objectDanger = 0;
|
||||
ui64 guardDanger = 0;
|
||||
|
||||
auto visitableObjects = cb->getVisitableObjs(tile);
|
||||
// in some scenarios hero happens to be "under" the object (eg town). Then we consider ONLY the hero.
|
||||
if(vstd::contains_if(visitableObjects, objWithID<Obj::HERO>))
|
||||
{
|
||||
vstd::erase_if(visitableObjects, [](const CGObjectInstance * obj)
|
||||
{
|
||||
return !objWithID<Obj::HERO>(obj);
|
||||
});
|
||||
}
|
||||
|
||||
if(const CGObjectInstance * dangerousObject = vstd::backOrNull(visitableObjects))
|
||||
{
|
||||
objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
|
||||
if(objectDanger)
|
||||
{
|
||||
//TODO: don't downcast objects AI shouldn't know about!
|
||||
auto armedObj = dynamic_cast<const CArmedInstance *>(dangerousObject);
|
||||
if(armedObj)
|
||||
{
|
||||
float tacticalAdvantage = fh->tacticalAdvantageEngine.getTacticalAdvantage(visitor, armedObj);
|
||||
objectDanger *= tacticalAdvantage; //this line tends to go infinite for allied towns (?)
|
||||
}
|
||||
}
|
||||
if(dangerousObject->ID == Obj::SUBTERRANEAN_GATE)
|
||||
{
|
||||
//check guard on the other side of the gate
|
||||
auto it = ai->knownSubterraneanGates.find(dangerousObject);
|
||||
if(it != ai->knownSubterraneanGates.end())
|
||||
{
|
||||
auto guards = cb->getGuardingCreatures(it->second->visitablePos());
|
||||
for(auto cre : guards)
|
||||
{
|
||||
vstd::amax(guardDanger, evaluateDanger(cre) * fh->tacticalAdvantageEngine.getTacticalAdvantage(visitor, dynamic_cast<const CArmedInstance *>(cre)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto guards = cb->getGuardingCreatures(tile);
|
||||
for(auto cre : guards)
|
||||
{
|
||||
vstd::amax(guardDanger, evaluateDanger(cre) * fh->tacticalAdvantageEngine.getTacticalAdvantage(visitor, dynamic_cast<const CArmedInstance *>(cre))); //we are interested in strongest monster around
|
||||
}
|
||||
|
||||
//TODO mozna odwiedzic blockvis nie ruszajac straznika
|
||||
return std::max(objectDanger, guardDanger);
|
||||
}
|
||||
|
||||
ui64 evaluateDanger(const CGObjectInstance * obj)
|
||||
{
|
||||
if(obj->tempOwner < PlayerColor::PLAYER_LIMIT && cb->getPlayerRelations(obj->tempOwner, ai->playerID) != PlayerRelations::ENEMIES) //owned or allied objects don't pose any threat
|
||||
return 0;
|
||||
|
||||
switch(obj->ID)
|
||||
{
|
||||
case Obj::HERO:
|
||||
{
|
||||
InfoAboutHero iah;
|
||||
cb->getHeroInfo(obj, iah);
|
||||
return iah.army.getStrength();
|
||||
}
|
||||
case Obj::TOWN:
|
||||
case Obj::GARRISON:
|
||||
case Obj::GARRISON2:
|
||||
{
|
||||
InfoAboutTown iat;
|
||||
cb->getTownInfo(obj, iat);
|
||||
return iat.army.getStrength();
|
||||
}
|
||||
case Obj::MONSTER:
|
||||
{
|
||||
//TODO!!!!!!!!
|
||||
const CGCreature * cre = dynamic_cast<const CGCreature *>(obj);
|
||||
return cre->getArmyStrength();
|
||||
}
|
||||
case Obj::CREATURE_GENERATOR1:
|
||||
case Obj::CREATURE_GENERATOR4:
|
||||
{
|
||||
const CGDwelling * d = dynamic_cast<const CGDwelling *>(obj);
|
||||
return d->getArmyStrength();
|
||||
}
|
||||
case Obj::MINE:
|
||||
case Obj::ABANDONED_MINE:
|
||||
{
|
||||
const CArmedInstance * a = dynamic_cast<const CArmedInstance *>(obj);
|
||||
return a->getArmyStrength();
|
||||
}
|
||||
case Obj::CRYPT: //crypt
|
||||
case Obj::CREATURE_BANK: //crebank
|
||||
case Obj::DRAGON_UTOPIA:
|
||||
case Obj::SHIPWRECK: //shipwreck
|
||||
case Obj::DERELICT_SHIP: //derelict ship
|
||||
// case Obj::PYRAMID:
|
||||
return fh->estimateBankDanger(dynamic_cast<const CBank *>(obj));
|
||||
case Obj::PYRAMID:
|
||||
{
|
||||
if(obj->subID == 0)
|
||||
return fh->estimateBankDanger(dynamic_cast<const CBank *>(obj));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool compareDanger(const CGObjectInstance * lhs, const CGObjectInstance * rhs)
|
||||
{
|
||||
return evaluateDanger(lhs) < evaluateDanger(rhs);
|
||||
return fh->evaluateDanger(lhs) < fh->evaluateDanger(rhs);
|
||||
}
|
||||
|
||||
bool isSafeToVisit(HeroPtr h, crint3 tile)
|
||||
{
|
||||
return isSafeToVisit(h, evaluateDanger(tile));
|
||||
return isSafeToVisit(h, fh->evaluateDanger(tile, h.get()));
|
||||
}
|
||||
|
||||
bool isSafeToVisit(HeroPtr h, uint64_t dangerStrength)
|
||||
|
@ -166,8 +166,6 @@ bool isBlockVisitObj(const int3 & pos);
|
||||
bool isWeeklyRevisitable(const CGObjectInstance * obj);
|
||||
bool shouldVisit(HeroPtr h, const CGObjectInstance * obj);
|
||||
|
||||
ui64 evaluateDanger(const CGObjectInstance * obj);
|
||||
ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor);
|
||||
bool isObjectRemovable(const CGObjectInstance * obj); //FIXME FIXME: move logic to object property!
|
||||
bool isSafeToVisit(HeroPtr h, uint64_t dangerStrength);
|
||||
bool isSafeToVisit(HeroPtr h, crint3 tile);
|
||||
|
@ -123,32 +123,37 @@ TResource AIhelper::allGold() const
|
||||
return resourceManager->allGold();
|
||||
}
|
||||
|
||||
Goals::TGoalVec AIhelper::howToVisitTile(int3 tile)
|
||||
Goals::TGoalVec AIhelper::howToVisitTile(const int3 & tile) const
|
||||
{
|
||||
return pathfindingManager->howToVisitTile(tile);
|
||||
}
|
||||
|
||||
Goals::TGoalVec AIhelper::howToVisitObj(ObjectIdRef obj)
|
||||
Goals::TGoalVec AIhelper::howToVisitObj(ObjectIdRef obj) const
|
||||
{
|
||||
return pathfindingManager->howToVisitObj(obj);
|
||||
}
|
||||
|
||||
Goals::TGoalVec AIhelper::howToVisitTile(HeroPtr hero, int3 tile, bool allowGatherArmy)
|
||||
Goals::TGoalVec AIhelper::howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy) const
|
||||
{
|
||||
return pathfindingManager->howToVisitTile(hero, tile, allowGatherArmy);
|
||||
}
|
||||
|
||||
Goals::TGoalVec AIhelper::howToVisitObj(HeroPtr hero, ObjectIdRef obj, bool allowGatherArmy)
|
||||
Goals::TGoalVec AIhelper::howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy) const
|
||||
{
|
||||
return pathfindingManager->howToVisitObj(hero, obj, allowGatherArmy);
|
||||
}
|
||||
|
||||
std::vector<AIPath> AIhelper::getPathsToTile(HeroPtr hero, int3 tile)
|
||||
std::vector<AIPath> AIhelper::getPathsToTile(const HeroPtr & hero, const int3 & tile) const
|
||||
{
|
||||
return pathfindingManager->getPathsToTile(hero, tile);
|
||||
}
|
||||
|
||||
void AIhelper::resetPaths()
|
||||
void AIhelper::updatePaths(std::vector<HeroPtr> heroes)
|
||||
{
|
||||
pathfindingManager->resetPaths();
|
||||
pathfindingManager->updatePaths(heroes);
|
||||
}
|
||||
|
||||
void AIhelper::updatePaths(const HeroPtr & hero)
|
||||
{
|
||||
pathfindingManager->updatePaths(hero);
|
||||
}
|
||||
|
@ -55,15 +55,16 @@ public:
|
||||
boost::optional<PotentialBuilding> expensiveBuilding() const override;
|
||||
boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays = 7) const override;
|
||||
|
||||
Goals::TGoalVec howToVisitTile(HeroPtr hero, int3 tile, bool allowGatherArmy = true) override;
|
||||
Goals::TGoalVec howToVisitObj(HeroPtr hero, ObjectIdRef obj, bool allowGatherArmy = true) override;
|
||||
Goals::TGoalVec howToVisitTile(int3 tile) override;
|
||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) override;
|
||||
std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) override;
|
||||
void resetPaths() override;
|
||||
Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitTile(const int3 & tile) const override;
|
||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) const override;
|
||||
std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const override;
|
||||
void updatePaths(std::vector<HeroPtr> heroes) override;
|
||||
void updatePaths(const HeroPtr & hero) override;
|
||||
|
||||
STRONG_INLINE
|
||||
bool isTileAccessible(const HeroPtr & hero, const int3 & tile)
|
||||
bool isTileAccessible(const HeroPtr & hero, const int3 & tile) const
|
||||
{
|
||||
return pathfindingManager->isTileAccessible(hero, tile);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
|
||||
|
||||
extern boost::thread_specific_ptr<VCAI> ai;
|
||||
extern FuzzyHelper * fh;
|
||||
|
||||
engineBase::engineBase()
|
||||
{
|
||||
@ -342,7 +343,7 @@ void HeroMovementGoalEngineBase::setSharedFuzzyVariables(Goals::AbstractGoal & g
|
||||
}
|
||||
|
||||
float strengthRatioData = 10.0f; //we are much stronger than enemy
|
||||
ui64 danger = evaluateDanger(goal.tile, goal.hero.h);
|
||||
ui64 danger = fh->evaluateDanger(goal.tile, goal.hero.h);
|
||||
if(danger)
|
||||
strengthRatioData = (fl::scalar)goal.hero.h->getTotalStrength() / danger;
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
FuzzyHelper * fh;
|
||||
|
||||
extern boost::thread_specific_ptr<VCAI> ai;
|
||||
extern boost::thread_specific_ptr<CCallback> cb;
|
||||
|
||||
Goals::TSubgoal FuzzyHelper::chooseSolution(Goals::TGoalVec vec)
|
||||
{
|
||||
@ -203,3 +204,123 @@ void FuzzyHelper::setPriority(Goals::TSubgoal & g) //calls evaluate - Visitor pa
|
||||
{
|
||||
g->setpriority(g->accept(this)); //this enforces returned value is set
|
||||
}
|
||||
|
||||
ui64 FuzzyHelper::evaluateDanger(crint3 tile, const CGHeroInstance * visitor)
|
||||
{
|
||||
return evaluateDanger(tile, visitor, cb.get());
|
||||
}
|
||||
|
||||
ui64 FuzzyHelper::evaluateDanger(crint3 tile, const CGHeroInstance * visitor, const CPlayerSpecificInfoCallback * cb)
|
||||
{
|
||||
const TerrainTile * t = cb->getTile(tile, false);
|
||||
if(!t) //we can know about guard but can't check its tile (the edge of fow)
|
||||
return 190000000; //MUCH
|
||||
|
||||
ui64 objectDanger = 0;
|
||||
ui64 guardDanger = 0;
|
||||
|
||||
auto visitableObjects = cb->getVisitableObjs(tile);
|
||||
// in some scenarios hero happens to be "under" the object (eg town). Then we consider ONLY the hero.
|
||||
if(vstd::contains_if(visitableObjects, objWithID<Obj::HERO>))
|
||||
{
|
||||
vstd::erase_if(visitableObjects, [](const CGObjectInstance * obj)
|
||||
{
|
||||
return !objWithID<Obj::HERO>(obj);
|
||||
});
|
||||
}
|
||||
|
||||
if(const CGObjectInstance * dangerousObject = vstd::backOrNull(visitableObjects))
|
||||
{
|
||||
objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
|
||||
if(objectDanger)
|
||||
{
|
||||
//TODO: don't downcast objects AI shouldn't know about!
|
||||
auto armedObj = dynamic_cast<const CArmedInstance *>(dangerousObject);
|
||||
if(armedObj)
|
||||
{
|
||||
float tacticalAdvantage = tacticalAdvantageEngine.getTacticalAdvantage(visitor, armedObj);
|
||||
objectDanger *= tacticalAdvantage; //this line tends to go infinite for allied towns (?)
|
||||
}
|
||||
}
|
||||
if(dangerousObject->ID == Obj::SUBTERRANEAN_GATE)
|
||||
{
|
||||
//check guard on the other side of the gate
|
||||
auto it = ai->knownSubterraneanGates.find(dangerousObject);
|
||||
if(it != ai->knownSubterraneanGates.end())
|
||||
{
|
||||
auto guards = cb->getGuardingCreatures(it->second->visitablePos());
|
||||
for(auto cre : guards)
|
||||
{
|
||||
vstd::amax(guardDanger, evaluateDanger(cre) * tacticalAdvantageEngine.getTacticalAdvantage(visitor, dynamic_cast<const CArmedInstance *>(cre)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto guards = cb->getGuardingCreatures(tile);
|
||||
for(auto cre : guards)
|
||||
{
|
||||
vstd::amax(guardDanger, evaluateDanger(cre) * tacticalAdvantageEngine.getTacticalAdvantage(visitor, dynamic_cast<const CArmedInstance *>(cre))); //we are interested in strongest monster around
|
||||
}
|
||||
|
||||
//TODO mozna odwiedzic blockvis nie ruszajac straznika
|
||||
return std::max(objectDanger, guardDanger);
|
||||
}
|
||||
|
||||
ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj)
|
||||
{
|
||||
if(obj->tempOwner < PlayerColor::PLAYER_LIMIT && cb->getPlayerRelations(obj->tempOwner, ai->playerID) != PlayerRelations::ENEMIES) //owned or allied objects don't pose any threat
|
||||
return 0;
|
||||
|
||||
switch(obj->ID)
|
||||
{
|
||||
case Obj::HERO:
|
||||
{
|
||||
InfoAboutHero iah;
|
||||
cb->getHeroInfo(obj, iah);
|
||||
return iah.army.getStrength();
|
||||
}
|
||||
case Obj::TOWN:
|
||||
case Obj::GARRISON:
|
||||
case Obj::GARRISON2:
|
||||
{
|
||||
InfoAboutTown iat;
|
||||
cb->getTownInfo(obj, iat);
|
||||
return iat.army.getStrength();
|
||||
}
|
||||
case Obj::MONSTER:
|
||||
{
|
||||
//TODO!!!!!!!!
|
||||
const CGCreature * cre = dynamic_cast<const CGCreature *>(obj);
|
||||
return cre->getArmyStrength();
|
||||
}
|
||||
case Obj::CREATURE_GENERATOR1:
|
||||
case Obj::CREATURE_GENERATOR4:
|
||||
{
|
||||
const CGDwelling * d = dynamic_cast<const CGDwelling *>(obj);
|
||||
return d->getArmyStrength();
|
||||
}
|
||||
case Obj::MINE:
|
||||
case Obj::ABANDONED_MINE:
|
||||
{
|
||||
const CArmedInstance * a = dynamic_cast<const CArmedInstance *>(obj);
|
||||
return a->getArmyStrength();
|
||||
}
|
||||
case Obj::CRYPT: //crypt
|
||||
case Obj::CREATURE_BANK: //crebank
|
||||
case Obj::DRAGON_UTOPIA:
|
||||
case Obj::SHIPWRECK: //shipwreck
|
||||
case Obj::DERELICT_SHIP: //derelict ship
|
||||
// case Obj::PYRAMID:
|
||||
return estimateBankDanger(dynamic_cast<const CBank *>(obj));
|
||||
case Obj::PYRAMID:
|
||||
{
|
||||
if(obj->subID == 0)
|
||||
return estimateBankDanger(dynamic_cast<const CBank *>(obj));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -42,4 +42,8 @@ public:
|
||||
|
||||
Goals::TSubgoal chooseSolution(Goals::TGoalVec vec);
|
||||
//std::shared_ptr<AbstractGoal> chooseSolution (std::vector<std::shared_ptr<AbstractGoal>> & vec);
|
||||
|
||||
ui64 evaluateDanger(const CGObjectInstance * obj);
|
||||
ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor, const CPlayerSpecificInfoCallback * cb);
|
||||
ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor);
|
||||
};
|
||||
|
@ -58,7 +58,6 @@ void AdventureSpellCast::accept(VCAI * ai)
|
||||
|
||||
cb->waitTillRealize = true;
|
||||
cb->castSpell(hero.h, spellID, tile);
|
||||
ai->ah->resetPaths();
|
||||
|
||||
if(town && spellID == SpellID::TOWN_PORTAL)
|
||||
{
|
||||
|
@ -53,7 +53,7 @@ TGoalVec VisitObj::getAllPossibleSubgoals()
|
||||
if(isSafeToVisit(hero, pos))
|
||||
goalList.push_back(sptr(VisitObj(obj->id.getNum()).sethero(hero)));
|
||||
else
|
||||
goalList.push_back(sptr(GatherArmy(evaluateDanger(pos, hero.h) * SAFE_ATTACK_CONSTANT).sethero(hero).setisAbstract(true)));
|
||||
goalList.push_back(sptr(GatherArmy(fh->evaluateDanger(pos, hero.h) * SAFE_ATTACK_CONSTANT).sethero(hero).setisAbstract(true)));
|
||||
|
||||
return goalList;
|
||||
}
|
||||
@ -67,7 +67,7 @@ TGoalVec VisitObj::getAllPossibleSubgoals()
|
||||
if(isSafeToVisit(potentialVisitor, pos))
|
||||
goalList.push_back(sptr(VisitObj(obj->id.getNum()).sethero(potentialVisitor)));
|
||||
else
|
||||
goalList.push_back(sptr(GatherArmy(evaluateDanger(pos, potentialVisitor) * SAFE_ATTACK_CONSTANT).sethero(potentialVisitor).setisAbstract(true)));
|
||||
goalList.push_back(sptr(GatherArmy(fh->evaluateDanger(pos, potentialVisitor) * SAFE_ATTACK_CONSTANT).sethero(potentialVisitor).setisAbstract(true)));
|
||||
}
|
||||
}
|
||||
if(!goalList.empty())
|
||||
|
@ -49,7 +49,7 @@ TSubgoal VisitTile::whatToDoToAchieve()
|
||||
}
|
||||
else
|
||||
{
|
||||
return sptr(GatherArmy(evaluateDanger(tile, *ret->hero) * SAFE_ATTACK_CONSTANT)
|
||||
return sptr(GatherArmy(fh->evaluateDanger(tile, *ret->hero) * SAFE_ATTACK_CONSTANT)
|
||||
.sethero(ret->hero).setisAbstract(true));
|
||||
}
|
||||
}
|
||||
|
@ -17,13 +17,11 @@
|
||||
#include "../../../lib/PathfinderUtil.h"
|
||||
#include "../../../lib/CPlayerState.h"
|
||||
|
||||
extern boost::thread_specific_ptr<CCallback> cb;
|
||||
|
||||
|
||||
AINodeStorage::AINodeStorage(const int3 & Sizes)
|
||||
: sizes(Sizes)
|
||||
{
|
||||
nodes.resize(boost::extents[sizes.x][sizes.y][sizes.z][EPathfindingLayer::NUM_LAYERS][NUM_CHAINS]);
|
||||
dangerEvaluator.reset(new FuzzyHelper());
|
||||
}
|
||||
|
||||
AINodeStorage::~AINodeStorage() = default;
|
||||
@ -187,9 +185,10 @@ std::vector<CGPathNode *> AINodeStorage::calculateNeighbours(
|
||||
return neighbours;
|
||||
}
|
||||
|
||||
void AINodeStorage::setHero(HeroPtr heroPtr)
|
||||
void AINodeStorage::setHero(HeroPtr heroPtr, const CPlayerSpecificInfoCallback * _cb)
|
||||
{
|
||||
hero = heroPtr.get();
|
||||
cb = _cb;
|
||||
}
|
||||
|
||||
std::vector<CGPathNode *> AINodeStorage::calculateTeleportations(
|
||||
@ -330,7 +329,7 @@ bool AINodeStorage::isTileAccessible(const int3 & pos, const EPathfindingLayer l
|
||||
return node.action != CGPathNode::ENodeAction::UNKNOWN;
|
||||
}
|
||||
|
||||
std::vector<AIPath> AINodeStorage::getChainInfo(int3 pos, bool isOnLand) const
|
||||
std::vector<AIPath> AINodeStorage::getChainInfo(const int3 & pos, bool isOnLand) const
|
||||
{
|
||||
std::vector<AIPath> paths;
|
||||
auto chains = nodes[pos.x][pos.y][pos.z][isOnLand ? EPathfindingLayer::LAND : EPathfindingLayer::SAIL];
|
||||
@ -360,6 +359,8 @@ std::vector<AIPath> AINodeStorage::getChainInfo(int3 pos, bool isOnLand) const
|
||||
current = getAINode(current->theNodeBefore);
|
||||
}
|
||||
|
||||
path.targetObjectDanger = evaluateDanger(pos);
|
||||
|
||||
paths.push_back(path);
|
||||
}
|
||||
|
||||
@ -405,8 +406,7 @@ float AIPath::movementCost() const
|
||||
uint64_t AIPath::getTotalDanger(HeroPtr hero) const
|
||||
{
|
||||
uint64_t pathDanger = getPathDanger();
|
||||
uint64_t objDanger = evaluateDanger(nodes.front().coord, hero.get()); // bank danger is not checked by pathfinder
|
||||
uint64_t danger = pathDanger > objDanger ? pathDanger : objDanger;
|
||||
uint64_t danger = pathDanger > targetObjectDanger ? pathDanger : targetObjectDanger;
|
||||
|
||||
return danger;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "../../../lib/CPathfinder.h"
|
||||
#include "../../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../AIUtility.h"
|
||||
#include "../FuzzyHelper.h"
|
||||
#include "../Goals/AbstractGoal.h"
|
||||
#include "Actions/ISpecialAction.h"
|
||||
|
||||
@ -38,6 +39,7 @@ struct AIPath
|
||||
{
|
||||
std::vector<AIPathNodeInfo> nodes;
|
||||
std::shared_ptr<const ISpecialAction> specialAction;
|
||||
uint64_t targetObjectDanger;
|
||||
|
||||
AIPath();
|
||||
|
||||
@ -59,7 +61,9 @@ private:
|
||||
|
||||
/// 1-3 - position on map, 4 - layer (air, water, land), 5 - chain (normal, battle, spellcast and combinations)
|
||||
boost::multi_array<AIPathNode, 5> nodes;
|
||||
const CPlayerSpecificInfoCallback * cb;
|
||||
const CGHeroInstance * hero;
|
||||
std::unique_ptr<FuzzyHelper> dangerEvaluator;
|
||||
|
||||
STRONG_INLINE
|
||||
void resetTile(const int3 & tile, EPathfindingLayer layer, CGPathNode::EAccessibility accessibility);
|
||||
@ -99,16 +103,21 @@ public:
|
||||
bool isBattleNode(const CGPathNode * node) const;
|
||||
bool hasBetterChain(const PathNodeInfo & source, CDestinationNodeInfo & destination) const;
|
||||
boost::optional<AIPathNode *> getOrCreateNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber);
|
||||
std::vector<AIPath> getChainInfo(int3 pos, bool isOnLand) const;
|
||||
std::vector<AIPath> getChainInfo(const int3 & pos, bool isOnLand) const;
|
||||
bool isTileAccessible(const int3 & pos, const EPathfindingLayer layer) const;
|
||||
|
||||
void setHero(HeroPtr heroPtr);
|
||||
void setHero(HeroPtr heroPtr, const CPlayerSpecificInfoCallback * cb);
|
||||
|
||||
const CGHeroInstance * getHero() const
|
||||
{
|
||||
return hero;
|
||||
}
|
||||
|
||||
uint64_t evaluateDanger(const int3 & tile) const
|
||||
{
|
||||
return dangerEvaluator->evaluateDanger(tile, hero, cb);
|
||||
}
|
||||
|
||||
private:
|
||||
void calculateTownPortalTeleportations(const PathNodeInfo & source, std::vector<CGPathNode *> & neighbours);
|
||||
};
|
||||
|
@ -15,41 +15,29 @@
|
||||
|
||||
std::vector<std::shared_ptr<AINodeStorage>> AIPathfinder::storagePool;
|
||||
std::map<HeroPtr, std::shared_ptr<AINodeStorage>> AIPathfinder::storageMap;
|
||||
boost::mutex AIPathfinder::storageMutex;
|
||||
|
||||
AIPathfinder::AIPathfinder(CPlayerSpecificInfoCallback * cb, VCAI * ai)
|
||||
:cb(cb), ai(ai)
|
||||
{
|
||||
}
|
||||
|
||||
void AIPathfinder::clear()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> storageLock(storageMutex);
|
||||
storageMap.clear();
|
||||
}
|
||||
|
||||
void AIPathfinder::init()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> storageLock(storageMutex);
|
||||
storagePool.clear();
|
||||
storageMap.clear();
|
||||
}
|
||||
|
||||
bool AIPathfinder::isTileAccessible(const HeroPtr & hero, const int3 & tile)
|
||||
bool AIPathfinder::isTileAccessible(const HeroPtr & hero, const int3 & tile) const
|
||||
{
|
||||
boost::unique_lock<boost::mutex> storageLock(storageMutex);
|
||||
|
||||
std::shared_ptr<AINodeStorage> nodeStorage = getOrCreateStorage(hero);
|
||||
std::shared_ptr<const AINodeStorage> nodeStorage = getStorage(hero);
|
||||
|
||||
return nodeStorage->isTileAccessible(tile, EPathfindingLayer::LAND)
|
||||
|| nodeStorage->isTileAccessible(tile, EPathfindingLayer::SAIL);
|
||||
}
|
||||
|
||||
std::vector<AIPath> AIPathfinder::getPathInfo(HeroPtr hero, int3 tile)
|
||||
std::vector<AIPath> AIPathfinder::getPathInfo(const HeroPtr & hero, const int3 & tile) const
|
||||
{
|
||||
boost::unique_lock<boost::mutex> storageLock(storageMutex);
|
||||
|
||||
std::shared_ptr<AINodeStorage> nodeStorage = getOrCreateStorage(hero);
|
||||
std::shared_ptr<const AINodeStorage> nodeStorage = getStorage(hero);
|
||||
|
||||
const TerrainTile * tileInfo = cb->getTile(tile, false);
|
||||
|
||||
@ -61,14 +49,24 @@ std::vector<AIPath> AIPathfinder::getPathInfo(HeroPtr hero, int3 tile)
|
||||
return nodeStorage->getChainInfo(tile, !tileInfo->isWater());
|
||||
}
|
||||
|
||||
std::shared_ptr<AINodeStorage> AIPathfinder::getOrCreateStorage(const HeroPtr & hero)
|
||||
void AIPathfinder::updatePaths(std::vector<HeroPtr> heroes)
|
||||
{
|
||||
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||
storageMap.clear();
|
||||
|
||||
if(!vstd::contains(storageMap, hero))
|
||||
auto calculatePaths = [&](const CGHeroInstance * hero, std::shared_ptr<AIPathfinding::AIPathfinderConfig> config)
|
||||
{
|
||||
logAi->debug("Recalculate paths for %s", hero->name);
|
||||
|
||||
cb->calculatePaths(config, hero);
|
||||
};
|
||||
|
||||
std::vector<Task> calculationTasks;
|
||||
|
||||
// TODO: go parallel?
|
||||
for(HeroPtr hero : heroes)
|
||||
{
|
||||
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||
|
||||
if(storageMap.size() < storagePool.size())
|
||||
{
|
||||
nodeStorage = storagePool.at(storageMap.size());
|
||||
@ -80,17 +78,64 @@ std::shared_ptr<AINodeStorage> AIPathfinder::getOrCreateStorage(const HeroPtr &
|
||||
}
|
||||
|
||||
storageMap[hero] = nodeStorage;
|
||||
nodeStorage->setHero(hero.get());
|
||||
nodeStorage->setHero(hero, cb);
|
||||
|
||||
auto config = std::make_shared<AIPathfinding::AIPathfinderConfig>(cb, ai, nodeStorage);
|
||||
|
||||
cb->calculatePaths(config, hero.get());
|
||||
calculationTasks.push_back(std::bind(calculatePaths, hero.get(), config));
|
||||
}
|
||||
|
||||
int threadsCount = std::min(
|
||||
boost::thread::hardware_concurrency(),
|
||||
(uint32_t)calculationTasks.size());
|
||||
|
||||
if(threadsCount <= 1)
|
||||
{
|
||||
for(auto task : calculationTasks)
|
||||
{
|
||||
task();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CThreadHelper helper(&calculationTasks, threadsCount);
|
||||
|
||||
helper.run();
|
||||
}
|
||||
}
|
||||
|
||||
void AIPathfinder::updatePaths(const HeroPtr & hero)
|
||||
{
|
||||
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||
|
||||
if(!vstd::contains(storageMap, hero))
|
||||
{
|
||||
if(storageMap.size() < storagePool.size())
|
||||
{
|
||||
nodeStorage = storagePool.at(storageMap.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeStorage = std::make_shared<AINodeStorage>(cb->getMapSize());
|
||||
storagePool.push_back(nodeStorage);
|
||||
}
|
||||
|
||||
storageMap[hero] = nodeStorage;
|
||||
nodeStorage->setHero(hero, cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeStorage = storageMap.at(hero);
|
||||
}
|
||||
|
||||
return nodeStorage;
|
||||
logAi->debug("Recalculate paths for %s", hero->name);
|
||||
auto config = std::make_shared<AIPathfinding::AIPathfinderConfig>(cb, ai, nodeStorage);
|
||||
|
||||
cb->calculatePaths(config, hero.get());
|
||||
}
|
||||
|
||||
std::shared_ptr<const AINodeStorage> AIPathfinder::getStorage(const HeroPtr & hero) const
|
||||
{
|
||||
return storageMap.at(hero);
|
||||
}
|
||||
|
||||
|
@ -19,15 +19,15 @@ class AIPathfinder
|
||||
private:
|
||||
static std::vector<std::shared_ptr<AINodeStorage>> storagePool;
|
||||
static std::map<HeroPtr, std::shared_ptr<AINodeStorage>> storageMap;
|
||||
static boost::mutex storageMutex;
|
||||
CPlayerSpecificInfoCallback * cb;
|
||||
VCAI * ai;
|
||||
|
||||
std::shared_ptr<AINodeStorage> getOrCreateStorage(const HeroPtr & hero);
|
||||
std::shared_ptr<const AINodeStorage> getStorage(const HeroPtr & hero) const;
|
||||
public:
|
||||
AIPathfinder(CPlayerSpecificInfoCallback * cb, VCAI * ai);
|
||||
std::vector<AIPath> getPathInfo(HeroPtr hero, int3 tile);
|
||||
bool isTileAccessible(const HeroPtr & hero, const int3 & tile);
|
||||
void clear();
|
||||
std::vector<AIPath> getPathInfo(const HeroPtr & hero, const int3 & tile) const;
|
||||
bool isTileAccessible(const HeroPtr & hero, const int3 & tile) const;
|
||||
void updatePaths(std::vector<HeroPtr> heroes);
|
||||
void updatePaths(const HeroPtr & heroes);
|
||||
void init();
|
||||
};
|
||||
|
@ -28,7 +28,7 @@ namespace AIPathfinding
|
||||
}
|
||||
|
||||
void SummonBoatAction::applyOnDestination(
|
||||
const HeroPtr & hero,
|
||||
const CGHeroInstance * hero,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathNodeInfo & source,
|
||||
AIPathNode * dstMode,
|
||||
@ -38,7 +38,7 @@ namespace AIPathfinding
|
||||
dstMode->theNodeBefore = source.node;
|
||||
}
|
||||
|
||||
bool SummonBoatAction::isAffordableBy(const HeroPtr & hero, const AIPathNode * source) const
|
||||
bool SummonBoatAction::isAffordableBy(const CGHeroInstance * hero, const AIPathNode * source) const
|
||||
{
|
||||
#ifdef VCMI_TRACE_PATHFINDER
|
||||
logAi->trace(
|
||||
@ -52,7 +52,7 @@ namespace AIPathfinding
|
||||
return hero->mana >= source->manaCost + getManaCost(hero);
|
||||
}
|
||||
|
||||
uint32_t SummonBoatAction::getManaCost(const HeroPtr & hero) const
|
||||
uint32_t SummonBoatAction::getManaCost(const CGHeroInstance * hero) const
|
||||
{
|
||||
SpellID summonBoat = SpellID::SUMMON_BOAT;
|
||||
|
||||
|
@ -44,16 +44,16 @@ namespace AIPathfinding
|
||||
virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override;
|
||||
|
||||
virtual void applyOnDestination(
|
||||
const HeroPtr & hero,
|
||||
const CGHeroInstance * hero,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathNodeInfo & source,
|
||||
AIPathNode * dstMode,
|
||||
const AIPathNode * srcNode) const override;
|
||||
|
||||
bool isAffordableBy(const HeroPtr & hero, const AIPathNode * source) const;
|
||||
bool isAffordableBy(const CGHeroInstance * hero, const AIPathNode * source) const;
|
||||
|
||||
private:
|
||||
uint32_t getManaCost(const HeroPtr & hero) const;
|
||||
uint32_t getManaCost(const CGHeroInstance * hero) const;
|
||||
};
|
||||
|
||||
class BuildBoatAction : public VirtualBoatAction
|
||||
|
@ -21,7 +21,7 @@ public:
|
||||
virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const = 0;
|
||||
|
||||
virtual void applyOnDestination(
|
||||
const HeroPtr & hero,
|
||||
const CGHeroInstance * hero,
|
||||
CDestinationNodeInfo & destination,
|
||||
const PathNodeInfo & source,
|
||||
AIPathNode * dstMode,
|
||||
|
@ -32,7 +32,7 @@ void PathfindingManager::setAI(VCAI * AI)
|
||||
ai = AI;
|
||||
}
|
||||
|
||||
Goals::TGoalVec PathfindingManager::howToVisitTile(int3 tile)
|
||||
Goals::TGoalVec PathfindingManager::howToVisitTile(const int3 & tile) const
|
||||
{
|
||||
Goals::TGoalVec result;
|
||||
|
||||
@ -47,7 +47,7 @@ Goals::TGoalVec PathfindingManager::howToVisitTile(int3 tile)
|
||||
return result;
|
||||
}
|
||||
|
||||
Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj)
|
||||
Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj) const
|
||||
{
|
||||
Goals::TGoalVec result;
|
||||
|
||||
@ -62,7 +62,7 @@ Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj)
|
||||
return result;
|
||||
}
|
||||
|
||||
Goals::TGoalVec PathfindingManager::howToVisitTile(HeroPtr hero, int3 tile, bool allowGatherArmy)
|
||||
Goals::TGoalVec PathfindingManager::howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy) const
|
||||
{
|
||||
auto result = findPath(hero, tile, allowGatherArmy, [&](int3 firstTileToGet) -> Goals::TSubgoal
|
||||
{
|
||||
@ -77,7 +77,7 @@ Goals::TGoalVec PathfindingManager::howToVisitTile(HeroPtr hero, int3 tile, bool
|
||||
return result;
|
||||
}
|
||||
|
||||
Goals::TGoalVec PathfindingManager::howToVisitObj(HeroPtr hero, ObjectIdRef obj, bool allowGatherArmy)
|
||||
Goals::TGoalVec PathfindingManager::howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy) const
|
||||
{
|
||||
if(!obj)
|
||||
{
|
||||
@ -102,7 +102,7 @@ Goals::TGoalVec PathfindingManager::howToVisitObj(HeroPtr hero, ObjectIdRef obj,
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<AIPath> PathfindingManager::getPathsToTile(HeroPtr hero, int3 tile)
|
||||
std::vector<AIPath> PathfindingManager::getPathsToTile(const HeroPtr & hero, const int3 & tile) const
|
||||
{
|
||||
return pathfinder->getPathInfo(hero, tile);
|
||||
}
|
||||
@ -111,7 +111,7 @@ Goals::TGoalVec PathfindingManager::findPath(
|
||||
HeroPtr hero,
|
||||
crint3 dest,
|
||||
bool allowGatherArmy,
|
||||
const std::function<Goals::TSubgoal(int3)> doVisitTile)
|
||||
const std::function<Goals::TSubgoal(int3)> doVisitTile) const
|
||||
{
|
||||
Goals::TGoalVec result;
|
||||
boost::optional<uint64_t> armyValueRequired;
|
||||
@ -184,7 +184,7 @@ Goals::TGoalVec PathfindingManager::findPath(
|
||||
return result;
|
||||
}
|
||||
|
||||
Goals::TSubgoal PathfindingManager::clearWayTo(HeroPtr hero, int3 firstTileToGet)
|
||||
Goals::TSubgoal PathfindingManager::clearWayTo(HeroPtr hero, int3 firstTileToGet) const
|
||||
{
|
||||
if(isBlockedBorderGate(firstTileToGet))
|
||||
{
|
||||
@ -235,8 +235,13 @@ Goals::TSubgoal PathfindingManager::clearWayTo(HeroPtr hero, int3 firstTileToGet
|
||||
return sptr(Goals::VisitTile(firstTileToGet).sethero(hero).setisAbstract(true));
|
||||
}
|
||||
|
||||
void PathfindingManager::resetPaths()
|
||||
void PathfindingManager::updatePaths(std::vector<HeroPtr> heroes)
|
||||
{
|
||||
logAi->debug("AIPathfinder has been reseted.");
|
||||
pathfinder->clear();
|
||||
pathfinder->updatePaths(heroes);
|
||||
}
|
||||
|
||||
void PathfindingManager::updatePaths(const HeroPtr & hero)
|
||||
{
|
||||
pathfinder->updatePaths(hero);
|
||||
}
|
||||
|
@ -20,12 +20,13 @@ public:
|
||||
virtual void init(CPlayerSpecificInfoCallback * CB) = 0;
|
||||
virtual void setAI(VCAI * AI) = 0;
|
||||
|
||||
virtual void resetPaths() = 0;
|
||||
virtual Goals::TGoalVec howToVisitTile(HeroPtr hero, int3 tile, bool allowGatherArmy = true) = 0;
|
||||
virtual Goals::TGoalVec howToVisitObj(HeroPtr hero, ObjectIdRef obj, bool allowGatherArmy = true) = 0;
|
||||
virtual Goals::TGoalVec howToVisitTile(int3 tile) = 0;
|
||||
virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj) = 0;
|
||||
virtual std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) = 0;
|
||||
virtual void updatePaths(std::vector<HeroPtr> heroes) = 0;
|
||||
virtual void updatePaths(const HeroPtr & hero) = 0;
|
||||
virtual Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const = 0;
|
||||
virtual Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const = 0;
|
||||
virtual Goals::TGoalVec howToVisitTile(const int3 & tile) const = 0;
|
||||
virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj) const = 0;
|
||||
virtual std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const = 0;
|
||||
};
|
||||
|
||||
class DLL_EXPORT PathfindingManager : public IPathfindingManager
|
||||
@ -41,15 +42,16 @@ public:
|
||||
PathfindingManager() = default;
|
||||
PathfindingManager(CPlayerSpecificInfoCallback * CB, VCAI * AI = nullptr); //for tests only
|
||||
|
||||
Goals::TGoalVec howToVisitTile(HeroPtr hero, int3 tile, bool allowGatherArmy = true) override;
|
||||
Goals::TGoalVec howToVisitObj(HeroPtr hero, ObjectIdRef obj, bool allowGatherArmy = true) override;
|
||||
Goals::TGoalVec howToVisitTile(int3 tile) override;
|
||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) override;
|
||||
std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) override;
|
||||
void resetPaths() override;
|
||||
Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const override;
|
||||
Goals::TGoalVec howToVisitTile(const int3 & tile) const override;
|
||||
Goals::TGoalVec howToVisitObj(ObjectIdRef obj) const override;
|
||||
std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const override;
|
||||
void updatePaths(std::vector<HeroPtr> heroes) override;
|
||||
void updatePaths(const HeroPtr & hero) override;
|
||||
|
||||
STRONG_INLINE
|
||||
bool isTileAccessible(const HeroPtr & hero, const int3 & tile)
|
||||
bool isTileAccessible(const HeroPtr & hero, const int3 & tile) const
|
||||
{
|
||||
return pathfinder->isTileAccessible(hero, tile);
|
||||
}
|
||||
@ -62,7 +64,7 @@ private:
|
||||
HeroPtr hero,
|
||||
crint3 dest,
|
||||
bool allowGatherArmy,
|
||||
const std::function<Goals::TSubgoal(int3)> goalFactory);
|
||||
const std::function<Goals::TSubgoal(int3)> goalFactory) const;
|
||||
|
||||
Goals::TSubgoal clearWayTo(HeroPtr hero, int3 firstTileToGet);
|
||||
Goals::TSubgoal clearWayTo(HeroPtr hero, int3 firstTileToGet) const;
|
||||
};
|
||||
|
@ -121,8 +121,7 @@ namespace AIPathfinding
|
||||
return;
|
||||
}
|
||||
|
||||
auto hero = nodeStorage->getHero();
|
||||
auto danger = evaluateDanger(destination.coord, hero);
|
||||
auto danger = nodeStorage->evaluateDanger(destination.coord);
|
||||
|
||||
destination.node = battleNode;
|
||||
nodeStorage->commit(destination, source);
|
||||
|
@ -96,7 +96,6 @@ void VCAI::heroMoved(const TryMoveHero & details)
|
||||
|
||||
validateObject(details.id); //enemy hero may have left visible area
|
||||
auto hero = cb->getHero(details.id);
|
||||
ah->resetPaths();
|
||||
|
||||
const int3 from = CGHeroInstance::convertPosition(details.start, false);
|
||||
const int3 to = CGHeroInstance::convertPosition(details.end, false);
|
||||
@ -376,8 +375,6 @@ void VCAI::newObject(const CGObjectInstance * obj)
|
||||
NET_EVENT_HANDLER;
|
||||
if(obj->isVisitable())
|
||||
addVisitableObj(obj);
|
||||
|
||||
ah->resetPaths();
|
||||
}
|
||||
|
||||
//to prevent AI from accessing objects that got deleted while they became invisible (Cover of Darkness, enemy hero moved etc.) below code allows AI to know deletion of objects out of sight
|
||||
@ -437,8 +434,6 @@ void VCAI::objectRemoved(const CGObjectInstance * obj)
|
||||
}
|
||||
}
|
||||
|
||||
ah->resetPaths();
|
||||
|
||||
//TODO
|
||||
//there are other places where CGObjectinstance ptrs are stored...
|
||||
//
|
||||
@ -795,7 +790,6 @@ void VCAI::makeTurn()
|
||||
}
|
||||
markHeroAbleToExplore(primaryHero());
|
||||
visitedHeroes.clear();
|
||||
ai->ah->resetPaths();
|
||||
|
||||
try
|
||||
{
|
||||
@ -829,6 +823,18 @@ void VCAI::makeTurn()
|
||||
endTurn();
|
||||
}
|
||||
|
||||
std::vector<HeroPtr> VCAI::getMyHeroes() const
|
||||
{
|
||||
std::vector<HeroPtr> ret;
|
||||
|
||||
for(auto h : cb->getHeroesInfo())
|
||||
{
|
||||
ret.push_back(h);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void VCAI::mainLoop()
|
||||
{
|
||||
std::vector<Goals::TSubgoal> elementarGoals; //no duplicates allowed (operator ==)
|
||||
@ -861,6 +867,8 @@ void VCAI::mainLoop()
|
||||
goalsToRemove.clear();
|
||||
elementarGoals.clear();
|
||||
ultimateGoalsFromBasic.clear();
|
||||
|
||||
ah->updatePaths(getMyHeroes());
|
||||
|
||||
logAi->debug("Main loop: decomposing %i basic goals", basicGoals.size());
|
||||
|
||||
@ -1414,6 +1422,8 @@ void VCAI::wander(HeroPtr h)
|
||||
while(h->movement)
|
||||
{
|
||||
validateVisitableObjs();
|
||||
ah->updatePaths(h);
|
||||
|
||||
std::vector<ObjectIdRef> dests;
|
||||
|
||||
//also visit our reserved objects - but they are not prioritized to avoid running back and forth
|
||||
@ -1698,7 +1708,6 @@ bool VCAI::isAbleToExplore(HeroPtr h)
|
||||
void VCAI::clearPathsInfo()
|
||||
{
|
||||
heroesUnableToExplore.clear();
|
||||
ah->resetPaths();
|
||||
}
|
||||
|
||||
void VCAI::validateVisitableObjs()
|
||||
|
@ -257,6 +257,7 @@ public:
|
||||
Goals::TSubgoal getGoal(HeroPtr h) const;
|
||||
bool canAct(HeroPtr h) const;
|
||||
std::vector<HeroPtr> getUnblockedHeroes() const;
|
||||
std::vector<HeroPtr> getMyHeroes() const;
|
||||
HeroPtr primaryHero() const;
|
||||
void checkHeroArmy(HeroPtr h);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user