AIPathfind.h 44 KB

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