2015-10-27 02:34:47 +02:00
# pragma once
# include "VCMI_Lib.h"
# include "mapping/CMap.h"
# include "IGameCallback.h"
# include "int3.h"
2015-11-07 20:11:07 +02:00
# include <boost/heap/priority_queue.hpp>
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
*
*/
class CGHeroInstance ;
class CGObjectInstance ;
struct TerrainTile ;
2015-11-10 13:26:45 +02:00
class CPathfinderHelper ;
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-07 23:26:41 +02:00
enum ENodeAction
{
UNKNOWN = - 1 ,
NORMAL = 0 ,
EMBARK = 1 ,
DISEMBARK , //2
BATTLE , //3
VISIT , //4
BLOCKING_VISIT //5
} ;
2015-10-27 02:34:47 +02:00
enum EAccessibility
{
NOT_SET = 0 ,
ACCESSIBLE = 1 , //tile can be entered and passed
VISITABLE , //tile can be entered as the last tile in path
BLOCKVIS , //visitable from neighbouring tile but not passable
BLOCKED //tile can't be entered nor visited
} ;
2015-11-07 20:11:07 +02:00
bool locked ;
2015-10-27 02:34:47 +02:00
EAccessibility accessible ;
ui8 turns ; //how many turns we have to wait before reachng the tile - 0 means current turn
ui32 moveRemains ; //remaining tiles after hero reaches the tile
CGPathNode * theNodeBefore ;
int3 coord ; //coordinates
2015-11-08 07:27:51 +02:00
ELayer layer ;
2015-11-07 23:26:41 +02:00
ENodeAction action ;
2015-10-27 02:34:47 +02:00
2015-11-08 07:27:51 +02:00
CGPathNode ( int3 Coord , ELayer Layer ) ;
2015-11-07 21:16:45 +02:00
void reset ( ) ;
2015-10-27 02:34:47 +02:00
bool reachable ( ) const ;
} ;
struct DLL_LINKAGE CGPath
{
std : : vector < CGPathNode > nodes ; //just get node by node
int3 startPos ( ) const ; // start point
int3 endPos ( ) const ; //destination point
void convert ( ui8 mode ) ; //mode=0 -> from 'manifest' to 'object'
} ;
struct DLL_LINKAGE CPathsInfo
{
2015-11-08 07:27:51 +02:00
typedef EPathfindingLayer ELayer ;
2015-10-27 02:34:47 +02:00
mutable boost : : mutex pathMx ;
2015-11-11 21:08:15 +02:00
const CGHeroInstance * hero ;
2015-10-27 02:34:47 +02:00
int3 hpos ;
int3 sizes ;
2015-11-07 21:00:31 +02:00
boost : : multi_array < CGPathNode * , 4 > nodes ; //[w][h][level][layer]
2015-10-27 02:34:47 +02:00
2015-11-11 21:08:15 +02:00
CPathsInfo ( const int3 & Sizes ) ;
2015-10-27 02:34:47 +02:00
~ CPathsInfo ( ) ;
2015-11-11 21:08:15 +02:00
const CGPathNode * getPathInfo ( const int3 & tile , const ELayer layer = ELayer : : AUTO ) const ;
bool getPath ( CGPath & out , const int3 & dst , const ELayer layer = ELayer : : AUTO ) const ;
int getDistance ( const int3 & tile , const ELayer layer = ELayer : : AUTO ) const ;
CGPathNode * getNode ( const int3 & coord , const ELayer layer ) const ;
2015-10-27 02:34:47 +02:00
} ;
class CPathfinder : private CGameInfoCallback
{
public :
2015-11-11 21:08:15 +02:00
CPathfinder ( CPathsInfo & _out , CGameState * _gs , const CGHeroInstance * _hero ) ;
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
private :
2015-11-08 07:27:51 +02:00
typedef EPathfindingLayer ELayer ;
2015-10-27 02:34:47 +02:00
struct 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)
2015-11-08 09:06:24 +02:00
/// 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 ;
2015-11-04 14:05:22 +02:00
/// 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.
bool lightweightFlyingMode ;
2015-11-08 06:44:00 +02:00
/// 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.
bool oneTurnSpecialLayersLimit ;
2015-11-10 20:07:27 +02:00
/// 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
bool originalMovementRules ;
2015-10-27 02:34:47 +02:00
PathfinderOptions ( ) ;
2015-10-27 02:50:38 +02:00
} options ;
2015-10-27 02:34:47 +02:00
2015-11-11 21:08:15 +02:00
CPathsInfo & out ;
const CGHeroInstance * hero ;
2015-11-10 18:15:59 +02:00
unique_ptr < CPathfinderHelper > hlp ;
2015-10-27 02:34:47 +02:00
2015-11-07 20:11:07 +02:00
struct NodeComparer
{
bool operator ( ) ( const CGPathNode * lhs , const CGPathNode * rhs ) const
{
if ( rhs - > turns > lhs - > turns )
return false ;
else if ( rhs - > turns = = lhs - > turns & & rhs - > moveRemains < lhs - > moveRemains )
return false ;
return true ;
}
} ;
boost : : heap : : priority_queue < CGPathNode * , boost : : heap : : compare < NodeComparer > > pq ;
2015-10-27 02:34:47 +02:00
std : : vector < int3 > neighbours ;
2015-11-11 21:08:15 +02:00
CGPathNode * cp ; //current (source) path node -> we took it from the queue
CGPathNode * dp ; //destination node -> it's a neighbour of cp that we consider
const TerrainTile * ct , * dt ; //tile info for both nodes
2015-11-11 18:51:08 +02:00
const CGObjectInstance * cObj , * dObj ;
2015-11-07 23:26:41 +02:00
CGPathNode : : ENodeAction destAction ;
2015-10-27 02:34:47 +02:00
2015-11-11 21:08:15 +02:00
void addNeighbours ( const int3 & coord ) ;
2015-10-27 02:34:47 +02:00
void addTeleportExits ( bool noTeleportExcludes = false ) ;
2015-11-11 21:08:15 +02:00
bool isLayerAvailable ( const ELayer layer , const int turn ) const ;
2015-11-08 07:39:00 +02:00
bool isLayerTransitionPossible ( ) const ;
2015-11-11 18:51:08 +02:00
bool isMovementToDestPossible ( ) const ;
2015-11-08 07:39:00 +02:00
bool isMovementAfterDestPossible ( ) const ;
2015-11-11 18:51:08 +02:00
CGPathNode : : ENodeAction getDestAction ( ) const ;
2015-10-27 02:34:47 +02:00
2015-11-08 07:39:00 +02:00
bool isSourceInitialPosition ( ) const ;
int3 getSourceGuardPosition ( ) const ;
bool isSourceGuarded ( ) const ;
bool isDestinationGuarded ( const bool ignoreAccessibility = true ) const ;
bool isDestinationGuardian ( ) const ;
2015-10-27 02:34:47 +02:00
void initializeGraph ( ) ;
2015-11-11 21:08:15 +02:00
CGPathNode : : EAccessibility evaluateAccessibility ( const int3 & pos , const TerrainTile * tinfo ) 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)
2015-10-27 02:34:47 +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 ;
2015-11-02 10:06:06 +02:00
bool canVisitObject ( ) const ;
2015-11-02 15:03:03 +02:00
2015-10-27 02:34:47 +02:00
} ;
2015-11-10 01:15:27 +02:00
2015-11-10 13:26:45 +02:00
struct TurnInfo
{
int turn ;
int maxMovePointsLand ;
int maxMovePointsWater ;
const Bonus * bonusFlying ;
const Bonus * bonusWaterWalking ;
} ;
2015-11-10 01:15:27 +02:00
class DLL_LINKAGE CPathfinderHelper
{
public :
2015-11-10 13:26:45 +02:00
TurnInfo * ti ;
const CGHeroInstance * hero ;
CPathfinderHelper ( const CGHeroInstance * Hero ) ;
2015-11-11 21:08:15 +02:00
void updateTurnInfo ( const int turn = 0 ) ;
int getMaxMovePoints ( const EPathfindingLayer layer ) const ;
static TurnInfo * getTurnInfo ( const CGHeroInstance * h , const int turn = 0 ) ;
2015-11-10 13:26:45 +02:00
2015-11-11 21:08:15 +02:00
static void getNeighbours ( CGameState * gs , const TerrainTile & srct , const int3 & tile , std : : vector < int3 > & vec , const boost : : logic : : tribool & onLand , const bool limitCoastSailing ) ;
2015-11-10 01:15:27 +02:00
2015-11-11 21:08:15 +02:00
static int getMovementCost ( const CGHeroInstance * h , const int3 & src , const int3 & dst , const int remainingMovePoints = - 1 , const TurnInfo * ti = nullptr , const bool checkLast = true ) ;
static int getMovementCost ( const CGHeroInstance * h , const int3 & dst ) ;
2015-11-10 13:26:45 +02:00
private :
std : : vector < TurnInfo * > turnsInfo ;
2015-11-10 01:15:27 +02:00
} ;