Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

473 lines
13 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // nav.h
  9. // Data structures and constants for the Navigation Mesh system
  10. // Author: Michael S. Booth ([email protected]), January 2003
  11. #ifndef _NAV_H_
  12. #define _NAV_H_
  13. #include "modelentities.h" // for CFuncBrush
  14. /**
  15. * Below are several constants used by the navigation system.
  16. * @todo Move these into TheNavMesh singleton.
  17. */
  18. const float GenerationStepSize = 25.0f; // (30) was 20, but bots can't fit always fit
  19. const float JumpHeight = 41.8f; // if delta Z is less than this, we can jump up on it
  20. #if defined(CSTRIKE_DLL)
  21. const float JumpCrouchHeight = 58.0f; // (48) if delta Z is less than or equal to this, we can jumpcrouch up on it
  22. #else
  23. const float JumpCrouchHeight = 64.0f; // (48) if delta Z is less than or equal to this, we can jumpcrouch up on it
  24. #endif
  25. // There are 3 different definitions of StepHeight throughout the code, waiting to produce bugs if the 18.0 is ever changed.
  26. #ifdef INFESTED_DLL
  27. const float StepHeight = 24.0f; ///< if delta Z is greater than this, we have to jump to get up
  28. #else
  29. const float StepHeight = 18.0f; // if delta Z is greater than this, we have to jump to get up
  30. #endif // INFESTED_DLL
  31. // TERROR: Increased DeathDrop from 200, since zombies don't take falling damage
  32. #if defined(CSTRIKE_DLL)
  33. const float DeathDrop = 200.0f; // (300) distance at which we will die if we fall - should be about 600, and pay attention to fall damage during pathfind
  34. #else
  35. const float DeathDrop = 400.0f; // (300) distance at which we will die if we fall - should be about 600, and pay attention to fall damage during pathfind
  36. #endif
  37. #if defined(CSTRIKE_DLL)
  38. const float ClimbUpHeight = JumpCrouchHeight; // CSBots assume all jump up links are reachable
  39. #else
  40. const float ClimbUpHeight = 200.0f; // height to check for climbing up
  41. #endif
  42. const float CliffHeight = 300.0f; // height which we consider a significant cliff which we would not want to fall off of
  43. // TERROR: Converted these values to use the same numbers as the player bounding boxes etc
  44. #define HalfHumanWidth 16
  45. #define HalfHumanHeight 35.5
  46. #define HumanHeight 71
  47. #define HumanEyeHeight 62
  48. #define HumanCrouchHeight 55
  49. #define HumanCrouchEyeHeight 37
  50. #define NAV_MAGIC_NUMBER 0xFEEDFACE // to help identify nav files
  51. /**
  52. * A place is a named group of navigation areas
  53. */
  54. typedef unsigned int Place;
  55. #define UNDEFINED_PLACE 0 // ie: "no place"
  56. #define ANY_PLACE 0xFFFF
  57. enum NavErrorType
  58. {
  59. NAV_OK,
  60. NAV_CANT_ACCESS_FILE,
  61. NAV_INVALID_FILE,
  62. NAV_BAD_FILE_VERSION,
  63. NAV_FILE_OUT_OF_DATE,
  64. NAV_CORRUPT_DATA,
  65. NAV_OUT_OF_MEMORY,
  66. };
  67. enum NavAttributeType
  68. {
  69. NAV_MESH_INVALID = 0,
  70. NAV_MESH_CROUCH = 0x0000001, // must crouch to use this node/area
  71. NAV_MESH_JUMP = 0x0000002, // must jump to traverse this area (only used during generation)
  72. NAV_MESH_PRECISE = 0x0000004, // do not adjust for obstacles, just move along area
  73. NAV_MESH_NO_JUMP = 0x0000008, // inhibit discontinuity jumping
  74. NAV_MESH_STOP = 0x0000010, // must stop when entering this area
  75. NAV_MESH_RUN = 0x0000020, // must run to traverse this area
  76. NAV_MESH_WALK = 0x0000040, // must walk to traverse this area
  77. NAV_MESH_AVOID = 0x0000080, // avoid this area unless alternatives are too dangerous
  78. NAV_MESH_TRANSIENT = 0x0000100, // area may become blocked, and should be periodically checked
  79. NAV_MESH_DONT_HIDE = 0x0000200, // area should not be considered for hiding spot generation
  80. NAV_MESH_STAND = 0x0000400, // bots hiding in this area should stand
  81. NAV_MESH_NO_HOSTAGES = 0x0000800, // hostages shouldn't use this area
  82. NAV_MESH_STAIRS = 0x0001000, // this area represents stairs, do not attempt to climb or jump them - just walk up
  83. NAV_MESH_NO_MERGE = 0x0002000, // don't merge this area with adjacent areas
  84. NAV_MESH_OBSTACLE_TOP = 0x0004000, // this nav area is the climb point on the tip of an obstacle
  85. NAV_MESH_CLIFF = 0x0008000, // this nav area is adjacent to a drop of at least CliffHeight
  86. NAV_MESH_FIRST_CUSTOM = 0x00010000, // apps may define custom app-specific bits starting with this value
  87. NAV_MESH_LAST_CUSTOM = 0x04000000, // apps must not define custom app-specific bits higher than with this value
  88. NAV_MESH_BLOCKED_PROPDOOR = 0x10000000, // area is blocked by prop_door_rotating
  89. NAV_MESH_HAS_ELEVATOR = 0x40000000, // area is in an elevator's path
  90. NAV_MESH_NAV_BLOCKER = 0x80000000 // area is blocked by nav blocker ( Alas, needed to hijack a bit in the attributes to get within a cache line [7/24/2008 tom])
  91. };
  92. extern NavAttributeType NameToNavAttribute( const char *name );
  93. enum NavDirType
  94. {
  95. NORTH = 0,
  96. EAST = 1,
  97. SOUTH = 2,
  98. WEST = 3,
  99. NUM_DIRECTIONS
  100. };
  101. /**
  102. * Defines possible ways to move from one area to another
  103. */
  104. enum NavTraverseType
  105. {
  106. // NOTE: First 4 directions MUST match NavDirType
  107. GO_NORTH = 0,
  108. GO_EAST,
  109. GO_SOUTH,
  110. GO_WEST,
  111. GO_LADDER_UP,
  112. GO_LADDER_DOWN,
  113. GO_JUMP,
  114. GO_ELEVATOR_UP,
  115. GO_ELEVATOR_DOWN,
  116. NUM_TRAVERSE_TYPES
  117. };
  118. enum NavCornerType
  119. {
  120. NORTH_WEST = 0,
  121. NORTH_EAST = 1,
  122. SOUTH_EAST = 2,
  123. SOUTH_WEST = 3,
  124. NUM_CORNERS
  125. };
  126. enum NavRelativeDirType
  127. {
  128. FORWARD = 0,
  129. RIGHT,
  130. BACKWARD,
  131. LEFT,
  132. UP,
  133. DOWN,
  134. NUM_RELATIVE_DIRECTIONS
  135. };
  136. struct Extent
  137. {
  138. Vector lo, hi;
  139. void Init( void )
  140. {
  141. lo.Init();
  142. hi.Init();
  143. }
  144. void Init( CBaseEntity *entity )
  145. {
  146. entity->CollisionProp()->WorldSpaceSurroundingBounds( &lo, &hi );
  147. }
  148. float SizeX( void ) const { return hi.x - lo.x; }
  149. float SizeY( void ) const { return hi.y - lo.y; }
  150. float SizeZ( void ) const { return hi.z - lo.z; }
  151. float Area( void ) const { return SizeX() * SizeY(); }
  152. // Increase bounds to contain the given point
  153. void Encompass( const Vector &pos )
  154. {
  155. for ( int i=0; i<3; ++i )
  156. {
  157. if ( pos[i] < lo[i] )
  158. {
  159. lo[i] = pos[i];
  160. }
  161. else if ( pos[i] > hi[i] )
  162. {
  163. hi[i] = pos[i];
  164. }
  165. }
  166. }
  167. // Increase bounds to contain the given extent
  168. void Encompass( const Extent &extent )
  169. {
  170. Encompass( extent.lo );
  171. Encompass( extent.hi );
  172. }
  173. /// return true if 'pos' is inside of this extent
  174. bool Contains( const Vector &pos ) const
  175. {
  176. return (pos.x >= lo.x && pos.x <= hi.x &&
  177. pos.y >= lo.y && pos.y <= hi.y &&
  178. pos.z >= lo.z && pos.z <= hi.z);
  179. }
  180. /// return true if this extent overlaps the given one
  181. bool IsOverlapping( const Extent &other ) const
  182. {
  183. return (lo.x <= other.hi.x && hi.x >= other.lo.x &&
  184. lo.y <= other.hi.y && hi.y >= other.lo.y &&
  185. lo.z <= other.hi.z && hi.z >= other.lo.z);
  186. }
  187. };
  188. struct Ray
  189. {
  190. Vector from, to;
  191. };
  192. class CNavArea;
  193. class CNavNode;
  194. //--------------------------------------------------------------------------------------------------------------
  195. inline NavDirType OppositeDirection( NavDirType dir )
  196. {
  197. switch( dir )
  198. {
  199. case NORTH: return SOUTH;
  200. case SOUTH: return NORTH;
  201. case EAST: return WEST;
  202. case WEST: return EAST;
  203. }
  204. return NORTH;
  205. }
  206. //--------------------------------------------------------------------------------------------------------------
  207. inline NavDirType DirectionLeft( NavDirType dir )
  208. {
  209. switch( dir )
  210. {
  211. case NORTH: return WEST;
  212. case SOUTH: return EAST;
  213. case EAST: return NORTH;
  214. case WEST: return SOUTH;
  215. }
  216. return NORTH;
  217. }
  218. //--------------------------------------------------------------------------------------------------------------
  219. inline NavDirType DirectionRight( NavDirType dir )
  220. {
  221. switch( dir )
  222. {
  223. case NORTH: return EAST;
  224. case SOUTH: return WEST;
  225. case EAST: return SOUTH;
  226. case WEST: return NORTH;
  227. }
  228. return NORTH;
  229. }
  230. //--------------------------------------------------------------------------------------------------------------
  231. inline void AddDirectionVector( Vector *v, NavDirType dir, float amount )
  232. {
  233. switch( dir )
  234. {
  235. case NORTH: v->y -= amount; return;
  236. case SOUTH: v->y += amount; return;
  237. case EAST: v->x += amount; return;
  238. case WEST: v->x -= amount; return;
  239. }
  240. }
  241. //--------------------------------------------------------------------------------------------------------------
  242. inline float DirectionToAngle( NavDirType dir )
  243. {
  244. switch( dir )
  245. {
  246. case NORTH: return 270.0f;
  247. case SOUTH: return 90.0f;
  248. case EAST: return 0.0f;
  249. case WEST: return 180.0f;
  250. }
  251. return 0.0f;
  252. }
  253. //--------------------------------------------------------------------------------------------------------------
  254. inline NavDirType AngleToDirection( float angle )
  255. {
  256. while( angle < 0.0f )
  257. angle += 360.0f;
  258. while( angle > 360.0f )
  259. angle -= 360.0f;
  260. if (angle < 45 || angle > 315)
  261. return EAST;
  262. if (angle >= 45 && angle < 135)
  263. return SOUTH;
  264. if (angle >= 135 && angle < 225)
  265. return WEST;
  266. return NORTH;
  267. }
  268. //--------------------------------------------------------------------------------------------------------------
  269. inline void DirectionToVector2D( NavDirType dir, Vector2D *v )
  270. {
  271. switch( dir )
  272. {
  273. case NORTH: v->x = 0.0f; v->y = -1.0f; break;
  274. case SOUTH: v->x = 0.0f; v->y = 1.0f; break;
  275. case EAST: v->x = 1.0f; v->y = 0.0f; break;
  276. case WEST: v->x = -1.0f; v->y = 0.0f; break;
  277. }
  278. }
  279. //--------------------------------------------------------------------------------------------------------------
  280. inline void CornerToVector2D( NavCornerType dir, Vector2D *v )
  281. {
  282. switch( dir )
  283. {
  284. case NORTH_WEST: v->x = -1.0f; v->y = -1.0f; break;
  285. case NORTH_EAST: v->x = 1.0f; v->y = -1.0f; break;
  286. case SOUTH_EAST: v->x = 1.0f; v->y = 1.0f; break;
  287. case SOUTH_WEST: v->x = -1.0f; v->y = 1.0f; break;
  288. }
  289. v->NormalizeInPlace();
  290. }
  291. //--------------------------------------------------------------------------------------------------------------
  292. // Gets the corner types that surround the given direction
  293. inline void GetCornerTypesInDirection( NavDirType dir, NavCornerType *first, NavCornerType *second )
  294. {
  295. switch ( dir )
  296. {
  297. case NORTH:
  298. *first = NORTH_WEST;
  299. *second = NORTH_EAST;
  300. break;
  301. case SOUTH:
  302. *first = SOUTH_WEST;
  303. *second = SOUTH_EAST;
  304. break;
  305. case EAST:
  306. *first = NORTH_EAST;
  307. *second = SOUTH_EAST;
  308. break;
  309. case WEST:
  310. *first = NORTH_WEST;
  311. *second = SOUTH_WEST;
  312. break;
  313. }
  314. }
  315. //--------------------------------------------------------------------------------------------------------------
  316. inline float RoundToUnits( float val, float unit )
  317. {
  318. val = val + ((val < 0.0f) ? -unit*0.5f : unit*0.5f);
  319. return (float)( unit * ( ((int)val) / (int)unit ) );
  320. }
  321. //--------------------------------------------------------------------------------------------------------------
  322. /**
  323. * Return true if given entity can be ignored when moving
  324. */
  325. #define WALK_THRU_PROP_DOORS 0x01
  326. #define WALK_THRU_FUNC_DOORS 0x02
  327. #define WALK_THRU_DOORS (WALK_THRU_PROP_DOORS | WALK_THRU_FUNC_DOORS)
  328. #define WALK_THRU_BREAKABLES 0x04
  329. #define WALK_THRU_TOGGLE_BRUSHES 0x08
  330. #define WALK_THRU_EVERYTHING (WALK_THRU_DOORS | WALK_THRU_BREAKABLES | WALK_THRU_TOGGLE_BRUSHES)
  331. extern ConVar nav_solid_props;
  332. inline bool IsEntityWalkable( CBaseEntity *entity, unsigned int flags )
  333. {
  334. if (FClassnameIs( entity, "worldspawn" ))
  335. return false;
  336. if (FClassnameIs( entity, "player" ))
  337. return false;
  338. // if we hit a door, assume its walkable because it will open when we touch it
  339. if (FClassnameIs( entity, "func_door*" ))
  340. return (flags & WALK_THRU_FUNC_DOORS) ? true : false;
  341. if (FClassnameIs( entity, "prop_door*" ))
  342. return (flags & WALK_THRU_PROP_DOORS) ? true : false;
  343. // if we hit a clip brush, ignore it if it is not BRUSHSOLID_ALWAYS
  344. if (FClassnameIs( entity, "func_brush" ))
  345. {
  346. CFuncBrush *brush = (CFuncBrush *)entity;
  347. switch ( brush->m_iSolidity )
  348. {
  349. case CFuncBrush::BRUSHSOLID_ALWAYS:
  350. return false;
  351. case CFuncBrush::BRUSHSOLID_NEVER:
  352. return true;
  353. case CFuncBrush::BRUSHSOLID_TOGGLE:
  354. return (flags & WALK_THRU_TOGGLE_BRUSHES) ? true : false;
  355. }
  356. }
  357. // if we hit a breakable object, assume its walkable because we will shoot it when we touch it
  358. if (FClassnameIs( entity, "func_breakable" ) && entity->GetHealth() && entity->m_takedamage == DAMAGE_YES)
  359. return (flags & WALK_THRU_BREAKABLES) ? true : false;
  360. if (FClassnameIs( entity, "func_breakable_surf" ) && entity->m_takedamage == DAMAGE_YES)
  361. return (flags & WALK_THRU_BREAKABLES) ? true : false;
  362. if ( FClassnameIs( entity, "func_playerinfected_clip" ) == true )
  363. return true;
  364. if ( nav_solid_props.GetBool() && FClassnameIs( entity, "prop_*" ) )
  365. return true;
  366. return false;
  367. }
  368. //--------------------------------------------------------------------------------------------------------------
  369. /**
  370. * Trace filter that ignores players, NPCs, and objects that can be walked through
  371. */
  372. class CTraceFilterWalkableEntities : public CTraceFilterNoNPCsOrPlayer
  373. {
  374. public:
  375. CTraceFilterWalkableEntities( const IHandleEntity *passentity, int collisionGroup, unsigned int flags )
  376. : CTraceFilterNoNPCsOrPlayer( passentity, collisionGroup ), m_flags( flags )
  377. {
  378. }
  379. virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
  380. {
  381. if ( CTraceFilterNoNPCsOrPlayer::ShouldHitEntity(pServerEntity, contentsMask) )
  382. {
  383. CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
  384. return ( !IsEntityWalkable( pEntity, m_flags ) );
  385. }
  386. return false;
  387. }
  388. private:
  389. unsigned int m_flags;
  390. };
  391. extern bool IsWalkableTraceLineClear( const Vector &from, const Vector &to, unsigned int flags = 0 );
  392. extern bool IsWalkableTraceHullClear( const Vector &from, const Vector &to, const Vector &mins, const Vector &maxs, unsigned int flags );
  393. #endif // _NAV_H_