194 lines
7.7 KiB
SourcePawn
194 lines
7.7 KiB
SourcePawn
#pragma semicolon 1
|
|
|
|
#include <sourcemod>
|
|
#include <tf2_stocks>
|
|
|
|
#define PL_VERSION "0.6"
|
|
|
|
#define TF_CLASS_DEMOMAN 4
|
|
#define TF_CLASS_ENGINEER 9
|
|
#define TF_CLASS_HEAVY 6
|
|
#define TF_CLASS_MEDIC 5
|
|
#define TF_CLASS_PYRO 7
|
|
#define TF_CLASS_SCOUT 1
|
|
#define TF_CLASS_SNIPER 2
|
|
#define TF_CLASS_SOLDIER 3
|
|
#define TF_CLASS_SPY 8
|
|
#define TF_CLASS_UNKNOWN 0
|
|
|
|
#define TF_TEAM_BLU 3
|
|
#define TF_TEAM_RED 2
|
|
|
|
public Plugin:myinfo =
|
|
{
|
|
name = "TF2 Class Restrictions",
|
|
author = "Tsunami",
|
|
description = "Restrict classes in TF2.",
|
|
version = PL_VERSION,
|
|
url = "http://www.tsunami-productions.nl"
|
|
}
|
|
|
|
new g_iClass[MAXPLAYERS + 1];
|
|
new Handle:g_hEnabled;
|
|
new Handle:g_hFlags;
|
|
new Handle:g_hImmunity;
|
|
new Handle:g_hLimits[4][10];
|
|
new String:g_sSounds[10][24] = {"", "vo/scout_no03.wav", "vo/sniper_no04.wav", "vo/soldier_no01.wav",
|
|
"vo/demoman_no03.wav", "vo/medic_no03.wav", "vo/heavy_no02.wav",
|
|
"vo/pyro_no01.wav", "vo/spy_no02.wav", "vo/engineer_no03.wav"};
|
|
|
|
public OnPluginStart()
|
|
{
|
|
CreateConVar("sm_classrestrict_version", PL_VERSION, "Restrict classes in TF2.", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY);
|
|
g_hEnabled = CreateConVar("sm_classrestrict_enabled", "1", "Enable/disable restricting classes in TF2.");
|
|
g_hFlags = CreateConVar("sm_classrestrict_flags", "", "Admin flags for restricted classes in TF2.");
|
|
g_hImmunity = CreateConVar("sm_classrestrict_immunity", "0", "Enable/disable admins being immune for restricted classes in TF2.");
|
|
g_hLimits[TF_TEAM_BLU][TF_CLASS_DEMOMAN] = CreateConVar("sm_classrestrict_blu_demomen", "-1", "Limit for Blu demomen in TF2.");
|
|
g_hLimits[TF_TEAM_BLU][TF_CLASS_ENGINEER] = CreateConVar("sm_classrestrict_blu_engineers", "-1", "Limit for Blu engineers in TF2.");
|
|
g_hLimits[TF_TEAM_BLU][TF_CLASS_HEAVY] = CreateConVar("sm_classrestrict_blu_heavies", "-1", "Limit for Blu heavies in TF2.");
|
|
g_hLimits[TF_TEAM_BLU][TF_CLASS_MEDIC] = CreateConVar("sm_classrestrict_blu_medics", "-1", "Limit for Blu medics in TF2.");
|
|
g_hLimits[TF_TEAM_BLU][TF_CLASS_PYRO] = CreateConVar("sm_classrestrict_blu_pyros", "-1", "Limit for Blu pyros in TF2.");
|
|
g_hLimits[TF_TEAM_BLU][TF_CLASS_SCOUT] = CreateConVar("sm_classrestrict_blu_scouts", "-1", "Limit for Blu scouts in TF2.");
|
|
g_hLimits[TF_TEAM_BLU][TF_CLASS_SNIPER] = CreateConVar("sm_classrestrict_blu_snipers", "-1", "Limit for Blu snipers in TF2.");
|
|
g_hLimits[TF_TEAM_BLU][TF_CLASS_SOLDIER] = CreateConVar("sm_classrestrict_blu_soldiers", "-1", "Limit for Blu soldiers in TF2.");
|
|
g_hLimits[TF_TEAM_BLU][TF_CLASS_SPY] = CreateConVar("sm_classrestrict_blu_spies", "-1", "Limit for Blu spies in TF2.");
|
|
g_hLimits[TF_TEAM_RED][TF_CLASS_DEMOMAN] = CreateConVar("sm_classrestrict_red_demomen", "-1", "Limit for Red demomen in TF2.");
|
|
g_hLimits[TF_TEAM_RED][TF_CLASS_ENGINEER] = CreateConVar("sm_classrestrict_red_engineers", "-1", "Limit for Red engineers in TF2.");
|
|
g_hLimits[TF_TEAM_RED][TF_CLASS_HEAVY] = CreateConVar("sm_classrestrict_red_heavies", "-1", "Limit for Red heavies in TF2.");
|
|
g_hLimits[TF_TEAM_RED][TF_CLASS_MEDIC] = CreateConVar("sm_classrestrict_red_medics", "-1", "Limit for Red medics in TF2.");
|
|
g_hLimits[TF_TEAM_RED][TF_CLASS_PYRO] = CreateConVar("sm_classrestrict_red_pyros", "-1", "Limit for Red pyros in TF2.");
|
|
g_hLimits[TF_TEAM_RED][TF_CLASS_SCOUT] = CreateConVar("sm_classrestrict_red_scouts", "-1", "Limit for Red scouts in TF2.");
|
|
g_hLimits[TF_TEAM_RED][TF_CLASS_SNIPER] = CreateConVar("sm_classrestrict_red_snipers", "-1", "Limit for Red snipers in TF2.");
|
|
g_hLimits[TF_TEAM_RED][TF_CLASS_SOLDIER] = CreateConVar("sm_classrestrict_red_soldiers", "-1", "Limit for Red soldiers in TF2.");
|
|
g_hLimits[TF_TEAM_RED][TF_CLASS_SPY] = CreateConVar("sm_classrestrict_red_spies", "-1", "Limit for Red spies in TF2.");
|
|
|
|
HookEvent("player_changeclass", Event_PlayerClass);
|
|
HookEvent("player_spawn", Event_PlayerSpawn);
|
|
HookEvent("player_team", Event_PlayerTeam);
|
|
|
|
AutoExecConfig(true);
|
|
}
|
|
|
|
public OnMapStart()
|
|
{
|
|
decl i, String:sSound[32];
|
|
for(i = 1; i < sizeof(g_sSounds); i++)
|
|
{
|
|
Format(sSound, sizeof(sSound), "sound/%s", g_sSounds[i]);
|
|
PrecacheSound(g_sSounds[i]);
|
|
AddFileToDownloadsTable(sSound);
|
|
}
|
|
}
|
|
|
|
public OnClientPutInServer(client)
|
|
{
|
|
g_iClass[client] = TF_CLASS_UNKNOWN;
|
|
}
|
|
|
|
public Event_PlayerClass(Handle:event, const String:name[], bool:dontBroadcast)
|
|
{
|
|
new iClient = GetClientOfUserId(GetEventInt(event, "userid")),
|
|
iClass = GetEventInt(event, "class"),
|
|
iTeam = GetClientTeam(iClient);
|
|
|
|
if(!(GetConVarBool(g_hImmunity) && IsImmune(iClient)) && IsFull(iTeam, iClass))
|
|
{
|
|
ShowVGUIPanel(iClient, iTeam == TF_TEAM_BLU ? "class_blue" : "class_red");
|
|
EmitSoundToClient(iClient, g_sSounds[iClass]);
|
|
TF2_SetPlayerClass(iClient, TFClassType:g_iClass[iClient]);
|
|
}
|
|
}
|
|
|
|
public Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast)
|
|
{
|
|
new iClient = GetClientOfUserId(GetEventInt(event, "userid")),
|
|
iTeam = GetClientTeam(iClient);
|
|
|
|
if(!(GetConVarBool(g_hImmunity) && IsImmune(iClient)) && IsFull(iTeam, (g_iClass[iClient] = _:TF2_GetPlayerClass(iClient))))
|
|
{
|
|
ShowVGUIPanel(iClient, iTeam == TF_TEAM_BLU ? "class_blue" : "class_red");
|
|
EmitSoundToClient(iClient, g_sSounds[g_iClass[iClient]]);
|
|
PickClass(iClient);
|
|
}
|
|
}
|
|
|
|
public Event_PlayerTeam(Handle:event, const String:name[], bool:dontBroadcast)
|
|
{
|
|
new iClient = GetClientOfUserId(GetEventInt(event, "userid")),
|
|
iTeam = GetEventInt(event, "team");
|
|
|
|
if(!(GetConVarBool(g_hImmunity) && IsImmune(iClient)) && IsFull(iTeam, g_iClass[iClient]))
|
|
{
|
|
ShowVGUIPanel(iClient, iTeam == TF_TEAM_BLU ? "class_blue" : "class_red");
|
|
EmitSoundToClient(iClient, g_sSounds[g_iClass[iClient]]);
|
|
PickClass(iClient);
|
|
}
|
|
}
|
|
|
|
bool:IsFull(iTeam, iClass)
|
|
{
|
|
// If plugin is disabled, or team or class is invalid, class is not full
|
|
if(!GetConVarBool(g_hEnabled) || iTeam < TF_TEAM_RED || iClass < TF_CLASS_SCOUT)
|
|
return false;
|
|
|
|
// Get team's class limit
|
|
new iLimit,
|
|
Float:flLimit = GetConVarFloat(g_hLimits[iTeam][iClass]);
|
|
|
|
// If limit is a percentage, calculate real limit
|
|
if(flLimit > 0.0 && flLimit < 1.0)
|
|
iLimit = RoundToNearest(flLimit * GetTeamClientCount(iTeam));
|
|
else
|
|
iLimit = RoundToNearest(flLimit);
|
|
|
|
// If limit is -1, class is not full
|
|
if(iLimit == -1)
|
|
return false;
|
|
// If limit is 0, class is full
|
|
else if(iLimit == 0)
|
|
return true;
|
|
|
|
// Loop through all clients
|
|
for(new i = 1, iCount = 0; i <= MaxClients; i++)
|
|
{
|
|
// If client is in game, on this team, has this class and limit has been reached, class is full
|
|
if(IsClientInGame(i) && GetClientTeam(i) == iTeam && _:TF2_GetPlayerClass(i) == iClass && ++iCount > iLimit)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool:IsImmune(iClient)
|
|
{
|
|
if(!iClient || !IsClientInGame(iClient))
|
|
return false;
|
|
|
|
decl String:sFlags[32];
|
|
GetConVarString(g_hFlags, sFlags, sizeof(sFlags));
|
|
|
|
// If flags are specified and client has generic or root flag, client is immune
|
|
return !StrEqual(sFlags, "") && GetUserFlagBits(iClient) & (ReadFlagString(sFlags)|ADMFLAG_ROOT);
|
|
}
|
|
|
|
PickClass(iClient)
|
|
{
|
|
// Loop through all classes, starting at random class
|
|
for(new i = GetRandomInt(TF_CLASS_SCOUT, TF_CLASS_ENGINEER), iClass = i, iTeam = GetClientTeam(iClient);;)
|
|
{
|
|
// If team's class is not full, set client's class
|
|
if(!IsFull(iTeam, i))
|
|
{
|
|
TF2_SetPlayerClass(iClient, TFClassType:i);
|
|
TF2_RespawnPlayer(iClient);
|
|
g_iClass[iClient] = i;
|
|
break;
|
|
}
|
|
// If next class index is invalid, start at first class
|
|
else if(++i > TF_CLASS_ENGINEER)
|
|
i = TF_CLASS_SCOUT;
|
|
// If loop has finished, stop searching
|
|
else if(i == iClass)
|
|
break;
|
|
}
|
|
} |