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.
 
 
 
 
 
 

297 lines
7.3 KiB

/**
* EntityUtil.h
* Various utility functions
*/
#ifndef _ENTITY_UTIL_H_
#define _ENTITY_UTIL_H_
//------------------------------------------------------------------------------------------
enum WhoType
{
ANYONE,
ONLY_FRIENDS,
ONLY_ENEMIES
};
//--------------------------------------------------------------------------------------------------------------
/**
* Iterate over all entities in the game, invoking functor on each.
* If functor returns false, stop iteration and return false.
*/
template < typename Functor >
bool ForEachEntity( Functor &func )
{
CBaseEntity *entity = gEntList.FirstEnt();
while ( entity )
{
if ( func( entity ) == false )
return false;
entity = gEntList.NextEnt( entity );
}
return true;
}
//--------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
#ifdef GAME_DLL
class FindInViewConeFunctor
{
public:
FindInViewConeFunctor( CBasePlayer *me, WhoType who, float tolerance, CBaseEntity *ignore = NULL )
{
m_me = me;
m_who = who;
m_tolerance = tolerance;
m_target = NULL;
m_range = 9999999.9f;
m_ignore = ignore;
me->EyeVectors(&m_dir, NULL, NULL);
m_origin = me->GetAbsOrigin() + me->GetViewOffset();
}
bool operator() ( CBasePlayer *player )
{
if (player != m_me && player != m_ignore && player->IsAlive())
{
if (m_who == ONLY_FRIENDS && m_me->GetTeamNumber() != player->GetTeamNumber() )
return true;
if (m_who == ONLY_ENEMIES && m_me->GetTeamNumber() == player->GetTeamNumber() )
return true;
Vector to = player->WorldSpaceCenter() - m_origin;
float range = to.NormalizeInPlace();
if (DotProduct( to, m_dir ) > m_tolerance && range < m_range)
{
if ( m_me->IsLineOfSightClear( player ) )
{
m_target = player;
m_range = range;
}
}
}
return true;
}
CBasePlayer *m_me;
WhoType m_who;
float m_tolerance;
CBaseEntity *m_ignore;
Vector m_origin;
Vector m_dir;
CBasePlayer *m_target;
float m_range;
};
/**
* Find the closest player within the given view cone
*/
inline CBasePlayer *GetClosestPlayerInViewCone( CBasePlayer *me, WhoType who, float tolerance = 0.95f, float *range = NULL, CBaseEntity *ignore = NULL )
{
// choke the victim we are pointing at
FindInViewConeFunctor checkCone( me, who, tolerance, ignore );
ForEachPlayer( checkCone );
if (range)
*range = checkCone.m_range;
return checkCone.m_target;
}
#endif
//--------------------------------------------------------------------------------------------------------------
/**
* Find player closest to ray.
* Return perpendicular distance to ray in 'offset' if it is non-NULL.
*/
extern CBasePlayer *GetPlayerClosestToRay( CBasePlayer *me, WhoType who, const Vector &start, const Vector &end, float *offset = NULL );
//--------------------------------------------------------------------------------------------------------------
/**
* Compute the closest point on the ray to 'pos' and return it in 'pointOnRay'.
* If point projects beyond the ends of the ray, return false - but clamp 'pointOnRay' to the correct endpoint.
*/
inline bool ClosestPointOnRay( const Vector &pos, const Vector &rayStart, const Vector &rayEnd, Vector *pointOnRay )
{
Vector to = pos - rayStart;
Vector dir = rayEnd - rayStart;
float length = dir.NormalizeInPlace();
float rangeAlong = DotProduct( dir, to );
if (rangeAlong < 0.0f)
{
// off start point
*pointOnRay = rayStart;
return false;
}
else if (rangeAlong > length)
{
// off end point
*pointOnRay = rayEnd;
return false;
}
else // within ray bounds
{
Vector onRay = rayStart + rangeAlong * dir;
*pointOnRay = onRay;
return true;
}
}
//------------------------------------------------------------------------------------------
/**
* Functor to find the player closest to a ray.
* For use with ForEachPlayerNearRay().
*/
class ClosestToRayFunctor
{
public:
ClosestToRayFunctor( CBasePlayer *ignore, WhoType who = ANYONE )
{
m_ignore = ignore;
m_who = who;
m_closestPlayer = NULL;
m_closestPlayerRange = 999999999.9f;
}
bool operator() ( CBasePlayer *player, float rangeToRay )
{
if (player == m_ignore)
return true;
if (!player->IsAlive())
return true;
if (m_who == ONLY_FRIENDS && m_ignore->GetTeamNumber() != player->GetTeamNumber() )
return true;
if (m_who == ONLY_ENEMIES && m_ignore->GetTeamNumber() == player->GetTeamNumber() )
return true;
// keep the player closest to the ray
if (rangeToRay < m_closestPlayerRange)
{
m_closestPlayerRange = rangeToRay;
m_closestPlayer = player;
}
return true;
}
CBasePlayer *m_ignore;
WhoType m_who;
CBasePlayer *m_closestPlayer;
float m_closestPlayerRange;
};
//--------------------------------------------------------------------------------------------------------------
/**
* Iterate over all players that are within range of the ray and invoke functor.
* If functor returns false, stop iteration and return false.
* @todo Check LOS to ray.
*/
template < typename Functor >
bool ForEachPlayerNearRay( Functor &func, const Vector &start, const Vector &end, float maxRadius )
{
for( int i=1; i<=gpGlobals->maxClients; ++i )
{
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
if (player == NULL)
continue;
if (FNullEnt( player->edict() ))
continue;
if (!player->IsPlayer())
continue;
if (!player->IsAlive())
continue;
float range = DistanceToRay( player->WorldSpaceCenter(), start, end );
if (range < 0.0f || range > maxRadius)
continue;
if (func( player, range ) == false)
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------------------
/**
* Iterate over all players that are within range of the sphere and invoke functor.
* If functor returns false, stop iteration and return false.
* @todo Check LOS to ray.
*/
template < typename Functor >
bool ForEachPlayerNearSphere( Functor &func, const Vector &origin, float radius )
{
for( int i=1; i<=gpGlobals->maxClients; ++i )
{
CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
if (player == NULL)
continue;
if (FNullEnt( player->edict() ))
continue;
if (!player->IsPlayer())
continue;
if (!player->IsAlive())
continue;
Vector to = player->WorldSpaceCenter() - origin;
float range = to.Length();
if (range > radius)
continue;
if (func( player, range ) == false)
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------------------
/**
* Reflect a vector.
* Assumes 'unitNormal' is normalized.
*/
inline Vector VectorReflect( const Vector &in, const Vector &unitNormal )
{
// compute the unit vector out of the plane of 'in' and 'unitNormal'
Vector lat = CrossProduct( in, unitNormal );
Vector forward = CrossProduct( unitNormal, lat );
forward.NormalizeInPlace();
Vector forwardComponent = forward * DotProduct( in, forward );
Vector normalComponent = unitNormal * DotProduct( in, unitNormal );
return forwardComponent - normalComponent;
}
#endif // _ENTITY_UTIL_H_