sm-plugins/classrestrict.sp

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;
}
}