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.

297 lines
7.3 KiB

  1. /**
  2. * EntityUtil.h
  3. * Various utility functions
  4. */
  5. #ifndef _ENTITY_UTIL_H_
  6. #define _ENTITY_UTIL_H_
  7. //------------------------------------------------------------------------------------------
  8. enum WhoType
  9. {
  10. ANYONE,
  11. ONLY_FRIENDS,
  12. ONLY_ENEMIES
  13. };
  14. //--------------------------------------------------------------------------------------------------------------
  15. /**
  16. * Iterate over all entities in the game, invoking functor on each.
  17. * If functor returns false, stop iteration and return false.
  18. */
  19. template < typename Functor >
  20. bool ForEachEntity( Functor &func )
  21. {
  22. CBaseEntity *entity = gEntList.FirstEnt();
  23. while ( entity )
  24. {
  25. if ( func( entity ) == false )
  26. return false;
  27. entity = gEntList.NextEnt( entity );
  28. }
  29. return true;
  30. }
  31. //--------------------------------------------------------------------------------------------------------------
  32. //--------------------------------------------------------------------------------------------------------------
  33. #ifdef GAME_DLL
  34. class FindInViewConeFunctor
  35. {
  36. public:
  37. FindInViewConeFunctor( CBasePlayer *me, WhoType who, float tolerance, CBaseEntity *ignore = NULL )
  38. {
  39. m_me = me;
  40. m_who = who;
  41. m_tolerance = tolerance;
  42. m_target = NULL;
  43. m_range = 9999999.9f;
  44. m_ignore = ignore;
  45. me->EyeVectors(&m_dir, NULL, NULL);
  46. m_origin = me->GetAbsOrigin() + me->GetViewOffset();
  47. }
  48. bool operator() ( CBasePlayer *player )
  49. {
  50. if (player != m_me && player != m_ignore && player->IsAlive())
  51. {
  52. if (m_who == ONLY_FRIENDS && m_me->GetTeamNumber() != player->GetTeamNumber() )
  53. return true;
  54. if (m_who == ONLY_ENEMIES && m_me->GetTeamNumber() == player->GetTeamNumber() )
  55. return true;
  56. Vector to = player->WorldSpaceCenter() - m_origin;
  57. float range = to.NormalizeInPlace();
  58. if (DotProduct( to, m_dir ) > m_tolerance && range < m_range)
  59. {
  60. if ( m_me->IsLineOfSightClear( player ) )
  61. {
  62. m_target = player;
  63. m_range = range;
  64. }
  65. }
  66. }
  67. return true;
  68. }
  69. CBasePlayer *m_me;
  70. WhoType m_who;
  71. float m_tolerance;
  72. CBaseEntity *m_ignore;
  73. Vector m_origin;
  74. Vector m_dir;
  75. CBasePlayer *m_target;
  76. float m_range;
  77. };
  78. /**
  79. * Find the closest player within the given view cone
  80. */
  81. inline CBasePlayer *GetClosestPlayerInViewCone( CBasePlayer *me, WhoType who, float tolerance = 0.95f, float *range = NULL, CBaseEntity *ignore = NULL )
  82. {
  83. // choke the victim we are pointing at
  84. FindInViewConeFunctor checkCone( me, who, tolerance, ignore );
  85. ForEachPlayer( checkCone );
  86. if (range)
  87. *range = checkCone.m_range;
  88. return checkCone.m_target;
  89. }
  90. #endif
  91. //--------------------------------------------------------------------------------------------------------------
  92. /**
  93. * Find player closest to ray.
  94. * Return perpendicular distance to ray in 'offset' if it is non-NULL.
  95. */
  96. extern CBasePlayer *GetPlayerClosestToRay( CBasePlayer *me, WhoType who, const Vector &start, const Vector &end, float *offset = NULL );
  97. //--------------------------------------------------------------------------------------------------------------
  98. /**
  99. * Compute the closest point on the ray to 'pos' and return it in 'pointOnRay'.
  100. * If point projects beyond the ends of the ray, return false - but clamp 'pointOnRay' to the correct endpoint.
  101. */
  102. inline bool ClosestPointOnRay( const Vector &pos, const Vector &rayStart, const Vector &rayEnd, Vector *pointOnRay )
  103. {
  104. Vector to = pos - rayStart;
  105. Vector dir = rayEnd - rayStart;
  106. float length = dir.NormalizeInPlace();
  107. float rangeAlong = DotProduct( dir, to );
  108. if (rangeAlong < 0.0f)
  109. {
  110. // off start point
  111. *pointOnRay = rayStart;
  112. return false;
  113. }
  114. else if (rangeAlong > length)
  115. {
  116. // off end point
  117. *pointOnRay = rayEnd;
  118. return false;
  119. }
  120. else // within ray bounds
  121. {
  122. Vector onRay = rayStart + rangeAlong * dir;
  123. *pointOnRay = onRay;
  124. return true;
  125. }
  126. }
  127. //------------------------------------------------------------------------------------------
  128. /**
  129. * Functor to find the player closest to a ray.
  130. * For use with ForEachPlayerNearRay().
  131. */
  132. class ClosestToRayFunctor
  133. {
  134. public:
  135. ClosestToRayFunctor( CBasePlayer *ignore, WhoType who = ANYONE )
  136. {
  137. m_ignore = ignore;
  138. m_who = who;
  139. m_closestPlayer = NULL;
  140. m_closestPlayerRange = 999999999.9f;
  141. }
  142. bool operator() ( CBasePlayer *player, float rangeToRay )
  143. {
  144. if (player == m_ignore)
  145. return true;
  146. if (!player->IsAlive())
  147. return true;
  148. if (m_who == ONLY_FRIENDS && m_ignore->GetTeamNumber() != player->GetTeamNumber() )
  149. return true;
  150. if (m_who == ONLY_ENEMIES && m_ignore->GetTeamNumber() == player->GetTeamNumber() )
  151. return true;
  152. // keep the player closest to the ray
  153. if (rangeToRay < m_closestPlayerRange)
  154. {
  155. m_closestPlayerRange = rangeToRay;
  156. m_closestPlayer = player;
  157. }
  158. return true;
  159. }
  160. CBasePlayer *m_ignore;
  161. WhoType m_who;
  162. CBasePlayer *m_closestPlayer;
  163. float m_closestPlayerRange;
  164. };
  165. //--------------------------------------------------------------------------------------------------------------
  166. /**
  167. * Iterate over all players that are within range of the ray and invoke functor.
  168. * If functor returns false, stop iteration and return false.
  169. * @todo Check LOS to ray.
  170. */
  171. template < typename Functor >
  172. bool ForEachPlayerNearRay( Functor &func, const Vector &start, const Vector &end, float maxRadius )
  173. {
  174. for( int i=1; i<=gpGlobals->maxClients; ++i )
  175. {
  176. CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
  177. if (player == NULL)
  178. continue;
  179. if (FNullEnt( player->edict() ))
  180. continue;
  181. if (!player->IsPlayer())
  182. continue;
  183. if (!player->IsAlive())
  184. continue;
  185. float range = DistanceToRay( player->WorldSpaceCenter(), start, end );
  186. if (range < 0.0f || range > maxRadius)
  187. continue;
  188. if (func( player, range ) == false)
  189. return false;
  190. }
  191. return true;
  192. }
  193. //--------------------------------------------------------------------------------------------------------------
  194. /**
  195. * Iterate over all players that are within range of the sphere and invoke functor.
  196. * If functor returns false, stop iteration and return false.
  197. * @todo Check LOS to ray.
  198. */
  199. template < typename Functor >
  200. bool ForEachPlayerNearSphere( Functor &func, const Vector &origin, float radius )
  201. {
  202. for( int i=1; i<=gpGlobals->maxClients; ++i )
  203. {
  204. CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
  205. if (player == NULL)
  206. continue;
  207. if (FNullEnt( player->edict() ))
  208. continue;
  209. if (!player->IsPlayer())
  210. continue;
  211. if (!player->IsAlive())
  212. continue;
  213. Vector to = player->WorldSpaceCenter() - origin;
  214. float range = to.Length();
  215. if (range > radius)
  216. continue;
  217. if (func( player, range ) == false)
  218. return false;
  219. }
  220. return true;
  221. }
  222. //--------------------------------------------------------------------------------------------------------------
  223. /**
  224. * Reflect a vector.
  225. * Assumes 'unitNormal' is normalized.
  226. */
  227. inline Vector VectorReflect( const Vector &in, const Vector &unitNormal )
  228. {
  229. // compute the unit vector out of the plane of 'in' and 'unitNormal'
  230. Vector lat = CrossProduct( in, unitNormal );
  231. Vector forward = CrossProduct( unitNormal, lat );
  232. forward.NormalizeInPlace();
  233. Vector forwardComponent = forward * DotProduct( in, forward );
  234. Vector normalComponent = unitNormal * DotProduct( in, unitNormal );
  235. return forwardComponent - normalComponent;
  236. }
  237. #endif // _ENTITY_UTIL_H_