diff --git a/lib/CPathfinder.cpp b/lib/CPathfinder.cpp index 8be71f212..8046f461d 100644 --- a/lib/CPathfinder.cpp +++ b/lib/CPathfinder.cpp @@ -37,7 +37,7 @@ CPathfinder::PathfinderOptions::PathfinderOptions() } CPathfinder::CPathfinder(CPathsInfo & _out, CGameState * _gs, const CGHeroInstance * _hero) - : CGameInfoCallback(_gs, boost::optional()), out(_out), hero(_hero), FoW(getPlayerTeam(hero->tempOwner)->fogOfWarMap) + : CGameInfoCallback(_gs, boost::optional()), out(_out), hero(_hero), FoW(getPlayerTeam(hero->tempOwner)->fogOfWarMap), patrolTiles({}) { assert(hero); assert(hero == getHero(hero->id)); @@ -52,6 +52,7 @@ CPathfinder::CPathfinder(CPathsInfo & _out, CGameState * _gs, const CGHeroInstan hlp = make_unique(hero, options); + initializePatrol(); initializeGraph(); neighbourTiles.reserve(8); neighbours.reserve(16); @@ -95,8 +96,10 @@ void CPathfinder::calculatePaths() CGPathNode * initialNode = out.getNode(out.hpos, hero->boat ? ELayer::SAIL : ELayer::LAND); initialNode->turns = 0; initialNode->moveRemains = hero->movement; - pq.push(initialNode); + if(isHeroPatrolLocked()) + return; + pq.push(initialNode); while(!pq.empty()) { cp = pq.top(); @@ -119,6 +122,9 @@ void CPathfinder::calculatePaths() addNeighbours(); for(auto & neighbour : neighbours) { + if(!isPatrolMovementAllowed(neighbour)) + continue; + dt = &gs->map->getTile(neighbour); dtObj = dt->topVisitableObj(); for(ELayer i = ELayer::LAND; i <= ELayer::AIR; i.advance(1)) @@ -215,7 +221,9 @@ void CPathfinder::addNeighbours() void CPathfinder::addTeleportExits() { neighbours.clear(); - if(!isSourceVisitableObj()) + /// For now we disable teleports usage for patrol movement + /// VCAI not aware about patrol and may stuck while attempt to use teleport + if(!isSourceVisitableObj() || patrolState == PATROL_RADIUS) return; const CGTeleport * objTeleport = dynamic_cast(ctObj); @@ -256,6 +264,22 @@ void CPathfinder::addTeleportExits() } } +bool CPathfinder::isHeroPatrolLocked() const +{ + return patrolState == PATROL_LOCKED; +} + +bool CPathfinder::isPatrolMovementAllowed(const int3 & dst) const +{ + if(patrolState == PATROL_RADIUS) + { + if(!vstd::contains(patrolTiles, dst)) + return false; + } + + return true; +} + bool CPathfinder::isLayerTransitionPossible(const ELayer destLayer) const { /// No layer transition allowed when previous node action is BATTLE @@ -564,6 +588,23 @@ bool CPathfinder::isDestinationGuardian() const return gs->guardingCreaturePosition(cp->coord) == dp->coord; } +void CPathfinder::initializePatrol() +{ + auto state = PATROL_NONE; + if(hero->patrol.patrolling && !getPlayer(hero->tempOwner)->human) + { + if(hero->patrol.patrolRadious) + { + state = PATROL_RADIUS; + gs->getTilesInRange(patrolTiles, hero->patrol.initialPos, hero->patrol.patrolRadious); + } + else + state = PATROL_LOCKED; + } + + patrolState = state; +} + void CPathfinder::initializeGraph() { auto updateNode = [&](int3 pos, ELayer layer, const TerrainTile * tinfo) diff --git a/lib/CPathfinder.h b/lib/CPathfinder.h index 29c5bd35e..e3e533864 100644 --- a/lib/CPathfinder.h +++ b/lib/CPathfinder.h @@ -159,6 +159,13 @@ private: const std::vector > > &FoW; unique_ptr hlp; + enum EPatrolState { + PATROL_NONE = 0, + PATROL_LOCKED = 1, + PATROL_RADIUS + } patrolState; + std::unordered_set patrolTiles; + struct NodeComparer { bool operator()(const CGPathNode * lhs, const CGPathNode * rhs) const @@ -185,6 +192,9 @@ private: void addNeighbours(); void addTeleportExits(); + bool isHeroPatrolLocked() const; + bool isPatrolMovementAllowed(const int3 & dst) const; + bool isLayerTransitionPossible(const ELayer dstLayer) const; bool isLayerTransitionPossible() const; bool isMovementToDestPossible() const; @@ -198,6 +208,7 @@ private: bool isDestinationGuarded(const bool ignoreAccessibility = true) const; bool isDestinationGuardian() const; + void initializePatrol(); void initializeGraph(); CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo, const ELayer layer) const; diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 869681360..859abc110 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -1658,7 +1658,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(ObjectInstanceID idToBeGiven, const i else { nhi->patrol.patrolling = true; - nhi->patrol.initialPos = initialPos; + nhi->patrol.initialPos = CGHeroInstance::convertPosition(initialPos, false); } if(map->version > EMapFormat::ROE)