// 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_