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.

450 lines
9.4 KiB

  1. // FunctorUtils.h
  2. // Useful functors
  3. //========= Copyright Valve Corporation, All rights reserved. ============//
  4. #ifndef _FUNCTOR_UTILS_H_
  5. #define _FUNCTOR_UTILS_H_
  6. #ifdef NEXT_BOT
  7. #include "NextBotInterface.h"
  8. #include "NextBotManager.h"
  9. #endif // NEXT_BOT
  10. //--------------------------------------------------------------------------------------------------------
  11. /**
  12. * NOTE: The functors in this file should ideally be game-independent,
  13. * and work for any Source based game
  14. */
  15. //--------------------------------------------------------------------------------------------------------
  16. //--------------------------------------------------------------------------------------------------------
  17. /**
  18. * Count the number of living players on a given team (or TEAM_ANY)
  19. */
  20. class LivePlayerCounter
  21. {
  22. public:
  23. static const bool EXCLUDE_BOTS = false;
  24. LivePlayerCounter( int team, bool includeBots = true )
  25. {
  26. m_team = team;
  27. m_includeBots = includeBots;
  28. m_count = 0;
  29. }
  30. bool operator() ( CBasePlayer *player )
  31. {
  32. if (player->IsAlive() && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team))
  33. {
  34. if (m_includeBots || !player->IsBot())
  35. {
  36. ++m_count;
  37. }
  38. }
  39. return true;
  40. }
  41. int GetCount( void ) const
  42. {
  43. return m_count;
  44. }
  45. int m_team;
  46. bool m_includeBots;
  47. int m_count;
  48. };
  49. //--------------------------------------------------------------------------------------------------------
  50. /**
  51. * Count the number of dead players on a given team (or TEAM_ANY)
  52. */
  53. class DeadPlayerCounter
  54. {
  55. public:
  56. static const bool EXCLUDE_BOTS = false;
  57. DeadPlayerCounter( int team, bool includeBots = true )
  58. {
  59. m_team = team;
  60. m_includeBots = includeBots;
  61. m_count = 0;
  62. }
  63. bool operator() ( CBasePlayer *player )
  64. {
  65. if (!player->IsAlive() && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team))
  66. {
  67. if (m_includeBots || !player->IsBot())
  68. {
  69. ++m_count;
  70. }
  71. }
  72. return true;
  73. }
  74. int GetCount( void ) const
  75. {
  76. return m_count;
  77. }
  78. int m_team;
  79. bool m_includeBots;
  80. int m_count;
  81. };
  82. //--------------------------------------------------------------------------------------------------------
  83. /**
  84. * Count the number of players on a given team (or TEAM_ANY)
  85. */
  86. class PlayerCounter
  87. {
  88. public:
  89. static const bool EXCLUDE_BOTS = false;
  90. PlayerCounter( int team, int lifeState = -1, bool includeBots = true )
  91. {
  92. m_team = team;
  93. m_includeBots = includeBots;
  94. m_count = 0;
  95. m_lifeState = lifeState;
  96. }
  97. bool operator() ( CBasePlayer *player )
  98. {
  99. if ((player->m_lifeState == m_lifeState || m_lifeState == -1) && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team))
  100. {
  101. if (m_includeBots || !player->IsBot())
  102. {
  103. ++m_count;
  104. }
  105. }
  106. return true;
  107. }
  108. int GetCount( void ) const
  109. {
  110. return m_count;
  111. }
  112. int m_lifeState;
  113. int m_team;
  114. bool m_includeBots;
  115. int m_count;
  116. };
  117. //--------------------------------------------------------------------------------------------------------
  118. /**
  119. * Return the closest living player on the given team (or TEAM_ANY)
  120. */
  121. class ClosestPlayerScan
  122. {
  123. public:
  124. static const bool EXCLUDE_BOTS = false;
  125. ClosestPlayerScan( const Vector &spot, int team, float maxRange = 0.0f, CBasePlayer *ignore = NULL, bool includeBots = true )
  126. {
  127. m_spot = spot;
  128. m_team = team;
  129. m_includeBots = includeBots;
  130. m_close = NULL;
  131. if ( maxRange > 0.0f )
  132. {
  133. m_closeRangeSq = maxRange * maxRange;
  134. }
  135. else
  136. {
  137. m_closeRangeSq = 999999999.9f;
  138. }
  139. m_ignore = ignore;
  140. }
  141. bool operator() ( CBasePlayer *player )
  142. {
  143. if (player == m_ignore)
  144. return true;
  145. if (player->IsAlive() && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team))
  146. {
  147. if ( !m_includeBots && player->IsBot() )
  148. return true;
  149. Vector to = player->WorldSpaceCenter() - m_spot;
  150. float rangeSq = to.LengthSqr();
  151. if (rangeSq < m_closeRangeSq)
  152. {
  153. m_closeRangeSq = rangeSq;
  154. m_close = player;
  155. }
  156. }
  157. return true;
  158. }
  159. CBasePlayer *GetPlayer( void ) const
  160. {
  161. return m_close;
  162. }
  163. bool IsCloserThan( float range )
  164. {
  165. return (m_closeRangeSq < (range * range));
  166. }
  167. bool IsFartherThan( float range )
  168. {
  169. return (m_closeRangeSq > (range * range));
  170. }
  171. Vector m_spot;
  172. int m_team;
  173. bool m_includeBots;
  174. CBasePlayer *m_close;
  175. float m_closeRangeSq;
  176. CBasePlayer *m_ignore;
  177. };
  178. //--------------------------------------------------------------------------------------------------------
  179. /**
  180. * Return the closest living BaseCombatCharacter on the given team (or TEAM_ANY)
  181. */
  182. class ClosestActorScan
  183. {
  184. public:
  185. ClosestActorScan( const Vector &spot, int team, float maxRange = 0.0f, CBaseCombatCharacter *ignore = NULL )
  186. {
  187. m_spot = spot;
  188. m_team = team;
  189. m_close = NULL;
  190. if ( maxRange > 0.0f )
  191. {
  192. m_closeRangeSq = maxRange * maxRange;
  193. }
  194. else
  195. {
  196. m_closeRangeSq = 999999999.9f;
  197. }
  198. m_ignore = ignore;
  199. }
  200. bool operator() ( CBaseCombatCharacter *actor )
  201. {
  202. if (actor == m_ignore)
  203. return true;
  204. if (actor->IsAlive() && (m_team == TEAM_ANY || actor->GetTeamNumber() == m_team))
  205. {
  206. Vector to = actor->WorldSpaceCenter() - m_spot;
  207. float rangeSq = to.LengthSqr();
  208. if (rangeSq < m_closeRangeSq)
  209. {
  210. m_closeRangeSq = rangeSq;
  211. m_close = actor;
  212. }
  213. }
  214. return true;
  215. }
  216. CBaseCombatCharacter *GetClosestActor( void ) const
  217. {
  218. return m_close;
  219. }
  220. bool IsClosestActorCloserThan( float range )
  221. {
  222. return (m_closeRangeSq < (range * range));
  223. }
  224. bool IsClosestActorFartherThan( float range )
  225. {
  226. return (m_closeRangeSq > (range * range));
  227. }
  228. Vector m_spot;
  229. int m_team;
  230. CBaseCombatCharacter *m_close;
  231. float m_closeRangeSq;
  232. CBaseCombatCharacter *m_ignore;
  233. };
  234. //--------------------------------------------------------------------------------------------------------
  235. class CShowViewportPanel
  236. {
  237. int m_team;
  238. const char *m_panelName;
  239. bool m_show;
  240. KeyValues *m_data;
  241. public:
  242. CShowViewportPanel( int team, const char *panelName, bool show, KeyValues *data = NULL )
  243. {
  244. m_team = team;
  245. m_panelName = panelName;
  246. m_show = show;
  247. m_data = data;
  248. }
  249. bool operator() ( CBasePlayer *player )
  250. {
  251. if ( m_team != TEAM_ANY && m_team != player->GetTeamNumber() )
  252. return true;
  253. player->ShowViewPortPanel( m_panelName, m_show, m_data );
  254. return true;
  255. }
  256. };
  257. //--------------------------------------------------------------------------------------------------------------
  258. /**
  259. * Iterate each "actor" in the game, where an actor is a Player or NextBot
  260. */
  261. template < typename Functor >
  262. inline bool ForEachActor( Functor &func )
  263. {
  264. // iterate all non-bot players
  265. for( int i=1; i<=gpGlobals->maxClients; ++i )
  266. {
  267. CBasePlayer *player = UTIL_PlayerByIndex( i );
  268. if ( player == NULL )
  269. continue;
  270. if ( FNullEnt( player->edict() ) )
  271. continue;
  272. if ( !player->IsPlayer() )
  273. continue;
  274. if ( !player->IsConnected() )
  275. continue;
  276. #ifdef NEXT_BOT
  277. // skip bots - ForEachCombatCharacter will catch them
  278. INextBot *bot = player->MyNextBotPointer();
  279. if ( bot )
  280. {
  281. continue;
  282. }
  283. #endif // NEXT_BOT
  284. if ( func( player ) == false )
  285. {
  286. return false;
  287. }
  288. }
  289. #ifdef NEXT_BOT
  290. // iterate all NextBots
  291. return TheNextBots().ForEachCombatCharacter( func );
  292. #else
  293. return true;
  294. #endif // NEXT_BOT
  295. }
  296. //--------------------------------------------------------------------------------------------------------------
  297. /**
  298. * The interface for functors for use with ForEachActor() that
  299. * want notification before iteration starts and after interation
  300. * is complete (successful or not).
  301. */
  302. class IActorFunctor
  303. {
  304. public:
  305. virtual void OnBeginIteration( void ) { } // invoked once before iteration begins
  306. virtual bool operator() ( CBaseCombatCharacter *them ) = 0;
  307. virtual void OnEndIteration( bool allElementsIterated ) { } // invoked once after iteration is complete whether successful or not
  308. };
  309. //--------------------------------------------------------------------------------------------------------------
  310. /**
  311. * Iterate each "actor" in the game, where an actor is a Player or NextBot
  312. * Template specialization for IActorFunctors.
  313. */
  314. template <>
  315. inline bool ForEachActor( IActorFunctor &func )
  316. {
  317. func.OnBeginIteration();
  318. bool isComplete = true;
  319. // iterate all non-bot players
  320. for( int i=1; i<=gpGlobals->maxClients; ++i )
  321. {
  322. CBasePlayer *player = UTIL_PlayerByIndex( i );
  323. if ( player == NULL )
  324. continue;
  325. if ( FNullEnt( player->edict() ) )
  326. continue;
  327. if ( !player->IsPlayer() )
  328. continue;
  329. if ( !player->IsConnected() )
  330. continue;
  331. #ifdef NEXT_BOT
  332. // skip bots - ForEachCombatCharacter will catch them
  333. INextBot *bot = dynamic_cast< INextBot * >( player );
  334. if ( bot )
  335. {
  336. continue;
  337. }
  338. #endif // NEXT_BOT
  339. if ( func( player ) == false )
  340. {
  341. isComplete = false;
  342. break;
  343. }
  344. }
  345. #ifdef NEXT_BOT
  346. if ( !isComplete )
  347. {
  348. // iterate all NextBots
  349. isComplete = TheNextBots().ForEachCombatCharacter( func );
  350. }
  351. #endif // NEXT_BOT
  352. func.OnEndIteration( isComplete );
  353. return isComplete;
  354. }
  355. //--------------------------------------------------------------------------------------------------------
  356. class CTraceFilterOnlyClassname : public CTraceFilterSimple
  357. {
  358. public:
  359. CTraceFilterOnlyClassname( const IHandleEntity *passentity, const char *pchClassname, int collisionGroup ) :
  360. CTraceFilterSimple( passentity, collisionGroup ), m_pchClassname( pchClassname )
  361. {
  362. }
  363. virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  364. {
  365. CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
  366. if ( !pEntity )
  367. return false;
  368. return FClassnameIs( pEntity, m_pchClassname ) && CTraceFilterSimple::ShouldHitEntity( pHandleEntity, contentsMask );
  369. }
  370. private:
  371. const char *m_pchClassname;
  372. };
  373. #endif // _FUNCTOR_UTILS_H_