Created
June 14, 2017 04:05
-
-
Save hjhee/33860c5cf0b0e873fdb19a51ebb362ab to your computer and use it in GitHub Desktop.
adjusted MaxSpecials, DominatorLimit...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//# vim: set filetype=cpp : | |
/* | |
ABM a SourceMod L4D2 Plugin | |
Copyright (C) 2016 Victor NgBUCKWANGS Gonzalez | |
This program is free software; you can redistribute it and/or | |
modify it under the terms of the GNU General Public License | |
as published by the Free Software Foundation; either version 2 | |
of the License, or (at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program; if not, write to the | |
Free Software Foundation, Inc. | |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
*/ | |
// TODO: | |
//SetEntProp(client, Prop_Send,"m_bHasNightVision", 1); | |
//SetEntProp(client, Prop_Send, "m_bNightVisionOn", 1); | |
#pragma semicolon 1 | |
#include <sourcemod> | |
#include <sdktools> | |
#include <sdkhooks> | |
#undef REQUIRE_EXTENSIONS | |
#include <left4downtown> | |
#define PLUGIN_VERSION "0.1.38" | |
#define LOGFILE "addons/sourcemod/logs/abm.log" // TODO change this to DATE/SERVER FORMAT? | |
Handle g_GameData = null; | |
ArrayList g_sQueue; | |
ArrayList g_iQueue; | |
int g_OS; // no one wants to do OS specific stuff but a bug on Windows crashes the server | |
// menu parameters | |
#define menuArgs g_menuItems[client] // Global argument tracking for the menu system | |
#define menuArg0 g_menuItems[client][0] // GetItem(1...) | |
#define menuArg1 g_menuItems[client][1] // GetItem(2...) | |
g_menuItems[MAXPLAYERS + 1][2]; | |
// menu tracking | |
#define g_callBacks g_menuStack[client] | |
ArrayStack g_menuStack[MAXPLAYERS + 1]; | |
new Function:callBack; | |
char g_QKey[64]; // holds players by STEAM_ID | |
StringMap g_QDB; // holds player records linked by STEAM_ID | |
StringMap g_QRecord; // changes to an individual STEAM_ID mapping | |
StringMap g_Cvars; | |
char g_InfectedNames[11][] = {"Boomer", "Smoker", "Boomer", "Hunter", "Spitter", "Jockey", "Charger", "Boomer", "Tank", "Boomer", "Witch"}; | |
char g_SurvivorNames[8][] = {"Nick", "Rochelle", "Coach", "Ellis", "Bill", "Zoey", "Francis", "Louis"}; | |
char g_SurvivorPaths[8][] = { | |
"models/survivors/survivor_gambler.mdl", | |
"models/survivors/survivor_producer.mdl", | |
"models/survivors/survivor_coach.mdl", | |
"models/survivors/survivor_mechanic.mdl", | |
"models/survivors/survivor_namvet.mdl", | |
"models/survivors/survivor_teenangst.mdl", | |
"models/survivors/survivor_biker.mdl", | |
"models/survivors/survivor_manager.mdl", | |
}; | |
char g_dB[512]; // generic debug string buffer | |
char g_sB[512]; // generic catch all string buffer | |
char g_pN[128]; // a dedicated buffer to storing a players name | |
int g_client; // g_QDB client id | |
int g_target; // g_QDB player (human or bot) id | |
int g_lastid; // g_QDB client's last known bot id | |
int g_onteam = 1; // g_QDB client's team | |
char g_model[64]; // g_QDB client's model | |
char g_ghost[64]; // g_QDB client model backup (for activation) | |
bool g_queued = false; // g_QDB client's takeover state | |
float g_origin[3]; // g_QDB client's origin vector | |
bool g_inspec = false; // g_QDB check client's specator mode | |
char g_cisi[MAXPLAYERS + 1][64]; // g_QDB client Id to steam Id array | |
Handle g_AD; // Assistant Director Timer | |
char g_GameMode[16]; | |
bool g_IsVs = false; | |
bool g_IsCoop = false; | |
bool g_AssistedSpawning = false; | |
bool g_RemovedPlayers = false; | |
bool g_AddedPlayers = false; | |
bool g_ADFreeze = true; | |
int g_ADInterval; | |
ConVar g_cvLogLevel; | |
ConVar g_cvMinPlayers; | |
ConVar g_cvPrimaryWeapon; | |
ConVar g_cvSecondaryWeapon; | |
ConVar g_cvThrowable; | |
ConVar g_cvHealItem; | |
ConVar g_cvConsumable; | |
ConVar g_cvZoey; | |
ConVar g_cvExtraPlayers; | |
ConVar g_cvTankHealth; | |
ConVar g_cvTankChunkHp; | |
ConVar g_cvSpawnInterval; | |
ConVar g_cvMaxSI; | |
ConVar g_cvAutoHard; | |
ConVar g_cvJoinMenu; | |
ConVar g_cvTeamLimit; | |
ConVar g_cvOfferTakeover; | |
int g_LogLevel; | |
int g_MinPlayers; | |
char g_PrimaryWeapon[64]; | |
char g_SecondaryWeapon[64]; | |
char g_Throwable[64]; | |
char g_HealItem[64]; | |
char g_Consumable[64]; | |
int g_Zoey; | |
int g_ExtraPlayers; | |
int g_TankChunkHp; | |
int g_SpawnInterval; | |
int g_MaxSI; | |
int g_AutoHard; | |
int g_JoinMenu; | |
int g_TeamLimit; | |
int g_OfferTakeover; | |
public Plugin myinfo= { | |
name = "ABM", | |
author = "Victor \"NgBUCKWANGS\" Gonzalez", | |
description = "A 5+ Player Enhancement Plugin for L4D2", | |
version = PLUGIN_VERSION, | |
url = "https://gitlab.com/vbgunz/ABM" | |
} | |
public OnPluginStart() { | |
Echo(1, "OnPluginStart"); | |
g_GameData = LoadGameConfigFile("abm"); | |
if (g_GameData == null) { | |
SetFailState("[ABM] Game data missing!"); | |
} | |
HookEvent("player_first_spawn", OnSpawnHook); | |
HookEvent("player_death", OnDeathHook, EventHookMode_Pre); | |
HookEvent("player_disconnect", CleanQDBHook); | |
HookEvent("player_afk", GoIdleHook); | |
HookEvent("player_team", QTeamHook); | |
HookEvent("player_bot_replace", QAfkHook); | |
HookEvent("bot_player_replace", QBakHook); | |
HookEvent("player_activate", PlayerActivateHook, EventHookMode_Pre); | |
HookEvent("player_connect", PlayerActivateHook, EventHookMode_Pre); | |
HookEvent("round_end", RoundFreezeEndHook, EventHookMode_Pre); | |
HookEvent("mission_lost", RoundFreezeEndHook, EventHookMode_Pre); | |
HookEvent("round_freeze_end", RoundFreezeEndHook, EventHookMode_Pre); | |
HookEvent("map_transition", RoundFreezeEndHook, EventHookMode_Pre); | |
HookEvent("round_start", RoundStartHook, EventHookMode_Pre); | |
RegAdminCmd("abm", MainMenuCmd, ADMFLAG_GENERIC); | |
RegAdminCmd("abm-menu", MainMenuCmd, ADMFLAG_GENERIC, "Menu: (Main ABM menu)"); | |
RegAdminCmd("abm-join", SwitchTeamCmd, ADMFLAG_GENERIC, "Menu/Cmd: <TEAM> | <ID> <TEAM>"); | |
RegAdminCmd("abm-takeover", SwitchToBotCmd, ADMFLAG_GENERIC, "Menu/Cmd: <ID> | <ID1> <ID2>"); | |
RegAdminCmd("abm-respawn", RespawnClientCmd, ADMFLAG_GENERIC, "Menu/Cmd: <ID> [ID]"); | |
RegAdminCmd("abm-model", AssignModelCmd, ADMFLAG_GENERIC, "Menu/Cmd: <MODEL> | <MODEL> <ID>"); | |
RegAdminCmd("abm-strip", StripClientCmd, ADMFLAG_GENERIC, "Menu/Cmd: <ID> [SLOT]"); | |
RegAdminCmd("abm-teleport", TeleportClientCmd, ADMFLAG_GENERIC, "Menu/Cmd: <ID1> <ID2>"); | |
RegAdminCmd("abm-cycle", CycleBotsCmd, ADMFLAG_GENERIC, "Menu/Cmd: <TEAM> | <ID> <TEAM>"); | |
RegAdminCmd("abm-reset", ResetCmd, ADMFLAG_GENERIC, "Cmd: (Use only in case of emergency)"); | |
RegAdminCmd("abm-info", QuickClientPrintCmd, ADMFLAG_GENERIC, "Cmd: (Print some diagnostic information)"); | |
RegAdminCmd("abm-mk", MkBotsCmd, ADMFLAG_GENERIC, "Cmd: <N|-N> <TEAM>"); | |
RegAdminCmd("abm-rm", RmBotsCmd, ADMFLAG_GENERIC, "Cmd: <TEAM> | <N|-N> <TEAM>"); | |
RegConsoleCmd("takeover", SwitchToBotCmd, "Menu/Cmd: <ID> | <ID1> <ID2>"); | |
RegConsoleCmd("join", SwitchTeamCmd, "Menu/Cmd: <TEAM> | <ID> <TEAM>"); | |
g_OS = GetOS(); // 0: Linux 1: Windows | |
g_QDB = new StringMap(); | |
g_QRecord = new StringMap(); | |
g_Cvars = new StringMap(); | |
g_sQueue = new ArrayList(2); | |
g_iQueue = new ArrayList(2); | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
g_menuStack[i] = new ArrayStack(128); | |
} | |
// Register everyone that we can find | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (!GetQRecord(i)) { | |
if (SetQRecord(i) != -1) { | |
g_cisi[i] = g_QKey; | |
} | |
} | |
} | |
g_cvTankHealth = FindConVar("z_tank_health"); | |
FindConVar("mp_gamemode").GetString(g_GameMode, sizeof(g_GameMode)); | |
g_IsVs = (StrEqual(g_GameMode, "versus") || StrEqual(g_GameMode, "scavenge")); | |
g_IsCoop = StrEqual(g_GameMode, "coop"); | |
CreateConVar("abm_version", PLUGIN_VERSION, "ABM plugin version", FCVAR_DONTRECORD); | |
g_cvLogLevel = CreateConVar("abm_loglevel", "0", "Development logging level 0: Off, 4: Max"); | |
g_cvMinPlayers = CreateConVar("abm_minplayers", "4", "Pruning extra survivors stops at this size"); | |
g_cvPrimaryWeapon = CreateConVar("abm_primaryweapon", "", "5+ survivor primary weapon"); | |
g_cvSecondaryWeapon = CreateConVar("abm_secondaryweapon", "", "5+ survivor secondary weapon"); | |
g_cvThrowable = CreateConVar("abm_throwable", "", "5+ survivor throwable item"); | |
g_cvHealItem = CreateConVar("abm_healitem", "", "5+ survivor healing item"); | |
g_cvConsumable = CreateConVar("abm_consumable", "", "5+ survivor consumable item"); | |
g_cvExtraPlayers = CreateConVar("abm_extraplayers", "4", "Extra survivors to start the round with"); | |
g_cvTankChunkHp = CreateConVar("abm_tankchunkhp", "2500", "Health chunk per survivor on 5+ missions"); | |
g_cvSpawnInterval = CreateConVar("abm_spawninterval", "0", "SI full team spawn in (5 x N)"); | |
g_cvAutoHard = CreateConVar("abm_autohard", "2", "0: Off 1: Non-Vs > 4 2: Non-Vs >= 1"); | |
g_cvJoinMenu = CreateConVar("abm_joinmenu", "0", "0: Off 1: Admins only 2: Everyone"); | |
g_cvTeamLimit = CreateConVar("abm_teamlimit", "16", "Humans on team limit"); | |
g_cvOfferTakeover = CreateConVar("abm_offertakeover", "0", "0: Off 1: Survivors 2: Infected 3: All"); | |
g_cvMaxSI = FindConVar("z_max_player_zombies"); | |
SetConVarBounds(g_cvMaxSI, ConVarBound_Lower, true, 1.0); | |
SetConVarBounds(g_cvMaxSI, ConVarBound_Upper, true, 24.0); | |
switch(g_OS) { | |
case 0: Format(g_sB, sizeof(g_sB), "5"); | |
case 1: Format(g_sB, sizeof(g_sB), "1"); | |
default: PrintToChatAll("Zoey has gone Sarah Palin"); | |
} | |
g_cvZoey = CreateConVar("abm_zoey", g_sB, "0:Nick 1:Rochelle 2:Coach 3:Ellis 4:Bill 5:Zoey 6:Francis 7:Louis"); | |
HookConVarChange(g_cvLogLevel, UpdateConVarsHook); | |
HookConVarChange(g_cvMinPlayers, UpdateConVarsHook); | |
HookConVarChange(g_cvPrimaryWeapon, UpdateConVarsHook); | |
HookConVarChange(g_cvSecondaryWeapon, UpdateConVarsHook); | |
HookConVarChange(g_cvThrowable, UpdateConVarsHook); | |
HookConVarChange(g_cvHealItem, UpdateConVarsHook); | |
HookConVarChange(g_cvConsumable, UpdateConVarsHook); | |
HookConVarChange(g_cvExtraPlayers, UpdateConVarsHook); | |
HookConVarChange(g_cvTankChunkHp, UpdateConVarsHook); | |
HookConVarChange(g_cvSpawnInterval, UpdateConVarsHook); | |
HookConVarChange(g_cvZoey, UpdateConVarsHook); | |
HookConVarChange(g_cvAutoHard, UpdateConVarsHook); | |
HookConVarChange(g_cvJoinMenu, UpdateConVarsHook); | |
HookConVarChange(g_cvTeamLimit, UpdateConVarsHook); | |
HookConVarChange(g_cvOfferTakeover, UpdateConVarsHook); | |
UpdateConVarsHook(g_cvLogLevel, "0", "0"); | |
UpdateConVarsHook(g_cvMinPlayers, "4", "4"); | |
UpdateConVarsHook(g_cvPrimaryWeapon, "", ""); | |
UpdateConVarsHook(g_cvSecondaryWeapon, "", ""); | |
UpdateConVarsHook(g_cvThrowable, "", ""); | |
UpdateConVarsHook(g_cvHealItem, "", ""); | |
UpdateConVarsHook(g_cvConsumable, "", ""); | |
UpdateConVarsHook(g_cvExtraPlayers, "4", "4"); | |
UpdateConVarsHook(g_cvTankChunkHp, "2500", "2500"); | |
UpdateConVarsHook(g_cvSpawnInterval, "0", "0"); | |
UpdateConVarsHook(g_cvZoey, g_sB, g_sB); | |
UpdateConVarsHook(g_cvAutoHard, "2", "2"); | |
UpdateConVarsHook(g_cvJoinMenu, "0", "0"); | |
UpdateConVarsHook(g_cvTeamLimit, "16", "16"); | |
UpdateConVarsHook(g_cvOfferTakeover, "0", "0"); | |
// AutoExecConfig(false, "abm"); | |
StartAD(); | |
} | |
public OnEntityCreated(int ent, const char[] classname) { | |
Echo(1, "OnEntityCreated: %d %s", ent, classname); | |
if(classname[0] == 'f') { | |
bool gClip = !StrEqual(classname, "func_playerghostinfected_clip", false); | |
bool iClip = !StrEqual(classname, "func_playerinfected_clip", false); | |
if (!(gClip && iClip)) { | |
CreateTimer(1.0, KillEntTimer, EntIndexToEntRef(ent)); | |
} | |
} | |
} | |
public Action KillEntTimer(Handle timer, any ref) { | |
Echo(1, "KillEntTimer: %d", ref); | |
int ent = EntRefToEntIndex(ref); | |
if (ent != INVALID_ENT_REFERENCE || IsValidEntity(ent)) { | |
AcceptEntityInput(ent, "kill"); | |
} | |
return Plugin_Stop; | |
} | |
public Action L4D_OnGetScriptValueInt(const String:key[], &retVal) { | |
Echo(4, "L4D_OnGetScriptValueInt: %s, %d", key, retVal); | |
if (g_AutoHard > 0 && g_AutoHard!=3) { | |
int val = retVal; | |
if (StrEqual(key, "ShouldIgnoreClearStateForSpawn")) val = 0; | |
// else if (StrEqual(key, "AlwaysAllowWanderers")) val = 1; | |
// else if (StrEqual(key, "ClearedWandererRespawnChance")) val = 50; | |
else if (StrEqual(key, "EnforceFinaleNavSpawnRules")) val = 0; | |
else if (StrEqual(key, "DisallowThreatType")) val = 0; | |
else if (StrEqual(key, "ProhibitBosses")) val = 0; | |
else if (StrEqual(key, "MaxSpecials")) val = g_MaxSI-1>5?5:g_MaxSI-1; | |
else if (StrEqual(key, "DominatorLimit")) val = (g_MaxSI+3)/4; | |
else if (StrEqual(key, "BoomerLimit")) val = 4; | |
else if (StrEqual(key, "SmokerLimit")) val = 1; | |
else if (StrEqual(key, "HunterLimit")) val = 1; | |
else if (StrEqual(key, "ChargerLimit")) val = 1; | |
else if (StrEqual(key, "SpitterLimit")) val = 4; | |
else if (StrEqual(key, "JockeyLimit")) val = 1; | |
// else if (StrEqual(key, "RelaxMaxFlowTravel")) val = 1000; | |
else if (StrEqual(key, "ZombieDontClear")) val = 0; | |
//else if (StrEqual(key, "CommonLimit")) val = 30; | |
if (val != retVal) { | |
retVal = val; | |
return Plugin_Handled; | |
} | |
} | |
return Plugin_Continue; | |
} | |
public RoundFreezeEndHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(1, "RoundFreezeEndHook: %s", name); | |
if (g_ADFreeze) { | |
return; | |
} | |
StopAD(); | |
StringMapSnapshot keys = g_QDB.Snapshot(); | |
g_iQueue.Clear(); | |
if (!g_IsVs) { | |
for (int i ; i < keys.Length ; i++) { | |
keys.GetKey(i, g_sB, sizeof(g_sB)); | |
g_QDB.GetValue(g_sB, g_QRecord); | |
g_QRecord.GetValue("onteam", g_onteam); | |
g_QRecord.GetValue("client", g_client); | |
g_QRecord.GetString("model", g_model, sizeof(g_model)); | |
g_QRecord.SetString("ghost", g_model, true); | |
if (g_onteam == 3) { | |
SwitchToSpec(g_client); | |
g_QRecord.SetValue("queued", true, true); | |
g_QRecord.SetValue("inspec", false, true); | |
} | |
} | |
} | |
delete keys; | |
} | |
public PlayerActivateHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(1, "PlayerActivateHook: %s", name); | |
int userid = GetEventInt(event, "userid"); | |
int client = GetClientOfUserId(userid); | |
PlayerActivate(client); | |
} | |
PlayerActivate(int client) { | |
Echo(1, "PlayerActivate: %d", client); | |
if (GetQRecord(client)) { | |
StartAD(); | |
AssignModel(client, g_ghost); | |
if (!g_IsVs) { | |
if (g_onteam == 3) { | |
SwitchTeam(client, 3); | |
} | |
} | |
} | |
} | |
public RoundStartHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(1, "RoundStartHook: %s", name); | |
StartAD(); | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (GetQRecord(i)) { | |
if (!g_IsVs && g_onteam == 3) { | |
SwitchTeam(i, 3); | |
} | |
} | |
} | |
} | |
bool StopAD() { | |
Echo(1, "StopAD"); | |
if (g_AD != null) { | |
g_ADFreeze = true; | |
g_AssistedSpawning = false; | |
g_RemovedPlayers = false; | |
g_AddedPlayers = false; | |
g_ADInterval = 0; | |
delete g_AD; | |
g_AD = null; | |
} | |
return g_AD == null; | |
} | |
bool StartAD() { | |
Echo(1, "StartAD"); | |
if (g_AD == null) { | |
g_ADFreeze = true; | |
g_AssistedSpawning = false; | |
g_RemovedPlayers = false; | |
g_AddedPlayers = false; | |
g_ADInterval = 0; | |
g_AD = CreateTimer( | |
5.0, ADTimer, _, TIMER_REPEAT | |
); | |
CreateTimer(5.0, PrintWaitingMessageTimer); | |
} | |
return g_AD != null; | |
} | |
public Action ADTimer(Handle timer) { | |
Echo(3, "ADTimer"); | |
if (g_ADFreeze) { | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (IsClientConnected(i)) { | |
if (!IsClientInGame(i)) { | |
Echo(1, " -- ADTimer: Client %d isn't loaded in yet.", i); | |
return Plugin_Continue; | |
} | |
else { | |
if (!g_IsVs) { | |
if (GetQRecord(i)) { | |
if (g_onteam == 3 && g_queued) { | |
SwitchTeam(i, 3); | |
} | |
} | |
} | |
} | |
} | |
} | |
Echo(1, " -- ADTimer: All clients are loaded in. Assisting."); | |
g_ADFreeze = false; | |
} | |
if (!g_RemovedPlayers && CountTeamMates(2) >= 1) { | |
RmBots((g_MinPlayers + g_ExtraPlayers) * -1, 2); | |
g_RemovedPlayers = true; | |
} | |
if (g_RemovedPlayers) { | |
if (!g_AddedPlayers && CountTeamMates(2) >= 1) { | |
MkBots((g_MinPlayers + g_ExtraPlayers) * -1, 2); | |
g_AddedPlayers = true; | |
} | |
} | |
g_ADInterval++; | |
int teamSize = CountTeamMates(2); | |
if (teamSize == 0) { | |
g_ADInterval = 0; | |
return Plugin_Continue; | |
} | |
static lastSize; | |
bool autoWave; | |
if (g_IsCoop) { | |
if (lastSize != teamSize) { | |
lastSize = teamSize; | |
AutoSetTankHp(); | |
} | |
} | |
// Auto difficulty here will not spawn SI in competitive modes. | |
// SI are unlocked (without spawn) see L4D_OnGetScriptValueInt. | |
switch (g_IsVs) { | |
case 1: autoWave = false; | |
case 0: autoWave = g_AutoHard == 2 || teamSize > 4 && g_AutoHard == 1; | |
} | |
if (autoWave || g_AssistedSpawning) { | |
if (g_SpawnInterval > 0) { | |
if (g_ADInterval >= g_SpawnInterval) { | |
if (g_ADInterval % g_SpawnInterval == 0) { | |
Echo(1, " -- Assisting SI %d: Matching Full Team", g_ADInterval); | |
MkBots(teamSize * -1, 3); | |
} | |
else if (g_ADInterval % (g_SpawnInterval / 2) == 0) { | |
Echo(1, " -- Assisting SI %d: Matching Half Team", g_ADInterval); | |
MkBots((teamSize / 2) * -1, 3); | |
} | |
} | |
} | |
} | |
int onteam; | |
float nTakeover = 0.1; | |
g_AssistedSpawning = false; | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (GetQRecord(i)) { | |
if (g_onteam == 3) { | |
if (!g_IsVs) { | |
g_AssistedSpawning = true; | |
if (!IsPlayerAlive(i) && !g_queued && !g_inspec) { | |
g_QRecord.SetValue("queued", true, true); | |
QueueUp(i, 3); | |
} | |
} | |
continue; | |
} | |
onteam = GetClientTeam(i); | |
if (onteam == 3) { | |
continue; | |
} | |
if (!g_inspec && onteam <= 1) { | |
CreateTimer(nTakeover, TakeoverTimer, i); | |
nTakeover += 0.1; | |
} | |
} | |
} | |
return Plugin_Continue; | |
} | |
public UpdateConVarsHook(Handle convar, const char[] oldCv, const char[] newCv) { | |
GetConVarName(convar, g_sB, sizeof(g_sB)); | |
Echo(1, "UpdateConVarsHook: %s %s %s", g_sB, oldCv, newCv); | |
char name[32]; | |
char value[32]; | |
Format(name, sizeof(name), g_sB); | |
Format(value, sizeof(value), "%s", newCv); | |
if (StrContains(newCv, "-l") == 0) { | |
ReplaceString(value, sizeof(value), "-l", ""); | |
g_Cvars.SetString(name, value, true); | |
} | |
else if (StrContains(newCv, "-u") == 0) { | |
ReplaceString(value, sizeof(value), "-u", ""); | |
g_Cvars.Remove(name); | |
} | |
g_Cvars.GetString(name, value, sizeof(value)); | |
TrimString(value); | |
if (value[0] == EOS) { | |
Format(value, sizeof(value), oldCv); | |
} | |
SetConVarString(convar, value); | |
if (StrEqual(name, "abm_loglevel")) { | |
g_LogLevel = GetConVarInt(g_cvLogLevel); | |
} | |
else if (StrEqual(name, "abm_extraplayers")) { | |
g_ExtraPlayers = GetConVarInt(g_cvExtraPlayers); | |
} | |
else if (StrEqual(name, "abm_tankchunkhp")) { | |
g_TankChunkHp = GetConVarInt(g_cvTankChunkHp); | |
AutoSetTankHp(); | |
} | |
else if (StrEqual(name, "abm_spawninterval")) { | |
g_SpawnInterval = GetConVarInt(g_cvSpawnInterval); | |
} | |
else if (StrEqual(name, "abm_primaryweapon")) { | |
GetConVarString(g_cvPrimaryWeapon, g_PrimaryWeapon, sizeof(g_PrimaryWeapon)); | |
} | |
else if (StrEqual(name, "abm_secondaryweapon")) { | |
GetConVarString(g_cvSecondaryWeapon, g_SecondaryWeapon, sizeof(g_SecondaryWeapon)); | |
} | |
else if (StrEqual(name, "abm_throwable")) { | |
GetConVarString(g_cvThrowable, g_Throwable, sizeof(g_Throwable)); | |
} | |
else if (StrEqual(name, "abm_healitem")) { | |
GetConVarString(g_cvHealItem, g_HealItem, sizeof(g_HealItem)); | |
} | |
else if (StrEqual(name, "abm_consumable")) { | |
GetConVarString(g_cvConsumable, g_Consumable, sizeof(g_Consumable)); | |
} | |
else if (StrEqual(name, "abm_minplayers")) { | |
g_MinPlayers = GetConVarInt(g_cvMinPlayers); | |
} | |
else if (StrEqual(name, "abm_autohard")) { | |
g_AutoHard = GetConVarInt(g_cvAutoHard); | |
AutoSetTankHp(); | |
} | |
else if (StrEqual(name, "abm_joinmenu")) { | |
g_JoinMenu = GetConVarInt(g_cvJoinMenu); | |
} | |
else if (StrEqual(name, "abm_teamlimit")) { | |
g_TeamLimit = GetConVarInt(g_cvTeamLimit); | |
} | |
else if (StrEqual(name, "abm_offertakeover")) { | |
g_OfferTakeover = GetConVarInt(g_cvOfferTakeover); | |
} | |
switch(g_OS) { // Zoey hates Windows :'( | |
case 0: g_Zoey = 5; | |
default: g_Zoey = GetConVarInt(g_cvZoey); | |
} | |
} | |
AutoSetTankHp() { | |
Echo(1, "AutoSetTankHp"); | |
int tankHp; | |
int teamSize = CountTeamMates(2); | |
if (teamSize > 4 || g_AutoHard == 2 || g_AutoHard == 3) { | |
tankHp = teamSize * g_TankChunkHp; | |
} | |
if (g_AutoHard == 0 || tankHp == 0) { | |
GetConVarDefault(g_cvTankHealth, g_sB, sizeof(g_sB)); | |
tankHp = StringToInt(g_sB); | |
} | |
SetConVarInt(g_cvTankHealth, tankHp); | |
} | |
public OnConfigsExecuted() { | |
Echo(1, "OnConfigsExecuted"); | |
PrecacheModels(); | |
} | |
public OnClientPostAdminCheck(int client) { | |
Echo(1, "OnClientPostAdminCheck: %d", client); | |
if (!GetQRecord(client)) { | |
if (SetQRecord(client) >= 0) { | |
g_cisi[client] = g_QKey; | |
Echo(0, "AUTH ID: %s, ADDED TO QDB.", g_QKey); | |
if (g_JoinMenu == 2 || g_JoinMenu == 1 && IsAdmin(client)) { | |
GoIdle(client, 1); | |
menuArg0 = client; | |
SwitchTeamHandler(client, 1); | |
} | |
else if (CountTeamMates(2) >= 1) { | |
CreateTimer(0.1, TakeoverTimer, client); | |
} | |
} | |
} | |
} | |
public GoIdleHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(1, "GoIdleHook: %s", name); | |
int player = GetEventInt(event, "player"); | |
int client = GetClientOfUserId(player); | |
if (GetQRecord(client)) { | |
switch (g_onteam) { | |
case 2: GoIdle(client); | |
case 3: SwitchTeam(client, 3); | |
} | |
} | |
} | |
GoIdle(int client, onteam=0) { | |
Echo(1, "GoIdle: %d %d", client, onteam); | |
if (GetQRecord(client)) { | |
int spec_target; | |
if (g_onteam == 2) { | |
SwitchToSpec(client); | |
SetHumanSpecSig(g_target, client); | |
if (onteam == 1) { | |
SwitchToSpec(client); | |
Unqueue(client); | |
} | |
AssignModel(g_target, g_model); | |
} | |
else { | |
SwitchToSpec(client); | |
} | |
switch (IsClientValid(g_target) && IsFakeClient(g_target)) { | |
case 1: spec_target = g_target; | |
case 0: spec_target = GetSafeSurvivor(client); | |
} | |
if (IsClientValid(spec_target)) { | |
SetEntPropEnt(client, Prop_Send, "m_hObserverTarget", spec_target); | |
SetEntProp(client, Prop_Send, "m_iObserverMode", 5); | |
} | |
} | |
} | |
public CleanQDBHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(1, "CleanQDBHook: %s", name); | |
int userid = GetEventInt(event, "userid"); | |
int client = GetClientOfUserId(userid); | |
RemoveQDBKey(client); | |
} | |
RemoveQDBKey(int client) { | |
Echo(1, "RemoveQDBKey: %d", client); | |
// during map change, GetQRecord is not reliable :'( | |
Format(g_sB, sizeof(g_sB), "%s", g_cisi[client]); | |
if (g_QDB.Remove(g_sB)) { | |
g_cisi[client] = ""; | |
Echo(0, "AUTH ID: %s, REMOVED FROM QDB.", g_sB); | |
int survivors = CountTeamMates(2); | |
if (survivors > (g_MinPlayers + g_ExtraPlayers)) { | |
CreateTimer(1.0, RmBotsTimer, 1); | |
} | |
} | |
} | |
public Action RmBotsTimer(Handle timer, any asmany) { | |
Echo(3, "RmBotsTimer: %d", asmany); | |
if (!g_IsVs) { | |
RmBots(asmany, 2); | |
} | |
} | |
bool IsAdmin(int client) { | |
Echo(1, "IsAdmin: %d", client); | |
return CheckCommandAccess( | |
client, "generic_admin", ADMFLAG_GENERIC, false | |
); | |
} | |
bool IsClientValid(int client) { | |
Echo(3, "IsClientValid: %d", client); | |
if (client >= 1 && client <= MaxClients) { | |
if (IsClientConnected(client)) { | |
if (IsClientInGame(client)) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
bool CanClientTarget(int client, int target) { | |
Echo(1, "CanClientTarget: %d %d", client, target); | |
if (client == target) { | |
return true; | |
} | |
else if (!IsClientValid(client) || !IsClientValid(target)) { | |
return false; | |
} | |
else if (IsFakeClient(target)) { | |
int manager = GetClientManager(target); | |
if (manager != -1) { | |
if (manager == 0) { | |
return true; | |
} | |
else { | |
return CanClientTarget(client, manager); | |
} | |
} | |
} | |
return CanUserTarget(client, target); | |
} | |
int GetPlayClient(int client) { | |
Echo(2, "GetPlayClient: %d", client); | |
if (GetQRecord(client)) { | |
return g_target; | |
} | |
else if (IsClientValid(client)) { | |
return client; | |
} | |
return -1; | |
} | |
int ClientHomeTeam(int client) { | |
Echo(1, "ClientHomeTeam: %d", client); | |
if (GetQRecord(client)) { | |
return g_onteam; | |
} | |
else if (IsClientValid(client)) { | |
return GetClientTeam(client); | |
} | |
return -1; | |
} | |
// ================================================================== // | |
// g_QDB MANAGEMENT | |
// ================================================================== // | |
bool SetQKey(int client) { | |
Echo(2, "SetQKey: %d", client); | |
if (IsClientValid(client) && !IsFakeClient(client)) { | |
if (GetClientAuthId(client, AuthId_Steam2, g_QKey, sizeof(g_QKey), true)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
bool GetQRecord(int client) { | |
Echo(2, "GetQRecord: %d", client); | |
if (SetQKey(client)) { | |
if (g_QDB.GetValue(g_QKey, g_QRecord)) { | |
if (IsClientValid(client) && IsPlayerAlive(client)) { | |
GetClientAbsOrigin(client, g_origin); | |
g_QRecord.SetArray("origin", g_origin, sizeof(g_origin), true); | |
} | |
g_QRecord.GetValue("client", g_client); | |
g_QRecord.GetValue("target", g_target); | |
g_QRecord.GetValue("lastid", g_lastid); | |
g_QRecord.GetValue("onteam", g_onteam); | |
g_QRecord.GetValue("queued", g_queued); | |
g_QRecord.GetValue("inspec", g_inspec); | |
if (GetClientTeam(client) == 2) { | |
int i = GetClientModelIndex(client); | |
if (i >= 0) { | |
Format(g_model, sizeof(g_model), "%s", g_SurvivorNames[i]); | |
g_QRecord.SetString("model", g_model, true); | |
} | |
} | |
g_QRecord.GetString("model", g_model, sizeof(g_model)); | |
g_QRecord.GetString("ghost", g_ghost, sizeof(g_ghost)); | |
return true; | |
} | |
} | |
return false; | |
} | |
bool NewQRecord(int client) { | |
Echo(2, "NewQRecord: %d", client); | |
g_QRecord = new StringMap(); | |
GetClientAbsOrigin(client, g_origin); | |
g_QRecord.SetArray("origin", g_origin, sizeof(g_origin), true); | |
g_QRecord.SetValue("client", client, true); | |
g_QRecord.SetValue("target", client, true); | |
g_QRecord.SetValue("lastid", client, true); | |
g_QRecord.SetValue("onteam", GetClientTeam(client), true); | |
g_QRecord.SetValue("queued", false, true); | |
g_QRecord.SetValue("inspec", false, true); | |
g_QRecord.SetString("model", "", true); | |
g_QRecord.SetString("ghost", "", true); | |
return true; | |
} | |
int SetQRecord(int client) { | |
Echo(2, "SetQRecord: %d", client); | |
int result = -1; | |
if (SetQKey(client)) { | |
if (g_QDB.GetValue(g_QKey, g_QRecord)) { | |
result = 0; | |
} | |
else if (NewQRecord(client)) { | |
g_QDB.SetValue(g_QKey, g_QRecord, true); | |
result = 1; | |
} | |
GetQRecord(client); | |
} | |
return result; | |
} | |
QueueUp(int client, int onteam) { | |
Echo(1, "QueueUp: %d %d", client, onteam); | |
if (onteam >= 2 && GetQRecord(client)) { | |
Unqueue(client); | |
switch (onteam) { | |
case 2: g_sQueue.Push(client); | |
case 3: g_iQueue.Push(client); | |
} | |
g_QRecord.SetValue("queued", true, true); | |
} | |
} | |
Unqueue(int client) { | |
Echo(1, "Unqueue: %d", client); | |
if (GetQRecord(client)) { | |
g_QRecord.SetValue("queued", false, true); | |
int iLength = g_iQueue.Length; | |
int sLength = g_sQueue.Length; | |
if (iLength > 0) { | |
for (int i = iLength - 1 ; i > -1 ; i--) { | |
if (g_iQueue.Get(i) == client) { | |
g_iQueue.Erase(i); | |
} | |
} | |
} | |
if (sLength > 0) { | |
for (int i = sLength - 1 ; i > -1 ; i--) { | |
if (g_sQueue.Get(i) == client) { | |
g_sQueue.Erase(i); | |
} | |
} | |
} | |
} | |
} | |
public OnSpawnHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(1, "OnSpawnHook: %s", name); | |
int userid = GetEventInt(event, "userid"); | |
int target = GetClientOfUserId(userid); | |
GetClientName(target, g_pN, sizeof(g_pN)); | |
int flag1 = StrContains(g_pN, "SPECIAL"); | |
int flag2 = StrContains(g_pN, "SURVIVOR"); | |
if (flag1 >= 0 || flag2 >= 0) { | |
return; | |
} | |
int client; | |
int onteam = GetClientTeam(target); | |
if (onteam == 3) { | |
if (!g_IsVs) { | |
if (g_AssistedSpawning) { | |
int zClass = GetEntProp(target, Prop_Send, "m_zombieClass"); | |
if (zClass == 8) { | |
int j = 1; | |
static i = 1; | |
for ( ; i <= MaxClients + 1 ; i++) { | |
if (i == MaxClients + 1) { | |
i = 1; | |
} | |
if (GetQRecord(i) && g_onteam == 3 && !g_inspec) { | |
if (GetEntProp(i, Prop_Send, "m_zombieClass") != 8) { | |
client = i; | |
i++; | |
break; | |
} | |
if (j++ >= MaxClients) { | |
i++; | |
break; | |
} | |
} | |
} | |
switch (IsClientValid(client)) { | |
case 1: SwitchToBot(client, target); | |
case 0: CreateTimer(1.0, TankAssistTimer, target, TIMER_REPEAT); | |
} | |
} | |
} | |
if (g_iQueue.Length > 0) { | |
SwitchToBot(g_iQueue.Get(0), target); | |
return; | |
} | |
} | |
} | |
if (onteam == 2) { | |
CreateTimer(0.2, AutoModelTimer, target); | |
CreateTimer(0.4, OnSpawnHookTimer, target); | |
} | |
} | |
public Action TankAssistTimer(Handle timer, any client) { | |
Echo(3, "TankAssistTimer: %d", client); | |
/* | |
* Human players on the infected team in modes that do not officially | |
* support them, can get Tanks stuck in "stasis" until they die. This | |
* function works around the issue by watching Tanks for movement. If | |
* a Tank does not move in 11 seconds, it is replaced with another. | |
*/ | |
float origin[3]; | |
static const float nullOrigin[3]; | |
static times[MAXPLAYERS + 1] = {11, ...}; | |
static float origins[MAXPLAYERS + 1][3]; | |
static i; | |
if (IsClientValid(client)) { | |
i = times[client]--; | |
if (i == 11) { | |
GetClientAbsOrigin(client, origins[client]); | |
return Plugin_Continue; | |
} | |
else if (i >= 0) { | |
GetClientAbsOrigin(client, origin); | |
if (origin[0] == origins[client][0]) { | |
if (i == 0) { | |
TeleportEntity(client, nullOrigin, NULL_VECTOR, NULL_VECTOR); | |
ForcePlayerSuicide(client); | |
AddInfected(0, "tank"); | |
} | |
return Plugin_Continue; | |
} | |
} | |
} | |
i = times[client] = 11; | |
return Plugin_Stop; | |
} | |
public Action ForceSpawnTimer(Handle timer, any client) { | |
Echo(3, "ForceSpawnTimer: %d", client); | |
static times[MAXPLAYERS + 1] = {20, ...}; | |
static i; | |
if (IsClientValid(client)) { | |
i = times[client]--; | |
if (GetEntProp(client, Prop_Send, "m_isGhost") == 1) { | |
if (i >= 1) { | |
PrintHintText(client, "FORCING SPAWN IN: %d", i); | |
return Plugin_Continue; | |
} | |
if (GetEntProp(client, Prop_Send, "m_ghostSpawnState") <= 2) { | |
SetEntProp(client, Prop_Send, "m_isGhost", 0); | |
} | |
return Plugin_Continue; | |
} | |
if (GetClientTeam(client) == 3) { | |
PrintHintText(client, "KILL ALL HUMANS"); | |
} | |
} | |
i = times[client] = 20; | |
return Plugin_Stop; | |
} | |
public Action OnSpawnHookTimer(Handle timer, any target) { | |
Echo(1, "OnSpawnHookTimer: %d", target); | |
if (g_sQueue.Length > 0) { | |
SwitchToBot(g_sQueue.Get(0), target); | |
return; | |
} | |
} | |
public OnDeathHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(3, "OnDeathHook: %s", name); | |
int userid = GetEventInt(event, "userid"); | |
int client = GetClientOfUserId(userid); | |
if (GetQRecord(client)) { | |
GetClientAbsOrigin(client, g_origin); | |
g_QRecord.SetValue("target", client, true); | |
g_QRecord.SetArray("origin", g_origin, sizeof(g_origin), true); | |
bool offerTakeover; | |
switch (g_onteam) { | |
case 3: { | |
if (!g_IsVs) { | |
switch (g_OfferTakeover) { | |
case 2, 3: { | |
QueueUp(client, 3); | |
GoIdle(client, 1); | |
offerTakeover = true; | |
} | |
default: SwitchTeam(client, 3); | |
} | |
} | |
} | |
case 2: { | |
switch (g_OfferTakeover) { | |
case 1, 3: offerTakeover = true; | |
} | |
} | |
} | |
if (offerTakeover) { | |
GenericMenuCleaner(client); | |
menuArg0 = client; | |
SwitchToBotHandler(client, 1); | |
} | |
} | |
} | |
public QTeamHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(1, "QTeamHook: %s", name); | |
int userid = GetEventInt(event, "userid"); | |
int client = GetClientOfUserId(userid); | |
int onteam = GetEventInt(event, "team"); | |
if (GetQRecord(client)) { | |
if (onteam >= 2) { | |
g_QRecord.SetValue("inspec", false, true); | |
g_QRecord.SetValue("target", client, true); | |
g_QRecord.SetValue("onteam", onteam, true); | |
g_QRecord.SetValue("queued", false, true); | |
if (onteam == 3) { | |
g_QRecord.SetString("model", "", true); | |
return; | |
} | |
} | |
if (onteam <= 1) { // cycling requires 0.2 or higher? | |
CreateTimer(0.2, QTeamHookTimer, client); | |
} | |
} | |
} | |
public Action PrintWaitingMessageTimer(Handle timer) { | |
if (g_ADFreeze) { | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (GetClientTeam(i) <= 1) { | |
PrintToChat(i, "Awaiting all clients ready for bots creation, please be patient..."); | |
CreateTimer(5.0, PrintWaitingMessageTimer, i); | |
} | |
} | |
} | |
} | |
public Action QTeamHookTimer(Handle timer, any client) { | |
Echo(1, "QTeamHookTimer: %d", client); | |
if (GetQRecord(client) && !g_inspec) { | |
if (g_onteam == 2) { | |
if (IsClientValid(g_target) && g_target != client) { | |
SetHumanSpecSig(g_target, client); | |
} | |
} | |
} | |
} | |
public QAfkHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(1, "QAfkHook: %s", name); | |
int client = GetClientOfUserId(GetEventInt(event, "player")); | |
int target = GetClientOfUserId(GetEventInt(event, "bot")); | |
int clientTeam = GetClientTeam(client); | |
int targetTeam = GetClientTeam(target); | |
if (GetQRecord(client)) { | |
int onteam = GetClientTeam(client); | |
if (onteam == 2) { | |
g_QRecord.SetValue("target", target, true); | |
AssignModel(target, g_model); | |
} | |
} | |
if (targetTeam == 2 && IsClientValid(client)) { | |
if (IsClientInKickQueue(client)) { | |
if (client && target && clientTeam == targetTeam) { | |
int safeClient = GetSafeSurvivor(target); | |
RespawnClient(target, safeClient); | |
} | |
} | |
} | |
} | |
public QBakHook(Handle event, const char[] name, bool dontBroadcast) { | |
Echo(1, "QBakHook: %s", name); | |
int client = GetClientOfUserId(GetEventInt(event, "player")); | |
int target = GetClientOfUserId(GetEventInt(event, "bot")); | |
if (GetQRecord(client)) { | |
if (g_target != target) { | |
g_QRecord.SetValue("lastid", target); | |
g_QRecord.SetValue("target", client); | |
GetClientName(target, g_pN, sizeof(g_pN)); | |
int i = GetModelIndexByName(g_pN); | |
if (i != -1) { | |
Format(g_model, sizeof(g_model), "%s", g_SurvivorNames[i]); | |
g_QRecord.SetString("model", g_model, true); | |
} | |
} | |
if (GetClientTeam(client) == 2) { | |
AssignModel(client, g_model); | |
} | |
} | |
} | |
// ================================================================== // | |
// UNORGANIZED AS OF YET | |
// ================================================================== // | |
StripClient(int client) { | |
Echo(1, "StripClient: %d", client); | |
if (IsClientValid(client)) { | |
if (GetClientTeam(client) == 2) { | |
for (int i = 4 ; i >= 0 ; i--) { | |
StripClientSlot(client, i); | |
} | |
} | |
} | |
} | |
StripClientSlot(int client, int slot) { | |
Echo(1, "StripClientSlot: %d %d", client, slot); | |
client = GetPlayClient(client); | |
if (IsClientValid(client)) { | |
if (GetClientTeam(client) == 2) { | |
int ent = GetPlayerWeaponSlot(client, slot); | |
if (IsValidEntity(ent)) { | |
RemovePlayerItem(client, ent); | |
RemoveEdict(ent); | |
} | |
} | |
} | |
} | |
RespawnClient(int client, int target=0) { | |
Echo(1, "RespawnClient: %d %d", client, target); | |
if (!IsClientValid(client)) { | |
return; | |
} | |
else if (GetQRecord(client)) { | |
if (g_onteam == 3) { | |
Takeover(client, 3); | |
return; | |
} | |
} | |
float origin[3]; | |
client = GetPlayClient(client); | |
target = GetPlayClient(target); | |
if (!IsClientValid(target)) { | |
target = client; | |
} | |
RoundRespawnSig(client); | |
GetClientAbsOrigin(target, origin); | |
QuickCheat(client, "give", g_PrimaryWeapon); | |
QuickCheat(client, "give", g_SecondaryWeapon); | |
QuickCheat(client, "give", g_Throwable); | |
QuickCheat(client, "give", g_HealItem); | |
QuickCheat(client, "give", g_Consumable); | |
TeleportEntity(client, origin, NULL_VECTOR, NULL_VECTOR); | |
} | |
TeleportClient(int client, int target) { | |
Echo(1, "TeleportClient: %d %d", client, target); | |
float origin[3]; | |
client = GetPlayClient(client); | |
target = GetPlayClient(target); | |
if (IsClientValid(client) && IsClientValid(target)) { | |
GetClientAbsOrigin(target, origin); | |
TeleportEntity(client, origin, NULL_VECTOR, NULL_VECTOR); | |
} | |
} | |
int GetSafeSurvivor(int client) { | |
Echo(1, "GetSafeSurvivor: %d", client); | |
int last_survivor; | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (IsClientValid(i) && i != client) { | |
if (IsPlayerAlive(i) && GetClientTeam(i) == 2) { | |
last_survivor = i; | |
if (GetEntProp(i, Prop_Send, "m_isHangingFromLedge") == 0) { | |
return i; | |
} | |
} | |
} | |
} | |
return last_survivor; | |
} | |
bool AddSurvivor() { | |
Echo(1, "AddSurvivor"); | |
bool result = false; | |
int survivor = CreateFakeClient("SURVIVOR"); | |
if (IsClientValid(survivor)) { | |
if (DispatchKeyValue(survivor, "classname", "SurvivorBot")) { | |
ChangeClientTeam(survivor, 2); | |
if (DispatchSpawn(survivor)) { | |
KickClient(survivor); | |
result = true; | |
} | |
} | |
} | |
return result; | |
} | |
GhostsModeProtector(int state) { | |
Echo(1, "GhostsModeProtector: %d", state); | |
// CAREFUL: 0 starts this function and you must close it with 1 or | |
// risk breaking things. Close this with 1 immediately when done. | |
// e.g., | |
// GhostsModeProtector(0); | |
// z_spawn_old tank auto; | |
// GhostsModeProtector(1); | |
if (CountTeamMates(3, 1) == 0) { | |
return; | |
} | |
static ghosts[MAXPLAYERS + 1]; | |
switch (state) { | |
case 0: { | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (GetQRecord(i) && g_onteam == 3) { | |
if (GetEntProp(i, Prop_Send, "m_isGhost") == 1) { | |
SetEntProp(i, Prop_Send, "m_isGhost", 0); | |
ghosts[i] = 1; | |
} | |
} | |
} | |
} | |
case 1: { | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (ghosts[i] == 1) { | |
SetEntProp(i, Prop_Send, "m_isGhost", 1); | |
ghosts[i] = 0; | |
} | |
} | |
} | |
} | |
} | |
CleanSIName(char model[32], bool randomize=true) { | |
Echo(1, "CleanSIName: %s %d", model, randomize); | |
int i = GetModelIndexByName(model, 3); | |
static char infected[6][] = {"Boomer", "Smoker", "Hunter", "Spitter", "Jockey", "Charger"}; | |
switch (model[0] != EOS && i >= 0) { | |
case 1: { | |
model = g_InfectedNames[i]; | |
} | |
default: { | |
if (randomize) { | |
i = GetRandomInt(0, sizeof(infected) - 1); | |
model = infected[i]; | |
} | |
else { | |
model = ""; | |
} | |
} | |
} | |
} | |
bool AddInfected(int version=0, char model[32]="") { | |
Echo(1, "AddInfected: %d %s", version, model); | |
// GetEntProp(i, Prop_Send, "m_ghostSpawnState"); | |
// considering above in spawning all with z_spawn | |
bool result = false; | |
char cmd[12]; | |
float i[3]; | |
CleanSIName(model); | |
int special = CreateFakeClient("SPECIAL"); | |
if (IsClientValid(special)) { | |
switch (version) { | |
case 0: cmd = "z_spawn_old"; | |
case 1: cmd = "z_spawn"; | |
} | |
ChangeClientTeam(special, 3); | |
Format(g_sB, sizeof(g_sB), "%s auto area", model); | |
// if (!StrEqual(cmd, "z_spawn")) { | |
// for (int j = 1 ; j <= MaxClients ; j++) { | |
// if (IsClientValid(j) && GetClientTeam(j) == 3 && !IsFakeClient(j)) { | |
// if (GetEntProp(j, Prop_Send, "m_ghostSpawnState") <= 2) { | |
// GetClientAbsOrigin(j, i); | |
// cmd = "z_spawn"; | |
// break; | |
// } | |
// } | |
// } | |
// } | |
GhostsModeProtector(0); | |
QuickCheat(special, cmd, g_sB); | |
KickClient(special); | |
GhostsModeProtector(1); | |
// use z_spawn for humans that request SI | |
// for all others, always use z_spawn_old | |
if (StrEqual(cmd, "z_spawn")) { | |
TeleportEntity(special, i, i, i); | |
} | |
result = true; | |
} | |
return result; | |
} | |
SwitchToSpec(int client, int onteam=1) { | |
Echo(1, "SwitchToSpectator: %d %d", client, onteam); | |
if (GetQRecord(client)) { | |
g_QRecord.SetValue("inspec", true, true); | |
ChangeClientTeam(client, onteam); | |
if (client != g_target) { | |
SetEntProp(g_target, Prop_Send, "m_humanSpectatorUserID", 0); | |
} | |
} | |
} | |
QuickCheat(int client, char [] cmd, char [] arg) { | |
Echo(1, "QuickCheat: %d %s %s", client, cmd, arg); | |
int flags = GetCommandFlags(cmd); | |
SetCommandFlags(cmd, flags & ~FCVAR_CHEAT); | |
FakeClientCommand(client, "%s %s", cmd, arg); | |
SetCommandFlags(cmd, flags); | |
} | |
SwitchToBot(int client, int bot, bool si_ghost=true) { | |
Echo(1, "SwitchToBot: %d %d %d", client, bot, si_ghost); | |
if (client != bot && IsClientValid(bot)) { | |
switch (GetClientTeam(bot)) { | |
case 2: TakeoverBotSig(client, bot); | |
case 3: TakeoverZombieBotSig(client, bot, si_ghost); | |
} | |
} | |
} | |
Takeover(int client, int onteam) { | |
Echo(1, "Takeover: %d %d", client, onteam); | |
if (GetQRecord(client)) { | |
if (IsClientValid(g_target) && IsFakeClient(g_target)) { | |
if (client != g_target && GetClientTeam(g_target) == onteam) { | |
SwitchToBot(client, g_target); | |
return; | |
} | |
} | |
g_QRecord.SetValue("target", client, true); | |
g_QRecord.SetValue("inspec", false, true); | |
g_QRecord.SetValue("onteam", onteam, true); | |
g_QRecord.SetValue("queued", true, true); | |
int nextBot; | |
nextBot = GetNextBot(onteam); | |
if (nextBot >= 1) { | |
SwitchToBot(client, nextBot); | |
return; | |
} | |
switch (onteam) { | |
case 2: { | |
QueueUp(client, 2); | |
AddSurvivor(); | |
} | |
case 3: { | |
QueueUp(client, 3); | |
AddInfected(); | |
} | |
} | |
} | |
} | |
public Action TakeoverTimer(Handle timer, any client) { | |
Echo(3, "TakeoverTimer: %d", client); | |
if (CountTeamMates(2) <= 0) { | |
return Plugin_Handled; | |
} | |
static team2; | |
static team3; | |
static teamX; | |
if (GetQRecord(client)) { | |
if (GetClientTeam(client) >= 2) { | |
return Plugin_Handled; | |
} | |
teamX = 2; | |
if (g_onteam == 3) { | |
teamX = 3; | |
} | |
if (g_IsVs && g_onteam <= 1) { | |
team2 = CountTeamMates(2, 1); | |
team3 = CountTeamMates(3, 1); | |
if (team3 < team2) { | |
teamX = 3; | |
} | |
} | |
if (CountTeamMates(teamX, 1) < g_TeamLimit) { | |
Takeover(client, teamX); | |
} | |
} | |
return Plugin_Handled; | |
} | |
int CountTeamMates(int onteam, int mtype=2) { | |
Echo(1, "CountTeamMates: %d %d", onteam, mtype); | |
// mtype 0: counts only bots | |
// mtype 1: counts only humans | |
// mtype 2: counts all players on team | |
if (g_ADFreeze) { | |
return 0; | |
} | |
int result; | |
if (mtype == 2) { | |
static lastSize; | |
result = GetTeamClientCount(onteam); | |
if (result > 0 && onteam == 2) { | |
g_MaxSI = result; | |
if (g_MaxSI != lastSize) { | |
SetConVarFloat(g_cvMaxSI, float(result)); | |
lastSize = g_MaxSI; | |
} | |
} | |
return result; | |
} | |
int j; | |
int humans; | |
int bots; | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
j = GetClientManager(i); | |
if (j >= 0 && GetClientTeam(i) == onteam) { | |
switch (j) { | |
case 0: bots++; | |
default: humans++; | |
} | |
} | |
} | |
switch (mtype) { | |
case 0: result = bots; | |
case 1: result = humans; | |
} | |
return result; | |
} | |
int GetClientManager(int target) { | |
Echo(3, "GetClientManager: %d", target); | |
int result; | |
int userid; | |
int client; | |
if (GetQRecord(target)) { | |
return target; | |
} | |
else if (IsClientValid(target)) { | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (IsClientValid(i) && IsFakeClient(i) && GetClientTeam(i) == 2) { | |
// let's really put a stop to the "idling 2 bots at once" problem | |
userid = GetEntData(i, FindSendPropInfo("SurvivorBot", "m_humanSpectatorUserID")); | |
client = GetClientOfUserId(userid); | |
if (GetQRecord(client) && i != g_target) { | |
if (HasEntProp(i, Prop_Send, "m_humanSpectatorUserID")) { | |
SetEntProp(i, Prop_Send, "m_humanSpectatorUserID", 0); | |
} | |
} | |
} | |
} | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (GetQRecord(i)) { | |
if (IsClientValid(g_target) && g_target == target) { | |
result = i; | |
break; | |
} | |
} | |
} | |
} | |
else { | |
result = -1; // this target is NOT valid | |
} | |
return result; // target IS valid and NOT managed | |
} | |
int GetNextBot(int onteam, int skipIndex=0, alive=false) { | |
Echo(1, "GetNextBot: %d %d", onteam, skipIndex); | |
int bot; | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (GetClientManager(i) == 0) { | |
if (GetClientTeam(i) == onteam) { | |
if (bot == 0) { | |
if (!alive || alive && IsPlayerAlive(i)) { | |
bot = i; | |
} | |
} | |
if (i > skipIndex) { | |
if (!alive || alive && IsPlayerAlive(i)) { | |
bot = i; | |
break; | |
} | |
} | |
} | |
} | |
} | |
return bot; | |
} | |
CycleBots(int client, int onteam) { | |
Echo(1, "CycleBots: %d %d", client, onteam); | |
if (onteam <= 1) { | |
return; | |
} | |
if (GetQRecord(client)) { | |
int bot = GetNextBot(onteam, g_lastid, true); | |
if (GetClientManager(bot) == 0) { | |
SwitchToBot(client, bot, false); | |
} | |
} | |
} | |
SwitchTeam(int client, int onteam, char model[32]="") { | |
Echo(1, "SwitchTeam: %d %d", client, onteam); | |
if (GetQRecord(client)) { | |
switch (onteam) { | |
case 0: GoIdle(client, 0); | |
case 1: GoIdle(client, 1); | |
//case 4: ChangeClientTeam(client, 4); | |
default: { | |
if (onteam <= 3 && onteam >= 2) { | |
if (g_onteam != onteam) { | |
GoIdle(client, 1); | |
} | |
g_QRecord.SetValue("queued", true, true); | |
g_QRecord.SetValue("onteam", onteam, true); | |
if (onteam == 3) { | |
if (g_IsVs) { | |
ChangeClientTeam(client, 3); | |
return; | |
} | |
switch (g_model[0] == EOS && model[0] != EOS) { | |
case 1: CleanSIName(model); | |
case 0: { | |
Format(model, sizeof(model), "%s", g_model); | |
CleanSIName(model); | |
} | |
} | |
g_QRecord.SetString("model", model, true); | |
QueueUp(client, 3); | |
AddInfected(1, model); | |
return; | |
} | |
Takeover(client, onteam); | |
} | |
} | |
} | |
} | |
} | |
public Action MkBotsCmd(int client, args) { | |
Echo(1, "MkBotsCmd: %d", client); | |
switch(args) { | |
case 2: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
int asmany = StringToInt(g_sB); | |
GetCmdArg(2, g_sB, sizeof(g_sB)); | |
int onteam = StringToInt(g_sB); | |
if (onteam >= 2 || onteam <= 3) { | |
MkBots(asmany, onteam); | |
} | |
} | |
} | |
} | |
MkBots(int asmany, int onteam) { | |
Echo(1, "MkBots: %d %d", asmany, onteam); | |
if (asmany < 0) { | |
asmany = asmany * -1 - CountTeamMates(onteam); | |
} | |
float rate; | |
DataPack pack = new DataPack(); | |
switch (onteam) { | |
case 2: rate = 0.2; | |
case 3: rate = 0.4; | |
} | |
CreateDataTimer(rate, MkBotsTimer, pack, TIMER_REPEAT); | |
pack.WriteCell(asmany); | |
pack.WriteCell(onteam); | |
} | |
public Action MkBotsTimer(Handle timer, Handle pack) { | |
Echo(1, "MkBotsTimer"); | |
static i; | |
ResetPack(pack); | |
int asmany = ReadPackCell(pack); | |
int onteam = ReadPackCell(pack); | |
if (i++ < asmany) { | |
switch (onteam) { | |
case 2: AddSurvivor(); | |
case 3: AddInfected(); | |
} | |
return Plugin_Continue; | |
} | |
i = 0; | |
return Plugin_Stop; | |
} | |
public Action RmBotsCmd(int client, args) { | |
Echo(1, "RmBotsCmd: %d", client); | |
int asmany; | |
int onteam; | |
switch(args) { | |
case 1: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
onteam = StringToInt(g_sB); | |
asmany = MaxClients; | |
} | |
case 2: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
asmany = StringToInt(g_sB); | |
GetCmdArg(2, g_sB, sizeof(g_sB)); | |
onteam = StringToInt(g_sB); | |
} | |
} | |
if (onteam >= 2 || onteam <= 3) { | |
RmBots(asmany, onteam); | |
} | |
} | |
RmBots(int asmany, int onteam) { | |
Echo(1, "RmBots: %d %d", asmany, onteam); | |
int j; | |
if (onteam == 0) { | |
onteam = asmany; | |
asmany = MaxClients; | |
} | |
else if (asmany == -0) { | |
return; | |
} | |
else if (asmany < 0) { | |
asmany += CountTeamMates(onteam); | |
if (asmany <= 0) { | |
return; | |
} | |
} | |
for (int i = MaxClients ; i >= 1 ; i--) { | |
if (GetClientManager(i) == 0 && GetClientTeam(i) == onteam) { | |
j++; | |
StripClient(i); | |
KickClient(i); | |
if (j >= asmany) { | |
break; | |
} | |
} | |
} | |
} | |
// ================================================================== // | |
// MODEL FEATURES | |
// ================================================================== // | |
public Action AutoModelTimer(Handle timer, any client) { | |
Echo(1, "AutoModelTimer: %d", client); | |
if (!IsClientValid(client)) { | |
return Plugin_Handled; | |
} | |
int target = GetClientManager(client); | |
if (GetQRecord(target) && g_model[0] != EOS) { | |
return Plugin_Handled; | |
} | |
int smq[8]; // survivor model queue | |
int model; | |
int count; | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (IsClientValid(i) && GetClientTeam(i) == 2) { | |
model = GetClientModelIndex(i); | |
if (model != -1) { | |
smq[model]++; | |
} | |
} | |
} | |
model = GetClientModelIndex(client); | |
if (model == -1) model = 0; | |
count = smq[model]; | |
if (count <= 1 || count <= CountTeamMates(2) / 8) { | |
return Plugin_Handled; | |
} | |
for (int i = 1 ; i <= (MaxClients / 8) + 1 ; i++) { | |
for (model = 0 ; model < 8 ; model++) { | |
if (smq[model] < i) { | |
i = MaxClients; | |
break; | |
} | |
} | |
} | |
AssignModel(client, g_SurvivorNames[model]); | |
return Plugin_Handled; | |
} | |
PrecacheModels() { | |
Echo(1, "PrecacheModels"); | |
for (int i = 0 ; i < sizeof(g_SurvivorPaths) ; i++) { | |
Format(g_sB, sizeof(g_sB), "%s", g_SurvivorPaths[i]); | |
if (!IsModelPrecached(g_sB)) { | |
int retcode = PrecacheModel(g_sB); | |
Echo(1, " - Precaching Survivor %s, retcode: %d", g_sB, retcode); | |
} | |
} | |
} | |
AssignModel(int client, char [] model) { | |
Echo(1, "AssignModel: %d %s", client, model); | |
if (GetClientTeam(client) != 2 || IsClientsModel(client, model)) { | |
return; | |
} | |
if (IsClientValid(client)) { | |
int i = GetModelIndexByName(model); | |
if (i >= 0 && i < sizeof(g_SurvivorPaths)) { | |
switch(i == 5) { | |
case 1: SetEntProp(client, Prop_Send, "m_survivorCharacter", g_Zoey); | |
case 0: SetEntProp(client, Prop_Send, "m_survivorCharacter", i); | |
} | |
SetEntityModel(client, g_SurvivorPaths[i]); | |
Format(g_pN, sizeof(g_pN), "%s", g_SurvivorNames[i]); | |
if (IsFakeClient(client)) { | |
SetClientInfo(client, "name", g_pN); | |
int boss = GetClientManager(client); | |
if (boss > 0) { | |
client = boss; | |
} | |
} | |
if (GetQRecord(client)) { | |
g_QRecord.SetString("model", g_pN); | |
} | |
} | |
} | |
} | |
int GetClientModelIndex(int client) { | |
Echo(2, "GetClientModelIndex: %d", client); | |
if (!IsClientValid(client)) { | |
return -2; | |
} | |
char modelName[64]; | |
GetEntPropString(client, Prop_Data, "m_ModelName", modelName, sizeof(modelName)); | |
for (int i = 0 ; i < sizeof(g_SurvivorPaths) ; i++) { | |
if (StrEqual(modelName, g_SurvivorPaths[i], false)) { | |
return i; | |
} | |
} | |
return -1; | |
} | |
int GetModelIndexByName(char [] name, int onteam=2) { | |
Echo(1, "GetModelIndexByName: %s %d", name, onteam); | |
if (onteam == 2) { | |
for (int i ; i < sizeof(g_SurvivorNames) ; i ++) { | |
if (StrContains(name, g_SurvivorNames[i], false) != -1) { | |
return i; | |
} | |
} | |
} | |
else if (onteam == 3) { | |
for (int i ; i < sizeof(g_InfectedNames) ; i ++) { | |
if (StrContains(g_InfectedNames[i], name, false) != -1) { | |
return i; | |
} | |
} | |
} | |
return -1; | |
} | |
bool IsClientsModel(int client, char [] name) { | |
Echo(1, "IsClientsModel: %d %s", client, name); | |
int modelIndex = GetClientModelIndex(client); | |
Format(g_sB, sizeof(g_sB), "%s", g_SurvivorNames[modelIndex]); | |
return StrEqual(name, g_sB); | |
} | |
// ================================================================== // | |
// BLACK MAGIC SIGNATURES. SOME SPOOKY SHIT. | |
// ================================================================== // | |
int GetOS() { | |
Echo(1, "GetOS"); | |
return GameConfGetOffset(g_GameData, "OS"); | |
} | |
void RoundRespawnSig(int client) { | |
Echo(1, "RoundRespawnSig: %d", client); | |
static Handle hRoundRespawn; | |
if (hRoundRespawn == null) { | |
StartPrepSDKCall(SDKCall_Player); | |
PrepSDKCall_SetFromConf(g_GameData, SDKConf_Signature, "RoundRespawn"); | |
hRoundRespawn = EndPrepSDKCall(); | |
} | |
if (hRoundRespawn != null) { | |
SDKCall(hRoundRespawn, client); | |
} | |
else { | |
PrintToChat(client, "[ABM] RoundRespawnSig Signature broken."); | |
SetFailState("[ABM] RoundRespawnSig Signature broken."); | |
} | |
} | |
void SetHumanSpecSig(int bot, int client) { | |
Echo(1, "SetHumanSpecSig: %d %d", bot, client); | |
static Handle hSpec; | |
if (hSpec == null) { | |
StartPrepSDKCall(SDKCall_Player); | |
PrepSDKCall_SetFromConf(g_GameData, SDKConf_Signature, "SetHumanSpec"); | |
PrepSDKCall_AddParameter(SDKType_CBasePlayer, SDKPass_Pointer); | |
hSpec = EndPrepSDKCall(); | |
} | |
if(hSpec != null) { | |
SDKCall(hSpec, bot, client); | |
} | |
else { | |
PrintToChat(client, "[ABM] SetHumanSpecSig Signature broken."); | |
SetFailState("[ABM] SetHumanSpecSig Signature broken."); | |
} | |
} | |
void State_TransitionSig(int client, int mode) { | |
Echo(1, "State_TransitionSig: %d %d", client, mode); | |
static Handle hSpec; | |
if (hSpec == null) { | |
StartPrepSDKCall(SDKCall_Player); | |
PrepSDKCall_SetFromConf(g_GameData, SDKConf_Signature, "State_Transition"); | |
PrepSDKCall_AddParameter(SDKType_PlainOldData , SDKPass_Plain); | |
hSpec = EndPrepSDKCall(); | |
} | |
if(hSpec != null) { | |
SDKCall(hSpec, client, mode); // mode 8, press 8 to get closer | |
} | |
else { | |
PrintToChat(client, "[ABM] State_TransitionSig Signature broken."); | |
SetFailState("[ABM] State_TransitionSig Signature broken."); | |
} | |
} | |
bool TakeoverBotSig(int client, int bot) { | |
Echo(1, "TakeoverBotSig: %d %d", client, bot); | |
if (!GetQRecord(client)) { | |
return false; | |
} | |
static Handle hSwitch; | |
if (hSwitch == null) { | |
StartPrepSDKCall(SDKCall_Player); | |
PrepSDKCall_SetFromConf(g_GameData, SDKConf_Signature, "TakeOverBot"); | |
PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); | |
hSwitch = EndPrepSDKCall(); | |
} | |
if (hSwitch != null) { | |
if (IsClientInKickQueue(bot)) { | |
KickClient(bot); | |
} | |
else if (IsClientValid(bot) && IsFakeClient(bot)) { | |
if (GetClientTeam(bot) == 2) { | |
SwitchToSpec(client); | |
SetHumanSpecSig(bot, client); | |
SDKCall(hSwitch, client, true); | |
Unqueue(client); | |
return true; | |
} | |
} | |
} | |
else { | |
PrintToChat(client, "[ABM] TakeoverBotSig Signature broken."); | |
SetFailState("[ABM] TakeoverBotSig Signature broken."); | |
} | |
g_QRecord.SetValue("lastid", bot, true); | |
if (GetClientTeam(client) == 1) { | |
g_QRecord.SetValue("queued", true, true); | |
QueueUp(client, 2); | |
} | |
return false; | |
} | |
bool TakeoverZombieBotSig(int client, int bot, bool si_ghost) { | |
Echo(1, "TakeoverZombieBotSig: %d %d", client, bot); | |
if (!GetQRecord(client)) { | |
return false; | |
} | |
static Handle hSwitch; | |
if (hSwitch == null) { | |
StartPrepSDKCall(SDKCall_Player); | |
PrepSDKCall_SetFromConf(g_GameData, SDKConf_Signature, "TakeOverZombieBot"); | |
PrepSDKCall_AddParameter(SDKType_CBasePlayer, SDKPass_Pointer); | |
hSwitch = EndPrepSDKCall(); | |
} | |
if (hSwitch != null) { | |
if (IsClientInKickQueue(bot)) { | |
KickClient(bot); | |
} | |
else if (IsClientValid(bot) && IsFakeClient(bot) && IsPlayerAlive(bot)) { | |
if (GetClientTeam(bot) == 3) { | |
SwitchToSpec(client); | |
SDKCall(hSwitch, client, bot); | |
if (si_ghost) { | |
State_TransitionSig(client, 8); | |
if (GetEntProp(client, Prop_Send, "m_zombieClass") == 8) { | |
CreateTimer(1.0, ForceSpawnTimer, client, TIMER_REPEAT); | |
} | |
} | |
Unqueue(client); | |
g_AssistedSpawning = true; | |
return true; | |
} | |
} | |
} | |
else { | |
PrintToChat(client, "[ABM] TakeoverZombieBotSig Signature broken."); | |
SetFailState("[ABM] TakeoverZombieBotSig Signature broken."); | |
} | |
g_QRecord.SetValue("lastid", bot, true); | |
if (GetClientTeam(client) == 1) { | |
g_QRecord.SetValue("queued", true, true); | |
QueueUp(client, 3); | |
} | |
return false; | |
} | |
// ================================================================== // | |
// PUBLIC INTERFACE AND MENU HANDLERS | |
// ================================================================== // | |
public Action TeleportClientCmd(int client, args) { | |
Echo(1, "TeleportClientCmd: %d", client); | |
int level; | |
switch(args) { | |
case 1: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
case 2: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg0 = StringToInt(g_sB); | |
GetCmdArg(2, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
} | |
if (args) { | |
level = 2; | |
} | |
TeleportClientHandler(client, level); | |
return Plugin_Handled; | |
} | |
public TeleportClientHandler(int client, int level) { | |
Echo(1, "TeleportClientHandler: %d %d", client, level); | |
if (!RegMenuHandler(client, "TeleportClientHandler", level, 0)) { | |
return; | |
} | |
switch(level) { | |
case 0: TeamMatesMenu(client, "Teleport Client", 2, 1); | |
case 1: { | |
GetClientName(menuArg0, g_sB, sizeof(g_sB)); | |
Format(g_sB, sizeof(g_sB), "%s: Teleporting", g_sB); | |
TeamMatesMenu(client, g_sB, 2, 1); | |
} | |
case 2: { | |
if (CanClientTarget(client, menuArg0)) { | |
if (GetClientTeam(menuArg0) <= 1) { | |
menuArg0 = GetPlayClient(menuArg0); | |
} | |
TeleportClient(menuArg0, menuArg1); | |
} | |
GenericMenuCleaner(client); | |
} | |
} | |
} | |
public Action SwitchTeamCmd(int client, args) { | |
Echo(1, "SwitchTeamCmd: %d", client); | |
int level; | |
char model[32]; | |
GetCmdArg(args, model, sizeof(model)); | |
int result = StringToInt(model); | |
if (args == 1 || args == 2 && result == 0) { | |
menuArg0 = client; | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
else if (args >= 2) { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg0 = StringToInt(g_sB); | |
GetCmdArg(2, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
if (args) { | |
level = 2; | |
} | |
else if (!IsAdmin(client)) { | |
menuArg0 = client; | |
level = 1; | |
} | |
if (menuArg1 == 3 && GetQRecord(menuArg0)) { | |
g_QRecord.SetString("model", model); | |
} | |
SwitchTeamHandler(client, level); | |
return Plugin_Handled; | |
} | |
public SwitchTeamHandler(int client, int level) { | |
Echo(1, "SwitchTeamHandler: %d %d", client, level); | |
if (!RegMenuHandler(client, "SwitchTeamHandler", level, 0)) { | |
return; | |
} | |
switch(level) { | |
case 0: TeamMatesMenu(client, "Switch Client's Team", 1); | |
case 1: { | |
GetClientName(menuArg0, g_sB, sizeof(g_sB)); | |
Format(g_sB, sizeof(g_sB), "%s: Switching", g_sB); | |
TeamsMenu(client, g_sB); | |
} | |
case 2: { | |
if (CanClientTarget(client, menuArg0)) { | |
if (!IsAdmin(client) && menuArg1 == 3) { | |
GenericMenuCleaner(client); | |
return; | |
} | |
SwitchTeam(menuArg0, menuArg1); | |
} | |
GenericMenuCleaner(client); | |
} | |
} | |
} | |
public Action AssignModelCmd(int client, args) { | |
Echo(1, "AssignModelCmd: %d", client); | |
int level; | |
switch(args) { | |
case 1: { | |
menuArg0 = client; | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg1 = GetModelIndexByName(g_sB); | |
} | |
case 2: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg1 = GetModelIndexByName(g_sB); | |
GetCmdArg(2, g_sB, sizeof(g_sB)); | |
menuArg0 = StringToInt(g_sB); | |
} | |
} | |
if (args) { | |
level = 2; | |
} | |
AssignModelHandler(client, level); | |
return Plugin_Handled; | |
} | |
public AssignModelHandler(int client, int level) { | |
Echo(1, "AssignModelHandler: %d %d", client, level); | |
if (!RegMenuHandler(client, "AssignModelHandler", level, 0)) { | |
return; | |
} | |
switch(level) { | |
case 0: TeamMatesMenu(client, "Change Client's Model", 2, 0, false); | |
case 1: { | |
GetClientName(menuArg0, g_sB, sizeof(g_sB)); | |
Format(g_sB, sizeof(g_sB), "%s: Modeling", g_sB); | |
ModelsMenu(client, g_sB); | |
} | |
case 2: { | |
if (CanClientTarget(client, menuArg0)) { | |
if (GetClientTeam(menuArg0) <= 1) { | |
menuArg0 = GetPlayClient(menuArg0); | |
} | |
AssignModel(menuArg0, g_SurvivorNames[menuArg1]); | |
} | |
GenericMenuCleaner(client); | |
} | |
} | |
} | |
public Action SwitchToBotCmd(int client, args) { | |
Echo(1, "SwitchToBotCmd: %d", client); | |
int level; | |
switch(args) { | |
case 1: { | |
menuArg0 = client; | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
case 2: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg0 = StringToInt(g_sB); | |
GetCmdArg(2, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
} | |
if (args) { | |
level = 2; | |
} | |
else if (!IsAdmin(client)) { | |
menuArg0 = client; | |
level = 1; | |
} | |
SwitchToBotHandler(client, level); | |
return Plugin_Handled; | |
} | |
public SwitchToBotHandler(int client, int level) { | |
Echo(1, "SwitchToBotHandler: %d %d", client, level); | |
int homeTeam = ClientHomeTeam(client); | |
if (!RegMenuHandler(client, "SwitchToBotHandler", level, 0)) { | |
return; | |
} | |
switch(level) { | |
case 0: TeamMatesMenu(client, "Takeover Bot", 1); | |
case 1: { | |
GetClientName(menuArg0, g_sB, sizeof(g_sB)); | |
Format(g_sB, sizeof(g_sB), "%s: Takeover", g_sB); | |
TeamMatesMenu(client, g_sB, 0, 0, true, false, homeTeam); | |
} | |
case 2: { | |
if (CanClientTarget(client, menuArg0)) { | |
if (IsClientValid(menuArg1)) { | |
if (homeTeam != 3 && GetClientTeam(menuArg1) == 3) { | |
if (!IsAdmin(client)) { | |
GenericMenuCleaner(client); | |
return; | |
} | |
} | |
if (GetClientManager(menuArg1) == 0) { | |
SwitchToBot(menuArg0, menuArg1, false); | |
} | |
} | |
} | |
GenericMenuCleaner(client); | |
} | |
} | |
} | |
public Action RespawnClientCmd(int client, args) { | |
Echo(1, "RespawnClientCmd: %d", client); | |
int level; | |
switch(args) { | |
case 1: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg0 = StringToInt(g_sB); | |
menuArg1 = menuArg0; | |
} | |
case 2: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg0 = StringToInt(g_sB); | |
GetCmdArg(2, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
} | |
if (args) { | |
level = 2; | |
} | |
RespawnClientHandler(client, level); | |
return Plugin_Handled; | |
} | |
public RespawnClientHandler(int client, int level) { | |
Echo(1, "RespawnClientHandler: %d %d", client, level); | |
if (!RegMenuHandler(client, "RespawnClientHandler", level, 0)) { | |
return; | |
} | |
switch(level) { | |
case 0: TeamMatesMenu(client, "Respawn Client"); | |
case 1: { | |
GetClientName(menuArg0, g_sB, sizeof(g_sB)); | |
Format(g_sB, sizeof(g_sB), "%s: Respawning", g_sB); | |
TeamMatesMenu(client, g_sB); | |
} | |
case 2: { | |
if (CanClientTarget(client, menuArg0)) { | |
if (GetClientTeam(menuArg0) <= 1) { | |
menuArg0 = GetPlayClient(menuArg0); | |
} | |
RespawnClient(menuArg0, menuArg1); | |
} | |
GenericMenuCleaner(client); | |
} | |
} | |
} | |
public Action CycleBotsCmd(int client, args) { | |
Echo(1, "CycleBotsCmd: %d", client); | |
int level; | |
switch(args) { | |
case 1: { | |
menuArg0 = client; | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
case 2: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg0 = StringToInt(g_sB); | |
GetCmdArg(2, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
} | |
if (args) { | |
if (menuArg1 > 3 || menuArg1 < 2) { | |
return Plugin_Handled; | |
} | |
level = 2; | |
} | |
CycleBotsHandler(client, level); | |
return Plugin_Handled; | |
} | |
public CycleBotsHandler(int client, int level) { | |
Echo(1, "CycleBotsHandler: %d %d", client, level); | |
if (!RegMenuHandler(client, "CycleBotsHandler", level, 0)) { | |
return; | |
} | |
switch(level) { | |
case 0: TeamMatesMenu(client, "Cycle Client", 1); | |
case 1: { | |
GetClientName(menuArg0, g_sB, sizeof(g_sB)); | |
Format(g_sB, sizeof(g_sB), "%s: Cycling", g_sB); | |
TeamsMenu(client, g_sB, false); | |
} | |
case 2: { | |
if (CanClientTarget(client, menuArg0)) { | |
if (!IsAdmin(client) && menuArg1 == 3) { | |
GenericMenuCleaner(client); | |
return; | |
} | |
CycleBots(menuArg0, menuArg1); | |
menuArg1 = 0; | |
} | |
CycleBotsHandler(client, 1); | |
} | |
} | |
} | |
public Action StripClientCmd(int client, args) { | |
Echo(1, "StripClientCmd: %d", client); | |
int target; | |
int level; | |
switch(args) { | |
case 1: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
target = StringToInt(g_sB); | |
target = GetPlayClient(target); | |
if (CanClientTarget(client, target)) { | |
StripClient(target); | |
} | |
return Plugin_Handled; | |
} | |
case 2: { | |
GetCmdArg(1, g_sB, sizeof(g_sB)); | |
menuArg0 = StringToInt(g_sB); | |
GetCmdArg(2, g_sB, sizeof(g_sB)); | |
menuArg1 = StringToInt(g_sB); | |
} | |
} | |
if (args) { | |
level = 2; | |
} | |
StripClientHandler(client, level); | |
return Plugin_Handled; | |
} | |
public StripClientHandler(int client, int level) { | |
Echo(1, "StripClientHandler: %d %d", client, level); | |
if (!RegMenuHandler(client, "StripClientHandler", level, 0)) { | |
return; | |
} | |
switch(level) { | |
case 0: TeamMatesMenu(client, "Strip Client", 2, 1); | |
case 1: { | |
GetClientName(menuArg0, g_sB, sizeof(g_sB)); | |
Format(g_sB, sizeof(g_sB), "%s: Stripping", g_sB); | |
InvSlotsMenu(client, menuArg0, g_sB); | |
} | |
case 2: { | |
if (CanClientTarget(client, menuArg0)) { | |
if (GetClientTeam(menuArg0) <= 1) { | |
menuArg0 = GetPlayClient(menuArg0); | |
} | |
StripClientSlot(menuArg0, menuArg1); | |
menuArg1 = 0; | |
StripClientHandler(client, 1); | |
} | |
} | |
} | |
} | |
public Action ResetCmd(int client, args) { | |
Echo(1, "ResetCmd: %d", client); | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
GenericMenuCleaner(i); | |
if (GetQRecord(i)) { | |
CancelClientMenu(i, true, null); | |
} | |
} | |
} | |
bool RegMenuHandler(int client, char [] handler, int level, int clearance=0) { | |
Echo(1, "RegMenuHandler: %d %s %d %d", client, handler, level, clearance); | |
g_callBacks.PushString(handler); | |
if (!IsAdmin(client) && level <= clearance) { | |
GenericMenuCleaner(client); | |
return false; | |
} | |
return true; | |
} | |
public Action MainMenuCmd(int client, args) { | |
Echo(1, "MainMenuCmd: %d", client); | |
GenericMenuCleaner(client); | |
MainMenuHandler(client, 0); | |
return Plugin_Handled; | |
} | |
public MainMenuHandler(int client, int level) { | |
Echo(1, "MainMenuHandler: %d %d", client, level); | |
if (!RegMenuHandler(client, "MainMenuHandler", level, 0)) { | |
return; | |
} | |
int cmd = menuArg0; | |
menuArg0 = 0; | |
char title[32]; | |
Format(title, sizeof(title), "ABM Menu %s", PLUGIN_VERSION); | |
switch(level) { | |
case 0: MainMenu(client, title); | |
case 1: { | |
switch(cmd) { | |
case 0: TeleportClientCmd(client, 0); | |
case 1: SwitchTeamCmd(client, 0); | |
case 2: AssignModelCmd(client, 0); | |
case 3: SwitchToBotCmd(client, 0); | |
case 4: RespawnClientCmd(client, 0); | |
case 5: CycleBotsCmd(client, 0); | |
case 6: StripClientCmd(client, 0); | |
} | |
} | |
} | |
} | |
// ================================================================== // | |
// MENUS BACKBONE | |
// ================================================================== // | |
GenericMenuCleaner(int client, bool clearStack=true) { | |
Echo(1, "GenericMenuCleaner: %d %d", client, clearStack); | |
for (int i = 0 ; i < sizeof(g_menuItems[]) ; i++) { | |
g_menuItems[client][i] = 0; | |
} | |
if (clearStack == true) { | |
if (g_callBacks != null) { | |
delete g_callBacks; | |
} | |
g_callBacks = new ArrayStack(128); | |
} | |
} | |
public GenericMenuHandler(Menu menu, MenuAction action, int param1, int param2) { | |
Echo(1, "GenericMenuHandler: %d %d", param1, param2); | |
int client = param1; | |
int i; // -1; | |
char sB[128]; | |
if (IsClientValid(param1)) { | |
for (i = 0 ; i < sizeof(g_menuItems[]) ; i++) { | |
if (menuArgs[i] == 0) { | |
break; | |
} | |
} | |
} | |
switch(action) { | |
case MenuAction_Select: { | |
menu.GetItem(param2, g_sB, sizeof(g_sB)); | |
menuArgs[i] = StringToInt(g_sB); | |
i = i + 1; | |
} | |
case MenuAction_Cancel: { | |
if (param2 == MenuCancel_ExitBack) { | |
if (i > 0) { | |
i = i - 1; | |
menuArgs[i] = 0; | |
} | |
else if (i == 0) { | |
if (g_callBacks.Empty) { | |
GenericMenuCleaner(param1); | |
return; | |
} | |
g_callBacks.PopString(g_sB, sizeof(g_sB)); | |
GenericMenuCleaner(param1, false); | |
while (!g_callBacks.Empty) { | |
g_callBacks.PopString(sB, sizeof(sB)); | |
if (!StrEqual(g_sB, sB)) { | |
g_callBacks.PushString(sB); | |
break; | |
} | |
} | |
if (g_callBacks.Empty) { | |
GenericMenuCleaner(param1); | |
return; | |
} | |
} | |
} | |
else { | |
return; | |
} | |
} | |
case MenuAction_End: { | |
delete menu; | |
return; | |
} | |
} | |
if (g_callBacks == null || g_callBacks.Empty) { | |
GenericMenuCleaner(param1); | |
return; | |
} | |
g_callBacks.PopString(g_sB, sizeof(g_sB)); | |
callBack = GetFunctionByName(null, g_sB); | |
Call_StartFunction(null, callBack); | |
Call_PushCell(param1); | |
Call_PushCell(i); | |
Call_Finish(); | |
} | |
// ================================================================== // | |
// MENUS | |
// ================================================================== // | |
MainMenu(int client, char [] title) { | |
Echo(1, "MainMenu: %d %s", client, title); | |
Menu menu = new Menu(GenericMenuHandler); | |
menu.SetTitle(title); | |
menu.AddItem("0", "Teleport Client"); // "Telespiznat"); // teleport | |
menu.AddItem("1", "Switch Client Team"); //"Swintootle"); // switch team | |
menu.AddItem("2", "Change Client Model"); //"Changdangle"); // makeover | |
menu.AddItem("3", "Switch Client Bot"); //"Inbosnachup"); // takeover | |
menu.AddItem("4", "Respawn Client"); //"Respiggle"); // respawn | |
menu.AddItem("5", "Cycle Client"); //"Cycolicoo"); // cycle | |
menu.AddItem("6", "Strip Client"); //"Upsticky"); // strip | |
menu.ExitBackButton = true; | |
menu.ExitButton = true; | |
menu.Display(client, 120); | |
} | |
InvSlotsMenu(int client, int target, char [] title) { | |
Echo(1, "InvSlotsMenu: %d %d %s", client, target, title); | |
int ent; | |
char weapon[64]; | |
Menu menu = new Menu(GenericMenuHandler); | |
menu.SetTitle(title); | |
for (int i ; i < 5 ; i++) { | |
IntToString(i, g_sB, sizeof(g_sB)); | |
ent = GetPlayerWeaponSlot(target, i); | |
if (IsValidEntity(ent)) { | |
GetEntityClassname(ent, weapon, sizeof(weapon)); | |
menu.AddItem(g_sB, weapon); | |
} | |
} | |
menu.ExitBackButton = true; | |
menu.ExitButton = true; | |
menu.Display(client, 120); | |
} | |
ModelsMenu(int client, char [] title) { | |
Echo(1, "ModelsMenu: %d %s", client, title); | |
Menu menu = new Menu(GenericMenuHandler); | |
menu.SetTitle(title); | |
for (int i ; i < sizeof(g_SurvivorNames) ; i++) { | |
IntToString(i, g_sB, sizeof(g_sB)); | |
menu.AddItem(g_sB, g_SurvivorNames[i]); | |
} | |
menu.ExitBackButton = true; | |
menu.ExitButton = true; | |
menu.Display(client, 120); | |
} | |
TeamsMenu(int client, char [] title, bool all=true) { | |
Echo(1, "TeamsMenu: %d %s %d", client, title, all); | |
Menu menu = new Menu(GenericMenuHandler); | |
menu.SetTitle(title); | |
if (all) { | |
menu.AddItem("0", "Idler"); | |
menu.AddItem("1", "Spectator"); | |
} | |
menu.AddItem("2", "Survivor"); | |
if (IsAdmin(client)) { | |
menu.AddItem("3", "Infected"); | |
} | |
menu.ExitBackButton = true; | |
menu.ExitButton = true; | |
menu.Display(client, 120); | |
} | |
TeamMatesMenu(int client, char [] title, int mtype=2, int target=0, bool incDead=true, | |
bool repeat=false, int homeTeam=0) { | |
Echo(1, "TeamMatesMenu: %d %s %d %d %d %d %d", client, title, mtype, target, incDead, repeat, homeTeam); | |
Menu menu = new Menu(GenericMenuHandler); | |
menu.SetTitle(title); | |
int isAdmin = IsAdmin(client); | |
char health[32]; | |
bool mflag = false; | |
int isAlive; | |
int playClient; | |
int bossClient; | |
int targetClient; | |
int manager; | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
bossClient = i; | |
playClient = i; | |
if (GetQRecord(i)) { | |
if (mtype == 0) { | |
continue; | |
} | |
if (mtype == 1 || mtype == 2) { | |
mflag = true; | |
} | |
if (IsClientValid(g_target) && g_target != i) { | |
isAlive = IsPlayerAlive(g_target); | |
playClient = g_target; | |
} | |
else { | |
isAlive = IsPlayerAlive(i); | |
} | |
} | |
else if (IsClientValid(i)) { | |
isAlive = IsPlayerAlive(i); | |
if (mtype == 0 || mtype == 2) { | |
mflag = true; | |
} | |
manager = GetClientManager(i); | |
if (manager != 0) { | |
if (target == 0 || !repeat) { | |
mflag = false; | |
continue; | |
} | |
bossClient = manager; | |
} | |
} | |
else { | |
continue; | |
} | |
// at this point the client is valid. | |
// bossClient is the human (if there is one) | |
// playClient is the bot (or human if not idle) | |
if (!isAlive && !incDead) { | |
continue; | |
} | |
if (GetClientTeam(playClient) != homeTeam && !isAdmin) { | |
continue; | |
} | |
switch(target) { | |
case 0: targetClient = bossClient; | |
case 1: targetClient = playClient; | |
} | |
if (mflag) { | |
mflag = false; | |
Format(health, sizeof(health), "%d", GetClientHealth(playClient)); | |
if (!IsPlayerAlive(playClient)) { | |
Format(health, sizeof(health), "DEAD"); | |
} | |
else if (GetEntProp(playClient, Prop_Send, "m_isIncapacitated")) { | |
Format(health, sizeof(health), "DOWN"); | |
} | |
GetClientName(bossClient, g_pN, sizeof(g_pN)); | |
Format(g_pN, sizeof(g_pN), "%s (%s)", g_pN, health); | |
IntToString(targetClient, g_sB, sizeof(g_sB)); | |
switch(bossClient == client && menu.ItemCount > 0) { | |
case 0: menu.AddItem(g_sB, g_pN); | |
case 1: menu.InsertItem(0, g_sB, g_pN); | |
} | |
} | |
} | |
menu.ExitBackButton = true; | |
menu.ExitButton = true; | |
menu.Display(client, 120); | |
} | |
// ================================================================== // | |
// MISC STUFF USEFUL FOR TROUBLESHOOTING | |
// ================================================================== // | |
Echo(int level, char [] format, any ...) { | |
if (g_LogLevel >= level) { | |
VFormat(g_dB, sizeof(g_dB), format, 3); | |
LogToFile(LOGFILE, g_dB); | |
PrintToServer("%s", g_dB); | |
} | |
} | |
QDBCheckCmd(client) { | |
Echo(1, "QDBCheckCmd"); | |
PrintToConsole(client, "-- STAT: QDB Size is %d", g_QDB.Size); | |
PrintToConsole(client, "-- MinPlayers is %d", g_MinPlayers); | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (GetQRecord(i)) { | |
PrintToConsole(client, "\n -"); | |
GetClientName(i, g_pN, sizeof(g_pN)); | |
float x = g_origin[0]; | |
float y = g_origin[1]; | |
float z = g_origin[2]; | |
PrintToConsole(client, " - Name: %s", g_pN); | |
PrintToConsole(client, " - Origin: {%d.0, %d.0, %d.0}", x, y, z); | |
PrintToConsole(client, " - Status: %d", IsPlayerAlive(i)); | |
PrintToConsole(client, " - Client: %d", g_client); | |
PrintToConsole(client, " - Target: %d", g_target); | |
PrintToConsole(client, " - LastId: %d", g_lastid); | |
PrintToConsole(client, " - OnTeam: %d", g_onteam); | |
PrintToConsole(client, " - Queued: %d", g_queued); | |
PrintToConsole(client, " - InSpec: %d", g_inspec); | |
if (GetClientTeam(i) == 2) { | |
int j = GetClientModelIndex(i); | |
if (j != -1) { | |
PrintToConsole(client, " - Initialized Model: %s", g_SurvivorNames[j]); | |
} | |
} | |
PrintToConsole(client, " - Model: %s", g_model); | |
PrintToConsole(client, " -\n"); | |
} | |
} | |
} | |
public Action QuickClientPrintCmd(int client, args) { | |
Echo(1, "QuickClientPrintCmd: %d", client); | |
int onteam; | |
int state; | |
int manager; | |
PrintToConsole(client, "\nTeam\tState\tId\tManager\tName"); | |
for (int i = 1 ; i <= MaxClients ; i++) { | |
if (IsClientValid(i)) { | |
manager = i; | |
GetClientName(i, g_pN, sizeof(g_pN)); | |
onteam = GetClientTeam(i); | |
state = IsPlayerAlive(i); | |
if (IsFakeClient(i)) { | |
manager = GetClientManager(i); | |
} | |
PrintToConsole(client, | |
"%d, \t%d, \t%d, \t%d, \t%s", onteam, state, i, manager, g_pN | |
); | |
} | |
} | |
QDBCheckCmd(client); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment