This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

375 lines
10 KiB
C++

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