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.

1069 lines
46 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // nav_area.h
  9. // Navigation areas
  10. // Author: Michael S. Booth ([email protected]), January 2003
  11. #ifndef _NAV_AREA_H_
  12. #define _NAV_AREA_H_
  13. #include "nav_ladder.h"
  14. #include "tier1/memstack.h"
  15. // BOTPORT: Clean up relationship between team index and danger storage in nav areas
  16. enum { MAX_NAV_TEAMS = 2 };
  17. #ifdef STAGING_ONLY
  18. inline void DebuggerBreakOnNaN_StagingOnly( float val )
  19. {
  20. if ( IS_NAN( val ) )
  21. DebuggerBreak();
  22. }
  23. #else
  24. #define DebuggerBreakOnNaN_StagingOnly( _val )
  25. #endif
  26. class CFuncElevator;
  27. class CFuncNavPrerequisite;
  28. class CFuncNavCost;
  29. class CNavVectorNoEditAllocator
  30. {
  31. public:
  32. CNavVectorNoEditAllocator();
  33. static void Reset();
  34. static void *Alloc( size_t nSize );
  35. static void *Realloc( void *pMem, size_t nSize );
  36. static void Free( void *pMem );
  37. static size_t GetSize( void *pMem );
  38. private:
  39. static CMemoryStack m_memory;
  40. static void *m_pCurrent;
  41. static int m_nBytesCurrent;
  42. };
  43. #if !defined(_X360)
  44. typedef CUtlVectorUltraConservativeAllocator CNavVectorAllocator;
  45. #else
  46. typedef CNavVectorNoEditAllocator CNavVectorAllocator;
  47. #endif
  48. //-------------------------------------------------------------------------------------------------------------------
  49. /**
  50. * Functor interface for iteration
  51. */
  52. class IForEachNavArea
  53. {
  54. public:
  55. virtual bool Inspect( const CNavArea *area ) = 0; // Invoked once on each area of the iterated set. Return false to stop iterating.
  56. virtual void PostIteration( bool wasCompleteIteration ) { } // Invoked after the iteration has ended. 'wasCompleteIteration' will be true if the entire set was iterated (ie: Inspect() never returned false)
  57. };
  58. //-------------------------------------------------------------------------------------------------------------------
  59. /**
  60. * The NavConnect union is used to refer to connections to areas
  61. */
  62. struct NavConnect
  63. {
  64. NavConnect()
  65. {
  66. id = 0;
  67. length = -1;
  68. }
  69. union
  70. {
  71. unsigned int id;
  72. CNavArea *area;
  73. };
  74. mutable float length;
  75. bool operator==( const NavConnect &other ) const
  76. {
  77. return (area == other.area) ? true : false;
  78. }
  79. };
  80. typedef CUtlVectorUltraConservative<NavConnect, CNavVectorAllocator> NavConnectVector;
  81. //-------------------------------------------------------------------------------------------------------------------
  82. /**
  83. * The NavLadderConnect union is used to refer to connections to ladders
  84. */
  85. union NavLadderConnect
  86. {
  87. unsigned int id;
  88. CNavLadder *ladder;
  89. bool operator==( const NavLadderConnect &other ) const
  90. {
  91. return (ladder == other.ladder) ? true : false;
  92. }
  93. };
  94. typedef CUtlVectorUltraConservative<NavLadderConnect, CNavVectorAllocator> NavLadderConnectVector;
  95. //--------------------------------------------------------------------------------------------------------------
  96. /**
  97. * A HidingSpot is a good place for a bot to crouch and wait for enemies
  98. */
  99. class HidingSpot
  100. {
  101. public:
  102. virtual ~HidingSpot() { }
  103. enum
  104. {
  105. IN_COVER = 0x01, // in a corner with good hard cover nearby
  106. GOOD_SNIPER_SPOT = 0x02, // had at least one decent sniping corridor
  107. IDEAL_SNIPER_SPOT = 0x04, // can see either very far, or a large area, or both
  108. EXPOSED = 0x08 // spot in the open, usually on a ledge or cliff
  109. };
  110. bool HasGoodCover( void ) const { return (m_flags & IN_COVER) ? true : false; } // return true if hiding spot in in cover
  111. bool IsGoodSniperSpot( void ) const { return (m_flags & GOOD_SNIPER_SPOT) ? true : false; }
  112. bool IsIdealSniperSpot( void ) const { return (m_flags & IDEAL_SNIPER_SPOT) ? true : false; }
  113. bool IsExposed( void ) const { return (m_flags & EXPOSED) ? true : false; }
  114. int GetFlags( void ) const { return m_flags; }
  115. void Save( CUtlBuffer &fileBuffer, unsigned int version ) const;
  116. void Load( CUtlBuffer &fileBuffer, unsigned int version );
  117. NavErrorType PostLoad( void );
  118. const Vector &GetPosition( void ) const { return m_pos; } // get the position of the hiding spot
  119. unsigned int GetID( void ) const { return m_id; }
  120. const CNavArea *GetArea( void ) const { return m_area; } // return nav area this hiding spot is within
  121. void Mark( void ) { m_marker = m_masterMarker; }
  122. bool IsMarked( void ) const { return (m_marker == m_masterMarker) ? true : false; }
  123. static void ChangeMasterMarker( void ) { ++m_masterMarker; }
  124. public:
  125. void SetFlags( int flags ) { m_flags |= flags; } // FOR INTERNAL USE ONLY
  126. void SetPosition( const Vector &pos ) { m_pos = pos; } // FOR INTERNAL USE ONLY
  127. private:
  128. friend class CNavMesh;
  129. friend void ClassifySniperSpot( HidingSpot *spot );
  130. HidingSpot( void ); // must use factory to create
  131. Vector m_pos; // world coordinates of the spot
  132. unsigned int m_id; // this spot's unique ID
  133. unsigned int m_marker; // this spot's unique marker
  134. CNavArea *m_area; // the nav area containing this hiding spot
  135. unsigned char m_flags; // bit flags
  136. static unsigned int m_nextID; // used when allocating spot ID's
  137. static unsigned int m_masterMarker; // used to mark spots
  138. };
  139. typedef CUtlVectorUltraConservative< HidingSpot * > HidingSpotVector;
  140. extern HidingSpotVector TheHidingSpots;
  141. extern HidingSpot *GetHidingSpotByID( unsigned int id );
  142. //--------------------------------------------------------------------------------------------------------------
  143. /**
  144. * Stores a pointer to an interesting "spot", and a parametric distance along a path
  145. */
  146. struct SpotOrder
  147. {
  148. float t; // parametric distance along ray where this spot first has LOS to our path
  149. union
  150. {
  151. HidingSpot *spot; // the spot to look at
  152. unsigned int id; // spot ID for save/load
  153. };
  154. };
  155. typedef CUtlVector< SpotOrder > SpotOrderVector;
  156. /**
  157. * This struct stores possible path segments thru a CNavArea, and the dangerous spots
  158. * to look at as we traverse that path segment.
  159. */
  160. struct SpotEncounter
  161. {
  162. NavConnect from;
  163. NavDirType fromDir;
  164. NavConnect to;
  165. NavDirType toDir;
  166. Ray path; // the path segment
  167. SpotOrderVector spots; // list of spots to look at, in order of occurrence
  168. };
  169. typedef CUtlVectorUltraConservative< SpotEncounter * > SpotEncounterVector;
  170. //-------------------------------------------------------------------------------------------------------------------
  171. /**
  172. * A CNavArea is a rectangular region defining a walkable area in the environment
  173. */
  174. class CNavAreaCriticalData
  175. {
  176. protected:
  177. // --- Begin critical data, which is heavily hit during pathing operations and carefully arranged for cache performance [7/24/2008 tom] ---
  178. /* 0 */ Vector m_nwCorner; // north-west corner position (2D mins)
  179. /* 12 */ Vector m_seCorner; // south-east corner position (2D maxs)
  180. /* 24 */ float m_invDxCorners;
  181. /* 28 */ float m_invDyCorners;
  182. /* 32 */ float m_neZ; // height of the implicit corner defined by (m_seCorner.x, m_nwCorner.y, m_neZ)
  183. /* 36 */ float m_swZ; // height of the implicit corner defined by (m_nwCorner.x, m_seCorner.y, m_neZ)
  184. /* 40 */ Vector m_center; // centroid of area
  185. /* 52 */ unsigned char m_playerCount[ MAX_NAV_TEAMS ]; // the number of players currently in this area
  186. /* 54 */ bool m_isBlocked[ MAX_NAV_TEAMS ]; // if true, some part of the world is preventing movement through this nav area
  187. /* 56 */ unsigned int m_marker; // used to flag the area as visited
  188. /* 60 */ float m_totalCost; // the distance so far plus an estimate of the distance left
  189. /* 64 */ float m_costSoFar; // distance travelled so far
  190. /* 68 */ CNavArea *m_nextOpen, *m_prevOpen; // only valid if m_openMarker == m_masterMarker
  191. /* 76 */ unsigned int m_openMarker; // if this equals the current marker value, we are on the open list
  192. /* 80 */ int m_attributeFlags; // set of attribute bit flags (see NavAttributeType)
  193. //- connections to adjacent areas -------------------------------------------------------------------
  194. /* 84 */ NavConnectVector m_connect[ NUM_DIRECTIONS ]; // a list of adjacent areas for each direction
  195. /* 100*/ NavLadderConnectVector m_ladder[ CNavLadder::NUM_LADDER_DIRECTIONS ]; // list of ladders leading up and down from this area
  196. /* 108*/ NavConnectVector m_elevatorAreas; // a list of areas reachable via elevator from this area
  197. /* 112*/ unsigned int m_nearNavSearchMarker; // used in GetNearestNavArea()
  198. /* 116*/ CNavArea *m_parent; // the area just prior to this on in the search path
  199. /* 120*/ NavTraverseType m_parentHow; // how we get from parent to us
  200. /* 124*/ float m_pathLengthSoFar; // length of path so far, needed for limiting pathfind max path length
  201. /* *************** 360 cache line *************** */
  202. /* 128*/ CFuncElevator *m_elevator; // if non-NULL, this area is in an elevator's path. The elevator can transport us vertically to another area.
  203. // --- End critical data ---
  204. };
  205. class CNavArea : protected CNavAreaCriticalData
  206. {
  207. public:
  208. DECLARE_CLASS_NOBASE( CNavArea )
  209. CNavArea( void );
  210. virtual ~CNavArea();
  211. virtual void OnServerActivate( void ); // (EXTEND) invoked when map is initially loaded
  212. virtual void OnRoundRestart( void ); // (EXTEND) invoked for each area when the round restarts
  213. virtual void OnRoundRestartPreEntity( void ) { } // invoked for each area when the round restarts, but before entities are deleted and recreated
  214. virtual void OnEnter( CBaseCombatCharacter *who, CNavArea *areaJustLeft ) { } // invoked when player enters this area
  215. virtual void OnExit( CBaseCombatCharacter *who, CNavArea *areaJustEntered ) { } // invoked when player exits this area
  216. virtual void OnDestroyNotify( CNavArea *dead ); // invoked when given area is going away
  217. virtual void OnDestroyNotify( CNavLadder *dead ); // invoked when given ladder is going away
  218. virtual void OnEditCreateNotify( CNavArea *newArea ) { } // invoked when given area has just been added to the mesh in edit mode
  219. virtual void OnEditDestroyNotify( CNavArea *deadArea ) { } // invoked when given area has just been deleted from the mesh in edit mode
  220. virtual void OnEditDestroyNotify( CNavLadder *deadLadder ) { } // invoked when given ladder has just been deleted from the mesh in edit mode
  221. virtual void Save( CUtlBuffer &fileBuffer, unsigned int version ) const; // (EXTEND)
  222. virtual NavErrorType Load( CUtlBuffer &fileBuffer, unsigned int version, unsigned int subVersion ); // (EXTEND)
  223. virtual NavErrorType PostLoad( void ); // (EXTEND) invoked after all areas have been loaded - for pointer binding, etc
  224. virtual void SaveToSelectedSet( KeyValues *areaKey ) const; // (EXTEND) saves attributes for the area to a KeyValues
  225. virtual void RestoreFromSelectedSet( KeyValues *areaKey ); // (EXTEND) restores attributes from a KeyValues
  226. // for interactively building or generating nav areas
  227. void Build( CNavNode *nwNode, CNavNode *neNode, CNavNode *seNode, CNavNode *swNode );
  228. void Build( const Vector &corner, const Vector &otherCorner );
  229. void Build( const Vector &nwCorner, const Vector &neCorner, const Vector &seCorner, const Vector &swCorner );
  230. void ConnectTo( CNavArea *area, NavDirType dir ); // connect this area to given area in given direction
  231. void Disconnect( CNavArea *area ); // disconnect this area from given area
  232. void ConnectTo( CNavLadder *ladder ); // connect this area to given ladder
  233. void Disconnect( CNavLadder *ladder ); // disconnect this area from given ladder
  234. unsigned int GetID( void ) const { return m_id; } // return this area's unique ID
  235. static void CompressIDs( void ); // re-orders area ID's so they are continuous
  236. unsigned int GetDebugID( void ) const { return m_debugid; }
  237. void SetAttributes( int bits ) { m_attributeFlags = bits; }
  238. int GetAttributes( void ) const { return m_attributeFlags; }
  239. bool HasAttributes( int bits ) const { return ( m_attributeFlags & bits ) ? true : false; }
  240. void RemoveAttributes( int bits ) { m_attributeFlags &= ( ~bits ); }
  241. void SetPlace( Place place ) { m_place = place; } // set place descriptor
  242. Place GetPlace( void ) const { return m_place; } // get place descriptor
  243. void MarkAsBlocked( int teamID, CBaseEntity *blocker, bool bGenerateEvent = true ); // An entity can force a nav area to be blocked
  244. virtual void UpdateBlocked( bool force = false, int teamID = TEAM_ANY ); // Updates the (un)blocked status of the nav area (throttled)
  245. virtual bool IsBlocked( int teamID, bool ignoreNavBlockers = false ) const;
  246. void UnblockArea( int teamID = TEAM_ANY ); // clear blocked status for the given team(s)
  247. void CheckFloor( CBaseEntity *ignore ); // Checks if there is a floor under the nav area, in case a breakable floor is gone
  248. void MarkObstacleToAvoid( float obstructionHeight );
  249. void UpdateAvoidanceObstacles( void );
  250. bool HasAvoidanceObstacle( float maxObstructionHeight = StepHeight ) const; // is there a large, immobile object obstructing this area
  251. float GetAvoidanceObstacleHeight( void ) const; // returns the maximum height of the obstruction above the ground
  252. #ifdef NEXT_BOT
  253. bool HasPrerequisite( CBaseCombatCharacter *actor = NULL ) const; // return true if this area has a prerequisite that applies to the given actor
  254. const CUtlVector< CHandle< CFuncNavPrerequisite > > &GetPrerequisiteVector( void ) const; // return vector of prerequisites that must be met before this area can be traversed
  255. void RemoveAllPrerequisites( void );
  256. void AddPrerequisite( CFuncNavPrerequisite *prereq );
  257. #endif
  258. void ClearAllNavCostEntities( void ); // clear set of func_nav_cost entities that affect this area
  259. void AddFuncNavCostEntity( CFuncNavCost *cost ); // add the given func_nav_cost entity to the cost of this area
  260. float ComputeFuncNavCost( CBaseCombatCharacter *who ) const; // return the cost multiplier of this area's func_nav_cost entities for the given actor
  261. bool HasFuncNavAvoid( void ) const;
  262. bool HasFuncNavPrefer( void ) const;
  263. void CheckWaterLevel( void );
  264. bool IsUnderwater( void ) const { return m_isUnderwater; }
  265. bool IsOverlapping( const Vector &pos, float tolerance = 0.0f ) const; // return true if 'pos' is within 2D extents of area.
  266. bool IsOverlapping( const CNavArea *area ) const; // return true if 'area' overlaps our 2D extents
  267. bool IsOverlapping( const Extent &extent ) const; // return true if 'extent' overlaps our 2D extents
  268. bool IsOverlappingX( const CNavArea *area ) const; // return true if 'area' overlaps our X extent
  269. bool IsOverlappingY( const CNavArea *area ) const; // return true if 'area' overlaps our Y extent
  270. inline float GetZ( const Vector * RESTRICT pPos ) const ; // return Z of area at (x,y) of 'pos'
  271. inline float GetZ( const Vector &pos ) const; // return Z of area at (x,y) of 'pos'
  272. float GetZ( float x, float y ) const RESTRICT; // return Z of area at (x,y) of 'pos'
  273. bool Contains( const Vector &pos ) const; // return true if given point is on or above this area, but no others
  274. bool Contains( const CNavArea *area ) const;
  275. bool IsCoplanar( const CNavArea *area ) const; // return true if this area and given area are approximately co-planar
  276. void GetClosestPointOnArea( const Vector * RESTRICT pPos, Vector *close ) const RESTRICT; // return closest point to 'pos' on this area - returned point in 'close'
  277. void GetClosestPointOnArea( const Vector &pos, Vector *close ) const { return GetClosestPointOnArea( &pos, close ); }
  278. float GetDistanceSquaredToPoint( const Vector &pos ) const; // return shortest distance between point and this area
  279. bool IsDegenerate( void ) const; // return true if this area is badly formed
  280. bool IsRoughlySquare( void ) const; // return true if this area is approximately square
  281. bool IsFlat( void ) const; // return true if this area is approximately flat
  282. bool HasNodes( void ) const;
  283. void GetNodes( NavDirType dir, CUtlVector< CNavNode * > *nodes ) const; // build a vector of nodes along the given direction
  284. CNavNode *FindClosestNode( const Vector &pos, NavDirType dir ) const; // returns the closest node along the given edge to the given point
  285. bool IsContiguous( const CNavArea *other ) const; // return true if the given area and 'other' share a colinear edge (ie: no drop-down or step/jump/climb)
  286. float ComputeAdjacentConnectionHeightChange( const CNavArea *destinationArea ) const; // return height change between edges of adjacent nav areas (not actual underlying ground)
  287. bool IsEdge( NavDirType dir ) const; // return true if there are no bi-directional links on the given side
  288. bool IsDamaging( void ) const; // Return true if continuous damage (ie: fire) is in this area
  289. void MarkAsDamaging( float duration ); // Mark this area is damaging for the next 'duration' seconds
  290. bool IsVisible( const Vector &eye, Vector *visSpot = NULL ) const; // return true if area is visible from the given eyepoint, return visible spot
  291. int GetAdjacentCount( NavDirType dir ) const { return m_connect[ dir ].Count(); } // return number of connected areas in given direction
  292. CNavArea *GetAdjacentArea( NavDirType dir, int i ) const; // return the i'th adjacent area in the given direction
  293. CNavArea *GetRandomAdjacentArea( NavDirType dir ) const;
  294. void CollectAdjacentAreas( CUtlVector< CNavArea * > *adjVector ) const; // build a vector of all adjacent areas
  295. const NavConnectVector *GetAdjacentAreas( NavDirType dir ) const { return &m_connect[dir]; }
  296. bool IsConnected( const CNavArea *area, NavDirType dir ) const; // return true if given area is connected in given direction
  297. bool IsConnected( const CNavLadder *ladder, CNavLadder::LadderDirectionType dir ) const; // return true if given ladder is connected in given direction
  298. float ComputeGroundHeightChange( const CNavArea *area ); // compute change in actual ground height from this area to given area
  299. const NavConnectVector *GetIncomingConnections( NavDirType dir ) const { return &m_incomingConnect[dir]; } // get areas connected TO this area by a ONE-WAY link (ie: we have no connection back to them)
  300. void AddIncomingConnection( CNavArea *source, NavDirType incomingEdgeDir );
  301. const NavLadderConnectVector *GetLadders( CNavLadder::LadderDirectionType dir ) const { return &m_ladder[dir]; }
  302. CFuncElevator *GetElevator( void ) const { Assert( !( m_attributeFlags & NAV_MESH_HAS_ELEVATOR ) == (m_elevator == NULL) ); return ( m_attributeFlags & NAV_MESH_HAS_ELEVATOR ) ? m_elevator : NULL; }
  303. const NavConnectVector &GetElevatorAreas( void ) const { return m_elevatorAreas; } // return collection of areas reachable via elevator from this area
  304. void ComputePortal( const CNavArea *to, NavDirType dir, Vector *center, float *halfWidth ) const; // compute portal to adjacent area
  305. NavDirType ComputeLargestPortal( const CNavArea *to, Vector *center, float *halfWidth ) const; // compute largest portal to adjacent area, returning direction
  306. void ComputeClosestPointInPortal( const CNavArea *to, NavDirType dir, const Vector &fromPos, Vector *closePos ) const; // compute closest point within the "portal" between to adjacent areas
  307. NavDirType ComputeDirection( Vector *point ) const; // return direction from this area to the given point
  308. //- for hunting algorithm ---------------------------------------------------------------------------
  309. void SetClearedTimestamp( int teamID ); // set this area's "clear" timestamp to now
  310. float GetClearedTimestamp( int teamID ) const; // get time this area was marked "clear"
  311. //- hiding spots ------------------------------------------------------------------------------------
  312. const HidingSpotVector *GetHidingSpots( void ) const { return &m_hidingSpots; }
  313. SpotEncounter *GetSpotEncounter( const CNavArea *from, const CNavArea *to ); // given the areas we are moving between, return the spots we will encounter
  314. int GetSpotEncounterCount( void ) const { return m_spotEncounters.Count(); }
  315. //- "danger" ----------------------------------------------------------------------------------------
  316. void IncreaseDanger( int teamID, float amount ); // increase the danger of this area for the given team
  317. float GetDanger( int teamID ); // return the danger of this area (decays over time)
  318. virtual float GetDangerDecayRate( void ) const; // return danger decay rate per second
  319. //- extents -----------------------------------------------------------------------------------------
  320. float GetSizeX( void ) const { return m_seCorner.x - m_nwCorner.x; }
  321. float GetSizeY( void ) const { return m_seCorner.y - m_nwCorner.y; }
  322. void GetExtent( Extent *extent ) const; // return a computed extent (XY is in m_nwCorner and m_seCorner, Z is computed)
  323. const Vector &GetCenter( void ) const { return m_center; }
  324. Vector GetRandomPoint( void ) const;
  325. Vector GetCorner( NavCornerType corner ) const;
  326. void SetCorner( NavCornerType corner, const Vector& newPosition );
  327. void ComputeNormal( Vector *normal, bool alternate = false ) const; // Computes the area's normal based on m_nwCorner. If 'alternate' is specified, m_seCorner is used instead.
  328. void RemoveOrthogonalConnections( NavDirType dir );
  329. //- occupy time ------------------------------------------------------------------------------------
  330. float GetEarliestOccupyTime( int teamID ) const; // returns the minimum time for someone of the given team to reach this spot from their spawn
  331. bool IsBattlefront( void ) const { return m_isBattlefront; } // true if this area is a "battlefront" - where rushing teams initially meet
  332. //- player counting --------------------------------------------------------------------------------
  333. void IncrementPlayerCount( int teamID, int entIndex ); // add one player to this area's count
  334. void DecrementPlayerCount( int teamID, int entIndex ); // subtract one player from this area's count
  335. unsigned char GetPlayerCount( int teamID = 0 ) const; // return number of players of given team currently within this area (team of zero means any/all)
  336. //- lighting ----------------------------------------------------------------------------------------
  337. float GetLightIntensity( const Vector &pos ) const; // returns a 0..1 light intensity for the given point
  338. float GetLightIntensity( float x, float y ) const; // returns a 0..1 light intensity for the given point
  339. float GetLightIntensity( void ) const; // returns a 0..1 light intensity averaged over the whole area
  340. //- A* pathfinding algorithm ------------------------------------------------------------------------
  341. static void MakeNewMarker( void ) { ++m_masterMarker; if (m_masterMarker == 0) m_masterMarker = 1; }
  342. void Mark( void ) { m_marker = m_masterMarker; }
  343. BOOL IsMarked( void ) const { return (m_marker == m_masterMarker) ? true : false; }
  344. void SetParent( CNavArea *parent, NavTraverseType how = NUM_TRAVERSE_TYPES ) { m_parent = parent; m_parentHow = how; }
  345. CNavArea *GetParent( void ) const { return m_parent; }
  346. NavTraverseType GetParentHow( void ) const { return m_parentHow; }
  347. bool IsOpen( void ) const; // true if on "open list"
  348. void AddToOpenList( void ); // add to open list in decreasing value order
  349. void AddToOpenListTail( void ); // add to tail of the open list
  350. void UpdateOnOpenList( void ); // a smaller value has been found, update this area on the open list
  351. void RemoveFromOpenList( void );
  352. static bool IsOpenListEmpty( void );
  353. static CNavArea *PopOpenList( void ); // remove and return the first element of the open list
  354. bool IsClosed( void ) const; // true if on "closed list"
  355. void AddToClosedList( void ); // add to the closed list
  356. void RemoveFromClosedList( void );
  357. static void ClearSearchLists( void ); // clears the open and closed lists for a new search
  358. void SetTotalCost( float value ) { DebuggerBreakOnNaN_StagingOnly( value ); Assert( value >= 0.0 && !IS_NAN(value) ); m_totalCost = value; }
  359. float GetTotalCost( void ) const { DebuggerBreakOnNaN_StagingOnly( m_totalCost ); return m_totalCost; }
  360. void SetCostSoFar( float value ) { DebuggerBreakOnNaN_StagingOnly( value ); Assert( value >= 0.0 && !IS_NAN(value) ); m_costSoFar = value; }
  361. float GetCostSoFar( void ) const { DebuggerBreakOnNaN_StagingOnly( m_costSoFar ); return m_costSoFar; }
  362. void SetPathLengthSoFar( float value ) { DebuggerBreakOnNaN_StagingOnly( value ); Assert( value >= 0.0 && !IS_NAN(value) ); m_pathLengthSoFar = value; }
  363. float GetPathLengthSoFar( void ) const { DebuggerBreakOnNaN_StagingOnly( m_pathLengthSoFar ); return m_pathLengthSoFar; }
  364. //- editing -----------------------------------------------------------------------------------------
  365. virtual void Draw( void ) const; // draw area for debugging & editing
  366. virtual void DrawFilled( int r, int g, int b, int a, float deltaT = 0.1f, bool noDepthTest = true, float margin = 5.0f ) const; // draw area as a filled rect of the given color
  367. virtual void DrawSelectedSet( const Vector &shift ) const; // draw this area as part of a selected set
  368. void DrawDragSelectionSet( Color &dragSelectionSetColor ) const;
  369. void DrawConnectedAreas( void ) const;
  370. void DrawHidingSpots( void ) const;
  371. bool SplitEdit( bool splitAlongX, float splitEdge, CNavArea **outAlpha = NULL, CNavArea **outBeta = NULL ); // split this area into two areas at the given edge
  372. bool MergeEdit( CNavArea *adj ); // merge this area and given adjacent area
  373. bool SpliceEdit( CNavArea *other ); // create a new area between this area and given area
  374. void RaiseCorner( NavCornerType corner, int amount, bool raiseAdjacentCorners = true ); // raise/lower a corner (or all corners if corner == NUM_CORNERS)
  375. void PlaceOnGround( NavCornerType corner, float inset = 0.0f ); // places a corner (or all corners if corner == NUM_CORNERS) on the ground
  376. NavCornerType GetCornerUnderCursor( void ) const;
  377. bool GetCornerHotspot( NavCornerType corner, Vector hotspot[NUM_CORNERS] ) const; // returns true if the corner is under the cursor
  378. void Shift( const Vector &shift ); // shift the nav area
  379. //- ladders -----------------------------------------------------------------------------------------
  380. void AddLadderUp( CNavLadder *ladder );
  381. void AddLadderDown( CNavLadder *ladder );
  382. //- generation and analysis -------------------------------------------------------------------------
  383. virtual void ComputeHidingSpots( void ); // analyze local area neighborhood to find "hiding spots" in this area - for map learning
  384. virtual void ComputeSniperSpots( void ); // analyze local area neighborhood to find "sniper spots" in this area - for map learning
  385. virtual void ComputeSpotEncounters( void ); // compute spot encounter data - for map learning
  386. virtual void ComputeEarliestOccupyTimes( void );
  387. virtual void CustomAnalysis( bool isIncremental = false ) { } // for game-specific analysis
  388. virtual bool ComputeLighting( void ); // compute 0..1 light intensity at corners and center (requires client via listenserver)
  389. bool TestStairs( void ); // Test an area for being on stairs
  390. virtual bool IsAbleToMergeWith( CNavArea *other ) const;
  391. virtual void InheritAttributes( CNavArea *first, CNavArea *second = NULL );
  392. //- visibility -------------------------------------------------------------------------------------
  393. enum VisibilityType
  394. {
  395. NOT_VISIBLE = 0x00,
  396. POTENTIALLY_VISIBLE = 0x01,
  397. COMPLETELY_VISIBLE = 0x02,
  398. };
  399. VisibilityType ComputeVisibility( const CNavArea *area, bool isPVSValid, bool bCheckPVS = true, bool *pOutsidePVS = NULL ) const; // do actual line-of-sight traces to determine if any part of given area is visible from this area
  400. void SetupPVS( void ) const;
  401. bool IsInPVS( void ) const; // return true if this area is within the current PVS
  402. struct AreaBindInfo // for pointer loading and binding
  403. {
  404. union
  405. {
  406. CNavArea *area;
  407. unsigned int id;
  408. };
  409. unsigned char attributes; // VisibilityType
  410. bool operator==( const AreaBindInfo &other ) const
  411. {
  412. return ( area == other.area );
  413. }
  414. };
  415. virtual bool IsEntirelyVisible( const Vector &eye, const CBaseEntity *ignore = NULL ) const; // return true if entire area is visible from given eyepoint (CPU intensive)
  416. virtual bool IsPartiallyVisible( const Vector &eye, const CBaseEntity *ignore = NULL ) const; // return true if any portion of the area is visible from given eyepoint (CPU intensive)
  417. virtual bool IsPotentiallyVisible( const CNavArea *area ) const; // return true if given area is potentially visible from somewhere in this area (very fast)
  418. virtual bool IsPotentiallyVisibleToTeam( int team ) const; // return true if any portion of this area is visible to anyone on the given team (very fast)
  419. virtual bool IsCompletelyVisible( const CNavArea *area ) const; // return true if given area is completely visible from somewhere in this area (very fast)
  420. virtual bool IsCompletelyVisibleToTeam( int team ) const; // return true if given area is completely visible from somewhere in this area by someone on the team (very fast)
  421. //-------------------------------------------------------------------------------------
  422. /**
  423. * Apply the functor to all navigation areas that are potentially
  424. * visible from this area.
  425. */
  426. template < typename Functor >
  427. bool ForAllPotentiallyVisibleAreas( Functor &func )
  428. {
  429. int i;
  430. ++s_nCurrVisTestCounter;
  431. for ( i=0; i<m_potentiallyVisibleAreas.Count(); ++i )
  432. {
  433. CNavArea *area = m_potentiallyVisibleAreas[i].area;
  434. if ( !area )
  435. continue;
  436. // If this assertion triggers, an area is in here twice!
  437. Assert( area->m_nVisTestCounter != s_nCurrVisTestCounter );
  438. area->m_nVisTestCounter = s_nCurrVisTestCounter;
  439. if ( m_potentiallyVisibleAreas[i].attributes == NOT_VISIBLE )
  440. continue;
  441. if ( func( area ) == false )
  442. return false;
  443. }
  444. // for each inherited area
  445. if ( !m_inheritVisibilityFrom.area )
  446. return true;
  447. CAreaBindInfoArray &inherited = m_inheritVisibilityFrom.area->m_potentiallyVisibleAreas;
  448. for ( i=0; i<inherited.Count(); ++i )
  449. {
  450. if ( !inherited[i].area )
  451. continue;
  452. // We may have visited this from m_potentiallyVisibleAreas
  453. if ( inherited[i].area->m_nVisTestCounter == s_nCurrVisTestCounter )
  454. continue;
  455. // Theoretically, this shouldn't matter. But, just in case!
  456. inherited[i].area->m_nVisTestCounter = s_nCurrVisTestCounter;
  457. if ( inherited[i].attributes == NOT_VISIBLE )
  458. continue;
  459. if ( func( inherited[i].area ) == false )
  460. return false;
  461. }
  462. return true;
  463. }
  464. //-------------------------------------------------------------------------------------
  465. /**
  466. * Apply the functor to all navigation areas that are
  467. * completely visible from somewhere in this area.
  468. */
  469. template < typename Functor >
  470. bool ForAllCompletelyVisibleAreas( Functor &func )
  471. {
  472. int i;
  473. ++s_nCurrVisTestCounter;
  474. for ( i=0; i<m_potentiallyVisibleAreas.Count(); ++i )
  475. {
  476. CNavArea *area = m_potentiallyVisibleAreas[i].area;
  477. if ( !area )
  478. continue;
  479. // If this assertion triggers, an area is in here twice!
  480. Assert( area->m_nVisTestCounter != s_nCurrVisTestCounter );
  481. area->m_nVisTestCounter = s_nCurrVisTestCounter;
  482. if ( ( m_potentiallyVisibleAreas[i].attributes & COMPLETELY_VISIBLE ) == 0 )
  483. continue;
  484. if ( func( area ) == false )
  485. return false;
  486. }
  487. if ( !m_inheritVisibilityFrom.area )
  488. return true;
  489. // for each inherited area
  490. CAreaBindInfoArray &inherited = m_inheritVisibilityFrom.area->m_potentiallyVisibleAreas;
  491. for ( i=0; i<inherited.Count(); ++i )
  492. {
  493. if ( !inherited[i].area )
  494. continue;
  495. // We may have visited this from m_potentiallyVisibleAreas
  496. if ( inherited[i].area->m_nVisTestCounter == s_nCurrVisTestCounter )
  497. continue;
  498. // Theoretically, this shouldn't matter. But, just in case!
  499. inherited[i].area->m_nVisTestCounter = s_nCurrVisTestCounter;
  500. if ( ( inherited[i].attributes & COMPLETELY_VISIBLE ) == 0 )
  501. continue;
  502. if ( func( inherited[i].area ) == false )
  503. return false;
  504. }
  505. return true;
  506. }
  507. private:
  508. friend class CNavMesh;
  509. friend class CNavLadder;
  510. friend class CCSNavArea; // allow CS load code to complete replace our default load behavior
  511. static bool m_isReset; // if true, don't bother cleaning up in destructor since everything is going away
  512. /*
  513. m_nwCorner
  514. nw ne
  515. +-----------+
  516. | +-->x |
  517. | | |
  518. | v |
  519. | y |
  520. | |
  521. +-----------+
  522. sw se
  523. m_seCorner
  524. */
  525. static unsigned int m_nextID; // used to allocate unique IDs
  526. unsigned int m_id; // unique area ID
  527. unsigned int m_debugid;
  528. Place m_place; // place descriptor
  529. CountdownTimer m_blockedTimer; // Throttle checks on our blocked state while blocked
  530. void UpdateBlockedFromNavBlockers( void ); // checks if nav blockers are still blocking the area
  531. bool m_isUnderwater; // true if the center of the area is underwater
  532. bool m_isBattlefront;
  533. float m_avoidanceObstacleHeight; // if nonzero, a prop is obstructing movement through this nav area
  534. CountdownTimer m_avoidanceObstacleTimer; // Throttle checks on our obstructed state while obstructed
  535. //- for hunting -------------------------------------------------------------------------------------
  536. float m_clearedTimestamp[ MAX_NAV_TEAMS ]; // time this area was last "cleared" of enemies
  537. //- "danger" ----------------------------------------------------------------------------------------
  538. float m_danger[ MAX_NAV_TEAMS ]; // danger of this area, allowing bots to avoid areas where they died in the past - zero is no danger
  539. float m_dangerTimestamp[ MAX_NAV_TEAMS ]; // time when danger value was set - used for decaying
  540. void DecayDanger( void );
  541. //- hiding spots ------------------------------------------------------------------------------------
  542. HidingSpotVector m_hidingSpots;
  543. bool IsHidingSpotCollision( const Vector &pos ) const; // returns true if an existing hiding spot is too close to given position
  544. //- encounter spots ---------------------------------------------------------------------------------
  545. SpotEncounterVector m_spotEncounters; // list of possible ways to move thru this area, and the spots to look at as we do
  546. void AddSpotEncounters( const CNavArea *from, NavDirType fromDir, const CNavArea *to, NavDirType toDir ); // add spot encounter data when moving from area to area
  547. float m_earliestOccupyTime[ MAX_NAV_TEAMS ]; // min time to reach this spot from spawn
  548. #ifdef DEBUG_AREA_PLAYERCOUNTS
  549. CUtlVector< int > m_playerEntIndices[ MAX_NAV_TEAMS ];
  550. #endif
  551. //- lighting ----------------------------------------------------------------------------------------
  552. float m_lightIntensity[ NUM_CORNERS ]; // 0..1 light intensity at corners
  553. //- A* pathfinding algorithm ------------------------------------------------------------------------
  554. static unsigned int m_masterMarker;
  555. static CNavArea *m_openList;
  556. static CNavArea *m_openListTail;
  557. //- connections to adjacent areas -------------------------------------------------------------------
  558. NavConnectVector m_incomingConnect[ NUM_DIRECTIONS ]; // a list of adjacent areas for each direction that connect TO us, but we have no connection back to them
  559. //---------------------------------------------------------------------------------------------------
  560. CNavNode *m_node[ NUM_CORNERS ]; // nav nodes at each corner of the area
  561. void ResetNodes( void ); // nodes are going away as part of an incremental nav generation
  562. void Strip( void ); // remove "analyzed" data from nav area
  563. void FinishMerge( CNavArea *adjArea ); // recompute internal data once nodes have been adjusted during merge
  564. void MergeAdjacentConnections( CNavArea *adjArea ); // for merging with "adjArea" - pick up all of "adjArea"s connections
  565. void AssignNodes( CNavArea *area ); // assign internal nodes to the given area
  566. void FinishSplitEdit( CNavArea *newArea, NavDirType ignoreEdge ); // given the portion of the original area, update its internal data
  567. void CalcDebugID();
  568. #ifdef NEXT_BOT
  569. CUtlVector< CHandle< CFuncNavPrerequisite > > m_prerequisiteVector; // list of prerequisites that must be met before this area can be traversed
  570. #endif
  571. CNavArea *m_prevHash, *m_nextHash; // for hash table in CNavMesh
  572. void ConnectElevators( void ); // find elevator connections between areas
  573. int m_damagingTickCount; // this area is damaging through this tick count
  574. //- visibility --------------------------------------------------------------------------------------
  575. void ComputeVisibilityToMesh( void ); // compute visibility to surrounding mesh
  576. void ResetPotentiallyVisibleAreas();
  577. static void ComputeVisToArea( CNavArea *&pOtherArea );
  578. #ifndef _X360
  579. typedef CUtlVectorConservative<AreaBindInfo> CAreaBindInfoArray; // shaves 8 bytes off structure caused by need to support editing
  580. #else
  581. typedef CUtlVector<AreaBindInfo> CAreaBindInfoArray; // Need to use this on 360 to support external allocation pattern
  582. #endif
  583. AreaBindInfo m_inheritVisibilityFrom; // if non-NULL, m_potentiallyVisibleAreas becomes a list of additions and deletions (NOT_VISIBLE) to the list of this area
  584. CAreaBindInfoArray m_potentiallyVisibleAreas; // list of areas potentially visible from inside this area (after PostLoad(), use area portion of union)
  585. bool m_isInheritedFrom; // latch used during visibility inheritance computation
  586. const CAreaBindInfoArray &ComputeVisibilityDelta( const CNavArea *other ) const; // return a list of the delta between our visibility list and the given adjacent area
  587. uint32 m_nVisTestCounter;
  588. static uint32 s_nCurrVisTestCounter;
  589. CUtlVector< CHandle< CFuncNavCost > > m_funcNavCostVector; // active, overlapping cost entities
  590. };
  591. typedef CUtlVector< CNavArea * > NavAreaVector;
  592. extern NavAreaVector TheNavAreas;
  593. //--------------------------------------------------------------------------------------------------------------
  594. //--------------------------------------------------------------------------------------------------------------
  595. //
  596. // Inlines
  597. //
  598. #ifdef NEXT_BOT
  599. //--------------------------------------------------------------------------------------------------------------
  600. inline bool CNavArea::HasPrerequisite( CBaseCombatCharacter *actor ) const
  601. {
  602. return m_prerequisiteVector.Count() > 0;
  603. }
  604. //--------------------------------------------------------------------------------------------------------------
  605. inline const CUtlVector< CHandle< CFuncNavPrerequisite > > &CNavArea::GetPrerequisiteVector( void ) const
  606. {
  607. return m_prerequisiteVector;
  608. }
  609. //--------------------------------------------------------------------------------------------------------------
  610. inline void CNavArea::RemoveAllPrerequisites( void )
  611. {
  612. m_prerequisiteVector.RemoveAll();
  613. }
  614. //--------------------------------------------------------------------------------------------------------------
  615. inline void CNavArea::AddPrerequisite( CFuncNavPrerequisite *prereq )
  616. {
  617. if ( m_prerequisiteVector.Find( prereq ) == m_prerequisiteVector.InvalidIndex() )
  618. {
  619. m_prerequisiteVector.AddToTail( prereq );
  620. }
  621. }
  622. #endif
  623. //--------------------------------------------------------------------------------------------------------------
  624. inline float CNavArea::GetDangerDecayRate( void ) const
  625. {
  626. // one kill == 1.0, which we will forget about in two minutes
  627. return 1.0f / 120.0f;
  628. }
  629. //--------------------------------------------------------------------------------------------------------------
  630. inline bool CNavArea::IsDegenerate( void ) const
  631. {
  632. return (m_nwCorner.x >= m_seCorner.x || m_nwCorner.y >= m_seCorner.y);
  633. }
  634. //--------------------------------------------------------------------------------------------------------------
  635. inline CNavArea *CNavArea::GetAdjacentArea( NavDirType dir, int i ) const
  636. {
  637. if ( ( i < 0 ) || ( i >= m_connect[dir].Count() ) )
  638. return NULL;
  639. return m_connect[dir][i].area;
  640. }
  641. //--------------------------------------------------------------------------------------------------------------
  642. inline bool CNavArea::IsOpen( void ) const
  643. {
  644. return (m_openMarker == m_masterMarker) ? true : false;
  645. }
  646. //--------------------------------------------------------------------------------------------------------------
  647. inline bool CNavArea::IsOpenListEmpty( void )
  648. {
  649. Assert( (m_openList && m_openList->m_prevOpen == NULL) || m_openList == NULL );
  650. return (m_openList) ? false : true;
  651. }
  652. //--------------------------------------------------------------------------------------------------------------
  653. inline CNavArea *CNavArea::PopOpenList( void )
  654. {
  655. Assert( (m_openList && m_openList->m_prevOpen == NULL) || m_openList == NULL );
  656. if ( m_openList )
  657. {
  658. CNavArea *area = m_openList;
  659. // disconnect from list
  660. area->RemoveFromOpenList();
  661. area->m_prevOpen = NULL;
  662. area->m_nextOpen = NULL;
  663. Assert( (m_openList && m_openList->m_prevOpen == NULL) || m_openList == NULL );
  664. return area;
  665. }
  666. Assert( (m_openList && m_openList->m_prevOpen == NULL) || m_openList == NULL );
  667. return NULL;
  668. }
  669. //--------------------------------------------------------------------------------------------------------------
  670. inline bool CNavArea::IsClosed( void ) const
  671. {
  672. if (IsMarked() && !IsOpen())
  673. return true;
  674. return false;
  675. }
  676. //--------------------------------------------------------------------------------------------------------------
  677. inline void CNavArea::AddToClosedList( void )
  678. {
  679. Mark();
  680. }
  681. //--------------------------------------------------------------------------------------------------------------
  682. inline void CNavArea::RemoveFromClosedList( void )
  683. {
  684. // since "closed" is defined as visited (marked) and not on open list, do nothing
  685. }
  686. //--------------------------------------------------------------------------------------------------------------
  687. inline void CNavArea::SetClearedTimestamp( int teamID )
  688. {
  689. m_clearedTimestamp[ teamID % MAX_NAV_TEAMS ] = gpGlobals->curtime;
  690. }
  691. //--------------------------------------------------------------------------------------------------------------
  692. inline float CNavArea::GetClearedTimestamp( int teamID ) const
  693. {
  694. return m_clearedTimestamp[ teamID % MAX_NAV_TEAMS ];
  695. }
  696. //--------------------------------------------------------------------------------------------------------------
  697. inline float CNavArea::GetEarliestOccupyTime( int teamID ) const
  698. {
  699. return m_earliestOccupyTime[ teamID % MAX_NAV_TEAMS ];
  700. }
  701. //--------------------------------------------------------------------------------------------------------------
  702. inline bool CNavArea::IsDamaging( void ) const
  703. {
  704. return ( gpGlobals->tickcount <= m_damagingTickCount );
  705. }
  706. //--------------------------------------------------------------------------------------------------------------
  707. inline void CNavArea::MarkAsDamaging( float duration )
  708. {
  709. m_damagingTickCount = gpGlobals->tickcount + TIME_TO_TICKS( duration );
  710. }
  711. //--------------------------------------------------------------------------------------------------------------
  712. inline bool CNavArea::HasAvoidanceObstacle( float maxObstructionHeight ) const
  713. {
  714. return m_avoidanceObstacleHeight > maxObstructionHeight;
  715. }
  716. //--------------------------------------------------------------------------------------------------------------
  717. inline float CNavArea::GetAvoidanceObstacleHeight( void ) const
  718. {
  719. return m_avoidanceObstacleHeight;
  720. }
  721. //--------------------------------------------------------------------------------------------------------------
  722. inline bool CNavArea::IsVisible( const Vector &eye, Vector *visSpot ) const
  723. {
  724. Vector corner;
  725. trace_t result;
  726. CTraceFilterNoNPCsOrPlayer traceFilter( NULL, COLLISION_GROUP_NONE );
  727. const float offset = 0.75f * HumanHeight;
  728. // check center first
  729. UTIL_TraceLine( eye, GetCenter() + Vector( 0, 0, offset ), MASK_BLOCKLOS_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE, &traceFilter, &result );
  730. if (result.fraction == 1.0f)
  731. {
  732. // we can see this area
  733. if (visSpot)
  734. {
  735. *visSpot = GetCenter();
  736. }
  737. return true;
  738. }
  739. for( int c=0; c<NUM_CORNERS; ++c )
  740. {
  741. corner = GetCorner( (NavCornerType)c );
  742. UTIL_TraceLine( eye, corner + Vector( 0, 0, offset ), MASK_BLOCKLOS_AND_NPCS|CONTENTS_IGNORE_NODRAW_OPAQUE, &traceFilter, &result );
  743. if (result.fraction == 1.0f)
  744. {
  745. // we can see this area
  746. if (visSpot)
  747. {
  748. *visSpot = corner;
  749. }
  750. return true;
  751. }
  752. }
  753. return false;
  754. }
  755. #ifndef DEBUG_AREA_PLAYERCOUNTS
  756. inline void CNavArea::IncrementPlayerCount( int teamID, int entIndex )
  757. {
  758. teamID = teamID % MAX_NAV_TEAMS;
  759. if (m_playerCount[ teamID ] == 255)
  760. {
  761. DevMsg( "CNavArea::IncrementPlayerCount: Overflow\n" );
  762. return;
  763. }
  764. ++m_playerCount[ teamID ];
  765. }
  766. inline void CNavArea::DecrementPlayerCount( int teamID, int entIndex )
  767. {
  768. teamID = teamID % MAX_NAV_TEAMS;
  769. if (m_playerCount[ teamID ] == 0)
  770. {
  771. DevMsg( "CNavArea::IncrementPlayerCount: Underflow\n" );
  772. return;
  773. }
  774. --m_playerCount[ teamID ];
  775. }
  776. #endif // !DEBUG_AREA_PLAYERCOUNTS
  777. inline unsigned char CNavArea::GetPlayerCount( int teamID ) const
  778. {
  779. if (teamID)
  780. {
  781. return m_playerCount[ teamID % MAX_NAV_TEAMS ];
  782. }
  783. // sum all players
  784. unsigned char total = 0;
  785. for( int i=0; i<MAX_NAV_TEAMS; ++i )
  786. {
  787. total += m_playerCount[i];
  788. }
  789. return total;
  790. }
  791. //--------------------------------------------------------------------------------------------------------------
  792. /**
  793. * Return Z of area at (x,y) of 'pos'
  794. * Trilinear interpolation of Z values at quad edges.
  795. * NOTE: pos->z is not used.
  796. */
  797. inline float CNavArea::GetZ( const Vector * RESTRICT pos ) const RESTRICT
  798. {
  799. return GetZ( pos->x, pos->y );
  800. }
  801. inline float CNavArea::GetZ( const Vector & pos ) const RESTRICT
  802. {
  803. return GetZ( pos.x, pos.y );
  804. }
  805. //--------------------------------------------------------------------------------------------------------------
  806. /**
  807. * Return the coordinates of the area's corner.
  808. */
  809. inline Vector CNavArea::GetCorner( NavCornerType corner ) const
  810. {
  811. // @TODO: Confirm compiler does the "right thing" in release builds, or change this function to to take a pointer [2/4/2009 tom]
  812. Vector pos;
  813. switch( corner )
  814. {
  815. default:
  816. Assert( false && "GetCorner: Invalid type" );
  817. case NORTH_WEST:
  818. return m_nwCorner;
  819. case NORTH_EAST:
  820. pos.x = m_seCorner.x;
  821. pos.y = m_nwCorner.y;
  822. pos.z = m_neZ;
  823. return pos;
  824. case SOUTH_WEST:
  825. pos.x = m_nwCorner.x;
  826. pos.y = m_seCorner.y;
  827. pos.z = m_swZ;
  828. return pos;
  829. case SOUTH_EAST:
  830. return m_seCorner;
  831. }
  832. }
  833. #endif // _NAV_AREA_H_