Team Fortress 2 Source Code as on 22/4/2020
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.

498 lines
14 KiB

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