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.

207 lines
4.6 KiB

  1. //-----------------------------------------------------------------------------
  2. // class CPointEntityFinder
  3. //
  4. // Purpose: Finds an entity using a specified heuristic and outputs it as !caller
  5. // with the OnFoundEntity output.
  6. //-----------------------------------------------------------------------------
  7. #include "cbase.h"
  8. #include "filters.h"
  9. // NOTE: This has to be the last file included!
  10. #include "tier0/memdbgon.h"
  11. enum EntFinderMethod_t
  12. {
  13. ENT_FIND_METHOD_NEAREST = 0,
  14. ENT_FIND_METHOD_FARTHEST,
  15. ENT_FIND_METHOD_RANDOM,
  16. };
  17. class CPointEntityFinder : public CBaseEntity
  18. {
  19. void Activate( void );
  20. DECLARE_CLASS( CPointEntityFinder, CBaseEntity );
  21. private:
  22. EHANDLE m_hEntity;
  23. string_t m_iFilterName;
  24. CHandle<class CBaseFilter> m_hFilter;
  25. string_t m_iRefName;
  26. EHANDLE m_hReference;
  27. EntFinderMethod_t m_FindMethod;
  28. void FindEntity( void );
  29. void FindByDistance( void );
  30. void FindByRandom( void );
  31. // Input handlers
  32. void InputFindEntity( inputdata_t &inputdata );
  33. // Output handlers
  34. COutputEvent m_OnFoundEntity;
  35. DECLARE_DATADESC();
  36. };
  37. LINK_ENTITY_TO_CLASS( point_entity_finder, CPointEntityFinder );
  38. BEGIN_DATADESC( CPointEntityFinder )
  39. DEFINE_KEYFIELD( m_FindMethod, FIELD_INTEGER, "method" ),
  40. DEFINE_KEYFIELD( m_iFilterName, FIELD_STRING, "filtername" ),
  41. DEFINE_FIELD( m_hFilter, FIELD_EHANDLE ),
  42. DEFINE_KEYFIELD( m_iRefName, FIELD_STRING, "referencename" ),
  43. DEFINE_FIELD( m_hReference, FIELD_EHANDLE ),
  44. DEFINE_OUTPUT( m_OnFoundEntity, "OnFoundEntity" ),
  45. //---------------------------------
  46. DEFINE_INPUTFUNC( FIELD_VOID, "FindEntity", InputFindEntity ),
  47. END_DATADESC()
  48. void CPointEntityFinder::Activate( void )
  49. {
  50. // Get the filter, if it exists.
  51. if (m_iFilterName != NULL_STRING)
  52. {
  53. m_hFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iFilterName ));
  54. }
  55. BaseClass::Activate();
  56. }
  57. void CPointEntityFinder::FindEntity( void )
  58. {
  59. // Get the reference entity, if it exists.
  60. if (m_iRefName != NULL_STRING)
  61. {
  62. m_hReference = gEntList.FindEntityByName( NULL, m_iRefName );
  63. }
  64. switch ( m_FindMethod )
  65. {
  66. case ( ENT_FIND_METHOD_NEAREST ):
  67. FindByDistance();
  68. break;
  69. case ( ENT_FIND_METHOD_FARTHEST ):
  70. FindByDistance();
  71. break;
  72. case ( ENT_FIND_METHOD_RANDOM ):
  73. FindByRandom();
  74. break;
  75. }
  76. }
  77. void CPointEntityFinder::FindByDistance( void )
  78. {
  79. m_hEntity = NULL;
  80. CBaseFilter *pFilter = m_hFilter.Get();
  81. // go through each entity and determine whether it's closer or farther from the current entity. Pick according to Method selected.
  82. float flBestDist = 0;
  83. CBaseEntity *pEntity = gEntList.FirstEnt();
  84. while ( pEntity )
  85. {
  86. if ( FStrEq( STRING( pEntity->m_iClassname ), "worldspawn" )
  87. || FStrEq( STRING( pEntity->m_iClassname ), "soundent" )
  88. || FStrEq( STRING( pEntity->m_iClassname ), "player_manager" )
  89. || FStrEq( STRING( pEntity->m_iClassname ), "bodyque" )
  90. || FStrEq( STRING( pEntity->m_iClassname ), "ai_network" )
  91. || pEntity == this
  92. || ( pFilter && !( pFilter->PassesFilter( this, pEntity ) ) ) )
  93. {
  94. pEntity = gEntList.NextEnt( pEntity );
  95. continue;
  96. }
  97. // if we have a reference entity, use that, otherwise, check against 'this'
  98. Vector vecStart;
  99. if ( m_hReference )
  100. {
  101. vecStart = m_hReference->GetAbsOrigin();
  102. }
  103. else
  104. {
  105. vecStart = GetAbsOrigin();
  106. }
  107. // init m_hEntity with a valid entity.
  108. if (m_hEntity == NULL )
  109. {
  110. m_hEntity = pEntity;
  111. flBestDist = ( pEntity->GetAbsOrigin() - vecStart ).LengthSqr();
  112. }
  113. float flNewDist = ( pEntity->GetAbsOrigin() - vecStart ).LengthSqr();
  114. switch ( m_FindMethod )
  115. {
  116. case ( ENT_FIND_METHOD_NEAREST ):
  117. if ( flNewDist < flBestDist )
  118. {
  119. m_hEntity = pEntity;
  120. flBestDist = flNewDist;
  121. }
  122. break;
  123. case ( ENT_FIND_METHOD_FARTHEST ):
  124. if ( flNewDist > flBestDist )
  125. {
  126. m_hEntity = pEntity;
  127. flBestDist = flNewDist;
  128. }
  129. break;
  130. default:
  131. Assert( false );
  132. break;
  133. }
  134. pEntity = gEntList.NextEnt( pEntity );
  135. }
  136. }
  137. void CPointEntityFinder::FindByRandom( void )
  138. {
  139. // TODO: optimize the case where there is no filter
  140. m_hEntity = NULL;
  141. CBaseFilter *pFilter = m_hFilter.Get();
  142. CUtlVector<CBaseEntity *> ValidEnts;
  143. CBaseEntity *pEntity = gEntList.FirstEnt();
  144. do // note all valid entities.
  145. {
  146. if ( pFilter && pFilter->PassesFilter( this, pEntity ) )
  147. {
  148. ValidEnts.AddToTail( pEntity );
  149. }
  150. pEntity = gEntList.NextEnt( pEntity );
  151. } while ( pEntity );
  152. // pick one at random
  153. if ( ValidEnts.Count() != 0 )
  154. {
  155. m_hEntity = ValidEnts[ RandomInt( 0, ValidEnts.Count() - 1 )];
  156. }
  157. }
  158. void CPointEntityFinder::InputFindEntity( inputdata_t &inputdata )
  159. {
  160. FindEntity();
  161. m_OnFoundEntity.FireOutput( inputdata.pActivator, m_hEntity );
  162. }