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.
449 lines
9.3 KiB
449 lines
9.3 KiB
// FunctorUtils.h |
|
// Useful functors |
|
// Author: Michael Booth, August 2005, Copyright 2005 Turtle Rock Studios, Inc. |
|
|
|
#ifndef _FUNCTOR_UTILS_H_ |
|
#define _FUNCTOR_UTILS_H_ |
|
|
|
#ifdef NEXTBOTS |
|
#include "NextBotInterface.h" |
|
#include "NextBotManager.h" |
|
#endif |
|
|
|
//-------------------------------------------------------------------------------------------------------- |
|
/** |
|
* 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; |
|
|
|
// skip bots - ForEachCombatCharacter will catch them |
|
INextBot *bot = player->MyNextBotPointer(); |
|
if ( bot ) |
|
{ |
|
continue; |
|
} |
|
|
|
if ( func( player ) == false ) |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
// iterate all NextBots |
|
#ifdef NEXTBOTS |
|
return TheNextBots().ForEachCombatCharacter( func ); |
|
#else |
|
return true; |
|
#endif |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------- |
|
/** |
|
* 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 ) |
|
{ |
|
#ifdef NEXTBOTS |
|
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; |
|
|
|
// skip bots - ForEachCombatCharacter will catch them |
|
INextBot *bot = dynamic_cast< INextBot * >( player ); |
|
if ( bot ) |
|
{ |
|
continue; |
|
} |
|
|
|
if ( func( player ) == false ) |
|
{ |
|
isComplete = false; |
|
break; |
|
} |
|
} |
|
|
|
if ( !isComplete ) |
|
{ |
|
// iterate all NextBots |
|
|
|
isComplete = TheNextBots().ForEachCombatCharacter( func ); |
|
} |
|
|
|
func.OnEndIteration( isComplete ); |
|
|
|
return isComplete; |
|
#else |
|
return true; |
|
#endif |
|
} |
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------- |
|
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_
|
|
|