AIPathfind.h 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // AIPathfind.h
  24. // AI pathfinding system
  25. // Author: Michael S. Booth, October 2001
  26. #pragma once
  27. #ifndef _PATHFIND_H_
  28. #define _PATHFIND_H_
  29. #include "Common/GameType.h"
  30. #include "Common/GameMemory.h"
  31. #include "Common/Snapshot.h"
  32. //#include "GameLogic/Locomotor.h" // no, do not include this, unless you like long recompiles
  33. #include "GameLogic/LocomotorSet.h"
  34. #include "GameLogic/GameLogic.h"
  35. class Bridge;
  36. class Object;
  37. class Weapon;
  38. class PathfindZoneManager;
  39. // How close is close enough when moving.
  40. #define PATHFIND_CLOSE_ENOUGH 1.0f
  41. #define PATH_MAX_PRIORITY 0x7FFFFFFF
  42. #define INFANTRY_MOVES_THROUGH_INFANTRY
  43. typedef UnsignedShort zoneStorageType;
  44. //----------------------------------------------------------------------------------------------------------
  45. /**
  46. * PathNodes are used to create a final Path to return from the
  47. * pathfinder. Note that these are not used during the A* search.
  48. */
  49. class PathNode : public MemoryPoolObject
  50. {
  51. public:
  52. PathNode();
  53. Coord3D *getPosition( void ) { return &m_pos; } ///< return position of this node
  54. const Coord3D *getPosition( void ) const { return &m_pos; } ///< return position of this node
  55. void setPosition( const Coord3D *pos ) { m_pos = *pos; } ///< set the position of this path node
  56. const Coord3D *computeDirectionVector( void ); ///< compute direction to next node
  57. PathNode *getNext( void ) { return m_next; } ///< return next node in the path
  58. PathNode *getPrevious( void ) { return m_prev; } ///< return previous node in the path
  59. const PathNode *getNext( void ) const { return m_next; } ///< return next node in the path
  60. const PathNode *getPrevious( void ) const { return m_prev; } ///< return previous node in the path
  61. PathfindLayerEnum getLayer( void ) const { return m_layer; } ///< return layer of this node.
  62. void setLayer( PathfindLayerEnum layer ) { m_layer = layer; } ///< set the layer of this path node
  63. void setNextOptimized( PathNode *node );
  64. PathNode *getNextOptimized(Coord2D* dir = NULL, Real* dist = NULL) ///< return next node in optimized path
  65. {
  66. if (dir)
  67. *dir = m_nextOptiDirNorm2D;
  68. if (dist)
  69. *dist = m_nextOptiDist2D;
  70. return m_nextOpti;
  71. }
  72. const PathNode *getNextOptimized(Coord2D* dir = NULL, Real* dist = NULL) const ///< return next node in optimized path
  73. {
  74. if (dir)
  75. *dir = m_nextOptiDirNorm2D;
  76. if (dist)
  77. *dist = m_nextOptiDist2D;
  78. return m_nextOpti;
  79. }
  80. void setCanOptimize(Bool canOpt) { m_canOptimize = canOpt;}
  81. Bool getCanOptimize( void ) const { return m_canOptimize;}
  82. /// given a list, prepend this node, return new list
  83. PathNode *prependToList( PathNode *list );
  84. /// given a list, append this node, return new list. slow implementation.
  85. /// @todo optimize this
  86. PathNode *appendToList( PathNode *list );
  87. /// given a node, append to this node
  88. void append( PathNode *list );
  89. public:
  90. mutable Int m_id; // Used in Path::xfer() to save & recreate the path list.
  91. private:
  92. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( PathNode, "PathNodePool" ); ///< @todo Set real numbers for mem alloc
  93. PathNode* m_nextOpti; ///< next node in the optimized path
  94. PathNode* m_next; ///< next node in the path
  95. PathNode* m_prev; ///< previous node in the path
  96. Coord3D m_pos; ///< position of node in space
  97. PathfindLayerEnum m_layer; ///< Layer for this section.
  98. Bool m_canOptimize; ///< True if this cell can be optimized out.
  99. Real m_nextOptiDist2D; ///< if nextOpti is nonnull, the dist to it.
  100. Coord2D m_nextOptiDirNorm2D; ///< if nextOpti is nonnull, normalized dir vec towards it.
  101. };
  102. // this doesn't actually seem to be a particularly useful win,
  103. // performance-wise, so I didn't enable it. (srj)
  104. #define NO_CPOP_STARTS_FROM_PREV_SEG
  105. struct ClosestPointOnPathInfo
  106. {
  107. Real distAlongPath;
  108. Coord3D posOnPath;
  109. PathfindLayerEnum layer;
  110. };
  111. /**
  112. * This class encapsulates a "path" returned by the Pathfinder.
  113. */
  114. class Path : public MemoryPoolObject, public Snapshot
  115. {
  116. public:
  117. Path();
  118. PathNode *getFirstNode( void ) { return m_path; }
  119. PathNode *getLastNode( void ) { return m_pathTail; }
  120. void updateLastNode( const Coord3D *pos );
  121. void prependNode( const Coord3D *pos, PathfindLayerEnum layer ); ///< Create a new node at the head of the path
  122. void appendNode( const Coord3D *pos, PathfindLayerEnum layer ); ///< Create a new node at the end of the path
  123. void setBlockedByAlly(Bool blocked) {m_blockedByAlly = blocked;}
  124. Bool getBlockedByAlly(void) {return m_blockedByAlly;}
  125. void optimize( const Object *obj, LocomotorSurfaceTypeMask acceptableSurfaces, Bool blocked ); ///< Optimize the path to discard redundant nodes
  126. void optimizeGroundPath( Bool crusher, Int diameter ); ///< Optimize the ground path to discard redundant nodes
  127. /// Given a location, return nearest location on path, and along-path dist to end as function result
  128. void computePointOnPath( const Object *obj, const LocomotorSet& locomotorSet, const Coord3D& pos, ClosestPointOnPathInfo& out);
  129. /// Given a location, return nearest location on path, and along-path dist to end as function result
  130. void peekCachedPointOnPath( Coord3D& pos ) const {pos = m_cpopOut.posOnPath;}
  131. /// Given a flight path, compute the distance to goal (0 if we are past it) & return the goal pos.
  132. Real computeFlightDistToGoal( const Coord3D *pos, Coord3D& goalPos );
  133. /// Given a location, return closest location on path, and along-path dist to end as function result
  134. void markOptimized(void) {m_isOptimized = true;}
  135. protected:
  136. // snapshot interface
  137. virtual void crc( Xfer *xfer );
  138. virtual void xfer( Xfer *xfer );
  139. virtual void loadPostProcess();
  140. protected:
  141. enum {MAX_CPOP=20}; ///< Max times we will return the cached cpop.
  142. MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( Path, "PathPool" ); ///< @todo Set real numbers for mem alloc
  143. PathNode* m_path; ///< The list of PathNode objects that define the path
  144. PathNode* m_pathTail;
  145. Bool m_isOptimized; ///< True if the path has been optimized
  146. Bool m_blockedByAlly; ///< An ally needs to move off of this path.
  147. // caching info for computePointOnPath.
  148. Bool m_cpopValid;
  149. Int m_cpopCountdown; ///< We only return the same cpop MAX_CPOP times. It is occasionally possible to get stuck.
  150. Coord3D m_cpopIn;
  151. ClosestPointOnPathInfo m_cpopOut;
  152. const PathNode* m_cpopRecentStart;
  153. };
  154. //----------------------------------------------------------------------------------------------------------
  155. // See GameType.h for
  156. // enum {LAYER_INVALID = 0, LAYER_GROUND = 1, LAYER_TOP=2 };
  157. // Fits in 4 bits for now
  158. enum {MAX_WALL_PIECES = 128};
  159. class PathfindCellInfo
  160. {
  161. friend class PathfindCell;
  162. public:
  163. static void allocateCellInfos(void);
  164. static void releaseCellInfos(void);
  165. static PathfindCellInfo * getACellInfo(PathfindCell *cell, const ICoord2D &pos);
  166. static void releaseACellInfo(PathfindCellInfo *theInfo);
  167. protected:
  168. static PathfindCellInfo *s_infoArray;
  169. static PathfindCellInfo *s_firstFree; ///<
  170. PathfindCellInfo *m_nextOpen, *m_prevOpen; ///< for A* "open" list, shared by closed list
  171. PathfindCellInfo *m_pathParent; ///< "parent" cell from pathfinder
  172. PathfindCell *m_cell; ///< Cell this info belongs to currently.
  173. UnsignedShort m_totalCost, m_costSoFar; ///< cost estimates for A* search
  174. /// have to include cell's coordinates, since cells are often accessed via pointer only
  175. ICoord2D m_pos;
  176. ObjectID m_goalUnitID; ///< The objectID of the ground unit whose goal this is.
  177. ObjectID m_posUnitID; ///< The objectID of the ground unit that is occupying this cell.
  178. ObjectID m_goalAircraftID; ///< The objectID of the aircraft whose goal this is.
  179. ObjectID m_obstacleID; ///< the object ID who overlaps this cell
  180. UnsignedInt m_isFree:1;
  181. UnsignedInt m_blockedByAlly:1;///< True if this cell is blocked by an allied unit.
  182. UnsignedInt m_obstacleIsFence:1;///< True if occupied by a fence.
  183. UnsignedInt m_obstacleIsTransparent:1;///< True if obstacle is transparent (undefined if obstacleid is invalid)
  184. /// @todo Do we need both mark values in this cell? Can't store a single value and compare it?
  185. UnsignedInt m_open:1; ///< place for marking this cell as on the open list
  186. UnsignedInt m_closed:1; ///< place for marking this cell as on the closed list
  187. };
  188. /**
  189. * This represents one cell in the pathfinding grid.
  190. * These cells categorize the world into idealized cellular states,
  191. * and are also used for efficient A* pathfinding.
  192. * @todo Optimize memory usage of pathfind grid.
  193. */
  194. class PathfindCell
  195. {
  196. public:
  197. enum CellType
  198. {
  199. CELL_CLEAR = 0x00, ///< clear, unobstructed ground
  200. CELL_WATER = 0x01, ///< water area
  201. CELL_CLIFF = 0x02, ///< steep altitude change
  202. CELL_RUBBLE = 0x03, ///< Cell is occupied by rubble.
  203. CELL_OBSTACLE = 0x04, ///< Occupied by a structure
  204. CELL_BRIDGE_IMPASSABLE = 0x05, ///< Piece of a bridge that is impassable.
  205. CELL_IMPASSABLE = 0x06 ///< Just plain impassable except for aircraft.
  206. };
  207. enum CellFlags
  208. {
  209. NO_UNITS = 0x00, ///< No units in this cell.
  210. UNIT_GOAL = 0x01, ///< A unit is heading to this cell.
  211. UNIT_PRESENT_MOVING = 0x02, ///< A unit is moving through this cell.
  212. UNIT_PRESENT_FIXED = 0x03, ///< A unit is stationary in this cell.
  213. UNIT_GOAL_OTHER_MOVING = 0x05 ///< A unit is moving through this cell, and another unit has this as it's goal.
  214. };
  215. /// reset the cell
  216. void reset( );
  217. PathfindCell(void);
  218. ~PathfindCell(void);
  219. Bool setTypeAsObstacle( Object *obstacle, Bool isFence, const ICoord2D &pos ); ///< flag this cell as an obstacle, from the given one
  220. Bool removeObstacle( Object *obstacle ); ///< unflag this cell as an obstacle, from the given one
  221. void setType( CellType type ); ///< set the cell type
  222. CellType getType( void ) const { return (CellType)m_type; } ///< get the cell type
  223. CellFlags getFlags( void ) const { return (CellFlags)m_flags; } ///< get the cell type
  224. Bool isAircraftGoal( void) const {return m_aircraftGoal != 0;}
  225. Bool isObstaclePresent( ObjectID objID ) const; ///< return true if the given object ID is registered as an obstacle in this cell
  226. Bool isObstacleTransparent( ) const{return m_info?m_info->m_obstacleIsTransparent:false; } ///< return true if the obstacle in the cell is KINDOF_CAN_SEE_THROUGHT_STRUCTURE
  227. Bool isObstacleFence( void ) const {return m_info?m_info->m_obstacleIsFence:false; }///< return true if the given obstacle in the cell is a fence.
  228. /// Return estimated cost from given cell to reach goal cell
  229. UnsignedInt costToGoal( PathfindCell *goal );
  230. UnsignedInt costToHierGoal( PathfindCell *goal );
  231. UnsignedInt costSoFar( PathfindCell *parent );
  232. /// put self on "open" list in ascending cost order, return new list
  233. PathfindCell *putOnSortedOpenList( PathfindCell *list );
  234. /// remove self from "open" list
  235. PathfindCell *removeFromOpenList( PathfindCell *list );
  236. /// put self on "closed" list, return new list
  237. PathfindCell *putOnClosedList( PathfindCell *list );
  238. /// remove self from "closed" list
  239. PathfindCell *removeFromClosedList( PathfindCell *list );
  240. /// remove all cells from closed list.
  241. static Int releaseClosedList( PathfindCell *list );
  242. /// remove all cells from closed list.
  243. static Int releaseOpenList( PathfindCell *list );
  244. inline PathfindCell *getNextOpen(void) {return m_info->m_nextOpen?m_info->m_nextOpen->m_cell:NULL;}
  245. inline UnsignedShort getXIndex(void) const {return m_info->m_pos.x;}
  246. inline UnsignedShort getYIndex(void) const {return m_info->m_pos.y;}
  247. inline Bool isBlockedByAlly(void) const {return m_info->m_blockedByAlly;}
  248. inline void setBlockedByAlly(Bool blocked) {m_info->m_blockedByAlly = (blocked!=0);}
  249. inline Bool getOpen(void) const {return m_info->m_open;}
  250. inline Bool getClosed(void) const {return m_info->m_closed;}
  251. inline UnsignedInt getCostSoFar(void) const {return m_info->m_costSoFar;}
  252. inline UnsignedInt getTotalCost(void) const {return m_info->m_totalCost;}
  253. inline void setCostSoFar(UnsignedInt cost) { if( m_info ) m_info->m_costSoFar = cost;}
  254. inline void setTotalCost(UnsignedInt cost) { if( m_info ) m_info->m_totalCost = cost;}
  255. void setParentCell(PathfindCell* parent);
  256. void clearParentCell(void);
  257. void setParentCellHierarchical(PathfindCell* parent);
  258. inline PathfindCell* getParentCell(void) const {return m_info ? m_info->m_pathParent ? m_info->m_pathParent->m_cell : NULL : NULL;}
  259. Bool startPathfind( PathfindCell *goalCell );
  260. Bool getPinched(void) const {return m_pinched;}
  261. void setPinched(Bool pinch) {m_pinched = pinch; }
  262. Bool allocateInfo(const ICoord2D &pos);
  263. void releaseInfo(void);
  264. Bool hasInfo(void) const {return m_info!=NULL;}
  265. zoneStorageType getZone(void) const {return m_zone;}
  266. void setZone(zoneStorageType zone) {m_zone = zone;}
  267. void setGoalUnit(ObjectID unit, const ICoord2D &pos );
  268. void setGoalAircraft(ObjectID unit, const ICoord2D &pos );
  269. void setPosUnit(ObjectID unit, const ICoord2D &pos );
  270. inline ObjectID getGoalUnit(void) const {ObjectID id = m_info?m_info->m_goalUnitID:INVALID_ID; return id;}
  271. inline ObjectID getGoalAircraft(void) const {ObjectID id = m_info?m_info->m_goalAircraftID:INVALID_ID; return id;}
  272. inline ObjectID getPosUnit(void) const {ObjectID id = m_info?m_info->m_posUnitID:INVALID_ID; return id;}
  273. inline ObjectID getObstacleID(void) const {ObjectID id = m_info?m_info->m_obstacleID:INVALID_ID; return id;}
  274. void setLayer( PathfindLayerEnum layer ) { m_layer = layer; } ///< set the cell layer
  275. PathfindLayerEnum getLayer( void ) const { return (PathfindLayerEnum)m_layer; } ///< get the cell layer
  276. void setConnectLayer( PathfindLayerEnum layer ) { m_connectsToLayer = layer; } ///< set the cell layer connect id
  277. PathfindLayerEnum getConnectLayer( void ) const { return (PathfindLayerEnum)m_connectsToLayer; } ///< get the cell layer connect id
  278. private:
  279. PathfindCellInfo *m_info;
  280. zoneStorageType m_zone:14; ///< Zone. Each zone is a set of adjacent terrain type. If from & to in the same zone, you can successfully pathfind. If not,
  281. // you still may be able to if you can cross multiple terrain types.
  282. UnsignedShort m_aircraftGoal:1; //< This is an aircraft goal cell.
  283. UnsignedShort m_pinched:1; //< This cell is surrounded by obstacle cells.
  284. UnsignedByte m_type:4; ///< what type of cell terrain this is.
  285. UnsignedByte m_flags:4; ///< what type of units are in or moving through this cell.
  286. UnsignedByte m_connectsToLayer:4; ///< This cell can pathfind onto this layer, if > LAYER_TOP.
  287. UnsignedByte m_layer:4; ///< Layer of this cell.
  288. };
  289. typedef PathfindCell *PathfindCellP;
  290. // how close a unit has to be in z to interact with the layer.
  291. #define LAYER_Z_CLOSE_ENOUGH_F 10.0f
  292. /**
  293. * This class represents a bridge in the map. This is effectively
  294. * a sub-rectangle of the big pathfind map.
  295. */
  296. class PathfindLayer
  297. {
  298. public:
  299. PathfindLayer();
  300. ~PathfindLayer();
  301. public:
  302. void reset(void);
  303. Bool init(Bridge *theBridge, PathfindLayerEnum layer);
  304. void allocateCells(const IRegion2D *extent);
  305. void allocateCellsForWallLayer(const IRegion2D *extent, ObjectID *wallPieces, Int numPieces);
  306. void classifyCells();
  307. void classifyWallCells(ObjectID *wallPieces, Int numPieces);
  308. Bool setDestroyed(Bool destroyed);
  309. Bool isUnused(void); // True if it doesn't contain a bridge.
  310. Bool isDestroyed(void) {return m_destroyed;} // True if it has been destroyed.
  311. PathfindCell *getCell(Int x, Int y);
  312. Int getZone(void) {return m_zone;}
  313. void setZone(Int zone) {m_zone = zone;}
  314. void applyZone(void); // Propagates m_zone to all cells.
  315. void getStartCellIndex(ICoord2D *start) {*start = m_startCell;}
  316. void getEndCellIndex(ICoord2D *end) {*end = m_endCell;}
  317. ObjectID getBridgeID(void);
  318. Bool connectsZones(PathfindZoneManager *zm, const LocomotorSet& locomotorSet,Int zone1, Int zone2);
  319. Bool isPointOnWall(ObjectID *wallPieces, Int numPieces, const Coord3D *pt);
  320. #if defined _DEBUG || defined _INTERNAL
  321. void doDebugIcons(void) ;
  322. #endif
  323. protected:
  324. void classifyLayerMapCell( Int i, Int j , PathfindCell *cell, Bridge *theBridge);
  325. void classifyWallMapCell( Int i, Int j, PathfindCell *cell , ObjectID *wallPieces, Int numPieces);
  326. private:
  327. PathfindCell *m_blockOfMapCells; ///< Pathfinding map - contains iconic representation of the map
  328. PathfindCell **m_layerCells; ///< Pathfinding map indexes - contains matrix indexing into the map.
  329. Int m_width; // Number of cells in x
  330. Int m_height; // Number of cells in y
  331. Int m_xOrigin; // Index of first cell in x
  332. Int m_yOrigin; // Index of first cell in y
  333. ICoord2D m_startCell; // pathfind cell indexes for center cell on the from side.
  334. ICoord2D m_endCell; // pathfind cell indexes for center cell on the to side.
  335. PathfindLayerEnum m_layer;
  336. Int m_zone; // Whole bridge is in same zone.
  337. Bridge *m_bridge; // Corresponding bridge in TerrainLogic.
  338. Bool m_destroyed;
  339. };
  340. #define PATHFIND_CELL_SIZE 10
  341. #define PATHFIND_CELL_SIZE_F 10.0f
  342. enum { PATHFIND_QUEUE_LEN=512};
  343. struct TCheckMovementInfo;
  344. /**
  345. * This class is a helper class for zone manager. It maintains information regarding the
  346. * LocomotorSurfaceTypeMask equivalencies within a ZONE_BLOCK_SIZE x ZONE_BLOCK_SIZE area of
  347. * cells. This is used in hierarchical pathfinding to find the best coarse path at the
  348. * block level.
  349. */
  350. class ZoneBlock
  351. {
  352. public:
  353. ZoneBlock();
  354. ~ZoneBlock(); // not virtual, please don't override without making virtual. jba.
  355. void blockCalculateZones( PathfindCell **map, PathfindLayer layers[], const IRegion2D &bounds); ///< Does zone calculations.
  356. zoneStorageType getEffectiveZone(LocomotorSurfaceTypeMask acceptableSurfaces, Bool crusher, zoneStorageType zone) const;
  357. void clearMarkedPassable(void) {m_markedPassable = false;}
  358. Bool isPassable(void) {return m_markedPassable;}
  359. void setPassable(Bool pass) {m_markedPassable = pass;}
  360. Bool getInteractsWithBridge(void) const {return m_interactsWithBridge;}
  361. void setInteractsWithBridge(Bool interacts) {m_interactsWithBridge = interacts;}
  362. protected:
  363. void allocateZones(void);
  364. void freeZones(void);
  365. protected:
  366. ICoord2D m_cellOrigin;
  367. zoneStorageType m_firstZone; // First zone in this block.
  368. UnsignedShort m_numZones; // Number of zones in this block. If == 1, there is only one zone, and
  369. // no zone equivalency arrays will be allocated.
  370. UnsignedShort m_zonesAllocated;
  371. zoneStorageType *m_groundCliffZones;
  372. zoneStorageType *m_groundWaterZones;
  373. zoneStorageType *m_groundRubbleZones;
  374. zoneStorageType *m_crusherZones;
  375. Bool m_interactsWithBridge;
  376. Bool m_markedPassable;
  377. };
  378. typedef ZoneBlock *ZoneBlockP;
  379. /**
  380. * This class manages the zones in the map. A zone is an area in the map that
  381. * is one contiguous type of terrain (clear, cliff, water, building). If
  382. * a unit is in a zone, and wants to move to another location, the destination
  383. * zone has to be the same, or it can't get there.
  384. * There are equivalency tables for meta-zones. For example, an amphibious craft can
  385. * travel through water and clear cells.
  386. */
  387. class PathfindZoneManager
  388. {
  389. public:
  390. enum {INITIAL_ZONES = 256};
  391. enum {ZONE_BLOCK_SIZE = 10}; // Zones are calculated in blocks of 20x20. This way, the raw zone numbers can be used to
  392. enum {UNINITIALIZED_ZONE = 0};
  393. // compute hierarchically between the 20x20 blocks of cells. jba.
  394. PathfindZoneManager();
  395. ~PathfindZoneManager();
  396. void reset(void);
  397. Bool needToCalculateZones(void) const {return m_nextFrameToCalculateZones <= TheGameLogic->getFrame() ;} ///< Returns true if the zones need to be recalculated.
  398. void markZonesDirty( Bool insert ) ; ///< Called when the zones need to be recalculated.
  399. void updateZonesForModify( PathfindCell **map, PathfindLayer layers[], const IRegion2D &structureBounds, const IRegion2D &globalBounds ) ; ///< Called to recalculate an area when a structure has been removed.
  400. void calculateZones( PathfindCell **map, PathfindLayer layers[], const IRegion2D &bounds); ///< Does zone calculations.
  401. zoneStorageType getEffectiveZone(LocomotorSurfaceTypeMask acceptableSurfaces, Bool crusher, zoneStorageType zone) const;
  402. zoneStorageType getEffectiveTerrainZone(zoneStorageType zone) const;
  403. zoneStorageType getNextZone(void);
  404. void getExtent(ICoord2D &extent) const {extent = m_zoneBlockExtent;}
  405. /// return zone relative the the block zone that this cell resides in.
  406. zoneStorageType getBlockZone(LocomotorSurfaceTypeMask acceptableSurfaces, Bool crusher, Int cellX, Int cellY, PathfindCell **map) const;
  407. void allocateBlocks(const IRegion2D &globalBounds);
  408. void clearPassableFlags(void);
  409. Bool isPassable(Int cellX, Int cellY) const;
  410. Bool clipIsPassable(Int cellX, Int cellY) const;
  411. void setPassable(Int cellX, Int cellY, Bool passable);
  412. void setAllPassable(void);
  413. void setBridge(Int cellX, Int cellY, Bool bridge);
  414. Bool interactsWithBridge(Int cellX, Int cellY) const;
  415. private:
  416. void allocateZones(void);
  417. void freeZones(void);
  418. void freeBlocks(void);
  419. private:
  420. ZoneBlock *m_blockOfZoneBlocks; ///< Zone blocks - Info for hierarchical pathfinding at a "blocky" level.
  421. ZoneBlock **m_zoneBlocks; ///< Zone blocks as a matrix - contains matrix indexing into the map.
  422. ICoord2D m_zoneBlockExtent; ///< Zone block extents. Not the same scale as the pathfind extents.
  423. UnsignedShort m_maxZone; ///< Max zone used.
  424. UnsignedInt m_nextFrameToCalculateZones; ///< WHen should I recalculate, next?.
  425. UnsignedShort m_zonesAllocated;
  426. zoneStorageType *m_groundCliffZones;
  427. zoneStorageType *m_groundWaterZones;
  428. zoneStorageType *m_groundRubbleZones;
  429. zoneStorageType *m_terrainZones;
  430. zoneStorageType *m_crusherZones;
  431. zoneStorageType *m_hierarchicalZones;
  432. };
  433. /**
  434. * The pathfinding services interface provides access to the 3 expensive path find calls:
  435. * findPath, findClosestPath, and findAttackPath.
  436. * It is only available to units when their ai interface doPathfind method is called.
  437. * This allows the pathfinder to spread out the pathfinding over a number of frames
  438. * when a lot of units are trying to pathfind all at the same time.
  439. */
  440. class PathfindServicesInterface {
  441. public:
  442. virtual Path *findPath( Object *obj, const LocomotorSet& locomotorSet, const Coord3D *from,
  443. const Coord3D *to )=0; ///< Find a short, valid path between given locations
  444. /** Find a short, valid path to a location NEAR the to location.
  445. This succeds when the destination is unreachable (like inside a building).
  446. If the destination is unreachable, it will adjust the to point. */
  447. virtual Path *findClosestPath( Object *obj, const LocomotorSet& locomotorSet, const Coord3D *from,
  448. Coord3D *to, Bool blocked, Real pathCostMultiplier, Bool moveAllies )=0;
  449. /** Find a short, valid path to a location that obj can attack victim from. */
  450. virtual Path *findAttackPath( const Object *obj, const LocomotorSet& locomotorSet, const Coord3D *from,
  451. const Object *victim, const Coord3D* victimPos, const Weapon *weapon )=0;
  452. /** Patch to the exiting path from the current position, either because we became blocked,
  453. or because we had to move off the path to avoid other units. */
  454. virtual Path *patchPath( const Object *obj, const LocomotorSet& locomotorSet,
  455. Path *originalPath, Bool blocked ) = 0;
  456. /** Find a short, valid path to a location that is away from the repulsors. */
  457. virtual Path *findSafePath( const Object *obj, const LocomotorSet& locomotorSet,
  458. const Coord3D *from, const Coord3D* repulsorPos1, const Coord3D* repulsorPos2, Real repulsorRadius ) = 0;
  459. };
  460. /**
  461. * The Pathfinding engine itself.
  462. */
  463. class Pathfinder : PathfindServicesInterface, public Snapshot
  464. {
  465. // The following routines are private, but available through the doPathfind callback to aiInterface. jba.
  466. private:
  467. virtual Path *findPath( Object *obj, const LocomotorSet& locomotorSet, const Coord3D *from, const Coord3D *to); ///< Find a short, valid path between given locations
  468. /** Find a short, valid path to a location NEAR the to location.
  469. This succeds when the destination is unreachable (like inside a building).
  470. If the destination is unreachable, it will adjust the to point. */
  471. virtual Path *findClosestPath( Object *obj, const LocomotorSet& locomotorSet, const Coord3D *from,
  472. Coord3D *to, Bool blocked, Real pathCostMultiplier, Bool moveAllies );
  473. /** Find a short, valid path to a location that obj can attack victim from. */
  474. virtual Path *findAttackPath( const Object *obj, const LocomotorSet& locomotorSet, const Coord3D *from,
  475. const Object *victim, const Coord3D* victimPos, const Weapon *weapon );
  476. /** Find a short, valid path to a location that is away from the repulsors. */
  477. virtual Path *findSafePath( const Object *obj, const LocomotorSet& locomotorSet,
  478. const Coord3D *from, const Coord3D* repulsorPos1, const Coord3D* repulsorPos2, Real repulsorRadius );
  479. /** Patch to the exiting path from the current position, either because we became blocked,
  480. or because we had to move off the path to avoid other units. */
  481. virtual Path *patchPath( const Object *obj, const LocomotorSet& locomotorSet,
  482. Path *originalPath, Bool blocked );
  483. public:
  484. Pathfinder( void );
  485. ~Pathfinder() ;
  486. void reset( void ); ///< Reset system in preparation for new map
  487. // --------------- inherited from Snapshot interface --------------
  488. void crc( Xfer *xfer );
  489. void xfer( Xfer *xfer );
  490. void loadPostProcess( void );
  491. Bool clientSafeQuickDoesPathExist( const LocomotorSet& locomotorSet, const Coord3D *from, const Coord3D *to ); ///< Can we build any path at all between the locations (terrain & buildings check - fast)
  492. Bool clientSafeQuickDoesPathExistForUI( const LocomotorSet& locomotorSet, const Coord3D *from, const Coord3D *to ); ///< Can we build any path at all between the locations (terrain onlyk - fast)
  493. Bool slowDoesPathExist( Object *obj, const Coord3D *from,
  494. const Coord3D *to, ObjectID ignoreObject=INVALID_ID ); ///< Can we build any path at all between the locations (terrain, buildings & units check - slower)
  495. Bool queueForPath(ObjectID id); ///< The object wants to request a pathfind, so put it on the list to process.
  496. void processPathfindQueue(void); ///< Process some or all of the queued pathfinds.
  497. void forceMapRecalculation( ); ///< Force pathfind map recomputation. If region is given, only that area is recomputed
  498. /** Returns an aircraft path to the goal. */
  499. Path *getAircraftPath( const Object *obj, const Coord3D *to);
  500. Path *findGroundPath( const Coord3D *from, const Coord3D *to, Int pathRadius,
  501. Bool crusher); ///< Find a short, valid path of the desired width on the ground.
  502. void addObjectToPathfindMap( class Object *obj ); ///< Classify the given object's cells in the map
  503. void removeObjectFromPathfindMap( class Object *obj ); ///< De-classify the given object's cells in the map
  504. void removeUnitFromPathfindMap( Object *obj ); ///< De-classify the given mobile unit's cells in the map
  505. void updateGoal( Object *obj, const Coord3D *newGoalPos, PathfindLayerEnum layer); ///< Update the given mobile unit's cells in the map
  506. void updateAircraftGoal( Object *obj, const Coord3D *newGoalPos); ///< Update the given aircraft unit's cells in the map
  507. void removeGoal( Object *obj); ///< Removes the given mobile unit's goal cells in the map
  508. void updatePos( Object *obj, const Coord3D *newPos); ///< Update the given mobile unit's cells in the map
  509. void removePos( Object *obj); ///< Removes the unit's position cells from the map
  510. Bool moveAllies(Object *obj, Path *path);
  511. // NOTE - The object MUST NOT MOVE between the call to createAWall... and removeWall...
  512. // or BAD THINGS will happen. jba.
  513. void createAWallFromMyFootprint( Object *obj ) {internal_classifyObjectFootprint(obj, true);} // Temporarily treat this object as an obstacle.
  514. void removeWallFromMyFootprint( Object *obj ){internal_classifyObjectFootprint(obj, false);} // Undo createAWallFromMyFootprint.
  515. Path *getMoveAwayFromPath(Object *obj, Object *otherObj, Path *pathToAvoid, Object *otherObj2, Path *pathToAvoid2);
  516. void changeBridgeState( PathfindLayerEnum layer, Bool repaired );
  517. Bool findBrokenBridge(const LocomotorSet &locomotorSet, const Coord3D *from, const Coord3D *to, ObjectID *bridgeID);
  518. void newMap(void);
  519. PathfindCell *getCell( PathfindLayerEnum layer, Int x, Int y ); ///< Return the cell at grid coords (x,y)
  520. PathfindCell *getCell( PathfindLayerEnum layer, const Coord3D *pos ); ///< Given a position, return associated grid cell
  521. PathfindCell *getClippedCell( PathfindLayerEnum layer, const Coord3D *pos ); ///< Given a position, return associated grid cell
  522. void clip(Coord3D *from, Coord3D *to);
  523. Bool worldToCell( const Coord3D *pos, ICoord2D *cell ); ///< Given a world position, return grid cell coordinate
  524. const ICoord2D *getExtent(void) const {return &m_extent.hi;}
  525. void setIgnoreObstacleID( ObjectID objID ); ///< if non-zero, the pathfinder will ignore the given obstacle
  526. Bool validMovementPosition( Bool isCrusher, LocomotorSurfaceTypeMask acceptableSurfaces, PathfindCell *toCell, PathfindCell *fromCell = NULL ); ///< Return true if given position is a valid movement location
  527. Bool validMovementPosition( Bool isCrusher, PathfindLayerEnum layer, const LocomotorSet& locomotorSet, Int x, Int y ); ///< Return true if given position is a valid movement location
  528. Bool validMovementPosition( Bool isCrusher, PathfindLayerEnum layer, const LocomotorSet& locomotorSet, const Coord3D *pos ); ///< Return true if given position is a valid movement location
  529. Bool validMovementTerrain( PathfindLayerEnum layer, const Locomotor* locomotor, const Coord3D *pos ); ///< Return true if given position is a valid movement location
  530. Locomotor* chooseBestLocomotorForPosition(PathfindLayerEnum layer, LocomotorSet* locomotorSet, const Coord3D* pos );
  531. Bool isViewBlockedByObstacle(const Object* obj, const Object* objOther); ///< Return true if the straight line between the given points contains any obstacle, and thus blocks vision
  532. Bool isAttackViewBlockedByObstacle(const Object* obj, const Coord3D& attackerPos, const Object* victim, const Coord3D& victimPos); ///< Return true if the straight line between the given points contains any obstacle, and thus blocks vision
  533. Bool isLinePassable( const Object *obj, LocomotorSurfaceTypeMask acceptableSurfaces,
  534. PathfindLayerEnum layer, const Coord3D& startWorld, const Coord3D& endWorld,
  535. Bool blocked, Bool allowPinched ); ///< Return true if the straight line between the given points is passable
  536. void moveAlliesAwayFromDestination( Object *obj,const Coord3D& destination);
  537. Bool isGroundPathPassable( Bool isCrusher, const Coord3D& startWorld, PathfindLayerEnum startLayer,
  538. const Coord3D& endWorld, Int pathDiameter); ///< Return true if the straight line between the given points is passable
  539. // for debugging
  540. const Coord3D *getDebugPathPosition( void );
  541. void setDebugPathPosition( const Coord3D *pos );
  542. Path *getDebugPath( void );
  543. void setDebugPath( Path *debugpath );
  544. void cleanOpenAndClosedLists(void);
  545. // Adjusts the destination to a spot near dest that is not occupied by other units.
  546. Bool adjustDestination(Object *obj, const LocomotorSet& locomotorSet,
  547. Coord3D *dest, const Coord3D *groupDest=NULL);
  548. // Adjusts the destination to a spot near dest for landing that is not occupied by other units.
  549. Bool adjustToLandingDestination(Object *obj, Coord3D *dest);
  550. // Adjusts the destination to a spot that can attack target that is not occupied by other units.
  551. Bool adjustTargetDestination(const Object *obj, const Object *target, const Coord3D *targetPos,
  552. const Weapon *weapon, Coord3D *dest);
  553. // Adjusts destination to a spot near dest that is possible to path to.
  554. Bool adjustToPossibleDestination(Object *obj, const LocomotorSet& locomotorSet, Coord3D *dest);
  555. void snapPosition(Object *obj, Coord3D *pos); // Snaps the current position to it's grid location.
  556. void snapClosestGoalPosition(Object *obj, Coord3D *pos); // Snaps the current position to a good goal position.
  557. Bool goalPosition(Object *obj, Coord3D *pos); // Returns the goal position on the grid.
  558. PathfindLayerEnum addBridge(Bridge *theBridge); // Adds a bridge layer, and returns the layer id.
  559. void addWallPiece(Object *wallPiece); // Adds a wall piece.
  560. void removeWallPiece(Object *wallPiece); // Removes a wall piece.
  561. Real getWallHeight(void) {return m_wallHeight;}
  562. Bool isPointOnWall(const Coord3D *pos);
  563. void updateLayer(Object *obj, PathfindLayerEnum layer); ///< Updates object's layer.
  564. static void classifyMapCell( Int x, Int y, PathfindCell *cell); ///< Classify the given map cell
  565. Int clearCellForDiameter( Bool crusher, Int cellX, Int cellY, PathfindLayerEnum layer, Int pathDiameter ); ///< Return true if given position is a valid movement location
  566. protected:
  567. virtual Path *internalFindPath( Object *obj, const LocomotorSet& locomotorSet, const Coord3D *from, const Coord3D *to); ///< Find a short, valid path between given locations
  568. Path *findHierarchicalPath( Bool isHuman, const LocomotorSet& locomotorSet, const Coord3D *from, const Coord3D *to, Bool crusher);
  569. Path *findClosestHierarchicalPath( Bool isHuman, const LocomotorSet& locomotorSet, const Coord3D *from, const Coord3D *to, Bool crusher);
  570. Path *internal_findHierarchicalPath( Bool isHuman, const LocomotorSurfaceTypeMask locomotorSurface, const Coord3D *from, const Coord3D *to, Bool crusher, Bool closestOK);
  571. void processHierarchicalCell( const ICoord2D &scanCell, const ICoord2D &deltaPathfindCell,
  572. PathfindCell *parentCell,
  573. PathfindCell *goalCell, zoneStorageType parentZone,
  574. zoneStorageType *examinedZones, Int &numExZones,
  575. Bool crusher, Int &cellCount);
  576. Bool checkForAdjust(Object *, const LocomotorSet& locomotorSet, Bool isHuman, Int cellX, Int cellY,
  577. PathfindLayerEnum layer, Int iRadius, Bool center,Coord3D *dest, const Coord3D *groupDest) ;
  578. Bool checkForLanding(Int cellX, Int cellY,
  579. PathfindLayerEnum layer, Int iRadius, Bool center,Coord3D *dest) ;
  580. Bool checkForTarget(const Object *obj, Int cellX, Int cellY, const Weapon *weapon,
  581. const Object *victim, const Coord3D *victimPos,
  582. Int iRadius, Bool center,Coord3D *dest) ;
  583. Bool checkForPossible(Bool isCrusher, Int fromZone, Bool center, const LocomotorSet& locomotorSet,
  584. Int cellX, Int cellY, PathfindLayerEnum layer, Coord3D *dest, Bool startingInObstacle) ;
  585. void getRadiusAndCenter(const Object *obj, Int &iRadius, Bool &center);
  586. void adjustCoordToCell(Int cellX, Int cellY, Bool centerInCell, Coord3D &pos, PathfindLayerEnum layer);
  587. Bool checkDestination(const Object *obj, Int cellX, Int cellY, PathfindLayerEnum layer, Int iRadius, Bool centerInCell);
  588. Bool checkForMovement(const Object *obj, TCheckMovementInfo &info);
  589. Bool segmentIntersectsTallBuilding(const PathNode *curNode, PathNode *nextNode,
  590. ObjectID ignoreBuilding, Coord3D *insertPos1, Coord3D *insertPos2, Coord3D *insertPos3); ///< Return true if the straight line between the given points intersects a tall building.
  591. Bool circleClipsTallBuilding(const Coord3D *from, const Coord3D *to, Real radius, ObjectID ignoreBuilding, Coord3D *adjustTo); ///< Return true if the circle at the end of the line between the given points intersects a tall building.
  592. enum {NO_ATTACK=0};
  593. Int examineNeighboringCells(PathfindCell *parentCell, PathfindCell *goalCell,
  594. const LocomotorSet& locomotorSet, Bool isHumanPlayer,
  595. Bool centerInCell, Int radius, const ICoord2D &startCellNdx,
  596. const Object *obj, Int attackDistance);
  597. Bool pathDestination( Object *obj, const LocomotorSet& locomotorSet, Coord3D *dest,
  598. PathfindLayerEnum layer, const Coord3D *groupDest); ///< Checks cost between given locations
  599. Int checkPathCost(Object *obj, const LocomotorSet& locomotorSet, const Coord3D *from,
  600. const Coord3D *to);
  601. void tightenPath(Object *obj, const LocomotorSet& locomotorSet, Coord3D *from,
  602. const Coord3D *to);
  603. /**
  604. return 0 to continue iterating the line, nonzero to terminate the iteration.
  605. the nonzero result will be returned as the result of iterateCellsAlongLine().
  606. iterateCellsAlongLine will return zero if it completes.
  607. */
  608. typedef Int (*CellAlongLineProc)(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  609. Int iterateCellsAlongLine(const Coord3D& startWorld, const Coord3D& endWorld,
  610. PathfindLayerEnum layer, CellAlongLineProc proc, void* userData);
  611. Int iterateCellsAlongLine(const ICoord2D &start, const ICoord2D &end,
  612. PathfindLayerEnum layer, CellAlongLineProc proc, void* userData);
  613. static Int linePassableCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  614. static Int groundPathPassableCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  615. static Int lineBlockedByObstacleCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  616. static Int tightenPathCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  617. static Int attackBlockedByObstacleCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  618. static Int examineCellsCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  619. static Int groundCellsCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  620. static Int moveAlliesDestinationCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  621. static Int segmentIntersectsBuildingCallback(Pathfinder* pathfinder, PathfindCell* from, PathfindCell* to, Int to_x, Int to_y, void* userData);
  622. void classifyMap( void ); ///< Classify all cells in grid as obstacles, etc
  623. void classifyObjectFootprint( Object *obj, Bool insert ); /** Classify the cells under the given object
  624. If 'insert' is true, object is being added
  625. If 'insert' is false, object is being removed */
  626. void internal_classifyObjectFootprint( Object *obj, Bool insert ); /** Classify the cells under the given object
  627. If 'insert' is true, object is being added
  628. If 'insert' is false, object is being removed */
  629. void classifyFence( Object *obj, Bool insert ); /** Classify the cells under the given fence object. */
  630. void classifyUnitFootprint( Object *obj, Bool insert, Bool remove, Bool update ); /** Classify the cells under the given object If 'insert' is true, object is being added */
  631. /// Convert world coordinate to array index
  632. void worldToGrid( const Coord3D *pos, ICoord2D *cellIndex );
  633. Bool evaluateCell(PathfindCell* newCell, PathfindCell *parentCell,
  634. const LocomotorSet& locomotorSet,
  635. Bool centerInCell, Int radius,
  636. const Object *obj, Int attackDistance);
  637. Path *buildActualPath( const Object *obj, LocomotorSurfaceTypeMask acceptableSurfaces,
  638. const Coord3D *fromPos, PathfindCell *goalCell, Bool center, Bool blocked ); ///< Work backwards from goal cell to construct final path
  639. Path *buildGroundPath( Bool isCrusher,const Coord3D *fromPos, PathfindCell *goalCell,
  640. Bool center, Int pathDiameter ); ///< Work backwards from goal cell to construct final path
  641. Path *buildHierachicalPath( const Coord3D *fromPos, PathfindCell *goalCell); ///< Work backwards from goal cell to construct final path
  642. void prependCells( Path *path, const Coord3D *fromPos,
  643. PathfindCell *goalCell, Bool center ); ///< Add pathfind cells to a path.
  644. void debugShowSearch( Bool pathFound ); ///< Show all cells touched in the last search
  645. static LocomotorSurfaceTypeMask validLocomotorSurfacesForCellType(PathfindCell::CellType t);
  646. void checkChangeLayers(PathfindCell *parentCell);
  647. #if defined _DEBUG || defined _INTERNAL
  648. void doDebugIcons(void) ;
  649. #endif
  650. private:
  651. /// This uses WAY too much memory. Should at least be array of pointers to cells w/ many fewer cells
  652. PathfindCell *m_blockOfMapCells; ///< Pathfinding map - contains iconic representation of the map
  653. PathfindCell **m_map; ///< Pathfinding map indexes - contains matrix indexing into the map.
  654. IRegion2D m_extent; ///< Grid extent limits
  655. IRegion2D m_logicalExtent; ///< Logical grid extent limits
  656. PathfindCell *m_openList; ///< Cells ready to be explored
  657. PathfindCell *m_closedList; ///< Cells already explored
  658. Bool m_isMapReady; ///< True if all cells of map have been classified
  659. Bool m_isTunneling; ///< True if path started in an obstacle
  660. Int m_frameToShowObstacles; ///< Time to redraw obstacles. For debug output.
  661. Coord3D debugPathPos; ///< Used for visual debugging
  662. Path *debugPath; ///< Used for visual debugging
  663. ObjectID m_ignoreObstacleID; ///< Ignore the given obstacle
  664. PathfindZoneManager m_zoneManager; ///< Handles the pathfind zones.
  665. PathfindLayer m_layers[LAYER_LAST+1];
  666. ObjectID m_wallPieces[MAX_WALL_PIECES];
  667. Int m_numWallPieces;
  668. Real m_wallHeight;
  669. Int m_moveAlliesDepth;
  670. // Pathfind queue
  671. ObjectID m_queuedPathfindRequests[PATHFIND_QUEUE_LEN];
  672. Int m_queuePRHead;
  673. Int m_queuePRTail;
  674. Int m_cumulativeCellsAllocated;
  675. };
  676. inline void Pathfinder::setIgnoreObstacleID( ObjectID objID )
  677. {
  678. m_ignoreObstacleID = objID;
  679. }
  680. inline void Pathfinder::worldToGrid( const Coord3D *pos, ICoord2D *cellIndex )
  681. {
  682. cellIndex->x = REAL_TO_INT(pos->x/PATHFIND_CELL_SIZE);
  683. cellIndex->y = REAL_TO_INT(pos->y/PATHFIND_CELL_SIZE);
  684. }
  685. inline Bool Pathfinder::validMovementPosition( Bool isCrusher, PathfindLayerEnum layer, const LocomotorSet& locomotorSet, Int x, Int y )
  686. {
  687. return validMovementPosition( isCrusher, locomotorSet.getValidSurfaces(), getCell( layer, x, y ) );
  688. }
  689. inline Bool Pathfinder::validMovementPosition( Bool isCrusher, PathfindLayerEnum layer, const LocomotorSet& locomotorSet, const Coord3D *pos )
  690. {
  691. Int x = REAL_TO_INT(pos->x/PATHFIND_CELL_SIZE);
  692. Int y = REAL_TO_INT(pos->y/PATHFIND_CELL_SIZE);
  693. return validMovementPosition( isCrusher, layer, locomotorSet, x, y );
  694. }
  695. inline const Coord3D *Pathfinder::getDebugPathPosition( void )
  696. {
  697. return &debugPathPos;
  698. }
  699. inline void Pathfinder::setDebugPathPosition( const Coord3D *pos )
  700. {
  701. debugPathPos = *pos;
  702. }
  703. inline Path *Pathfinder::getDebugPath( void )
  704. {
  705. return debugPath;
  706. }
  707. inline void Pathfinder::addObjectToPathfindMap( class Object *obj )
  708. {
  709. classifyObjectFootprint( obj, true );
  710. }
  711. inline void Pathfinder::removeObjectFromPathfindMap( class Object *obj )
  712. {
  713. classifyObjectFootprint( obj, false );
  714. }
  715. inline PathfindCell *Pathfinder::getCell( PathfindLayerEnum layer, Int x, Int y )
  716. {
  717. if (x >= m_extent.lo.x && x <= m_extent.hi.x &&
  718. y >= m_extent.lo.y && y <= m_extent.hi.y)
  719. {
  720. PathfindCell *cell = NULL;
  721. if (layer > LAYER_GROUND && layer <= LAYER_LAST)
  722. {
  723. cell = m_layers[layer].getCell(x, y);
  724. if (cell)
  725. return cell;
  726. }
  727. return &m_map[x][y];
  728. }
  729. else
  730. {
  731. return NULL;
  732. }
  733. }
  734. inline PathfindCell *Pathfinder::getCell( PathfindLayerEnum layer, const Coord3D *pos )
  735. {
  736. ICoord2D cell;
  737. Bool overflow = worldToCell( pos, &cell );
  738. if (overflow) return NULL;
  739. return getCell( layer, cell.x, cell.y );
  740. }
  741. inline PathfindCell *Pathfinder::getClippedCell( PathfindLayerEnum layer, const Coord3D *pos)
  742. {
  743. ICoord2D cell;
  744. worldToCell( pos, &cell );
  745. return getCell( layer, cell.x, cell.y );
  746. }
  747. inline Bool Pathfinder::worldToCell( const Coord3D *pos, ICoord2D *cell )
  748. {
  749. cell->x = REAL_TO_INT_FLOOR(pos->x/PATHFIND_CELL_SIZE);
  750. cell->y = REAL_TO_INT_FLOOR(pos->y/PATHFIND_CELL_SIZE);
  751. Bool overflow = false;
  752. if (cell->x < m_extent.lo.x) {overflow = true; cell->x = m_extent.lo.x;}
  753. if (cell->y < m_extent.lo.y) {overflow = true; cell->y = m_extent.lo.y;}
  754. if (cell->x > m_extent.hi.x) {overflow = true; cell->x = m_extent.hi.x;}
  755. if (cell->y > m_extent.hi.y) {overflow = true; cell->y = m_extent.hi.y;}
  756. return overflow;
  757. }
  758. /**
  759. * Return true if the given object ID is registered as an obstacle in this cell
  760. */
  761. inline Bool PathfindCell::isObstaclePresent( ObjectID objID ) const
  762. {
  763. if (objID != INVALID_ID && (getType() == PathfindCell::CELL_OBSTACLE))
  764. {
  765. DEBUG_ASSERTCRASH(m_info, ("Should have info to be obstacle."));
  766. return (m_info && m_info->m_obstacleID == objID);
  767. }
  768. return false;
  769. }
  770. #endif // _PATHFIND_H_