318 lines
6.5 KiB
SourcePawn
318 lines
6.5 KiB
SourcePawn
#if defined _smlib_teams_included
|
|
#endinput
|
|
#endif
|
|
#define _smlib_teams_included
|
|
|
|
#include <sourcemod>
|
|
#include <smlib/clients>
|
|
#include <smlib/entities>
|
|
|
|
#define MAX_TEAMS 32 // Max number of teams in a game
|
|
#define MAX_TEAM_NAME_LENGTH 32 // Max length of a team's name
|
|
|
|
// Team Defines
|
|
#define TEAM_INVALID -1
|
|
#define TEAM_UNASSIGNED 0
|
|
#define TEAM_SPECTATOR 1
|
|
#define TEAM_ONE 2
|
|
#define TEAM_TWO 3
|
|
#define TEAM_THREE 4
|
|
#define TEAM_FOUR 5
|
|
|
|
/*
|
|
* If one team is empty its assumed single team mode is enabled and the game won't start.
|
|
*
|
|
* @noparam
|
|
* @return True if one team is empty, false otherwise.
|
|
*/
|
|
stock bool Team_HaveAllPlayers(bool countFakeClients=true) {
|
|
|
|
int teamCount = GetTeamCount();
|
|
for (int i=2; i < teamCount; i++) {
|
|
|
|
if (Team_GetClientCount(i, ((countFakeClients) ? CLIENTFILTER_ALL : CLIENTFILTER_NOBOTS)) == 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Returns the client count of the players in a team.
|
|
*
|
|
* @param team Team Index.
|
|
* @param flags Client Filter Flags (Use the CLIENTFILTER_ constants).
|
|
* @return Client count in the server.
|
|
*/
|
|
stock int Team_GetClientCount(int team, int flags=0)
|
|
{
|
|
flags |= CLIENTFILTER_INGAME;
|
|
|
|
int numClients = 0;
|
|
for (int client=1; client <= MaxClients; client++) {
|
|
|
|
if (!Client_MatchesFilter(client, flags)) {
|
|
continue;
|
|
}
|
|
|
|
if (GetClientTeam(client) == team) {
|
|
numClients++;
|
|
}
|
|
}
|
|
|
|
return numClients;
|
|
}
|
|
|
|
/*
|
|
* Returns the client counts of the first two teams (eg.: Terrorists - Counter).
|
|
* Use this function for optimization if you have to get the counts of both teams,
|
|
* otherwise use Team_GetClientCount().
|
|
*
|
|
* @param team1 Pass an integer variable by reference
|
|
* @param team2 Pass an integer variable by reference
|
|
* @param flags Client Filter Flags (Use the CLIENTFILTER_ constants).
|
|
* @noreturn
|
|
*/
|
|
stock void Team_GetClientCounts(int &team1=0, int &team2=0, int flags=0)
|
|
{
|
|
flags |= CLIENTFILTER_INGAME;
|
|
|
|
for (int client=1; client <= MaxClients; client++) {
|
|
|
|
if (!Client_MatchesFilter(client, flags)) {
|
|
continue;
|
|
}
|
|
|
|
if (GetClientTeam(client) == TEAM_ONE) {
|
|
team1++;
|
|
}
|
|
else if (GetClientTeam(client) == TEAM_TWO) {
|
|
team2++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Gets the name of a team.
|
|
* Don't call this before OnMapStart()
|
|
*
|
|
* @param index Team Index.
|
|
* @param str String buffer
|
|
* @param size String Buffer Size
|
|
* @return True on success, false otherwise
|
|
*/
|
|
stock bool Team_GetName(int index, char[] str, int size)
|
|
{
|
|
int edict = Team_GetEdict(index);
|
|
|
|
if (edict == -1) {
|
|
str[0] = '\0';
|
|
return false;
|
|
}
|
|
|
|
GetEntPropString(edict, Prop_Send, "m_szTeamname", str, size);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Changes a team's name.
|
|
* Use this carefully !
|
|
* Only set the teamname OnMapStart() or OnEntityCreated()
|
|
* when no players are ingame, otherwise it can crash the server.
|
|
*
|
|
* @param index Team Index.
|
|
* @param name New Name String
|
|
* @return True on success, false otherwise
|
|
*/
|
|
stock bool Team_SetName(int index, const char[] name)
|
|
{
|
|
int edict = Team_GetEdict(index);
|
|
|
|
if (edict == -1) {
|
|
return false;
|
|
}
|
|
|
|
SetEntPropString(edict, Prop_Send, "m_szTeamname", name);
|
|
ChangeEdictState(edict, GetEntSendPropOffs(edict, "m_szTeamname", true));
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Changes a team's score.
|
|
* Don't use this before OnMapStart().
|
|
*
|
|
* @param index Team Index.
|
|
* @return Team Score or -1 if the team is not valid.
|
|
*/
|
|
stock int Team_GetScore(int index)
|
|
{
|
|
int edict = Team_GetEdict(index);
|
|
|
|
if (edict == -1) {
|
|
return -1;
|
|
}
|
|
|
|
return GetEntProp(edict, Prop_Send, "m_iScore");
|
|
}
|
|
|
|
/*
|
|
* Changes a team's score.
|
|
* Don't use this before OnMapStart().
|
|
*
|
|
* @param index Team Index.
|
|
* @param score Score value.
|
|
* @return True on success, false otherwise
|
|
*/
|
|
stock bool Team_SetScore(int index, int score)
|
|
{
|
|
int edict = Team_GetEdict(index);
|
|
|
|
if (edict == -1) {
|
|
return false;
|
|
}
|
|
|
|
SetEntProp(edict, Prop_Send, "m_iScore", score);
|
|
|
|
ChangeEdictState(edict, GetEntSendPropOffs(edict, "m_iScore", true));
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Gets a team's edict (*team_manager) Team Index.
|
|
* Don't call this before OnMapStart()
|
|
*
|
|
* @param edict Edict
|
|
* @return Team Index
|
|
*/
|
|
stock int Team_EdictGetNum(int edict)
|
|
{
|
|
return GetEntProp(edict, Prop_Send, "m_iTeamNum");
|
|
}
|
|
|
|
/*
|
|
* Check's whether the index is a valid team index or not.
|
|
* Don't call this before OnMapStart()
|
|
*
|
|
* @param index Index.
|
|
* @return True if the Index is a valid team, false otherwise.
|
|
*/
|
|
stock bool Team_IsValid(int index)
|
|
{
|
|
return (Team_GetEdict(index) != -1);
|
|
}
|
|
|
|
/*
|
|
* Gets a team's edict (team_manager) Team Index.
|
|
* Don't call this before OnMapStart()
|
|
*
|
|
* @param index Edict
|
|
* @return Team Index
|
|
*/
|
|
stock int Team_EdictIsValid(int edict)
|
|
{
|
|
return GetEntProp(edict, Prop_Send, "m_iTeamNum");
|
|
}
|
|
|
|
/*
|
|
* Gets a team's edict (team_manager).
|
|
* This function caches found team edicts.
|
|
* Don't call this before OnMapStart()
|
|
*
|
|
* @param index Team Index.
|
|
* @return Team edict or -1 if not found
|
|
*/
|
|
stock int Team_GetEdict(int index)
|
|
{
|
|
static int teams[MAX_TEAMS] = { INVALID_ENT_REFERENCE, ... };
|
|
|
|
if (index < 0 || index > MAX_TEAMS) {
|
|
return -1;
|
|
}
|
|
|
|
int edict = teams[index];
|
|
if (Entity_IsValid(edict)) {
|
|
return edict;
|
|
}
|
|
|
|
bool foundTeamManager = false;
|
|
|
|
int maxEntities = GetMaxEntities();
|
|
for (int entity=MaxClients+1; entity < maxEntities; entity++) {
|
|
|
|
if (!IsValidEntity(entity)) {
|
|
continue;
|
|
}
|
|
|
|
if (Entity_ClassNameMatches(entity, "team_manager", true)) {
|
|
foundTeamManager = true;
|
|
}
|
|
// Do not continue when no team managers are found anymore (for optimization)
|
|
else if (foundTeamManager) {
|
|
return -1;
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
|
|
int num = Team_EdictGetNum(entity);
|
|
|
|
if (num >= 0 && num <= MAX_TEAMS) {
|
|
teams[num] = EntIndexToEntRef(entity);
|
|
}
|
|
|
|
if (num == index) {
|
|
return entity;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Trys to find a client in the specified team.
|
|
* This function is NOT random, it returns the first
|
|
* or the cached player (Use Client_GetRandom() instead).
|
|
*
|
|
* @param index Team Index.
|
|
* @return Client Index or -1 if no client was found in the specified team.
|
|
*/
|
|
stock int Team_GetAnyClient(int index)
|
|
{
|
|
static int client_cache[MAX_TEAMS] = -1;
|
|
int client;
|
|
|
|
if (index > 0) {
|
|
client = client_cache[index];
|
|
|
|
if (client > 0 && client <= MaxClients) {
|
|
|
|
if (IsClientInGame(client) && GetClientTeam(client) == index) {
|
|
return client;
|
|
}
|
|
}
|
|
else {
|
|
client = -1;
|
|
}
|
|
}
|
|
|
|
for (client=1; client <= MaxClients; client++) {
|
|
|
|
if (!IsClientInGame(client)) {
|
|
continue;
|
|
}
|
|
|
|
if (GetClientTeam(client) != index) {
|
|
continue;
|
|
}
|
|
|
|
client_cache[index] = client;
|
|
|
|
return client;
|
|
}
|
|
|
|
return -1;
|
|
}
|