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
207 lines
4.6 KiB
//----------------------------------------------------------------------------- |
|
// 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 ); |
|
}
|
|
|