Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.

208 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 );
}