source-engine/game/server/functorutils.h

451 lines
9.4 KiB
C
Raw Normal View History

2020-04-22 16:56:21 +00:00
// FunctorUtils.h
// Useful functors
//========= Copyright Valve Corporation, All rights reserved. ============//
#ifndef _FUNCTOR_UTILS_H_
#define _FUNCTOR_UTILS_H_
#ifdef NEXT_BOT
#include "NextBotInterface.h"
#include "NextBotManager.h"
#endif // NEXT_BOT
//--------------------------------------------------------------------------------------------------------
/**
* NOTE: The functors in this file should ideally be game-independent,
* and work for any Source based game
*/
//--------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------
/**
* Count the number of living players on a given team (or TEAM_ANY)
*/
class LivePlayerCounter
{
public:
static const bool EXCLUDE_BOTS = false;
LivePlayerCounter( int team, bool includeBots = true )
{
m_team = team;
m_includeBots = includeBots;
m_count = 0;
}
bool operator() ( CBasePlayer *player )
{
if (player->IsAlive() && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team))
{
if (m_includeBots || !player->IsBot())
{
++m_count;
}
}
return true;
}
int GetCount( void ) const
{
return m_count;
}
int m_team;
bool m_includeBots;
int m_count;
};
//--------------------------------------------------------------------------------------------------------
/**
* Count the number of dead players on a given team (or TEAM_ANY)
*/
class DeadPlayerCounter
{
public:
static const bool EXCLUDE_BOTS = false;
DeadPlayerCounter( int team, bool includeBots = true )
{
m_team = team;
m_includeBots = includeBots;
m_count = 0;
}
bool operator() ( CBasePlayer *player )
{
if (!player->IsAlive() && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team))
{
if (m_includeBots || !player->IsBot())
{
++m_count;
}
}
return true;
}
int GetCount( void ) const
{
return m_count;
}
int m_team;
bool m_includeBots;
int m_count;
};
//--------------------------------------------------------------------------------------------------------
/**
* Count the number of players on a given team (or TEAM_ANY)
*/
class PlayerCounter
{
public:
static const bool EXCLUDE_BOTS = false;
PlayerCounter( int team, int lifeState = -1, bool includeBots = true )
{
m_team = team;
m_includeBots = includeBots;
m_count = 0;
m_lifeState = lifeState;
}
bool operator() ( CBasePlayer *player )
{
if ((player->m_lifeState == m_lifeState || m_lifeState == -1) && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team))
{
if (m_includeBots || !player->IsBot())
{
++m_count;
}
}
return true;
}
int GetCount( void ) const
{
return m_count;
}
int m_lifeState;
int m_team;
bool m_includeBots;
int m_count;
};
//--------------------------------------------------------------------------------------------------------
/**
* Return the closest living player on the given team (or TEAM_ANY)
*/
class ClosestPlayerScan
{
public:
static const bool EXCLUDE_BOTS = false;
ClosestPlayerScan( const Vector &spot, int team, float maxRange = 0.0f, CBasePlayer *ignore = NULL, bool includeBots = true )
{
m_spot = spot;
m_team = team;
m_includeBots = includeBots;
m_close = NULL;
if ( maxRange > 0.0f )
{
m_closeRangeSq = maxRange * maxRange;
}
else
{
m_closeRangeSq = 999999999.9f;
}
m_ignore = ignore;
}
bool operator() ( CBasePlayer *player )
{
if (player == m_ignore)
return true;
if (player->IsAlive() && (m_team == TEAM_ANY || player->GetTeamNumber() == m_team))
{
if ( !m_includeBots && player->IsBot() )
return true;
Vector to = player->WorldSpaceCenter() - m_spot;
float rangeSq = to.LengthSqr();
if (rangeSq < m_closeRangeSq)
{
m_closeRangeSq = rangeSq;
m_close = player;
}
}
return true;
}
CBasePlayer *GetPlayer( void ) const
{
return m_close;
}
bool IsCloserThan( float range )
{
return (m_closeRangeSq < (range * range));
}
bool IsFartherThan( float range )
{
return (m_closeRangeSq > (range * range));
}
Vector m_spot;
int m_team;
bool m_includeBots;
CBasePlayer *m_close;
float m_closeRangeSq;
CBasePlayer *m_ignore;
};
//--------------------------------------------------------------------------------------------------------
/**
* Return the closest living BaseCombatCharacter on the given team (or TEAM_ANY)
*/
class ClosestActorScan
{
public:
ClosestActorScan( const Vector &spot, int team, float maxRange = 0.0f, CBaseCombatCharacter *ignore = NULL )
{
m_spot = spot;
m_team = team;
m_close = NULL;
if ( maxRange > 0.0f )
{
m_closeRangeSq = maxRange * maxRange;
}
else
{
m_closeRangeSq = 999999999.9f;
}
m_ignore = ignore;
}
bool operator() ( CBaseCombatCharacter *actor )
{
if (actor == m_ignore)
return true;
if (actor->IsAlive() && (m_team == TEAM_ANY || actor->GetTeamNumber() == m_team))
{
Vector to = actor->WorldSpaceCenter() - m_spot;
float rangeSq = to.LengthSqr();
if (rangeSq < m_closeRangeSq)
{
m_closeRangeSq = rangeSq;
m_close = actor;
}
}
return true;
}
CBaseCombatCharacter *GetClosestActor( void ) const
{
return m_close;
}
bool IsClosestActorCloserThan( float range )
{
return (m_closeRangeSq < (range * range));
}
bool IsClosestActorFartherThan( float range )
{
return (m_closeRangeSq > (range * range));
}
Vector m_spot;
int m_team;
CBaseCombatCharacter *m_close;
float m_closeRangeSq;
CBaseCombatCharacter *m_ignore;
};
//--------------------------------------------------------------------------------------------------------
class CShowViewportPanel
{
int m_team;
const char *m_panelName;
bool m_show;
KeyValues *m_data;
public:
CShowViewportPanel( int team, const char *panelName, bool show, KeyValues *data = NULL )
{
m_team = team;
m_panelName = panelName;
m_show = show;
m_data = data;
}
bool operator() ( CBasePlayer *player )
{
if ( m_team != TEAM_ANY && m_team != player->GetTeamNumber() )
return true;
player->ShowViewPortPanel( m_panelName, m_show, m_data );
return true;
}
};
//--------------------------------------------------------------------------------------------------------------
/**
* Iterate each "actor" in the game, where an actor is a Player or NextBot
*/
template < typename Functor >
inline bool ForEachActor( Functor &func )
{
// iterate all non-bot players
for( int i=1; i<=gpGlobals->maxClients; ++i )
{
CBasePlayer *player = UTIL_PlayerByIndex( i );
if ( player == NULL )
continue;
if ( FNullEnt( player->edict() ) )
continue;
if ( !player->IsPlayer() )
continue;
if ( !player->IsConnected() )
continue;
#ifdef NEXT_BOT
// skip bots - ForEachCombatCharacter will catch them
INextBot *bot = player->MyNextBotPointer();
if ( bot )
{
continue;
}
#endif // NEXT_BOT
if ( func( player ) == false )
{
return false;
}
}
#ifdef NEXT_BOT
// iterate all NextBots
return TheNextBots().ForEachCombatCharacter( func );
#else
return true;
#endif // NEXT_BOT
}
//--------------------------------------------------------------------------------------------------------------
/**
* The interface for functors for use with ForEachActor() that
* want notification before iteration starts and after interation
* is complete (successful or not).
*/
class IActorFunctor
{
public:
virtual void OnBeginIteration( void ) { } // invoked once before iteration begins
virtual bool operator() ( CBaseCombatCharacter *them ) = 0;
virtual void OnEndIteration( bool allElementsIterated ) { } // invoked once after iteration is complete whether successful or not
};
//--------------------------------------------------------------------------------------------------------------
/**
* Iterate each "actor" in the game, where an actor is a Player or NextBot
* Template specialization for IActorFunctors.
*/
template <>
inline bool ForEachActor( IActorFunctor &func )
{
func.OnBeginIteration();
bool isComplete = true;
// iterate all non-bot players
for( int i=1; i<=gpGlobals->maxClients; ++i )
{
CBasePlayer *player = UTIL_PlayerByIndex( i );
if ( player == NULL )
continue;
if ( FNullEnt( player->edict() ) )
continue;
if ( !player->IsPlayer() )
continue;
if ( !player->IsConnected() )
continue;
#ifdef NEXT_BOT
// skip bots - ForEachCombatCharacter will catch them
INextBot *bot = dynamic_cast< INextBot * >( player );
if ( bot )
{
continue;
}
#endif // NEXT_BOT
if ( func( player ) == false )
{
isComplete = false;
break;
}
}
#ifdef NEXT_BOT
if ( !isComplete )
{
// iterate all NextBots
isComplete = TheNextBots().ForEachCombatCharacter( func );
}
#endif // NEXT_BOT
func.OnEndIteration( isComplete );
return isComplete;
}
//--------------------------------------------------------------------------------------------------------
class CTraceFilterOnlyClassname : public CTraceFilterSimple
{
public:
CTraceFilterOnlyClassname( const IHandleEntity *passentity, const char *pchClassname, int collisionGroup ) :
CTraceFilterSimple( passentity, collisionGroup ), m_pchClassname( pchClassname )
{
}
virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
{
CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
if ( !pEntity )
return false;
return FClassnameIs( pEntity, m_pchClassname ) && CTraceFilterSimple::ShouldHitEntity( pHandleEntity, contentsMask );
}
private:
const char *m_pchClassname;
};
#endif // _FUNCTOR_UTILS_H_