2015-10-27 02:34:47 +02:00
/*
* CPathfinder . h , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2017-07-13 10:26:03 +02:00
# pragma once
# include "VCMI_Lib.h"
# include "IGameCallback.h"
# include "HeroBonus.h"
# include "int3.h"
2020-09-21 23:19:40 +02:00
# include <boost/heap/fibonacci_heap.hpp>
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_BEGIN
2015-10-27 02:34:47 +02:00
class CGHeroInstance ;
class CGObjectInstance ;
struct TerrainTile ;
2015-11-10 13:26:45 +02:00
class CPathfinderHelper ;
2015-12-02 21:05:10 +02:00
class CMap ;
class CGWhirlpool ;
2018-08-12 13:31:31 +02:00
class CPathfinderHelper ;
class CPathfinder ;
2018-10-07 13:51:27 +02:00
class PathfinderConfig ;
2015-10-27 02:34:47 +02:00
2020-09-21 23:19:40 +02:00
template < typename N >
struct DLL_LINKAGE NodeComparer
{
STRONG_INLINE
bool operator ( ) ( const N * lhs , const N * rhs ) const
{
return lhs - > getCost ( ) > rhs - > getCost ( ) ;
}
} ;
2015-10-27 02:34:47 +02:00
struct DLL_LINKAGE CGPathNode
{
2015-11-08 07:27:51 +02:00
typedef EPathfindingLayer ELayer ;
2015-11-19 02:08:57 +02:00
enum ENodeAction : ui8
2015-11-07 23:26:41 +02:00
{
2015-11-19 02:08:57 +02:00
UNKNOWN = 0 ,
2015-11-07 23:26:41 +02:00
EMBARK = 1 ,
2015-11-19 02:08:57 +02:00
DISEMBARK ,
NORMAL ,
BATTLE ,
VISIT ,
2015-12-11 08:42:30 +02:00
BLOCKING_VISIT ,
TELEPORT_NORMAL ,
TELEPORT_BLOCKING_VISIT ,
TELEPORT_BATTLE
2015-11-07 23:26:41 +02:00
} ;
2015-11-19 02:08:57 +02:00
enum EAccessibility : ui8
2015-10-27 02:34:47 +02:00
{
NOT_SET = 0 ,
ACCESSIBLE = 1 , //tile can be entered and passed
VISITABLE , //tile can be entered as the last tile in path
2019-01-15 07:52:55 +02:00
BLOCKVIS , //visitable from neighboring tile but not passable
2015-11-17 02:59:02 +02:00
FLYABLE , //can only be accessed in air layer
2015-10-27 02:34:47 +02:00
BLOCKED //tile can't be entered nor visited
} ;
CGPathNode * theNodeBefore ;
int3 coord ; //coordinates
2015-11-08 07:27:51 +02:00
ELayer layer ;
2019-01-15 07:52:55 +02:00
ui32 moveRemains ; //remaining movement points after hero reaches the tile
ui8 turns ; //how many turns we have to wait before reaching the tile - 0 means current turn
2015-11-19 02:08:57 +02:00
EAccessibility accessible ;
2015-11-07 23:26:41 +02:00
ENodeAction action ;
2015-11-19 02:08:57 +02:00
bool locked ;
2020-09-21 23:19:40 +02:00
bool inPQ ;
2015-10-27 02:34:47 +02:00
2019-01-15 05:00:00 +02:00
CGPathNode ( )
2019-01-15 07:52:55 +02:00
: coord ( - 1 ) ,
2020-09-21 23:19:40 +02:00
layer ( ELayer : : WRONG ) ,
pqHandle ( nullptr )
2019-01-15 05:00:00 +02:00
{
reset ( ) ;
}
STRONG_INLINE
void reset ( )
{
locked = false ;
accessible = NOT_SET ;
moveRemains = 0 ;
2019-01-15 07:52:55 +02:00
cost = std : : numeric_limits < float > : : max ( ) ;
2019-01-15 05:00:00 +02:00
turns = 255 ;
theNodeBefore = nullptr ;
action = UNKNOWN ;
2020-09-21 23:19:40 +02:00
inPQ = false ;
pq = nullptr ;
}
STRONG_INLINE
float getCost ( ) const
{
return cost ;
}
STRONG_INLINE
void setCost ( float value )
{
if ( value = = cost )
return ;
bool getUpNode = value < cost ;
cost = value ;
// If the node is in the heap, update the heap.
if ( inPQ & & pq ! = nullptr )
{
if ( getUpNode )
{
2020-09-28 15:39:55 +02:00
pq - > increase ( this - > pqHandle ) ;
2020-09-21 23:19:40 +02:00
}
else
{
2020-09-28 15:39:55 +02:00
pq - > decrease ( this - > pqHandle ) ;
2020-09-21 23:19:40 +02:00
}
}
2019-01-15 05:00:00 +02:00
}
STRONG_INLINE
void update ( const int3 & Coord , const ELayer Layer , const EAccessibility Accessible )
{
if ( layer = = ELayer : : WRONG )
{
coord = Coord ;
layer = Layer ;
}
else
{
reset ( ) ;
}
accessible = Accessible ;
}
STRONG_INLINE
bool reachable ( ) const
{
return turns < 255 ;
}
2020-09-21 23:19:40 +02:00
2020-09-29 23:28:07 +02:00
typedef boost : : heap : : fibonacci_heap <
CGPathNode * ,
boost : : heap : : compare < NodeComparer < CGPathNode > >
> TFibHeap ;
TFibHeap : : handle_type pqHandle ;
TFibHeap * pq ;
2020-09-21 23:19:40 +02:00
private :
float cost ; //total cost of the path to this tile measured in turns with fractions
2015-10-27 02:34:47 +02:00
} ;
struct DLL_LINKAGE CGPath
{
std : : vector < CGPathNode > nodes ; //just get node by node
int3 startPos ( ) const ; // start point
int3 endPos ( ) const ; //destination point
} ;
struct DLL_LINKAGE CPathsInfo
{
2015-11-08 07:27:51 +02:00
typedef EPathfindingLayer ELayer ;
2015-11-11 21:08:15 +02:00
const CGHeroInstance * hero ;
2015-10-27 02:34:47 +02:00
int3 hpos ;
int3 sizes ;
2022-09-18 16:39:10 +02:00
boost : : multi_array < CGPathNode , 4 > nodes ; //[layer][level][w][h]
2015-10-27 02:34:47 +02:00
2019-01-15 05:00:00 +02:00
CPathsInfo ( const int3 & Sizes , const CGHeroInstance * hero_ ) ;
2015-10-27 02:34:47 +02:00
~ CPathsInfo ( ) ;
2015-11-11 23:05:20 +02:00
const CGPathNode * getPathInfo ( const int3 & tile ) const ;
bool getPath ( CGPath & out , const int3 & dst ) const ;
const CGPathNode * getNode ( const int3 & coord ) const ;
2019-01-15 05:00:00 +02:00
STRONG_INLINE
CGPathNode * getNode ( const int3 & coord , const ELayer layer )
{
2022-09-18 16:39:10 +02:00
return & nodes [ layer ] [ coord . z ] [ coord . x ] [ coord . y ] ;
2019-01-15 05:00:00 +02:00
}
2015-10-27 02:34:47 +02:00
} ;
2018-10-07 13:51:27 +02:00
struct DLL_LINKAGE PathNodeInfo
2018-07-29 13:50:22 +02:00
{
CGPathNode * node ;
const CGObjectInstance * nodeObject ;
2021-05-16 19:53:11 +02:00
const CGHeroInstance * nodeHero ;
2018-07-29 13:50:22 +02:00
const TerrainTile * tile ;
int3 coord ;
2018-08-01 20:46:06 +02:00
bool guarded ;
2018-08-01 22:21:14 +02:00
PlayerRelations : : PlayerRelations objectRelations ;
2021-05-16 19:53:11 +02:00
PlayerRelations : : PlayerRelations heroRelations ;
bool isInitialPosition ;
2018-07-29 13:50:22 +02:00
2018-10-07 13:51:27 +02:00
PathNodeInfo ( ) ;
2018-07-29 13:50:22 +02:00
2021-05-16 19:53:11 +02:00
virtual void setNode ( CGameState * gs , CGPathNode * n ) ;
void updateInfo ( CPathfinderHelper * hlp , CGameState * gs ) ;
2018-07-29 13:50:22 +02:00
bool isNodeObjectVisitable ( ) const ;
} ;
2018-10-07 13:51:27 +02:00
struct DLL_LINKAGE CDestinationNodeInfo : public PathNodeInfo
2018-08-01 20:46:06 +02:00
{
CGPathNode : : ENodeAction action ;
2018-08-08 21:24:18 +02:00
int turn ;
int movementLeft ;
2019-01-15 07:52:55 +02:00
float cost ; //same as CGPathNode::cost
2018-08-01 20:46:06 +02:00
bool blocked ;
2018-08-12 13:31:31 +02:00
bool isGuardianTile ;
2018-08-01 20:46:06 +02:00
CDestinationNodeInfo ( ) ;
2021-05-16 19:53:11 +02:00
virtual void setNode ( CGameState * gs , CGPathNode * n ) override ;
2018-08-08 21:24:18 +02:00
2018-08-12 13:31:31 +02:00
virtual bool isBetterWay ( ) const ;
2018-08-01 20:46:06 +02:00
} ;
2018-08-12 13:31:31 +02:00
class IPathfindingRule
2018-07-29 13:50:22 +02:00
{
public :
2022-05-19 14:14:50 +02:00
virtual ~ IPathfindingRule ( ) = default ;
2018-08-12 13:31:31 +02:00
virtual void process (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & source ,
2018-08-12 13:31:31 +02:00
CDestinationNodeInfo & destination ,
2018-10-07 13:51:27 +02:00
const PathfinderConfig * pathfinderConfig ,
2018-08-12 13:31:31 +02:00
CPathfinderHelper * pathfinderHelper ) const = 0 ;
2018-07-29 13:50:22 +02:00
} ;
2018-10-07 13:51:27 +02:00
class DLL_LINKAGE MovementCostRule : public IPathfindingRule
2018-08-12 13:31:31 +02:00
{
public :
virtual void process (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & source ,
2018-08-12 13:31:31 +02:00
CDestinationNodeInfo & destination ,
2018-10-07 13:51:27 +02:00
const PathfinderConfig * pathfinderConfig ,
2018-08-12 13:31:31 +02:00
CPathfinderHelper * pathfinderHelper ) const override ;
} ;
2018-07-29 13:50:22 +02:00
2018-10-07 13:51:27 +02:00
class DLL_LINKAGE LayerTransitionRule : public IPathfindingRule
2018-08-01 20:46:06 +02:00
{
public :
2018-08-08 21:24:18 +02:00
virtual void process (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & source ,
2018-08-08 21:24:18 +02:00
CDestinationNodeInfo & destination ,
2018-10-07 13:51:27 +02:00
const PathfinderConfig * pathfinderConfig ,
2018-08-12 13:31:31 +02:00
CPathfinderHelper * pathfinderHelper ) const override ;
2018-08-01 20:46:06 +02:00
} ;
2018-10-07 13:51:27 +02:00
class DLL_LINKAGE DestinationActionRule : public IPathfindingRule
2018-08-01 20:46:06 +02:00
{
public :
2018-08-08 21:24:18 +02:00
virtual void process (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & source ,
2018-08-08 21:24:18 +02:00
CDestinationNodeInfo & destination ,
2018-10-07 13:51:27 +02:00
const PathfinderConfig * pathfinderConfig ,
2018-08-12 13:31:31 +02:00
CPathfinderHelper * pathfinderHelper ) const override ;
2018-08-01 20:46:06 +02:00
} ;
2018-10-07 13:51:27 +02:00
class DLL_LINKAGE PathfinderBlockingRule : public IPathfindingRule
2018-08-11 21:39:42 +02:00
{
public :
virtual void process (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & source ,
2018-08-11 21:39:42 +02:00
CDestinationNodeInfo & destination ,
2018-10-07 13:51:27 +02:00
const PathfinderConfig * pathfinderConfig ,
2018-08-12 13:31:31 +02:00
CPathfinderHelper * pathfinderHelper ) const override
2018-08-11 21:39:42 +02:00
{
auto blockingReason = getBlockingReason ( source , destination , pathfinderConfig , pathfinderHelper ) ;
destination . blocked = blockingReason ! = BlockingReason : : NONE ;
}
protected :
enum class BlockingReason
{
NONE = 0 ,
SOURCE_GUARDED = 1 ,
DESTINATION_GUARDED = 2 ,
SOURCE_BLOCKED = 3 ,
DESTINATION_BLOCKED = 4 ,
DESTINATION_BLOCKVIS = 5 ,
DESTINATION_VISIT = 6
} ;
virtual BlockingReason getBlockingReason (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & source ,
const CDestinationNodeInfo & destination ,
const PathfinderConfig * pathfinderConfig ,
const CPathfinderHelper * pathfinderHelper ) const = 0 ;
2018-08-11 21:39:42 +02:00
} ;
2018-10-07 13:51:27 +02:00
class DLL_LINKAGE MovementAfterDestinationRule : public PathfinderBlockingRule
2018-08-11 21:39:42 +02:00
{
public :
virtual void process (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & source ,
2018-08-11 21:39:42 +02:00
CDestinationNodeInfo & destination ,
2018-10-07 13:51:27 +02:00
const PathfinderConfig * pathfinderConfig ,
2018-08-12 13:31:31 +02:00
CPathfinderHelper * pathfinderHelper ) const override ;
2018-08-11 21:39:42 +02:00
protected :
virtual BlockingReason getBlockingReason (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & source ,
const CDestinationNodeInfo & destination ,
const PathfinderConfig * pathfinderConfig ,
const CPathfinderHelper * pathfinderHelper ) const override ;
2018-08-11 21:39:42 +02:00
} ;
2018-10-07 13:51:27 +02:00
class DLL_LINKAGE MovementToDestinationRule : public PathfinderBlockingRule
2018-08-11 21:39:42 +02:00
{
protected :
virtual BlockingReason getBlockingReason (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & source ,
const CDestinationNodeInfo & destination ,
const PathfinderConfig * pathfinderConfig ,
const CPathfinderHelper * pathfinderHelper ) const override ;
2018-08-11 21:39:42 +02:00
} ;
2018-08-01 20:46:06 +02:00
struct DLL_LINKAGE PathfinderOptions
{
bool useFlying ;
bool useWaterWalking ;
bool useEmbarkAndDisembark ;
bool useTeleportTwoWay ; // Two-way monoliths and Subterranean Gate
bool useTeleportOneWay ; // One-way monoliths with one known exit only
bool useTeleportOneWayRandom ; // One-way monoliths with more than one known exit
bool useTeleportWhirlpool ; // Force enabled if hero protected or unaffected (have one stack of one creature)
/// TODO: Find out with client and server code, merge with normal teleporters.
/// Likely proper implementation would require some refactoring of CGTeleport.
/// So for now this is unfinished and disabled by default.
bool useCastleGate ;
/// If true transition into air layer only possible from initial node.
/// This is drastically decrease path calculation complexity (and time).
/// Downside is less MP effective paths calculation.
///
/// TODO: If this option end up useful for slow devices it's can be improved:
/// - Allow transition into air layer not only from initial position, but also from teleporters.
/// Movement into air can be also allowed when hero disembarked.
/// - Other idea is to allow transition into air within certain radius of N tiles around hero.
/// Patrol support need similar functionality so it's won't be ton of useless code.
/// Such limitation could be useful as it's can be scaled depend on device performance.
bool lightweightFlyingMode ;
/// This option enable one turn limitation for flying and water walking.
/// So if we're out of MP while cp is blocked or water tile we won't add dest tile to queue.
///
/// Following imitation is default H3 mechanics, but someone may want to disable it in mods.
/// After all this limit should benefit performance on maps with tons of water or blocked tiles.
///
/// TODO:
/// - Behavior when option is disabled not implemented and will lead to crashes.
bool oneTurnSpecialLayersLimit ;
/// VCMI have different movement rules to solve flaws original engine has.
/// If this option enabled you'll able to do following things in fly:
/// - Move from blocked tiles to visitable one
/// - Move from guarded tiles to blockvis tiles without being attacked
/// - Move from guarded tiles to guarded visitable tiles with being attacked after
/// TODO:
/// - Option should also allow same tile land <-> air layer transitions.
/// Current implementation only allow go into (from) air layer only to neighbour tiles.
/// I find it's reasonable limitation, but it's will make some movements more expensive than in H3.
bool originalMovementRules ;
PathfinderOptions ( ) ;
2018-07-29 13:50:22 +02:00
} ;
2019-01-15 05:00:00 +02:00
class DLL_LINKAGE INodeStorage
{
public :
using ELayer = EPathfindingLayer ;
2022-09-22 10:02:16 +02:00
virtual ~ INodeStorage ( ) = default ;
2021-05-16 19:53:11 +02:00
virtual std : : vector < CGPathNode * > getInitialNodes ( ) = 0 ;
2019-01-15 05:00:00 +02:00
virtual std : : vector < CGPathNode * > calculateNeighbours (
const PathNodeInfo & source ,
const PathfinderConfig * pathfinderConfig ,
const CPathfinderHelper * pathfinderHelper ) = 0 ;
virtual std : : vector < CGPathNode * > calculateTeleportations (
const PathNodeInfo & source ,
const PathfinderConfig * pathfinderConfig ,
const CPathfinderHelper * pathfinderHelper ) = 0 ;
virtual void commit ( CDestinationNodeInfo & destination , const PathNodeInfo & source ) = 0 ;
2021-05-16 19:53:11 +02:00
virtual void initialize ( const PathfinderOptions & options , const CGameState * gs ) = 0 ;
2019-01-15 05:00:00 +02:00
} ;
class DLL_LINKAGE NodeStorage : public INodeStorage
{
private :
CPathsInfo & out ;
STRONG_INLINE
void resetTile ( const int3 & tile , EPathfindingLayer layer , CGPathNode : : EAccessibility accessibility ) ;
public :
NodeStorage ( CPathsInfo & pathsInfo , const CGHeroInstance * hero ) ;
STRONG_INLINE
CGPathNode * getNode ( const int3 & coord , const EPathfindingLayer layer )
{
return out . getNode ( coord , layer ) ;
}
2021-05-16 19:53:11 +02:00
void initialize ( const PathfinderOptions & options , const CGameState * gs ) override ;
2022-05-19 14:14:50 +02:00
virtual ~ NodeStorage ( ) = default ;
2019-01-15 05:00:00 +02:00
2021-05-16 19:53:11 +02:00
virtual std : : vector < CGPathNode * > getInitialNodes ( ) override ;
2019-01-15 05:00:00 +02:00
virtual std : : vector < CGPathNode * > calculateNeighbours (
const PathNodeInfo & source ,
const PathfinderConfig * pathfinderConfig ,
const CPathfinderHelper * pathfinderHelper ) override ;
virtual std : : vector < CGPathNode * > calculateTeleportations (
const PathNodeInfo & source ,
const PathfinderConfig * pathfinderConfig ,
const CPathfinderHelper * pathfinderHelper ) override ;
virtual void commit ( CDestinationNodeInfo & destination , const PathNodeInfo & source ) override ;
} ;
2018-10-07 13:51:27 +02:00
class DLL_LINKAGE PathfinderConfig
2018-08-08 21:24:18 +02:00
{
public :
2018-08-12 13:31:31 +02:00
std : : shared_ptr < INodeStorage > nodeStorage ;
2018-08-08 21:24:18 +02:00
std : : vector < std : : shared_ptr < IPathfindingRule > > rules ;
PathfinderOptions options ;
2018-10-07 13:51:27 +02:00
PathfinderConfig (
2018-08-12 13:31:31 +02:00
std : : shared_ptr < INodeStorage > nodeStorage ,
2018-08-08 21:24:18 +02:00
std : : vector < std : : shared_ptr < IPathfindingRule > > rules ) ;
2022-09-22 10:02:16 +02:00
virtual ~ PathfinderConfig ( ) = default ;
2021-05-16 19:53:11 +02:00
virtual CPathfinderHelper * getOrCreatePathfinderHelper ( const PathNodeInfo & source , CGameState * gs ) = 0 ;
} ;
class DLL_LINKAGE SingleHeroPathfinderConfig : public PathfinderConfig
{
private :
std : : unique_ptr < CPathfinderHelper > pathfinderHelper ;
public :
SingleHeroPathfinderConfig ( CPathsInfo & out , CGameState * gs , const CGHeroInstance * hero ) ;
2022-05-19 14:14:50 +02:00
virtual ~ SingleHeroPathfinderConfig ( ) = default ;
2021-05-16 19:53:11 +02:00
virtual CPathfinderHelper * getOrCreatePathfinderHelper ( const PathNodeInfo & source , CGameState * gs ) override ;
static std : : vector < std : : shared_ptr < IPathfindingRule > > buildRuleSet ( ) ;
2018-08-08 21:24:18 +02:00
} ;
2022-12-07 21:50:45 +02:00
class CPathfinder
2015-10-27 02:34:47 +02:00
{
public :
2015-11-16 17:43:02 +02:00
friend class CPathfinderHelper ;
2018-07-29 13:50:22 +02:00
CPathfinder (
2019-01-15 05:00:00 +02:00
CGameState * _gs ,
2018-10-07 13:51:27 +02:00
std : : shared_ptr < PathfinderConfig > config ) ;
2018-07-29 13:50:22 +02:00
2015-10-27 02:34:47 +02:00
void calculatePaths ( ) ; //calculates possible paths for hero, uses current hero position and movement left; returns pointer to newly allocated CPath or nullptr if path does not exists
2018-08-01 20:46:06 +02:00
private :
2022-12-07 21:50:45 +02:00
CGameState * gamestate ;
2015-11-08 07:27:51 +02:00
typedef EPathfindingLayer ELayer ;
2019-01-15 05:00:00 +02:00
2018-10-07 13:51:27 +02:00
std : : shared_ptr < PathfinderConfig > config ;
2015-10-27 02:34:47 +02:00
2020-09-21 23:19:40 +02:00
boost : : heap : : fibonacci_heap < CGPathNode * , boost : : heap : : compare < NodeComparer < CGPathNode > > > pq ;
2015-10-27 02:34:47 +02:00
2018-10-07 13:51:27 +02:00
PathNodeInfo source ; //current (source) path node -> we took it from the queue
2018-08-01 20:46:06 +02:00
CDestinationNodeInfo destination ; //destination node -> it's a neighbour of source that we consider
2015-10-27 02:34:47 +02:00
2018-10-09 21:30:12 +02:00
bool isLayerTransitionPossible ( ) const ;
2015-12-11 08:42:30 +02:00
CGPathNode : : ENodeAction getTeleportDestAction ( ) const ;
2015-10-27 02:34:47 +02:00
2015-11-08 07:39:00 +02:00
bool isDestinationGuardian ( ) const ;
2015-10-27 02:34:47 +02:00
void initializeGraph ( ) ;
2020-09-21 23:19:40 +02:00
STRONG_INLINE
void push ( CGPathNode * node ) ;
STRONG_INLINE
CGPathNode * topAndPop ( ) ;
2015-10-27 02:34:47 +02:00
} ;
2015-11-10 01:15:27 +02:00
2015-11-12 13:04:33 +02:00
struct DLL_LINKAGE TurnInfo
2015-11-10 13:26:45 +02:00
{
2015-11-21 09:00:09 +02:00
/// This is certainly not the best design ever and certainly can be improved
/// Unfortunately for pathfinder that do hundreds of thousands calls onus system add too big overhead
struct BonusCache {
std : : vector < bool > noTerrainPenalty ;
bool freeShipBoarding ;
bool flyingMovement ;
int flyingMovementVal ;
bool waterWalking ;
int waterWalkingVal ;
2022-09-14 15:16:12 +02:00
int pathfindingVal ;
2015-11-21 09:00:09 +02:00
2020-10-01 07:55:41 +02:00
BonusCache ( TConstBonusListPtr bonusList ) ;
2015-11-21 09:00:09 +02:00
} ;
2015-12-29 04:43:33 +02:00
std : : unique_ptr < BonusCache > bonusCache ;
2015-11-21 09:00:09 +02:00
2015-11-12 13:04:33 +02:00
const CGHeroInstance * hero ;
2020-10-01 07:55:41 +02:00
TConstBonusListPtr bonuses ;
2015-11-12 13:04:33 +02:00
mutable int maxMovePointsLand ;
mutable int maxMovePointsWater ;
2022-09-29 11:44:46 +02:00
TerrainId nativeTerrain ;
2015-11-12 04:20:32 +02:00
2015-11-12 13:04:33 +02:00
TurnInfo ( const CGHeroInstance * Hero , const int Turn = 0 ) ;
2015-11-12 13:39:22 +02:00
bool isLayerAvailable ( const EPathfindingLayer layer ) const ;
2015-11-12 13:04:33 +02:00
bool hasBonusOfType ( const Bonus : : BonusType type , const int subtype = - 1 ) const ;
int valOfBonuses ( const Bonus : : BonusType type , const int subtype = - 1 ) const ;
2015-11-12 04:20:32 +02:00
int getMaxMovePoints ( const EPathfindingLayer layer ) const ;
2015-11-10 13:26:45 +02:00
} ;
2018-08-01 20:46:06 +02:00
class DLL_LINKAGE CPathfinderHelper : private CGameInfoCallback
2015-11-10 01:15:27 +02:00
{
public :
2021-05-16 19:53:11 +02:00
enum EPatrolState
{
PATROL_NONE = 0 ,
PATROL_LOCKED = 1 ,
PATROL_RADIUS
} patrolState ;
std : : unordered_set < int3 , ShashInt3 > patrolTiles ;
2018-08-01 20:46:06 +02:00
int turn ;
2021-05-16 19:53:11 +02:00
PlayerColor owner ;
2018-08-01 20:46:06 +02:00
const CGHeroInstance * hero ;
std : : vector < TurnInfo * > turnsInfo ;
const PathfinderOptions & options ;
CPathfinderHelper ( CGameState * gs , const CGHeroInstance * Hero , const PathfinderOptions & Options ) ;
2022-05-19 14:14:50 +02:00
virtual ~ CPathfinderHelper ( ) ;
2021-05-16 19:53:11 +02:00
void initializePatrol ( ) ;
bool isHeroPatrolLocked ( ) const ;
bool isPatrolMovementAllowed ( const int3 & dst ) const ;
2015-11-11 21:08:15 +02:00
void updateTurnInfo ( const int turn = 0 ) ;
2015-11-12 13:39:22 +02:00
bool isLayerAvailable ( const EPathfindingLayer layer ) const ;
2015-11-12 13:04:33 +02:00
const TurnInfo * getTurnInfo ( ) const ;
bool hasBonusOfType ( const Bonus : : BonusType type , const int subtype = - 1 ) const ;
int getMaxMovePoints ( const EPathfindingLayer layer ) const ;
2015-11-10 13:26:45 +02:00
2018-10-07 13:51:27 +02:00
std : : vector < int3 > getCastleGates ( const PathNodeInfo & source ) const ;
2018-08-01 20:46:06 +02:00
bool isAllowedTeleportEntrance ( const CGTeleport * obj ) const ;
2018-08-01 22:21:14 +02:00
std : : vector < int3 > getAllowedTeleportChannelExits ( TeleportChannelID channelID ) const ;
2018-08-01 20:46:06 +02:00
bool addTeleportTwoWay ( const CGTeleport * obj ) const ;
bool addTeleportOneWay ( const CGTeleport * obj ) const ;
bool addTeleportOneWayRandom ( const CGTeleport * obj ) const ;
bool addTeleportWhirlpool ( const CGWhirlpool * obj ) const ;
bool canMoveBetween ( const int3 & a , const int3 & b ) const ; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility)
2018-10-07 13:51:27 +02:00
std : : vector < int3 > getNeighbourTiles ( const PathNodeInfo & source ) const ;
std : : vector < int3 > getTeleportExits ( const PathNodeInfo & source ) const ;
2018-08-12 13:31:31 +02:00
void getNeighbours (
const TerrainTile & srct ,
2019-01-15 05:00:00 +02:00
const int3 & tile ,
std : : vector < int3 > & vec ,
const boost : : logic : : tribool & onLand ,
2018-08-12 13:31:31 +02:00
const bool limitCoastSailing ) const ;
2019-01-15 05:00:00 +02:00
2018-08-01 20:46:06 +02:00
int getMovementCost (
2019-01-15 05:00:00 +02:00
const int3 & src ,
const int3 & dst ,
2018-07-29 13:50:22 +02:00
const TerrainTile * ct ,
const TerrainTile * dt ,
2019-01-15 05:00:00 +02:00
const int remainingMovePoints = - 1 ,
2018-08-12 13:31:31 +02:00
const bool checkLast = true ) const ;
2018-07-29 13:50:22 +02:00
2018-08-01 20:46:06 +02:00
int getMovementCost (
2018-10-07 13:51:27 +02:00
const PathNodeInfo & src ,
const PathNodeInfo & dst ,
2018-07-29 13:50:22 +02:00
const int remainingMovePoints = - 1 ,
2018-08-12 13:31:31 +02:00
const bool checkLast = true ) const
2018-07-29 13:50:22 +02:00
{
return getMovementCost (
src . coord ,
dst . coord ,
src . tile ,
dst . tile ,
remainingMovePoints ,
checkLast
) ;
}
2018-08-08 21:24:18 +02:00
2019-01-15 07:52:55 +02:00
int movementPointsAfterEmbark ( int movement , int basicCost , bool disembark ) const ;
2018-10-07 13:51:27 +02:00
bool passOneTurnLimitCheck ( const PathNodeInfo & source ) const ;
2015-11-10 01:15:27 +02:00
} ;
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_END