|
|
//-----------------------------------------------------------------------------
// class CPointEntityFinder
//
// Purpose: Finds an entity using a specified heuristic and outputs it as !caller
// with the OnFoundEntity output.
//-----------------------------------------------------------------------------
#include "cbase.h"
#include "filters.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
enum EntFinderMethod_t { ENT_FIND_METHOD_NEAREST = 0, ENT_FIND_METHOD_FARTHEST, ENT_FIND_METHOD_RANDOM, };
class CPointEntityFinder : public CBaseEntity { void Activate( void );
DECLARE_CLASS( CPointEntityFinder, CBaseEntity );
private:
EHANDLE m_hEntity; string_t m_iFilterName; CHandle<class CBaseFilter> m_hFilter; string_t m_iRefName; EHANDLE m_hReference;
EntFinderMethod_t m_FindMethod;
void FindEntity( void ); void FindByDistance( void ); void FindByRandom( void );
// Input handlers
void InputFindEntity( inputdata_t &inputdata );
// Output handlers
COutputEvent m_OnFoundEntity;
DECLARE_DATADESC(); };
LINK_ENTITY_TO_CLASS( point_entity_finder, CPointEntityFinder );
BEGIN_DATADESC( CPointEntityFinder )
DEFINE_KEYFIELD( m_FindMethod, FIELD_INTEGER, "method" ), DEFINE_KEYFIELD( m_iFilterName, FIELD_STRING, "filtername" ), DEFINE_FIELD( m_hFilter, FIELD_EHANDLE ), DEFINE_KEYFIELD( m_iRefName, FIELD_STRING, "referencename" ), DEFINE_FIELD( m_hReference, FIELD_EHANDLE ),
DEFINE_OUTPUT( m_OnFoundEntity, "OnFoundEntity" ),
//---------------------------------
DEFINE_INPUTFUNC( FIELD_VOID, "FindEntity", InputFindEntity ),
END_DATADESC()
void CPointEntityFinder::Activate( void ) { // Get the filter, if it exists.
if (m_iFilterName != NULL_STRING) { m_hFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iFilterName )); }
BaseClass::Activate(); }
void CPointEntityFinder::FindEntity( void ) { // Get the reference entity, if it exists.
if (m_iRefName != NULL_STRING) { m_hReference = gEntList.FindEntityByName( NULL, m_iRefName ); }
switch ( m_FindMethod ) {
case ( ENT_FIND_METHOD_NEAREST ): FindByDistance(); break; case ( ENT_FIND_METHOD_FARTHEST ): FindByDistance(); break; case ( ENT_FIND_METHOD_RANDOM ): FindByRandom(); break; } }
void CPointEntityFinder::FindByDistance( void ) { m_hEntity = NULL; CBaseFilter *pFilter = m_hFilter.Get();
// go through each entity and determine whether it's closer or farther from the current entity. Pick according to Method selected.
float flBestDist = 0; CBaseEntity *pEntity = gEntList.FirstEnt(); while ( pEntity ) { if ( FStrEq( STRING( pEntity->m_iClassname ), "worldspawn" ) || FStrEq( STRING( pEntity->m_iClassname ), "soundent" ) || FStrEq( STRING( pEntity->m_iClassname ), "player_manager" ) || FStrEq( STRING( pEntity->m_iClassname ), "bodyque" ) || FStrEq( STRING( pEntity->m_iClassname ), "ai_network" ) || pEntity == this || ( pFilter && !( pFilter->PassesFilter( this, pEntity ) ) ) ) { pEntity = gEntList.NextEnt( pEntity ); continue; }
// if we have a reference entity, use that, otherwise, check against 'this'
Vector vecStart; if ( m_hReference ) { vecStart = m_hReference->GetAbsOrigin(); } else { vecStart = GetAbsOrigin(); }
// init m_hEntity with a valid entity.
if (m_hEntity == NULL ) { m_hEntity = pEntity; flBestDist = ( pEntity->GetAbsOrigin() - vecStart ).LengthSqr(); }
float flNewDist = ( pEntity->GetAbsOrigin() - vecStart ).LengthSqr();
switch ( m_FindMethod ) {
case ( ENT_FIND_METHOD_NEAREST ): if ( flNewDist < flBestDist ) { m_hEntity = pEntity; flBestDist = flNewDist; } break;
case ( ENT_FIND_METHOD_FARTHEST ): if ( flNewDist > flBestDist ) { m_hEntity = pEntity; flBestDist = flNewDist; } break;
default: Assert( false ); break; }
pEntity = gEntList.NextEnt( pEntity ); } }
void CPointEntityFinder::FindByRandom( void ) { // TODO: optimize the case where there is no filter
m_hEntity = NULL; CBaseFilter *pFilter = m_hFilter.Get(); CUtlVector<CBaseEntity *> ValidEnts;
CBaseEntity *pEntity = gEntList.FirstEnt(); do // note all valid entities.
{ if ( pFilter && pFilter->PassesFilter( this, pEntity ) ) { ValidEnts.AddToTail( pEntity ); }
pEntity = gEntList.NextEnt( pEntity );
} while ( pEntity );
// pick one at random
if ( ValidEnts.Count() != 0 ) { m_hEntity = ValidEnts[ RandomInt( 0, ValidEnts.Count() - 1 )]; } }
void CPointEntityFinder::InputFindEntity( inputdata_t &inputdata ) { FindEntity();
m_OnFoundEntity.FireOutput( inputdata.pActivator, m_hEntity ); }
|