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 ;
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 ;
const CGHeroInstance * hero ;
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
CPathsInfo ( const int3 & Sizes ) ;
~ CPathsInfo ( ) ;
2015-11-08 07:27:51 +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 :
CPathfinder ( CPathsInfo & _out , CGameState * _gs , const CGHeroInstance * _hero ) ;
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-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
CPathsInfo & out ;
const CGHeroInstance * hero ;
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 ;
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
const CGObjectInstance * sTileObj ;
2015-11-07 23:26:41 +02:00
CGPathNode : : ENodeAction destAction ;
2015-10-27 02:34:47 +02:00
void addNeighbours ( const int3 & coord ) ;
void addTeleportExits ( bool noTeleportExcludes = false ) ;
2015-11-09 18:57:26 +02:00
bool isLayerAvailable ( const ELayer & layer , const int & turn ) const ;
2015-11-08 07:39:00 +02:00
bool isLayerTransitionPossible ( ) const ;
2015-11-04 11:29:51 +02:00
bool isMovementToDestPossible ( ) ;
2015-11-08 07:39:00 +02:00
bool isMovementAfterDestPossible ( ) 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 ( ) ;
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)
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
class DLL_LINKAGE CPathfinderHelper
{
public :
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:30:05 +02:00
static int getMovementCost ( const CGHeroInstance * h , const int3 & src , const int3 & dst , const int & remainingMovePoints = - 1 , const int & turn = 0 , const bool & checkLast = true ) ;
static int getMovementCost ( const CGHeroInstance * h , const int3 & dst ) ;
2015-11-10 01:15:27 +02:00
} ;