diff --git a/Update_log.md b/Update_log.md index 8a38e4ea9..83fa30d83 100644 --- a/Update_log.md +++ b/Update_log.md @@ -178,3 +178,6 @@ PS:这种处理方式相比原来的换成写实处理有以下几点好处 #### l4d_boss_vote插件 - 修复9特以上无法投票的功能 +#### 其他 +增加大量对抗插件的i18n翻译 + diff --git a/addons/sourcemod/plugins/optional/AnneHappy/infected_control.smx b/addons/sourcemod/plugins/optional/AnneHappy/infected_control.smx index f18f33739..b14d53f84 100644 Binary files a/addons/sourcemod/plugins/optional/AnneHappy/infected_control.smx and b/addons/sourcemod/plugins/optional/AnneHappy/infected_control.smx differ diff --git a/addons/sourcemod/plugins/optional/autopause.smx b/addons/sourcemod/plugins/optional/autopause.smx index df39788d5..24c434ef9 100644 Binary files a/addons/sourcemod/plugins/optional/autopause.smx and b/addons/sourcemod/plugins/optional/autopause.smx differ diff --git a/addons/sourcemod/plugins/optional/checkpoint-rage-control.smx b/addons/sourcemod/plugins/optional/checkpoint-rage-control.smx index 125a49766..18e8b2603 100644 Binary files a/addons/sourcemod/plugins/optional/checkpoint-rage-control.smx and b/addons/sourcemod/plugins/optional/checkpoint-rage-control.smx differ diff --git a/addons/sourcemod/plugins/optional/coinflip.smx b/addons/sourcemod/plugins/optional/coinflip.smx index 1140c9a77..faa0ae9c9 100644 Binary files a/addons/sourcemod/plugins/optional/coinflip.smx and b/addons/sourcemod/plugins/optional/coinflip.smx differ diff --git a/addons/sourcemod/plugins/optional/current.smx b/addons/sourcemod/plugins/optional/current.smx index 684fededb..0c5055134 100644 Binary files a/addons/sourcemod/plugins/optional/current.smx and b/addons/sourcemod/plugins/optional/current.smx differ diff --git a/addons/sourcemod/plugins/optional/l4d2_stats.smx b/addons/sourcemod/plugins/optional/l4d2_stats.smx index 4c9a1d886..91a29d775 100644 Binary files a/addons/sourcemod/plugins/optional/l4d2_stats.smx and b/addons/sourcemod/plugins/optional/l4d2_stats.smx differ diff --git a/addons/sourcemod/plugins/optional/l4d_tank_control_eq.smx b/addons/sourcemod/plugins/optional/l4d_tank_control_eq.smx index 519343ee7..b5fd9e6cd 100644 Binary files a/addons/sourcemod/plugins/optional/l4d_tank_control_eq.smx and b/addons/sourcemod/plugins/optional/l4d_tank_control_eq.smx differ diff --git a/addons/sourcemod/plugins/optional/l4d_tank_damage_announce.smx b/addons/sourcemod/plugins/optional/l4d_tank_damage_announce.smx index e07077063..ee9e1f27c 100644 Binary files a/addons/sourcemod/plugins/optional/l4d_tank_damage_announce.smx and b/addons/sourcemod/plugins/optional/l4d_tank_damage_announce.smx differ diff --git a/addons/sourcemod/plugins/optional/nodeathcamskip.smx b/addons/sourcemod/plugins/optional/nodeathcamskip.smx index eddda5d36..e84ddba19 100644 Binary files a/addons/sourcemod/plugins/optional/nodeathcamskip.smx and b/addons/sourcemod/plugins/optional/nodeathcamskip.smx differ diff --git a/addons/sourcemod/plugins/optional/pause.smx b/addons/sourcemod/plugins/optional/pause.smx index a98b836e1..3ee915151 100644 Binary files a/addons/sourcemod/plugins/optional/pause.smx and b/addons/sourcemod/plugins/optional/pause.smx differ diff --git a/addons/sourcemod/plugins/optional/readyup.smx b/addons/sourcemod/plugins/optional/readyup.smx index 9246fc40f..d57a8b4ff 100644 Binary files a/addons/sourcemod/plugins/optional/readyup.smx and b/addons/sourcemod/plugins/optional/readyup.smx differ diff --git a/addons/sourcemod/plugins/optional/survivor_mvp.smx b/addons/sourcemod/plugins/optional/survivor_mvp.smx index 2cc05e6ec..bde99ffc1 100644 Binary files a/addons/sourcemod/plugins/optional/survivor_mvp.smx and b/addons/sourcemod/plugins/optional/survivor_mvp.smx differ diff --git a/addons/sourcemod/plugins/optional/teamflip.smx b/addons/sourcemod/plugins/optional/teamflip.smx index b0f294583..1987acc44 100644 Binary files a/addons/sourcemod/plugins/optional/teamflip.smx and b/addons/sourcemod/plugins/optional/teamflip.smx differ diff --git a/addons/sourcemod/plugins/optional/weapon_loadout_vote.smx b/addons/sourcemod/plugins/optional/weapon_loadout_vote.smx index 84a98f617..4a7cb57ae 100644 Binary files a/addons/sourcemod/plugins/optional/weapon_loadout_vote.smx and b/addons/sourcemod/plugins/optional/weapon_loadout_vote.smx differ diff --git a/addons/sourcemod/scripting/AnneHappy/infected_control.sp b/addons/sourcemod/scripting/AnneHappy/infected_control.sp index da963d775..1293aad2f 100644 --- a/addons/sourcemod/scripting/AnneHappy/infected_control.sp +++ b/addons/sourcemod/scripting/AnneHappy/infected_control.sp @@ -193,7 +193,7 @@ public void OnPluginStart() g_hSpawnDistanceMin.AddChangeHook(ConVarChanged_Cvars); g_hTeleportSi.AddChangeHook(ConVarChanged_Cvars); g_hTeleportCheckTime.AddChangeHook(ConVarChanged_Cvars); - g_hTeleportDistance.AddChangeHook(ConVarChanged_Cvars); + //g_hTeleportDistance.AddChangeHook(ConVarChanged_Cvars); g_hSiInterval.AddChangeHook(ConVarChanged_Cvars); g_hIgnoreIncappedSurvivorSight.AddChangeHook(ConVarChanged_Cvars); g_hEnableSIoption.AddChangeHook(ConVarChanged_Cvars); diff --git a/addons/sourcemod/scripting/autopause.sp b/addons/sourcemod/scripting/autopause.sp index 8d0a71b39..18879db20 100644 --- a/addons/sourcemod/scripting/autopause.sp +++ b/addons/sourcemod/scripting/autopause.sp @@ -1,173 +1,190 @@ /* - SourcePawn is Copyright (C) 2006-2015 AlliedModders LLC. All rights reserved. - SourceMod is Copyright (C) 2006-2015 AlliedModders LLC. All rights reserved. - Pawn and SMALL are Copyright (C) 1997-2015 ITB CompuPhase. - Source is Copyright (C) Valve Corporation. - All trademarks are property of their respective owners. - - 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 3 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, see . + SourcePawn is Copyright (C) 2006-2015 AlliedModders LLC. All rights reserved. + SourceMod is Copyright (C) 2006-2015 AlliedModders LLC. All rights reserved. + Pawn and SMALL are Copyright (C) 1997-2015 ITB CompuPhase. + Source is Copyright (C) Valve Corporation. + All trademarks are property of their respective owners. + + 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 3 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, see . */ -#include -#include +#pragma semicolon 1 +#pragma newdecls required + #include +#include +#include #undef REQUIRE_PLUGIN #include "readyup" -public Plugin:myinfo = +public Plugin myinfo = { - name = "L4D2 Auto-pause", - author = "Darkid, Griffin", - description = "When a player disconnects due to crash, automatically pause the game. When they rejoin, give them a correct spawn timer.", - version = "2.0", - url = "https://github.com/jbzdarkid/AutoPause" + name = "L4D2 Auto-pause", + author = "Darkid, Griffin", + description = "When a player disconnects due to crash, automatically pause the game. When they rejoin, give them a correct spawn timer.", + version = "2.1", + url = "https://github.com/jbzdarkid/AutoPause" } -new Handle:g_hCvarEnabled; -new Handle:g_hCvarForce; -new Handle:g_hCvarApdebug; - -new Handle:crashedPlayers; -new Handle:infectedPlayers; -new Handle:survivorPlayers; -new bool:readyUpIsAvailable; -new bool:RoundEnd; - -public OnPluginStart() { - // Suggestion by Nati: Disable for any 1v1 - g_hCvarEnabled = CreateConVar("autopause_enable", "1", "Whether or not to automatically pause when a player crashes."); - g_hCvarForce = CreateConVar("autopause_force", "0", "Whether or not to force pause when a player crashes."); - g_hCvarApdebug = CreateConVar("autopause_apdebug", "0", "Whether or not to debug information."); - - crashedPlayers = CreateTrie(); - infectedPlayers = CreateArray(64); - survivorPlayers = CreateArray(64); - - HookEvent("round_start", round_start); - HookEvent("round_end", round_end); - HookEvent("player_team", playerTeam); - HookEvent("player_disconnect", playerDisconnect, EventHookMode_Pre); +ConVar + g_hCvarEnabled, + g_hCvarForce, + g_hCvarApdebug; +Handle + crashedPlayers, + infectedPlayers, + survivorPlayers; +bool + readyUpIsAvailable, + RoundEnd; + +public void OnPluginStart() +{ + LoadTranslations("autopause.phrases"); + // Suggestion by Nati: Disable for any 1v1 + g_hCvarEnabled = CreateConVar("autopause_enable", "1", "Whether or not to automatically pause when a player crashes."); + g_hCvarForce = CreateConVar("autopause_force", "0", "Whether or not to force pause when a player crashes."); + g_hCvarApdebug = CreateConVar("autopause_apdebug", "0", "Whether or not to debug information."); + + crashedPlayers = CreateTrie(); + infectedPlayers = CreateArray(64); + survivorPlayers = CreateArray(64); + + HookEvent("round_start", RoundStart_Event); + HookEvent("round_end", RoundEnd_Event); + HookEvent("player_team", PlayerTeam_Event); + HookEvent("player_disconnect", PlayerDisconnect_Event, EventHookMode_Pre); } -public OnAllPluginsLoaded() +public void OnAllPluginsLoaded() { - readyUpIsAvailable = LibraryExists("readyup"); + readyUpIsAvailable = LibraryExists("readyup"); } -public OnLibraryRemoved(const String:name[]) +public void OnLibraryRemoved(const char[] name) { - if (StrEqual(name, "readyup")) readyUpIsAvailable = false; + if (StrEqual(name, "readyup")) readyUpIsAvailable = false; } -public OnLibraryAdded(const String:name[]) +public void OnLibraryAdded(const char[] name) { - if (StrEqual(name, "readyup")) readyUpIsAvailable = true; + if (StrEqual(name, "readyup")) readyUpIsAvailable = true; } -public round_start(Handle:event, const String:name[], bool:dontBroadcast) { - ClearTrie(crashedPlayers); - ClearArray(infectedPlayers); - ClearArray(survivorPlayers); - RoundEnd = false; +public void RoundStart_Event(Handle event, const char[] name, bool dontBroadcast) +{ + ClearTrie(crashedPlayers); + ClearArray(infectedPlayers); + ClearArray(survivorPlayers); + RoundEnd = false; } -public round_end(Handle:event, const String:name[], bool:dontBroadcast) { - RoundEnd = true; +public void RoundEnd_Event(Handle event, const char[] name, bool dontBroadcast) +{ + RoundEnd = true; } // Handles players leaving and joining the infected team. -public playerTeam(Handle:event, const String:name[], bool:dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "userid")); - if (client <= 0 || client > MaxClients) return; - decl String:steamId[64]; - GetClientAuthId(client, AuthId_Steam2, steamId, sizeof(steamId)); - if (strcmp(steamId, "BOT") == 0) return; - new oldTeam = GetEventInt(event, "oldteam"); - new newTeam = GetEventInt(event, "team"); - - new index = FindStringInArray(infectedPlayers, steamId); - new survindex = FindStringInArray(infectedPlayers, steamId); - if (oldTeam == 3) { - if (index != -1) RemoveFromArray(infectedPlayers, index); - if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Removed player %s from infected team.", steamId); - } - else if (oldTeam == 2) { - if (survindex != -1) RemoveFromArray(survivorPlayers, survindex); - if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Removed player %s from survivor team.", steamId); - } - if (newTeam == 3) { - decl Float:spawnTime; - if (GetTrieValue(crashedPlayers, steamId, spawnTime)) { - new CountdownTimer:spawnTimer = L4D2Direct_GetSpawnTimer(client); - CTimer_Start(spawnTimer, spawnTime); - RemoveFromTrie(crashedPlayers, steamId); - LogMessage("[AutoPause] Player %s rejoined, set spawn timer to %f.", steamId, spawnTime); - } else if (index == -1) { - PushArrayString(infectedPlayers, steamId); - if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Added player %s to infected team.", steamId); - } - } - else if (newTeam == 2 && survindex == -1) { - PushArrayString(survivorPlayers, steamId); - if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Added player %s to survivor team.", steamId); - } +public void PlayerTeam_Event(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(GetEventInt(event, "userid")); + if (client <= 0 || client > MaxClients) return; + char steamId[64]; + GetClientAuthId(client, AuthId_Steam2, steamId, sizeof(steamId)); + if (strcmp(steamId, "BOT") == 0) return; + int oldTeam = GetEventInt(event, "oldteam"); + int newTeam = GetEventInt(event, "team"); + + int index = FindStringInArray(infectedPlayers, steamId); + int survindex = FindStringInArray(infectedPlayers, steamId); + if (oldTeam == 3) + { + if (index != -1) RemoveFromArray(infectedPlayers, index); + if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Removed player %s from infected team.", steamId); + } + else if (oldTeam == 2) { + if (survindex != -1) RemoveFromArray(survivorPlayers, survindex); + if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Removed player %s from survivor team.", steamId); + } + if (newTeam == 3) + { + float spawnTime; + if (GetTrieValue(crashedPlayers, steamId, spawnTime)) + { + CountdownTimer spawnTimer = L4D2Direct_GetSpawnTimer(client); + CTimer_Start(spawnTimer, spawnTime); + RemoveFromTrie(crashedPlayers, steamId); + LogMessage("[AutoPause] Player %s rejoined, set spawn timer to %f.", steamId, spawnTime); + } + else if (index == -1) { + PushArrayString(infectedPlayers, steamId); + if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Added player %s to infected team.", steamId); + } + } + else if (newTeam == 2 && survindex == -1) { + PushArrayString(survivorPlayers, steamId); + if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Added player %s to survivor team.", steamId); + } } -public playerDisconnect(Handle:event, const String:name[], bool:dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "userid")); - if (client <= 0 || client > MaxClients) return; - decl String:steamId[64]; - GetClientAuthId(client, AuthId_Steam2, steamId, sizeof(steamId)); - if (strcmp(steamId, "BOT") == 0) return; - - // Player wasn't actually a gamer, ignore - if (FindStringInArray(infectedPlayers, steamId) == -1 && FindStringInArray(survivorPlayers, steamId) == -1) return; - - decl String:reason[128]; - GetEventString(event, "reason", reason, sizeof(reason)); - decl String:playerName[128]; - GetEventString(event, "name", playerName, sizeof(playerName)); - decl String:timedOut[256]; - Format(timedOut, sizeof(timedOut), "%s timed out", playerName); - - if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Player %s (%s) left the game: %s", playerName, steamId, reason); - - // If the leaving player crashed, pause. - if (strcmp(reason, timedOut) == 0 || strcmp(reason, "No Steam logon") == 0) - { - if ((!readyUpIsAvailable || !IsInReady()) && !RoundEnd && GetConVarBool(g_hCvarEnabled)) - { - if (GetConVarBool(g_hCvarForce)) - { - ServerCommand("sm_forcepause"); - } - else - { - FakeClientCommand(client, "sm_pause"); - } - CPrintToChatAll("{blue}[{default}AutoPause{blue}] {olive}%s {default}crashed.", playerName); - } - } - - // If the leaving player was on infected, save their spawn timer. - if (FindStringInArray(infectedPlayers, steamId) != -1) { - decl Float:timeLeft; - new CountdownTimer:spawnTimer = L4D2Direct_GetSpawnTimer(client); - if (spawnTimer != CTimer_Null) { - timeLeft = CTimer_GetRemainingTime(spawnTimer); - LogMessage("[AutoPause] Player %s left the game with %f time until spawn.", steamId, timeLeft); - SetTrieValue(crashedPlayers, steamId, timeLeft); - } - } +public void PlayerDisconnect_Event(Event hEvent, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(GetEventInt(hEvent, "userid")); + if (client <= 0 || client > MaxClients) return; + char steamId[64]; + GetClientAuthId(client, AuthId_Steam2, steamId, sizeof(steamId)); + if (strcmp(steamId, "BOT") == 0) return; + + // Player wasn't actually a gamer, ignore + if (FindStringInArray(infectedPlayers, steamId) == -1 && FindStringInArray(survivorPlayers, steamId) == -1) return; + + char reason[128]; + GetEventString(hEvent, "reason", reason, sizeof(reason)); + char playerName[128]; + GetEventString(hEvent, "name", playerName, sizeof(playerName)); + char timedOut[256]; + Format(timedOut, sizeof(timedOut), "%s timed out", playerName); + + if (GetConVarBool(g_hCvarApdebug)) LogMessage("[AutoPause] Player %s (%s) left the game: %s", playerName, steamId, reason); + + // If the leaving player crashed, pause. + if (strcmp(reason, timedOut) == 0 || strcmp(reason, "No Steam logon") == 0) + { + if ((!readyUpIsAvailable || !IsInReady()) && !RoundEnd && GetConVarBool(g_hCvarEnabled)) + { + if (GetConVarBool(g_hCvarForce)) + { + ServerCommand("sm_forcepause"); + } + else + { + FakeClientCommand(client, "sm_pause"); + } + CPrintToChatAll("%t %t", "Tag", "crashed", playerName); + } + } + + // If the leaving player was on infected, save their spawn timer. + if (FindStringInArray(infectedPlayers, steamId) != -1) + { + float timeLeft; + CountdownTimer spawnTimer = L4D2Direct_GetSpawnTimer(client); + if (spawnTimer != CTimer_Null) + { + timeLeft = CTimer_GetRemainingTime(spawnTimer); + LogMessage("[AutoPause] Player %s left the game with %f time until spawn.", steamId, timeLeft); + SetTrieValue(crashedPlayers, steamId, timeLeft); + } + } } \ No newline at end of file diff --git a/addons/sourcemod/scripting/checkpoint-rage-control.sp b/addons/sourcemod/scripting/checkpoint-rage-control.sp index d5b403882..d0434fad7 100644 --- a/addons/sourcemod/scripting/checkpoint-rage-control.sp +++ b/addons/sourcemod/scripting/checkpoint-rage-control.sp @@ -33,6 +33,7 @@ int ORIGINAL_BYTES[5]; Address g_pPatchTarget; bool g_bIsPatched; +ConVar g_hCvarDebug; Handle hAllMaps, @@ -49,8 +50,7 @@ public Plugin myinfo = } -public void - OnPluginStart() +public void OnPluginStart() { LoadTranslations("checkpoint-rage-control.phrases"); Handle hGamedata = LoadGameConfigFile("checkpoint-rage-control"); @@ -59,10 +59,10 @@ public void g_pPatchTarget = FindPatchTarget(hGamedata); CloseHandle(hGamedata); - hSaferoomFrustrationTickdownMaps = CreateTrie(); - hAllMaps = CreateConVar("crc_global", "0", "Remove saferoom frustration preservation mechanic on all maps by default"); + hAllMaps = CreateConVar("crc_global", "0", "Remove saferoom frustration preservation mechanic on all maps by default"); + g_hCvarDebug = CreateConVar("crc_debug", "0", "Whether or not to debug.", FCVAR_NONE, true, 0.0, true, 1.0); RegServerCmd("saferoom_frustration_tickdown", SetSaferoomFrustrationTickdown); } @@ -105,9 +105,13 @@ public void OnMapStart() public void L4D_OnSpawnTank_Post(int client, const float vecPos[3], const float vecAng[3]) { HookEvent("player_entered_start_area", Event_EnteredStartArea); + HookEvent("round_end", Event_RoundEndEvent); + HookEvent("tank_killed", Event_TankKilled); + if(g_hCvarDebug.BoolValue) CPrintToChatAll("%t Prepared Hook", "Tag"); + } -public void Event_EnteredStartArea(Event hEvent, const char[] eName, bool dontBroadcast) +public void Event_EnteredStartArea(Event hEvent, const char[] sName, bool dontBroadcast) { int client = GetClientOfUserId(GetEventInt(hEvent, "userid")); if (IsValidSurvivor(client)) @@ -120,8 +124,28 @@ public void Event_EnteredStartArea(Event hEvent, const char[] eName, bool dontBr { CPrintToChatAll("%t %t", "Tag", "KeepFrustration"); } + if(g_hCvarDebug.BoolValue) CPrintToChatAll("%t Unhook from player_entered_start_area hook", "Tag"); + UnhookAll(); } +} + +public void Event_RoundEndEvent(Event hEvent, const char[] sName, bool dontBroadcast) +{ + if(g_hCvarDebug.BoolValue) CPrintToChatAll("%t Unhook from round_end hook", "Tag"); + UnhookAll(); +} + +public void Event_TankKilled(Event hEvent, const char[] sName, bool dontBroadcast) +{ + if(g_hCvarDebug.BoolValue) CPrintToChatAll("%t Unhook from tank_killed hook", "Tag"); + UnhookAll(); +} + +public void UnhookAll() +{ UnhookEvent("player_entered_start_area", Event_EnteredStartArea); + UnhookEvent("round_end", Event_RoundEndEvent); + UnhookEvent("tank_killed", Event_TankKilled); } bool IsPatched() diff --git a/addons/sourcemod/scripting/coinflip.sp b/addons/sourcemod/scripting/coinflip.sp index 7a23140b1..6388a40a4 100644 --- a/addons/sourcemod/scripting/coinflip.sp +++ b/addons/sourcemod/scripting/coinflip.sp @@ -1,37 +1,46 @@ -/* - Coinflip +/* + Coinflip by purpletreefactory Credit for the idea goes to Fig This version was made out of convenience - + 1.0.2: added e-z-p-z commands, removed unnecessary colors.inc, removed generation of config file */ - -#include +#pragma semicolon 1 +#pragma newdecls required + +#include #include +#include + +char + client_name[32]; // Used to store the client_name of the player who calls coinflip +int + result_int, + previous_timeC = 0, // Used for coinflip + current_timeC = 0, // Used for coinflip + previous_timeN = 0, // Used for picknumber + current_timeN = 0, // Used for picknumber + number_max = 20; // Default maximum bound for picknumber -new result_int; -new String:client_name[32]; // Used to store the client_name of the player who calls coinflip -new previous_timeC = 0; // Used for coinflip -new current_timeC = 0; // Used for coinflip -new previous_timeN = 0; // Used for picknumber -new current_timeN = 0; // Used for picknumber -new Handle:delay_time; // Handle for the coinflip_delay cvar -new number_max = 20; // Default maximum bound for picknumber +ConVar + delay_time; // Handle for the coinflip_delay cvar -public Plugin:myinfo = +public Plugin myinfo = { - name = "Coinflip", - author = "purpletreefactory, epilimic", + name = "Coinflip", + author = "purpletreefactory, epilimic", description = "purpletreefactory's version of coinflip", - version = "1.0.2", - url = "http://www.sourcemod.net/" + version = "1.0.2", + url = "http://www.sourcemod.net/" + } - -public OnPluginStart() + +public void OnPluginStart() { - delay_time = CreateConVar("coinflip_delay","-1", "Time delay in seconds between allowed coinflips. Set at -1 if no delay at all is desired."); + LoadTranslations("coinflip.phrases"); + delay_time = CreateConVar("coinflip_delay", "-1", "Time delay in seconds between allowed coinflips. Set at -1 if no delay at all is desired."); RegConsoleCmd("sm_coinflip", Command_Coinflip); RegConsoleCmd("sm_cf", Command_Coinflip); @@ -40,60 +49,57 @@ public OnPluginStart() RegConsoleCmd("sm_picknumber", Command_Picknumber); } -public Action:Command_Coinflip(client, args) +public Action Command_Coinflip(int client, int args) { current_timeC = GetTime(); - - if((current_timeC - previous_timeC) > GetConVarInt(delay_time)) // Only perform a coinflip if enough time has passed since the last one. This prevents spamming. + + if ((current_timeC - previous_timeC) > GetConVarInt(delay_time)) // Only perform a coinflip if enough time has passed since the last one. This prevents spamming. { - result_int = GetURandomInt() % 2; // Gets a random integer and checks to see whether it's odd or even - GetClientName(client, client_name, sizeof(client_name)); // Gets the client_name of the person using the command - - if(result_int == 0) - PrintToChatAll("\x01[\x05Coinflip\x01] \x03%s\x01 flipped a coin!\nIt's \x04Heads\x01!", client_name); // Here \x04 is actually yellow - else - PrintToChatAll("\x01[\x05Coinflip\x01] \x03%s\x01 flipped a coin!\nIt's \x04Tails\x01!", client_name); - - previous_timeC = current_timeC; // Update the previous time + result_int = GetURandomInt() % 2; // Gets a random integer and checks to see whether it's odd or even + GetClientName(client, client_name, sizeof(client_name)); // Gets the client_name of the person using the command + + CPrintToChatAll("%t %t", "Tag", result_int == 0 ? "Tails" : "Heads", client_name); + previous_timeC = current_timeC; // Update the previous time } else { PrintToConsole(client, "[Coinflip] Whoa there buddy, slow down. Wait at least %d seconds.", GetConVarInt(delay_time)); } - + return Plugin_Handled; } -public Action:Command_Picknumber(client, args) +public Action Command_Picknumber(int client, int args) { current_timeN = GetTime(); - - if((current_timeN - previous_timeN) > GetConVarInt(delay_time)) // Only perform a numberpick if enough time has passed since the last one. + + if ((current_timeN - previous_timeN) > GetConVarInt(delay_time)) // Only perform a numberpick if enough time has passed since the last one. { - GetClientName(client, client_name, sizeof(client_name)); // Gets the client_name of the person using the command - - if(GetCmdArgs() == 0) + GetClientName(client, client_name, sizeof(client_name)); // Gets the client_name of the person using the command + + if (GetCmdArgs() == 0) { - result_int = GetURandomInt() % (number_max); // Generates a random number within the default range - - PrintToChatAll("\x01[\x05Coinflip\x01] \x03%s\x01 rolled a \x03%d \x01sided die!\nIt's \x04%d\x01!", client_name, number_max, result_int + 1); + result_int = GetURandomInt() % (number_max); // Generates a random number within the default range + + CPrintToChatAll("%t %t", "Tag", "rolled", client_name, number_max, result_int + 1); } else { - new String:arg[32]; - new max; - - GetCmdArg(1, arg, sizeof(arg)); // Get the command argument + char arg[32]; + int max; + + GetCmdArg(1, arg, sizeof(arg)); // Get the command argument max = StringToInt(arg); - - result_int = GetURandomInt() % (max); // Generates a random number within the specified range - PrintToChatAll("\x01[\x05Coinflip\x01] \x03%s\x01 rolled a \x03%d \x01sided die!\nIt's \x04%d\x01!", client_name, max, result_int + 1); + + result_int = GetURandomInt() % (max); // Generates a random number within the specified range + CPrintToChatAll("%t %t", "Tag", "rolled", client_name, max, result_int + 1); } - - previous_timeN = current_timeN; // Update the previous time + + previous_timeN = current_timeN; // Update the previous time } else { PrintToConsole(client, "[Coinflip] Whoa there buddy, slow down. Wait at least %d seconds.", GetConVarInt(delay_time)); } + return Plugin_Handled; } \ No newline at end of file diff --git a/addons/sourcemod/scripting/current.sp b/addons/sourcemod/scripting/current.sp index 10582c2d2..5f24b4c3e 100644 --- a/addons/sourcemod/scripting/current.sp +++ b/addons/sourcemod/scripting/current.sp @@ -1,8 +1,9 @@ #pragma semicolon 1 #pragma newdecls required -#include +#include #include +#include #define TEAM_SURVIVORS 2 @@ -10,15 +11,16 @@ ConVar g_hVsBossBuffer; public Plugin myinfo = { - name = "L4D2 Survivor Progress", - author = "CanadaRox, Visor", + name = "L4D2 Survivor Progress", + author = "CanadaRox, Visor", description = "Print survivor progress in flow percents ", - version = "2.0.2", - url = "https://github.com/SirPlease/L4D2-Competitive-Rework" + version = "2.0.2", + url = "https://github.com/SirPlease/L4D2-Competitive-Rework" }; public void OnPluginStart() { + LoadTranslations("current.phrases"); g_hVsBossBuffer = FindConVar("versus_boss_buffer"); RegConsoleCmd("sm_cur", CurrentCmd); @@ -28,7 +30,7 @@ public void OnPluginStart() public Action CurrentCmd(int client, int args) { int boss_proximity = RoundToNearest(GetBossProximity() * 100.0); - PrintToChat(client, "\x01Current: \x04%d%%", boss_proximity); + CPrintToChat(client, "%t", "Current", boss_proximity); return Plugin_Handled; } @@ -41,15 +43,18 @@ float GetBossProximity() float GetMaxSurvivorCompletion() { - float flow = 0.0, tmp_flow = 0.0, origin[3]; + float flow = 0.0, tmp_flow = 0.0, origin[3]; Address pNavArea; - for (int i = 1; i <= MaxClients; i++) { - if (IsClientInGame(i) && GetClientTeam(i) == TEAM_SURVIVORS) { + for (int i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i) && GetClientTeam(i) == TEAM_SURVIVORS) + { GetClientAbsOrigin(i, origin); pNavArea = L4D2Direct_GetTerrorNavArea(origin); - if (pNavArea != Address_Null) { + if (pNavArea != Address_Null) + { tmp_flow = L4D2Direct_GetTerrorNavAreaFlow(pNavArea); - flow = (flow > tmp_flow) ? flow : tmp_flow; + flow = (flow > tmp_flow) ? flow : tmp_flow; } } } diff --git a/addons/sourcemod/scripting/include/survivor_mvp.inc b/addons/sourcemod/scripting/include/survivor_mvp.inc new file mode 100644 index 000000000..2cda02ab8 --- /dev/null +++ b/addons/sourcemod/scripting/include/survivor_mvp.inc @@ -0,0 +1,82 @@ +#if defined _survivor_mvp_included_ + #endinput +#endif +#define _survivor_mvp_included_ + +/** + * Current round MVP. + * + * @return Client index. + */ +native int SURVMVP_GetMVP(); + +/** + * Damage of client. + * + * @param client Client to check. + * @return Damage. + */ +native int SURVMVP_GetMVPDmgCount(int client); + +/** + * SI kills of client. + * + * @param client Client to check. + * @return SI Kills. + */ +native int SURVMVP_GetMVPKills(int client); + +/** + * Damage percent of client. + * + * @param client Client to check. + * @return Damage. + */ +native float SURVMVP_GetMVPDmgPercent(int client); + +/** + * Current round MVP client (Common) + * + * @return Client index. + */ +native int SURVMVP_GetMVPCI(); + +/** + * Common kills for client. + * + * @param client Client to check. + * @return Kills. + */ +native int SURVMVP_GetMVPCIKills(int client); + +/** + * CI percent of client. + * + * @param client Client to check. + * @return CI Percent. + */ +native float SURVMVP_GetMVPCIPercent(int client); + +public SharedPlugin __pl_l4d2lib = +{ + name = "survivor_mvp", + file = "survivor_mvp.smx", +#if defined REQUIRE_PLUGIN + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_PLUGIN +public void __pl_l4d2lib_SetNTVOptional() +{ + MarkNativeAsOptional("SURVMVP_GetMVP"); + MarkNativeAsOptional("SURVMVP_GetMVPDmgCount"); + MarkNativeAsOptional("SURVMVP_GetMVPKills"); + MarkNativeAsOptional("SURVMVP_GetMVPDmgPercent"); + MarkNativeAsOptional("SURVMVP_GetMVPCI"); + MarkNativeAsOptional("SURVMVP_GetMVPCIKills"); + MarkNativeAsOptional("SURVMVP_GetMVPCIPercent"); +} +#endif diff --git a/addons/sourcemod/scripting/l4d2_stats.sp b/addons/sourcemod/scripting/l4d2_stats.sp index 049c53456..a02fd3e77 100644 --- a/addons/sourcemod/scripting/l4d2_stats.sp +++ b/addons/sourcemod/scripting/l4d2_stats.sp @@ -101,8 +101,7 @@ public void Event_PlayerSpawn(Event hEvent, const char[] sEventName, bool bDontB BoomerKillTime = 0.0; g_hBoomerKillTimer = CreateTimer(0.1, Timer_KillBoomer, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); } - //防止刷特软件把特感踢出后数值没有被重置 - ClearDamage(client); + g_iLastHealth[client] = GetClientHealth(client); } } diff --git a/addons/sourcemod/scripting/l4d_tank_control_eq.sp b/addons/sourcemod/scripting/l4d_tank_control_eq.sp index 81845f948..2d219cb8b 100644 --- a/addons/sourcemod/scripting/l4d_tank_control_eq.sp +++ b/addons/sourcemod/scripting/l4d_tank_control_eq.sp @@ -4,21 +4,21 @@ #pragma semicolon 1 #pragma newdecls required -#include #include +#include #undef REQUIRE_PLUGIN #include -#define IS_VALID_CLIENT(%1) (%1 > 0 && %1 <= MaxClients) -#define IS_INFECTED(%1) (GetClientTeam(%1) == 3) -#define IS_VALID_INGAME(%1) (IS_VALID_CLIENT(%1) && IsClientInGame(%1)) -#define IS_VALID_INFECTED(%1) (IS_VALID_INGAME(%1) && IS_INFECTED(%1)) -#define IS_VALID_CASTER(%1) (IS_VALID_INGAME(%1) && casterSystemAvailable && IsClientCaster(%1)) +#define IS_VALID_CLIENT(%1) (%1 > 0 && %1 <= MaxClients) +#define IS_INFECTED(%1) (GetClientTeam(%1) == 3) +#define IS_VALID_INGAME(%1) (IS_VALID_CLIENT(%1) && IsClientInGame(%1)) +#define IS_VALID_INFECTED(%1) (IS_VALID_INGAME(%1) && IS_INFECTED(%1)) +#define IS_VALID_CASTER(%1) (IS_VALID_INGAME(%1) && casterSystemAvailable && IsClientCaster(%1)) ArrayList h_whosHadTank; -char queuedTankSteamId[64]; -ConVar hTankPrint, hTankDebug; -bool casterSystemAvailable; +char queuedTankSteamId[64]; +ConVar hTankPrint, hTankDebug; +bool casterSystemAvailable; public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) { @@ -27,65 +27,83 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max return APLRes_Success; } -public int Native_GetTankSelection(Handle plugin, int numParams) { return getInfectedPlayerBySteamId(queuedTankSteamId); } - -public Plugin myinfo = +public int Native_GetTankSelection(Handle plugin, int numParams) { - name = "L4D2 Tank Control", - author = "arti", - description = "Distributes the role of the tank evenly throughout the team", - version = "0.0.18", - url = "https://github.com/alexberriman/l4d2-plugins/tree/master/l4d_tank_control" + return getInfectedPlayerBySteamId(queuedTankSteamId); } -enum L4D2Team +public Plugin myinfo = { - L4D2Team_None = 0, - L4D2Team_Spectator, - L4D2Team_Survivor, - L4D2Team_Infected + name = "L4D2 Tank Control", + author = "arti", + description = "Distributes the role of the tank evenly throughout the team", + version = "0.0.18", + url = "https://github.com/alexberriman/l4d2-plugins/tree/master/l4d_tank_control" + } -enum ZClass -{ - ZClass_Smoker = 1, - ZClass_Boomer = 2, - ZClass_Hunter = 3, - ZClass_Spitter = 4, - ZClass_Jockey = 5, - ZClass_Charger = 6, - ZClass_Witch = 7, - ZClass_Tank = 8 +enum L4D2Team { + L4D2Team_None = 0, + L4D2Team_Spectator, + L4D2Team_Survivor, + L4D2Team_Infected +} + +enum ZClass { + ZClass_Smoker = 1, + ZClass_Boomer = 2, + ZClass_Hunter = 3, + ZClass_Spitter = 4, + ZClass_Jockey = 5, + ZClass_Charger = 6, + ZClass_Witch = 7, + ZClass_Tank = 8 } public void OnPluginStart() { - // Load translations (for targeting player) - LoadTranslations("common.phrases"); - - // Event hooks - HookEvent("player_left_start_area", PlayerLeftStartArea_Event, EventHookMode_PostNoCopy); - HookEvent("round_start", RoundStart_Event, EventHookMode_PostNoCopy); - HookEvent("round_end", RoundEnd_Event, EventHookMode_PostNoCopy); - HookEvent("player_team", PlayerTeam_Event, EventHookMode_Post); - HookEvent("tank_killed", TankKilled_Event, EventHookMode_PostNoCopy); - HookEvent("player_death", PlayerDeath_Event, EventHookMode_Post); - - // Initialise the tank arrays/data values - h_whosHadTank = new ArrayList(ByteCountToCells(64)); - - // Admin commands - RegAdminCmd("sm_tankshuffle", TankShuffle_Cmd, ADMFLAG_SLAY, "Re-picks at random someone to become tank."); - RegAdminCmd("sm_givetank", GiveTank_Cmd, ADMFLAG_SLAY, "Gives the tank to a selected player"); - - // Register the boss commands - RegConsoleCmd("sm_tank", Tank_Cmd, "Shows who is becoming the tank."); - RegConsoleCmd("sm_boss", Tank_Cmd, "Shows who is becoming the tank."); - RegConsoleCmd("sm_witch", Tank_Cmd, "Shows who is becoming the tank."); - - // Cvars - hTankPrint = CreateConVar("tankcontrol_print_all", "0", "Who gets to see who will become the tank? (0 = Infected, 1 = Everyone)"); - hTankDebug = CreateConVar("tankcontrol_debug", "0", "Whether or not to debug to console"); + // Load translations (for targeting player) + LoadTranslations("common.phrases"); + LoadTranslation("l4d_tank_control_eq.phrases"); + + // Event hooks + HookEvent("player_left_start_area", PlayerLeftStartArea_Event, EventHookMode_PostNoCopy); + HookEvent("round_start", RoundStart_Event, EventHookMode_PostNoCopy); + HookEvent("round_end", RoundEnd_Event, EventHookMode_PostNoCopy); + HookEvent("player_team", PlayerTeam_Event, EventHookMode_Post); + HookEvent("tank_killed", TankKilled_Event, EventHookMode_PostNoCopy); + HookEvent("player_death", PlayerDeath_Event, EventHookMode_Post); + + // Initialise the tank arrays/data values + h_whosHadTank = new ArrayList(ByteCountToCells(64)); + + // Admin commands + RegAdminCmd("sm_tankshuffle", TankShuffle_Cmd, ADMFLAG_SLAY, "Re-picks at random someone to become tank."); + RegAdminCmd("sm_givetank", GiveTank_Cmd, ADMFLAG_SLAY, "Gives the tank to a selected player"); + + // Register the boss commands + RegConsoleCmd("sm_tank", Tank_Cmd, "Shows who is becoming the tank."); + RegConsoleCmd("sm_boss", Tank_Cmd, "Shows who is becoming the tank."); + RegConsoleCmd("sm_witch", Tank_Cmd, "Shows who is becoming the tank."); + + // Cvars + hTankPrint = CreateConVar("tankcontrol_print_all", "0", "Who gets to see who will become the tank? (0 = Infected, 1 = Everyone)"); + hTankDebug = CreateConVar("tankcontrol_debug", "0", "Whether or not to debug to console"); +} + +void LoadTranslation(char[] sTranslation) +{ + char + sPath[PLATFORM_MAX_PATH], + sName[64]; + + Format(sName, sizeof(sName), "translations/%s.txt", sTranslation); + BuildPath(Path_SM, sPath, sizeof(sPath), sName); + if (!FileExists(sPath)) + { + SetFailState("Missing translation file %s.txt", sTranslation); + } + LoadTranslations(sTranslation); } public void OnAllPluginsLoaded() @@ -103,10 +121,10 @@ public void OnLibraryRemoved(const char[] name) if (StrEqual(name, "caster_system")) casterSystemAvailable = false; } -/*public void OnClientDisconnect(int client) +/*public void OnClientDisconnect(int client) { char tmpSteamId[64]; - + if (client) { GetClientAuthId(client, AuthId_Steam2, tmpSteamId, sizeof(tmpSteamId)); @@ -121,10 +139,9 @@ public void OnLibraryRemoved(const char[] name) /** * When a new game starts, reset the tank pool. */ - public void RoundStart_Event(Event hEvent, const char[] eName, bool dontBroadcast) { - CreateTimer(10.0, newGame); + CreateTimer(10.0, newGame); } public Action newGame(Handle timer) @@ -145,31 +162,28 @@ public Action newGame(Handle timer) /** * When the round ends, reset the active tank. */ - public void RoundEnd_Event(Event hEvent, const char[] eName, bool dontBroadcast) { - queuedTankSteamId = ""; + queuedTankSteamId = ""; } /** * When a player leaves the start area, choose a tank and output to all. */ - public void PlayerLeftStartArea_Event(Event hEvent, const char[] eName, bool dontBroadcast) { - chooseTank(0); - outputTankToAll(0); + chooseTank(0); + outputTankToAll(0); } /** * When the queued tank switches teams, choose a new one */ - public void PlayerTeam_Event(Event hEvent, const char[] name, bool dontBroadcast) { L4D2Team oldTeam = view_as(hEvent.GetInt("oldteam")); - int client = GetClientOfUserId(hEvent.GetInt("userid")); - char tmpSteamId[64]; + int client = GetClientOfUserId(hEvent.GetInt("userid")); + char tmpSteamId[64]; if (client && oldTeam == view_as(L4D2Team_Infected)) { @@ -185,363 +199,354 @@ public void PlayerTeam_Event(Event hEvent, const char[] name, bool dontBroadcast /** * When the tank dies, requeue a player to become tank (for finales) */ - public void PlayerDeath_Event(Event hEvent, const char[] eName, bool dontBroadcast) { - int zombieClass = 0; - int victimId = hEvent.GetInt("userid"); - int victim = GetClientOfUserId(victimId); - - if (victimId && IsClientInGame(victim)) - { - zombieClass = GetEntProp(victim, Prop_Send, "m_zombieClass"); - if (view_as(zombieClass) == ZClass_Tank) - { - if (GetConVarBool(hTankDebug)) - { - PrintToConsoleAll("[TC] Tank died(1), choosing a new tank"); - } - chooseTank(0); - } - } + int zombieClass = 0; + int victimId = hEvent.GetInt("userid"); + int victim = GetClientOfUserId(victimId); + + if (victimId && IsClientInGame(victim)) + { + zombieClass = GetEntProp(victim, Prop_Send, "m_zombieClass"); + if (view_as(zombieClass) == ZClass_Tank) + { + if (GetConVarBool(hTankDebug)) + { + PrintToConsoleAll("[TC] Tank died(1), choosing a new tank"); + } + chooseTank(0); + } + } } public void TankKilled_Event(Event hEvent, const char[] eName, bool dontBroadcast) { - if (GetConVarBool(hTankDebug)) - { - PrintToConsoleAll("[TC] Tank died(2), choosing a new tank"); - } - chooseTank(0); + if (GetConVarBool(hTankDebug)) + { + PrintToConsoleAll("[TC] Tank died(2), choosing a new tank"); + } + chooseTank(0); } /** * When a player wants to find out whos becoming tank, * output to them. */ - public Action Tank_Cmd(int client, int args) { - if (!IsClientInGame(client)) - return Plugin_Handled; - - int tankClientId; - char tankClientName[128]; - - // Only output if we have a queued tank - if (! strcmp(queuedTankSteamId, "")) - { - return Plugin_Handled; - } - - tankClientId = getInfectedPlayerBySteamId(queuedTankSteamId); - if (tankClientId != -1) - { - GetClientName(tankClientId, tankClientName, sizeof(tankClientName)); - - // If on infected, print to entire team - if (view_as(GetClientTeam(client)) == L4D2Team_Infected || (casterSystemAvailable && IsClientCaster(client))) - { - if (client == tankClientId) CPrintToChat(client, "{red}<{default}Tank Selection{red}> {green}You {default}will become the {red}Tank{default}!"); - else CPrintToChat(client, "{red}<{default}Tank Selection{red}> {olive}%s {default}will become the {red}Tank!", tankClientName); - } - } - - return Plugin_Handled; + if (!IsClientInGame(client)) + return Plugin_Handled; + + int tankClientId; + char tankClientName[128]; + + // Only output if we have a queued tank + if (!strcmp(queuedTankSteamId, "")) + { + return Plugin_Handled; + } + + tankClientId = getInfectedPlayerBySteamId(queuedTankSteamId); + if (tankClientId != -1) + { + GetClientName(tankClientId, tankClientName, sizeof(tankClientName)); + + // If on infected, print to entire team + if (view_as(GetClientTeam(client)) == L4D2Team_Infected || (casterSystemAvailable && IsClientCaster(client))) + { + if (client == tankClientId) CPrintToChat(client, "%t %t", "Tag_Selecion", "YouBecomeTank"); + else CPrintToChat(client, "%t %t", "Tag_Selecion", "BecomeTank", tankClientName); + } + } + + return Plugin_Handled; } /** * Shuffle the tank (randomly give to another player in * the pool. */ - public Action TankShuffle_Cmd(int client, int args) { - chooseTank(0); - outputTankToAll(0); - - return Plugin_Handled; + chooseTank(0); + outputTankToAll(0); + + return Plugin_Handled; } /** * Give the tank to a specific player. */ - public Action GiveTank_Cmd(int client, int args) -{ - // Who are we targetting? - char arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - - // Try and find a matching player - int target = FindTarget(client, arg1); - if (target == -1) - { - return Plugin_Handled; - } - - // Get the players name - char name[MAX_NAME_LENGTH]; - GetClientName(target, name, sizeof(name)); - - // Set the tank - if (IsClientInGame(target) && ! IsFakeClient(target)) - { - // Checking if on our desired team - if (view_as(GetClientTeam(target)) != L4D2Team_Infected) - { - CPrintToChatAll("{olive}[SM] {default}%s not on infected. Unable to give tank", name); - return Plugin_Handled; - } - - char steamId[64]; - GetClientAuthId(target, AuthId_Steam2, steamId, sizeof(steamId)); +{ + // Who are we targetting? + char arg1[32]; + GetCmdArg(1, arg1, sizeof(arg1)); - strcopy(queuedTankSteamId, sizeof(queuedTankSteamId), steamId); - outputTankToAll(0); - } - - return Plugin_Handled; + // Try and find a matching player + int target = FindTarget(client, arg1); + if (target == -1) + { + return Plugin_Handled; + } + + // Get the players name + char name[MAX_NAME_LENGTH]; + GetClientName(target, name, sizeof(name)); + + // Set the tank + if (IsClientInGame(target) && !IsFakeClient(target)) + { + // Checking if on our desired team + if (view_as(GetClientTeam(target)) != L4D2Team_Infected) + { + CPrintToChatAll("%t", "UnableGiveTank", name); + return Plugin_Handled; + } + + char steamId[64]; + GetClientAuthId(target, AuthId_Steam2, steamId, sizeof(steamId)); + + strcopy(queuedTankSteamId, sizeof(queuedTankSteamId), steamId); + outputTankToAll(0); + } + + return Plugin_Handled; } /** * Selects a player on the infected team from random who hasn't been * tank and gives it to them. */ - public void chooseTank(any data) { - // Create our pool of players to choose from - ArrayList infectedPool = new ArrayList(ByteCountToCells(64)); - addTeamSteamIdsToArray(infectedPool, L4D2Team_Infected); - - // If there is nobody on the infected team, return (otherwise we'd be stuck trying to select forever) - if (GetArraySize(infectedPool) == 0) - { - delete infectedPool; - return; - } + // Create our pool of players to choose from + ArrayList infectedPool = new ArrayList(ByteCountToCells(64)); + addTeamSteamIdsToArray(infectedPool, L4D2Team_Infected); - // Remove players who've already had tank from the pool. - removeTanksFromPool(infectedPool, h_whosHadTank); - - // If the infected pool is empty, remove infected players from pool - if (GetArraySize(infectedPool) == 0) // (when nobody on infected ,error) - { - ArrayList infectedTeam = new ArrayList(ByteCountToCells(64)); - addTeamSteamIdsToArray(infectedTeam, L4D2Team_Infected); - if (GetArraySize(infectedTeam) > 1) - { - removeTanksFromPool(h_whosHadTank, infectedTeam); - chooseTank(0); - } - else - { - queuedTankSteamId = ""; - } - - delete infectedTeam; - delete infectedPool; - return; - } - - // Select a random person to become tank - int rndIndex = GetRandomInt(0, GetArraySize(infectedPool) - 1); - GetArrayString(infectedPool, rndIndex, queuedTankSteamId, sizeof(queuedTankSteamId)); - delete infectedPool; + // If there is nobody on the infected team, return (otherwise we'd be stuck trying to select forever) + if (GetArraySize(infectedPool) == 0) + { + delete infectedPool; + return; + } + + // Remove players who've already had tank from the pool. + removeTanksFromPool(infectedPool, h_whosHadTank); + + // If the infected pool is empty, remove infected players from pool + if (GetArraySize(infectedPool) == 0) // (when nobody on infected ,error) + { + ArrayList infectedTeam = new ArrayList(ByteCountToCells(64)); + addTeamSteamIdsToArray(infectedTeam, L4D2Team_Infected); + if (GetArraySize(infectedTeam) > 1) + { + removeTanksFromPool(h_whosHadTank, infectedTeam); + chooseTank(0); + } + else + { + queuedTankSteamId = ""; + } + + delete infectedTeam; + delete infectedPool; + return; + } + + // Select a random person to become tank + int rndIndex = GetRandomInt(0, GetArraySize(infectedPool) - 1); + GetArrayString(infectedPool, rndIndex, queuedTankSteamId, sizeof(queuedTankSteamId)); + delete infectedPool; } /** * Make sure we give the tank to our queued player. */ - -public Action L4D_OnTryOfferingTankBot(int tank_index, bool &enterStatis) -{ - // Reset the tank's frustration if need be - if (! IsFakeClient(tank_index)) - { - PrintHintText(tank_index, "Rage Meter Refilled"); - for (int i = 1; i <= MaxClients; i++) - { - if (! IsClientInGame(i) || GetClientTeam(i) != 3) - continue; +public Action L4D_OnTryOfferingTankBot(int tank_index, bool& enterStatis) +{ + // Reset the tank's frustration if need be + if (!IsFakeClient(tank_index)) + { + PrintHintText(tank_index, "%t", "Hit_RageMeterRefilled"); + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || GetClientTeam(i) != 3) + continue; - if (tank_index == i) CPrintToChat(i, "{red}<{default}Tank Rage{red}> {olive}Rage Meter {red}Refilled"); - else CPrintToChat(i, "{red}<{default}Tank Rage{red}> {default}({green}%N{default}'s) {olive}Rage Meter {red}Refilled", tank_index); - } - - SetTankFrustration(tank_index, 100); - L4D2Direct_SetTankPassedCount(L4D2Direct_GetTankPassedCount() + 1); - - return Plugin_Handled; - } - - // If we don't have a queued tank, choose one - if (! strcmp(queuedTankSteamId, "")) - chooseTank(0); - - // Mark the player as having had tank - if (strcmp(queuedTankSteamId, "") != 0) - { - setTankTickets(queuedTankSteamId, 20000); - PushArrayString(h_whosHadTank, queuedTankSteamId); - } - - return Plugin_Continue; + if (tank_index == i) CPrintToChat(i, "%t %t", "Tag_Rage", "YouRageMeterRefilled"); + else CPrintToChat(i, "%t %t", "Tag_Rage", "RageMeterRefilled", tank_index); + } + + SetTankFrustration(tank_index, 100); + L4D2Direct_SetTankPassedCount(L4D2Direct_GetTankPassedCount() + 1); + + return Plugin_Handled; + } + + // If we don't have a queued tank, choose one + if (!strcmp(queuedTankSteamId, "")) + chooseTank(0); + + // Mark the player as having had tank + if (strcmp(queuedTankSteamId, "") != 0) + { + setTankTickets(queuedTankSteamId, 20000); + PushArrayString(h_whosHadTank, queuedTankSteamId); + } + + return Plugin_Continue; } /** * Sets the amount of tickets for a particular player, essentially giving them tank. */ - public void setTankTickets(const char[] steamId, int tickets) { - int tankClientId = getInfectedPlayerBySteamId(steamId); - - for (int i = 1; i <= MaxClients; i++) - { - if (IsClientInGame(i) && ! IsFakeClient(i) && GetClientTeam(i) == 3) - { - L4D2Direct_SetTankTickets(i, (i == tankClientId) ? tickets : 0); - } - } + int tankClientId = getInfectedPlayerBySteamId(steamId); + + for (int i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i) && !IsFakeClient(i) && GetClientTeam(i) == 3) + { + L4D2Direct_SetTankTickets(i, (i == tankClientId) ? tickets : 0); + } + } } /** * Output who will become tank */ - public void outputTankToAll(any data) { - char tankClientName[MAX_NAME_LENGTH]; - int tankClientId = getInfectedPlayerBySteamId(queuedTankSteamId); - - if (tankClientId != -1) - { - GetClientName(tankClientId, tankClientName, sizeof(tankClientName)); - if (GetConVarBool(hTankPrint)) - { - CPrintToChatAll("{red}<{default}Tank Selection{red}> {olive}%s {default}will become the {red}Tank!", tankClientName); - } - else - { - for (int i = 1; i <= MaxClients; i++) - { - if (!IS_VALID_INFECTED(i) && !IS_VALID_CASTER(i)) - continue; - - if (tankClientId == i) CPrintToChat(i, "{red}<{default}Tank Selection{red}> {green}You {default}will become the {red}Tank{default}!"); - else CPrintToChat(i, "{red}<{default}Tank Selection{red}> {olive}%s {default}will become the {red}Tank!", tankClientName); - } - } - } + char tankClientName[MAX_NAME_LENGTH]; + int tankClientId = getInfectedPlayerBySteamId(queuedTankSteamId); + + if (tankClientId != -1) + { + GetClientName(tankClientId, tankClientName, sizeof(tankClientName)); + if (GetConVarBool(hTankPrint)) + { + CPrintToChatAll("%t %t", "Tag_Selecion", "BecomeTank", tankClientName); + } + else + { + for (int i = 1; i <= MaxClients; i++) + { + if (!IS_VALID_INFECTED(i) && !IS_VALID_CASTER(i)) + continue; + + if (tankClientId == i) CPrintToChat(i, "%t %t", "Tag_Selecion", "YouBecomeTank"); + else CPrintToChat(i, "%t %t", "Tag_Selecion", "BecomeTank", tankClientName); + } + } + } } -stock void PrintToInfected(const char[] Message, any ... ) +stock void PrintToInfected(const char[] Message, any...) { - char sPrint[256]; - VFormat(sPrint, sizeof(sPrint), Message, 2); + char sPrint[256]; + VFormat(sPrint, sizeof(sPrint), Message, 2); - for (int i = 1; i <= MaxClients; i++) - { - if (!IS_VALID_INFECTED(i) && !IS_VALID_CASTER(i)) - { - continue; - } + for (int i = 1; i <= MaxClients; i++) + { + if (!IS_VALID_INFECTED(i) && !IS_VALID_CASTER(i)) + { + continue; + } - CPrintToChat(i, "{default}%s", sPrint); - } + CPrintToChat(i, "{default}%s", sPrint); + } } /** * Adds steam ids for a particular team to an array. - * + * * @ param Handle:steamIds * The array steam ids will be added to. * @param L4D2Team:team * The team to get steam ids for. */ - public void addTeamSteamIdsToArray(ArrayList steamIds, L4D2Team team) { - char steamId[64]; + char steamId[64]; - for (int i = 1; i <= MaxClients; i++) - { - // Basic check - if (IsClientInGame(i) && ! IsFakeClient(i)) - { - // Checking if on our desired team - if (view_as(GetClientTeam(i)) != team) - continue; - - GetClientAuthId(i, AuthId_Steam2, steamId, sizeof(steamId)); - PushArrayString(steamIds, steamId); - } - } + for (int i = 1; i <= MaxClients; i++) + { + // Basic check + if (IsClientInGame(i) && !IsFakeClient(i)) + { + // Checking if on our desired team + if (view_as(GetClientTeam(i)) != team) + continue; + + GetClientAuthId(i, AuthId_Steam2, steamId, sizeof(steamId)); + PushArrayString(steamIds, steamId); + } + } } /** * Removes steam ids from the tank pool if they've already had tank. - * + * * @param Handle:steamIdTankPool * The pool of potential steam ids to become tank. * @ param Handle:tanks * The steam ids of players who've already had tank. - * + * * @return * The pool of steam ids who haven't had tank. */ - public void removeTanksFromPool(ArrayList steamIdTankPool, ArrayList tanks) { - int index; - char steamId[64]; - - int ArraySize = GetArraySize(tanks); - for (int i = 0; i < ArraySize; i++) - { - GetArrayString(tanks, i, steamId, sizeof(steamId)); - index = FindStringInArray(steamIdTankPool, steamId); - - if (index != -1) - { - RemoveFromArray(steamIdTankPool, index); - } - } + int index; + char steamId[64]; + + int ArraySize = GetArraySize(tanks); + for (int i = 0; i < ArraySize; i++) + { + GetArrayString(tanks, i, steamId, sizeof(steamId)); + index = FindStringInArray(steamIdTankPool, steamId); + + if (index != -1) + { + RemoveFromArray(steamIdTankPool, index); + } + } } /** * Retrieves a player's client index by their steam id. - * + * * @param const String:steamId[] * The steam id to look for. - * + * * @return * The player's client index. */ - -public int getInfectedPlayerBySteamId(const char[] steamId) +public int getInfectedPlayerBySteamId(const char[] steamId) { - char tmpSteamId[64]; - - for (int i = 1; i <= MaxClients; i++) - { - if (!IsClientInGame(i) || GetClientTeam(i) != 3) - continue; - - GetClientAuthId(i, AuthId_Steam2, tmpSteamId, sizeof(tmpSteamId)); - - if (strcmp(steamId, tmpSteamId) == 0) - return i; - } - - return -1; + char tmpSteamId[64]; + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsClientInGame(i) || GetClientTeam(i) != 3) + continue; + + GetClientAuthId(i, AuthId_Steam2, tmpSteamId, sizeof(tmpSteamId)); + + if (strcmp(steamId, tmpSteamId) == 0) + return i; + } + + return -1; } -void SetTankFrustration(int iTankClient, int iFrustration) { - if (iFrustration < 0 || iFrustration > 100) { - return; - } - - SetEntProp(iTankClient, Prop_Send, "m_frustration", 100-iFrustration); +void SetTankFrustration(int iTankClient, int iFrustration) +{ + if (iFrustration < 0 || iFrustration > 100) + { + return; + } + + SetEntProp(iTankClient, Prop_Send, "m_frustration", 100 - iFrustration); } \ No newline at end of file diff --git a/addons/sourcemod/scripting/l4d_tank_damage_announce.sp b/addons/sourcemod/scripting/l4d_tank_damage_announce.sp index 4eee5f62a..7632442a3 100644 --- a/addons/sourcemod/scripting/l4d_tank_damage_announce.sp +++ b/addons/sourcemod/scripting/l4d_tank_damage_announce.sp @@ -1,39 +1,45 @@ /* L4D_TANK_DAMAGE_ANNOUNCE -* L4D_TANK_DAMAGE_ANNOUNCE -*/ + * L4D_TANK_DAMAGE_ANNOUNCE + */ #pragma semicolon 1 -#include -#include #include +#include +#include -new const TEAM_SURVIVOR = 2; -new const TEAM_INFECTED = 3; -new const ZOMBIECLASS_TANK = 8; // Zombie class of the tank, used to find tank after he have been passed to another player -new bool: g_bEnabled = true; -new bool: g_bAnnounceTankDamage = false; // Whether or not tank damage should be announced -new bool: g_bIsTankInPlay = false; // Whether or not the tank is active -new bool: bPrintedHealth = false; // Is Remaining Health showed? -new g_iWasTank[MAXPLAYERS + 1] = {0, ...}; // Was Player Tank before he died. -new g_iWasTankAI = 0; -new g_iOffset_Incapacitated = 0; // Used to check if tank is dying -new g_iTankClient = 0; // Which client is currently playing as tank -new g_iLastTankHealth = 0; // Used to award the killing blow the exact right amount of damage -new g_iSurvivorLimit = 4; // For survivor array in damage print -new g_iDamage[MAXPLAYERS + 1]; -new Float: g_fMaxTankHealth = 6000.0; -new Handle: g_hCvarEnabled = INVALID_HANDLE; -new Handle: g_hCvarTankHealth = INVALID_HANDLE; -new Handle: g_hCvarDifficulty = INVALID_HANDLE; -new Handle: g_hCvarSurvivorLimit = INVALID_HANDLE; -new Handle:fwdOnTankDeath = INVALID_HANDLE; +#define TEAM_SURVIVOR 2 +#define TEAM_INFECTED 3 +#define ZOMBIECLASS_TANK 8 // Zombie class of the tank, used to find tank after he have been passed to another player + +bool + g_bEnabled = true, + g_bAnnounceTankDamage = false, // Whether or not tank damage should be announced + g_bIsTankInPlay = false, // Whether or not the tank is active + bPrintedHealth = false; // Is Remaining Health showed? +int + g_iWasTank[MAXPLAYERS + 1] = { 0, ... }, // Was Player Tank before he died. + g_iWasTankAI = 0, + g_iOffset_Incapacitated = 0, // Used to check if tank is dying + g_iTankClient = 0, // Which client is currently playing as tank + g_iLastTankHealth = 0, // Used to award the killing blow the exact right amount of damage + g_iSurvivorLimit = 4, // For survivor array in damage print + g_iDamage[MAXPLAYERS + 1]; +float + g_fMaxTankHealth = 6000.0; +ConVar + g_cvarEnabled, + g_cvarTankHealth, + g_cvarDifficulty, + g_cvarSurvivorLimit; +Handle + fwdOnTankDeath = INVALID_HANDLE; /* * Version 0.6.6 * - Better looking Output. * - Added Tank Name display when Tank dies, normally it only showed the Tank's name if the Tank survived -* +* * Version 0.6.6b * - Fixed Printing Two Tanks when last map Tank survived. * Added by; Sir @@ -41,46 +47,61 @@ new Handle:fwdOnTankDeath = INVALID_HANDLE; * Version 0.6.7 * - Added Campaign Difficulty Support. * Added by; Sir -*/ - -public Plugin:myinfo = -{ - name = "Tank Damage Announce L4D2", - author = "Griffin and Blade", +*/ +public Plugin myinfo = { + name = "Tank Damage Announce L4D2", + author = "Griffin and Blade", description = "Announce damage dealt to tanks by survivors", - version = "0.6.7", + version = "0.6.7", } -public OnPluginStart() +public void OnPluginStart() { - g_bIsTankInPlay = false; + LoadTranslation("l4d_tank_damage_announce.phrases"); + g_bIsTankInPlay = false; g_bAnnounceTankDamage = false; - g_iTankClient = 0; + g_iTankClient = 0; ClearTankDamage(); HookEvent("tank_spawn", Event_TankSpawn); HookEvent("player_death", Event_PlayerKilled); HookEvent("round_start", Event_RoundStart); HookEvent("round_end", Event_RoundEnd); HookEvent("player_hurt", Event_PlayerHurt); - - g_hCvarEnabled = CreateConVar("l4d_tankdamage_enabled", "1", "Announce damage done to tanks when enabled", FCVAR_NONE|FCVAR_SPONLY|FCVAR_NOTIFY, true, 0.0, true, 1.0); - g_hCvarSurvivorLimit = FindConVar("survivor_limit"); - g_hCvarTankHealth = FindConVar("z_tank_health"); - g_hCvarDifficulty = FindConVar("z_difficulty"); - - HookConVarChange(g_hCvarEnabled, Cvar_Enabled); - HookConVarChange(g_hCvarSurvivorLimit, Cvar_SurvivorLimit); - HookConVarChange(g_hCvarTankHealth, Cvar_TankHealth); - HookConVarChange(g_hCvarDifficulty, Cvar_TankHealth); + + g_cvarEnabled = CreateConVar("l4d_tankdamage_enabled", "1", "Announce damage done to tanks when enabled", FCVAR_NONE | FCVAR_SPONLY | FCVAR_NOTIFY, true, 0.0, true, 1.0); + g_cvarSurvivorLimit = FindConVar("survivor_limit"); + g_cvarTankHealth = FindConVar("z_tank_health"); + g_cvarDifficulty = FindConVar("z_difficulty"); + + HookConVarChange(g_cvarEnabled, Cvar_Enabled); + HookConVarChange(g_cvarSurvivorLimit, Cvar_SurvivorLimit); + HookConVarChange(g_cvarTankHealth, Cvar_TankHealth); + HookConVarChange(g_cvarDifficulty, Cvar_TankHealth); HookConVarChange(FindConVar("mp_gamemode"), Cvar_TankHealth); - g_bEnabled = GetConVarBool(g_hCvarEnabled); + + g_bEnabled = g_cvarEnabled.BoolValue; CalculateTankHealth(); - + g_iOffset_Incapacitated = FindSendPropInfo("Tank", "m_isIncapacitated"); - fwdOnTankDeath = CreateGlobalForward("OnTankDeath", ET_Event); + fwdOnTankDeath = CreateGlobalForward("OnTankDeath", ET_Event); } -public OnMapStart() +void LoadTranslation(char[] sTranslation) +{ + char + sPath[PLATFORM_MAX_PATH], + sName[64]; + + Format(sName, sizeof(sName), "translations/%s.txt", sTranslation); + BuildPath(Path_SM, sPath, sizeof(sPath), sName); + if (!FileExists(sPath)) + { + SetFailState("Missing translation file %s.txt", sTranslation); + } + LoadTranslations(sTranslation); +} + +public void OnMapStart() { // In cases where a tank spawns and map is changed manually, bypassing round end ClearTankDamage(); @@ -88,33 +109,33 @@ public OnMapStart() PrecacheSound("ui/pickup_secret01.wav"); } -public OnClientDisconnect_Post(client) +public void OnClientDisconnect_Post(int client) { if (!g_bIsTankInPlay || client != g_iTankClient) return; - CreateTimer(0.1, Timer_CheckTank, client); // Use a delayed timer due to bugs where the tank passes to another player + CreateTimer(0.1, Timer_CheckTank, client); // Use a delayed timer due to bugs where the tank passes to another player } -public Cvar_Enabled(Handle:convar, const String:oldValue[], const String:newValue[]) +public void Cvar_Enabled(Handle convar, const char[] oldValue, const char[] newValue) { - g_bEnabled = StringToInt(newValue) > 0 ? true:false; + g_bEnabled = StringToInt(newValue) > 0 ? true : false; } -public Cvar_SurvivorLimit(Handle:convar, const String:oldValue[], const String:newValue[]) +public void Cvar_SurvivorLimit(Handle convar, const char[] oldValue, const char[] newValue) { g_iSurvivorLimit = StringToInt(newValue); } -public Cvar_TankHealth(Handle:convar, const String:oldValue[], const String:newValue[]) +public void Cvar_TankHealth(Handle convar, const char[] oldValue, const char[] newValue) { CalculateTankHealth(); } -CalculateTankHealth() +void CalculateTankHealth() { - new String:sGameMode[32]; + char sGameMode[32]; GetConVarString(FindConVar("mp_gamemode"), sGameMode, sizeof(sGameMode)); - g_fMaxTankHealth = GetConVarFloat(g_hCvarTankHealth); + g_fMaxTankHealth = g_cvarTankHealth.FloatValue; if (g_fMaxTankHealth <= 0.0) g_fMaxTankHealth = 1.0; // Versus or Realism Versus @@ -122,85 +143,86 @@ CalculateTankHealth() g_fMaxTankHealth *= 1.5; // Anything else (should be fine...?) - else + else { - g_fMaxTankHealth = GetConVarFloat(g_hCvarTankHealth); + g_fMaxTankHealth = g_cvarTankHealth.FloatValue; char sDifficulty[16]; - GetConVarString(g_hCvarDifficulty, sDifficulty, sizeof(sDifficulty)); + GetConVarString(g_cvarDifficulty, sDifficulty, sizeof(sDifficulty)); - if (sDifficulty[0] == 'E') g_fMaxTankHealth *= 0.75; // Easy + if (sDifficulty[0] == 'E') g_fMaxTankHealth *= 0.75; // Easy else if (sDifficulty[0] == 'H' - || sDifficulty[0] == 'I') g_fMaxTankHealth *= 2.0; // Advanced or Expert + || sDifficulty[0] == 'I') g_fMaxTankHealth *= 2.0; // Advanced or Expert } } -public Event_PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) +public void Event_PlayerHurt(Handle event, const char[] name, bool dontBroadcast) { - if (!g_bIsTankInPlay) return; // No tank in play; no damage to record - - new victim = GetClientOfUserId(GetEventInt(event, "userid")); - if (victim != GetTankClient() || // Victim isn't tank; no damage to record - IsTankDying() // Something buggy happens when tank is dying with regards to damage - ) return; - - new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); + if (!g_bIsTankInPlay) + return; // No tank in play; no damage to record + + int victim = GetClientOfUserId(GetEventInt(event, "userid")); + if (victim != GetTankClient() || IsTankDying()) + return; + + int attacker = GetClientOfUserId(GetEventInt(event, "attacker")); // We only care about damage dealt by survivors, though it can be funny to see // claw/self inflicted hittable damage, so maybe in the future we'll do that - if (attacker == 0 || // Damage from world? - !IsClientInGame(attacker) || // Not sure if this happens - GetClientTeam(attacker) != TEAM_SURVIVOR - ) return; - + if (attacker == 0 || !IsClientInGame(attacker) || GetClientTeam(attacker) != TEAM_SURVIVOR) + return; + g_iDamage[attacker] += GetEventInt(event, "dmg_health"); g_iLastTankHealth = GetEventInt(event, "health"); } -public Event_PlayerKilled(Handle:event, const String:name[], bool:dontBroadcast) +public void Event_PlayerKilled(Handle event, const char[] name, bool dontBroadcast) { - if (!g_bIsTankInPlay) return; // No tank in play; no damage to record - - new victim = GetClientOfUserId(GetEventInt(event, "userid")); - if (victim != g_iTankClient) return; - + if (!g_bIsTankInPlay) + return; // No tank in play; no damage to record + + int victim = GetClientOfUserId(GetEventInt(event, "userid")); + if (victim != g_iTankClient) + return; + // Award the killing blow's damage to the attacker; we don't award // damage from player_hurt after the tank has died/is dying // If we don't do it this way, we get wonky/inaccurate damage values - new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); + int attacker = GetClientOfUserId(GetEventInt(event, "attacker")); if (attacker && IsClientInGame(attacker)) g_iDamage[attacker] += g_iLastTankHealth; - - //Player was Tank - if(!IsFakeClient(victim)) g_iWasTank[victim] = 1; + + // Player was Tank + if (!IsFakeClient(victim)) g_iWasTank[victim] = 1; else g_iWasTankAI = 1; // Damage announce could probably happen right here... - CreateTimer(0.1, Timer_CheckTank, victim); // Use a delayed timer due to bugs where the tank passes to another player + CreateTimer(0.1, Timer_CheckTank, victim); // Use a delayed timer due to bugs where the tank passes to another player } -public Event_TankSpawn(Handle:event, const String:name[], bool:dontBroadcast) +public void Event_TankSpawn(Handle event, const char[] name, bool dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "userid")); + int client = GetClientOfUserId(GetEventInt(event, "userid")); g_iTankClient = client; - - if (g_bIsTankInPlay) return; // Tank passed - + + if (g_bIsTankInPlay) + return; // Tank passed + EmitSoundToAll("ui/pickup_secret01.wav", _, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, 0.8); // New tank, damage has not been announced g_bAnnounceTankDamage = true; - g_bIsTankInPlay = true; + g_bIsTankInPlay = true; // Set health for damage print in case it doesn't get set by player_hurt (aka no one shoots the tank) - g_iLastTankHealth = GetClientHealth(client); + g_iLastTankHealth = GetClientHealth(client); } -public Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast) +public void Event_RoundStart(Handle event, const char[] name, bool dontBroadcast) { - bPrintedHealth = false; + bPrintedHealth = false; g_bIsTankInPlay = false; - g_iTankClient = 0; - ClearTankDamage(); // Probably redundant + g_iTankClient = 0; + ClearTankDamage(); // Probably redundant } // When survivors wipe or juke tank, announce damage -public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) +public void Event_RoundEnd(Handle event, const char[] name, bool dontBroadcast) { // But only if a tank that hasn't been killed exists if (g_bAnnounceTankDamage) @@ -211,164 +233,177 @@ public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) ClearTankDamage(); } -public Action:Timer_CheckTank(Handle:timer, any:oldtankclient) +public Action Timer_CheckTank(Handle timer, int oldtankclient) { - if (g_iTankClient != oldtankclient) return; // Tank passed - - new tankclient = FindTankClient(); + if (g_iTankClient != oldtankclient) + return Plugin_Continue; // Tank passed + + int tankclient = FindTankClient(); if (tankclient && tankclient != oldtankclient) { g_iTankClient = tankclient; - - return; // Found tank, done + return Plugin_Continue; // Found tank, done } - - if (g_bAnnounceTankDamage) PrintTankDamage(); + + if (g_bAnnounceTankDamage) + PrintTankDamage(); ClearTankDamage(); - g_bIsTankInPlay = false; // No tank in play + g_bIsTankInPlay = false; // No tank in play Call_StartForward(fwdOnTankDeath); Call_Finish(); + return Plugin_Continue; } -bool:IsTankDying() +bool IsTankDying() { - new tankclient = GetTankClient(); - if (!tankclient) return false; + int tankclient = GetTankClient(); + if (!tankclient) + return false; - return bool:GetEntData(tankclient, g_iOffset_Incapacitated); + return view_as(GetEntData(tankclient, g_iOffset_Incapacitated)); } -PrintRemainingHealth() +void PrintRemainingHealth() { bPrintedHealth = true; - if (!g_bEnabled) return; - new tankclient = GetTankClient(); - if (!tankclient) return; - - decl String:name[MAX_NAME_LENGTH]; - if (IsFakeClient(tankclient)) name = "AI"; - else GetClientName(tankclient, name, sizeof(name)); - CPrintToChatAll("{default}[{green}!{default}] {blue}Tank {default}({olive}%s{default}) had {green}%d {default}health remaining", name, g_iLastTankHealth); + if (!g_bEnabled) + return; + int tankclient = GetTankClient(); + if (!tankclient) + return; + + char + sName[MAX_NAME_LENGTH], + sIAName[8]; + Format(sIAName, sizeof(sIAName), "%t", "AI"); + GetClientName(tankclient, sName, sizeof(sName)); + CPrintToChatAll("%t %t", "Tag", "HealthRemaining", IsFakeClient(tankclient) ? sIAName : sName, g_iLastTankHealth); } -PrintTankDamage() +void PrintTankDamage() { - if (!g_bEnabled) return; - + if (!g_bEnabled) + return; + if (!bPrintedHealth) { - for (new i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if(g_iWasTank[i] > 0) + if (g_iWasTank[i] > 0) { - decl String:name[MAX_NAME_LENGTH]; - GetClientName(i, name, sizeof(name)); - CPrintToChatAll("{default}[{green}!{default}] {blue}Damage {default}dealt to {blue}Tank {default}({olive}%s{default})", name); + char sName[MAX_NAME_LENGTH]; + GetClientName(i, sName, sizeof(sName)); + CPrintToChatAll("%t %t", "Tag", "DealtToTank", sName); g_iWasTank[i] = 0; } - else if(g_iWasTankAI > 0) - CPrintToChatAll("{default}[{green}!{default}] {blue}Damage {default}dealt to {blue}Tank {default}({olive}AI{default})"); + else if (g_iWasTankAI > 0) + { + char sIAName[8]; + Format(sIAName, sizeof(sIAName), "%t", "AI"); + CPrintToChatAll("%t %t", "Tag", "DealtToTank", sIAName); + } g_iWasTankAI = 0; } } - - new client; - new percent_total; // Accumulated total of calculated percents, for fudging out numbers at the end - new damage_total; // Accumulated total damage dealt by survivors, to see if we need to fudge upwards to 100% - new survivor_index = -1; - new survivor_clients[g_iSurvivorLimit]; // Array to store survivor client indexes in, for the display iteration - decl percent_damage, damage; + + int + client, + percent_total, // Accumulated total of calculated percents, for fudging out numbers at the end + damage_total, // Accumulated total damage dealt by survivors, to see if we need to fudge upwards to 100% + survivor_index = -1, + percent_damage, + damage; + int[] survivor_clients = new int[g_iSurvivorLimit]; // Array to store survivor client indexes in, for the display iteration for (client = 1; client <= MaxClients; client++) { if (!IsClientInGame(client) || GetClientTeam(client) != TEAM_SURVIVOR || g_iDamage[client] == 0) continue; survivor_index++; survivor_clients[survivor_index] = client; - damage = g_iDamage[client]; + damage = g_iDamage[client]; damage_total += damage; percent_damage = GetDamageAsPercent(damage); percent_total += percent_damage; } SortCustom1D(survivor_clients, g_iSurvivorLimit, SortByDamageDesc); - - new percent_adjustment; + + int percent_adjustment; // Percents add up to less than 100% AND > 99.5% damage was dealt to tank if ((percent_total < 100 && float(damage_total) > (g_fMaxTankHealth - (g_fMaxTankHealth / 200.0)))) { percent_adjustment = 100 - percent_total; } - - new last_percent = 100; // Used to store the last percent in iteration to make sure an adjusted percent doesn't exceed the previous percent - decl adjusted_percent_damage; - for (new k; k <= survivor_index; k++) + + int + last_percent = 100, // Used to store the last percent in iteration to make sure an adjusted percent doesn't exceed the previous percent + adjusted_percent_damage; + for (int k; k <= survivor_index; k++) { - client = survivor_clients[k]; - damage = g_iDamage[client]; + client = survivor_clients[k]; + damage = g_iDamage[client]; percent_damage = GetDamageAsPercent(damage); // Attempt to adjust the top damager's percent, defer adjustment to next player if it's an exact percent // e.g. 3000 damage on 6k health tank shouldn't be adjusted - if (percent_adjustment != 0 && // Is there percent to adjust - damage > 0 && // Is damage dealt > 0% - !IsExactPercent(damage) // Percent representation is not exact, e.g. 3000 damage on 6k tank = 50% + if (percent_adjustment != 0 && // Is there percent to adjust + damage > 0 && // Is damage dealt > 0% + !IsExactPercent(damage) // Percent representation is not exact, e.g. 3000 damage on 6k tank = 50% ) { adjusted_percent_damage = percent_damage + percent_adjustment; - if (adjusted_percent_damage <= last_percent) // Make sure adjusted percent is not higher than previous percent, order must be maintained + if (adjusted_percent_damage <= last_percent) // Make sure adjusted percent is not higher than previous percent, order must be maintained { - percent_damage = adjusted_percent_damage; + percent_damage = adjusted_percent_damage; percent_adjustment = 0; } } last_percent = percent_damage; - for (new i = 1; i <= MaxClients; i++) + for (int i = 1; i <= MaxClients; i++) { - if (IsClientInGame(i)) - { - CPrintToChat(i, "{blue}[{default}%d{blue}] ({default}%i%%{blue}) {olive}%N", damage, percent_damage, client); + if (IsClientInGame(i)) + { + CPrintToChat(i, "%t", "PercentDamage", damage, percent_damage, client); } } } } -ClearTankDamage() +void ClearTankDamage() { g_iLastTankHealth = 0; - g_iWasTankAI = 0; - for (new i = 1; i <= MaxClients; i++) - { - g_iDamage[i] = 0; + g_iWasTankAI = 0; + for (int i = 1; i <= MaxClients; i++) + { + g_iDamage[i] = 0; g_iWasTank[i] = 0; } g_bAnnounceTankDamage = false; } - -GetTankClient() +int GetTankClient() { - if (!g_bIsTankInPlay) return 0; - - new tankclient = g_iTankClient; - - if (!IsClientInGame(tankclient)) // If tank somehow is no longer in the game (kicked, hence events didn't fire) + if (!g_bIsTankInPlay) + return 0; + + int tankclient = g_iTankClient; + + if (!IsClientInGame(tankclient)) // If tank somehow is no longer in the game (kicked, hence events didn't fire) { - tankclient = FindTankClient(); // find the tank client - if (!tankclient) return 0; + tankclient = FindTankClient(); // find the tank client + if (!tankclient) + return 0; g_iTankClient = tankclient; } - + return tankclient; } -FindTankClient() +int FindTankClient() { - for (new client = 1; client <= MaxClients; client++) + for (int client = 1; client <= MaxClients; client++) { - if (!IsClientInGame(client) || - GetClientTeam(client) != TEAM_INFECTED || - !IsPlayerAlive(client) || - GetEntProp(client, Prop_Send, "m_zombieClass") != ZOMBIECLASS_TANK) - continue; - - return client; // Found tank, return + if (!IsClientInGame(client) || GetClientTeam(client) != TEAM_INFECTED || !IsPlayerAlive(client) || GetEntProp(client, Prop_Send, "m_zombieClass") != ZOMBIECLASS_TANK) + continue; + + return client; // Found tank, return } return 0; } @@ -378,15 +413,15 @@ int GetDamageAsPercent(int damage) return RoundToNearest((damage / g_fMaxTankHealth) * 100.0); } -//comparing the type of int with the float, how different is it +// comparing the type of int with the float, how different is it bool IsExactPercent(int damage) { float fDamageAsPercent = (damage / g_fMaxTankHealth) * 100.0; - float fDifference = float(GetDamageAsPercent(damage)) - fDamageAsPercent; + float fDifference = float(GetDamageAsPercent(damage)) - fDamageAsPercent; return (FloatAbs(fDifference) < 0.001) ? true : false; } -public SortByDamageDesc(elem1, elem2, const array[], Handle:hndl) +public int SortByDamageDesc(elem1, elem2, const array[], Handle hndl) { // By damage, then by client index, descending if (g_iDamage[elem1] > g_iDamage[elem2]) return -1; diff --git a/addons/sourcemod/scripting/nodeathcamskip.sp b/addons/sourcemod/scripting/nodeathcamskip.sp index ba09f183d..96bdd8f45 100644 --- a/addons/sourcemod/scripting/nodeathcamskip.sp +++ b/addons/sourcemod/scripting/nodeathcamskip.sp @@ -44,23 +44,23 @@ public Action Listener_Join(int client, const char[] command, int argc) { if (GetInfectedPlayers() == (FindConVar("z_max_player_zombies")).IntValue) { return Plugin_Handled; } if (Blocked[client]) { - + // Warn Others. if (!bSkipPrint[client]) { - CPrintToChatAll("{red}[{default}Exploit{red}] {olive}%N {default}tried skipping the Death Timer.", client); + CPrintToChatAll("%t %t", "Tag", "DeathTimer", client); bSkipPrint[client] = true; } // Tell Offender. - CPrintToChat(client, "{red}[{default}Exploit{red}] {default}You will be unable to join the Team for {red}%.1f {default}Seconds.", (fSavedTime[client] + 6.0) - GetGameTime()); - CPrintToChat(client, "{red}[{default}Exploit{red}] {default}You will be moved automatically."); + CPrintToChat(client, "%t %t", "Tag", "UnableToJoin", (fSavedTime[client] + 6.0) - GetGameTime()); + CPrintToChat(client, "%t %t", "Tag", "Moved"); return Plugin_Handled; } if (GetInfectedPlayers() + GetBlockedPlayers() == (FindConVar("z_max_player_zombies").IntValue)) { - CPrintToChat(client, "{red}[{default}!{red}] {default}This team currently has slots {olive}reserved{default}."); + CPrintToChat(client, "%t %t", "Tag", "SlotsReserved"); return Plugin_Handled; } } diff --git a/addons/sourcemod/scripting/pause.sp b/addons/sourcemod/scripting/pause.sp index d4f2166ba..101b904a3 100644 --- a/addons/sourcemod/scripting/pause.sp +++ b/addons/sourcemod/scripting/pause.sp @@ -240,8 +240,14 @@ public Action Pause_Cmd(int client, int args) initiatorId = GetClientUserId(client); pauseTeam = GetClientTeam(client); GetClientName(client, initiatorName, sizeof(initiatorName)); - - CPrintToChatAll("%t %t", "Tag", "PauseCommand", client); + + char sPauseCount[64] = "."; + if(pauseLimitCvar.IntValue > 0) + { + Format(sPauseCount, sizeof(sPauseCount), "%t", "PauseCountFormat", PauseCount(client), pauseLimitCvar.IntValue); + } + + CPrintToChatAll("%t %t", "Tag", "PauseCommand", client, sPauseCount); pauseDelay = pauseDelayCvar.IntValue; if (pauseDelay == 0) @@ -424,7 +430,7 @@ bool AddPauseCount(int client) if (pauseLimit > 0 && pauseCount >= pauseLimit) { - CPrintToChat(client, "%t %t", "Tag", "PauseLimit"); + CPrintToChat(client, "%t %t", "Tag", "PauseLimit", pauseLimit); return false; } @@ -434,6 +440,16 @@ bool AddPauseCount(int client) return true; } +int PauseCount(int client) +{ + char authId[18]; + GetClientAuthId(client, AuthId_SteamID64, authId, 18, false); + int pauseCount = 0; + playerPauseCount.GetValue(authId, pauseCount); + + return pauseCount; +} + void AttemptPause() { if (deferredPauseTimer == null) diff --git a/addons/sourcemod/scripting/readyup.sp b/addons/sourcemod/scripting/readyup.sp index f1398729b..29a8fcd27 100644 --- a/addons/sourcemod/scripting/readyup.sp +++ b/addons/sourcemod/scripting/readyup.sp @@ -9,7 +9,7 @@ #undef REQUIRE_PLUGIN #include -#define PLUGIN_VERSION "10.2.3" +#define PLUGIN_VERSION "10.2.4" public Plugin myinfo = { @@ -80,7 +80,7 @@ ConVar // sound l4d_ready_enable_sound, l4d_ready_notify_sound, l4d_ready_countdown_sound, l4d_ready_live_sound, l4d_ready_autostart_sound, l4d_ready_chuckle, l4d_ready_secret, // action - l4d_ready_delay, l4d_ready_force_extra, l4d_ready_autostart_delay, l4d_ready_autostart_wait, l4d_ready_autostart_min, l4d_ready_unbalanced_start, l4d_ready_unbalanced_min; + l4d_ready_delay, l4d_ready_force_extra, l4d_ready_autostart_delay, l4d_ready_autostart_wait, l4d_ready_autostart_min, l4d_ready_unbalanced_start, l4d_ready_unbalanced_min, l4d_ready_unready_limit; // Server Name ConVar @@ -129,6 +129,9 @@ char g_sDisruptReason[disruptType_SIZE][] = "Admin aborted" }; +// Limit Cancel Ready +StringMap playerunReadyCount; + // Sub modules are included here #include "readyup/action.inc" #include "readyup/command.inc" @@ -158,6 +161,7 @@ public void OnPluginStart() SetupConVars(); SetupCommands(); + playerunReadyCount = new StringMap(); nativeFooter = new Footer(); readySurvFreeze = l4d_ready_survivor_freeze.BoolValue; @@ -383,6 +387,13 @@ public Action L4D_OnFirstSurvivorLeftSafeArea(int client) ReturnPlayerToSaferoom(client, false); return Plugin_Handled; } + else + { + if(l4d_ready_unready_limit.IntValue > 0) + { + playerunReadyCount.Clear(); + } + } return Plugin_Continue; } diff --git a/addons/sourcemod/scripting/readyup/action.inc b/addons/sourcemod/scripting/readyup/action.inc index c1c3847f7..d446c2307 100644 --- a/addons/sourcemod/scripting/readyup/action.inc +++ b/addons/sourcemod/scripting/readyup/action.inc @@ -232,16 +232,43 @@ void CancelFullReady(int client, disruptType type) if (s_readyCountdownTimer != null) { - delete s_readyCountdownTimer; - InitiateReadyUp(false); - - SetTeamFrozen(L4D2Team_Survivor, l4d_ready_survivor_freeze.BoolValue); - if (type == teamShuffle) // fix spectating - SetClientFrozen(client, false); - - PrintHintTextToAll("%t", "LiveCountdownCancelled"); - CPrintToChatAllEx(client, "%t", g_sDisruptReason[type], client); + if(l4d_ready_unready_limit.IntValue > 0 && type == readyStatus) + { + if (!AddUnReadyCount(client)) + return; + + delete s_readyCountdownTimer; + InitiateReadyUp(false); + + SetTeamFrozen(L4D2Team_Survivor, l4d_ready_survivor_freeze.BoolValue); + if (type == teamShuffle) // fix spectating + SetClientFrozen(client, false); + + char sbuffer[64] = ""; + Format(sbuffer, sizeof(sbuffer), "%t", "CountUnReady", GetUnReadyCount(client), l4d_ready_unready_limit.IntValue); + PrintHintTextToAll("%t", "LiveCountdownCancelled"); + CPrintToChatAllEx(client, "%t %t", "Tag", g_sDisruptReason[type], client, sbuffer); + } + else + { + delete s_readyCountdownTimer; + InitiateReadyUp(false); + + SetTeamFrozen(L4D2Team_Survivor, l4d_ready_survivor_freeze.BoolValue); + if (type == teamShuffle) // fix spectating + SetClientFrozen(client, false); + + PrintHintTextToAll("%t", "LiveCountdownCancelled"); + if(type == readyStatus) + { + CPrintToChatAllEx(client, "%t %t", "Tag", g_sDisruptReason[type], client, ""); + } + else + { + CPrintToChatAllEx(client, "%t %t", "Tag", g_sDisruptReason[type], client); + } + } if (g_hCountdownCancelledForward.FunctionCount) { Call_StartForward(g_hCountdownCancelledForward); @@ -249,5 +276,36 @@ void CancelFullReady(int client, disruptType type) Call_PushString(g_sDisruptReason[type]); Call_Finish(); } + } } + +bool AddUnReadyCount(int client) +{ + char authId[18]; + GetClientAuthId(client, AuthId_SteamID64, authId, 18, false); + int unReadyCount = 0; + int unReadyLimit = l4d_ready_unready_limit.IntValue; + playerunReadyCount.GetValue(authId, unReadyCount); + + if (unReadyLimit > 0 && unReadyCount >= unReadyLimit) + { + CPrintToChat(client, "%t %t", "Tag", "UnReadyLimit", unReadyLimit); + return false; + } + + unReadyCount++; + playerunReadyCount.SetValue(authId, unReadyCount); + + return true; +} + +int GetUnReadyCount(int client) +{ + char authId[18]; + GetClientAuthId(client, AuthId_SteamID64, authId, 18, false); + int unReadyCount = 0; + playerunReadyCount.GetValue(authId, unReadyCount); + + return unReadyCount; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/readyup/command.inc b/addons/sourcemod/scripting/readyup/command.inc index 3dababd63..9c980645f 100644 --- a/addons/sourcemod/scripting/readyup/command.inc +++ b/addons/sourcemod/scripting/readyup/command.inc @@ -92,7 +92,7 @@ Action ForceStart_Cmd(int client, int args) { isForceStart = true; InitiateLiveCountdown(); - CPrintToChatAll("%t", "ForceStartAdmin", client); + CPrintToChatAll("%t %t", "Tag", "ForceStartAdmin", client); return Plugin_Handled; } } @@ -108,7 +108,7 @@ Action Hide_Cmd(int client, int args) if (inReadyUp) { SetPlayerHiddenPanel(client, true); - CPrintToChat(client, "%t", "PanelHide"); + CPrintToChat(client, "%t %t", "Tag", "PanelHide"); return Plugin_Handled; } return Plugin_Continue; @@ -119,7 +119,7 @@ Action Show_Cmd(int client, int args) if (inReadyUp) { SetPlayerHiddenPanel(client, false); - CPrintToChat(client, "%t", "PanelShow"); + CPrintToChat(client, "%t %t", "Tag", "PanelShow"); return Plugin_Handled; } return Plugin_Continue; diff --git a/addons/sourcemod/scripting/readyup/panel.inc b/addons/sourcemod/scripting/readyup/panel.inc index 9f5a8b1c1..8344b7c36 100644 --- a/addons/sourcemod/scripting/readyup/panel.inc +++ b/addons/sourcemod/scripting/readyup/panel.inc @@ -85,15 +85,19 @@ void UpdatePanel() g_cvServerNamer.GetString(ServerName, sizeof(ServerName)); l4d_ready_cfg_name.GetString(cfgName, sizeof(cfgName)); - Format(ServerBuffer, sizeof(ServerBuffer), "▸ Server: %s \n▸ Slots: %d/%d\n▸ Config: %s", ServerName, GetSeriousClientCount(), FindConVar("sv_maxplayers").IntValue, cfgName); + Format(ServerBuffer, sizeof(ServerBuffer), "%T", "PanelSlots", LANG_SERVER, ServerName, GetSeriousClientCount(), FindConVar("sv_maxplayers").IntValue, cfgName); menuPanel.DrawText(ServerBuffer); - FormatTime(ServerBuffer, sizeof(ServerBuffer), "▸ %m/%d/%Y - %I:%M%p"); + // Format will be defined by sm_datetime_format + FormatTime(ServerBuffer, sizeof(ServerBuffer), NULL_STRING); + Format(ServerBuffer, sizeof(ServerBuffer), "▸ %s", ServerBuffer); + Format(ServerBuffer, sizeof(ServerBuffer), "%s (%02d:%02d)", ServerBuffer, iPassTime / 60, iPassTime % 60); menuPanel.DrawText(ServerBuffer); menuPanel.DrawText(" "); - menuPanel.DrawText("▸ Commands:"); + Format(ServerBuffer, sizeof(ServerBuffer), "%T", "PanelCommands", LANG_SERVER); + menuPanel.DrawText(ServerBuffer); menuPanel.DrawText(FooterGet(cmdFooter, curCmd)); menuPanel.DrawText(" "); @@ -157,7 +161,7 @@ void UpdatePanel() { survivorBuffer[bufLen] = '\0'; ReplaceString(survivorBuffer, sizeof(survivorBuffer), "#", "_"); - Format(nameBuf, sizeof(nameBuf), "->%d. Survivors%s", ++textCount, isTeamReadyMode ? teamReadySymbol[survivorReady] : ""); + Format(nameBuf, sizeof(nameBuf), "%T", "PanelSurvivors", LANG_SERVER, ++textCount, isTeamReadyMode ? teamReadySymbol[survivorReady] : ""); menuPanel.DrawText(nameBuf); menuPanel.DrawText(survivorBuffer); } @@ -167,7 +171,7 @@ void UpdatePanel() { infectedBuffer[bufLen] = '\0'; ReplaceString(infectedBuffer, sizeof(infectedBuffer), "#", "_"); - Format(nameBuf, sizeof(nameBuf), "->%d. Infected%s", ++textCount, isTeamReadyMode ? teamReadySymbol[infectedReady] : ""); + Format(nameBuf, sizeof(nameBuf), "%T", "PanelInfected", LANG_SERVER, ++textCount, isTeamReadyMode ? teamReadySymbol[infectedReady] : ""); menuPanel.DrawText(nameBuf); menuPanel.DrawText(infectedBuffer); } @@ -180,7 +184,7 @@ void UpdatePanel() if (bufLen != 0) { casterBuffer[bufLen] = '\0'; - Format(nameBuf, sizeof(nameBuf), "->%d. Caster%s", ++textCount, casterCount > 1 ? "s" : ""); + Format(nameBuf, sizeof(nameBuf), "%T", "PanelCaster", LANG_SERVER, ++textCount, casterCount > 1 ? "s" : ""); menuPanel.DrawText(nameBuf); ReplaceString(casterBuffer, sizeof(casterBuffer), "#", "_", true); menuPanel.DrawText(casterBuffer); @@ -191,11 +195,11 @@ void UpdatePanel() if (bufLen != 0) { specBuffer[bufLen] = '\0'; - Format(nameBuf, sizeof(nameBuf), "->%d. Spectator%s", ++textCount, specCount > 1 ? "s" : ""); + Format(nameBuf, sizeof(nameBuf), "%T", "PanelSpectator", LANG_SERVER, ++textCount, specCount > 1 ? "s" : ""); menuPanel.DrawText(nameBuf); ReplaceString(specBuffer, sizeof(specBuffer), "#", "_"); if (playerCount > l4d_ready_max_players.IntValue && specCount - casterCount > 1) - FormatEx(specBuffer, sizeof(specBuffer), "**Many** (%d)", specCount - casterCount); + FormatEx(specBuffer, sizeof(specBuffer), "%T", "PanelMany", LANG_SERVER, specCount - casterCount); menuPanel.DrawText(specBuffer); } diff --git a/addons/sourcemod/scripting/readyup/setup.inc b/addons/sourcemod/scripting/readyup/setup.inc index fe8649c14..0b4ca4f54 100644 --- a/addons/sourcemod/scripting/readyup/setup.inc +++ b/addons/sourcemod/scripting/readyup/setup.inc @@ -32,15 +32,15 @@ void SetupNatives() void SetupForwards() { - g_hPreInitiateForward = new GlobalForward("OnReadyUpInitiatePre", ET_Ignore); - g_hInitiateForward = new GlobalForward("OnReadyUpInitiate", ET_Ignore); - g_hPreCountdownForward = new GlobalForward("OnRoundLiveCountdownPre", ET_Ignore); - g_hCountdownForward = new GlobalForward("OnRoundLiveCountdown", ET_Ignore); - g_hPreLiveForward = new GlobalForward("OnRoundIsLivePre", ET_Ignore); - g_hLiveForward = new GlobalForward("OnRoundIsLive", ET_Ignore); - g_hCountdownCancelledForward = new GlobalForward("OnReadyCountdownCancelled", ET_Ignore, Param_Cell, Param_String); - g_hPlayerReadyForward = new GlobalForward("OnPlayerReady", ET_Ignore, Param_Cell); - g_hPlayerUnreadyForward = new GlobalForward("OnPlayerUnready", ET_Ignore, Param_Cell); + g_hPreInitiateForward = new GlobalForward("OnReadyUpInitiatePre", ET_Ignore); + g_hInitiateForward = new GlobalForward("OnReadyUpInitiate", ET_Ignore); + g_hPreCountdownForward = new GlobalForward("OnRoundLiveCountdownPre", ET_Ignore); + g_hCountdownForward = new GlobalForward("OnRoundLiveCountdown", ET_Ignore); + g_hPreLiveForward = new GlobalForward("OnRoundIsLivePre", ET_Ignore); + g_hLiveForward = new GlobalForward("OnRoundIsLive", ET_Ignore); + g_hCountdownCancelledForward = new GlobalForward("OnReadyCountdownCancelled", ET_Ignore, Param_Cell, Param_String); + g_hPlayerReadyForward = new GlobalForward("OnPlayerReady", ET_Ignore, Param_Cell); + g_hPlayerUnreadyForward = new GlobalForward("OnPlayerUnready", ET_Ignore, Param_Cell); } void SetupConVars() @@ -72,14 +72,15 @@ void SetupConVars() l4d_ready_autostart_min = CreateConVar("l4d_ready_autostart_min", "0.25", "Percent of max players (Versus = 8) in game to allow auto-start to proceed.", FCVAR_NOTIFY, true, 0.0, true, 1.0); l4d_ready_unbalanced_start = CreateConVar("l4d_ready_unbalanced_start", "0", "Allow game to go live when teams are not full.", FCVAR_NOTIFY, true, 0.0, true, 1.0); l4d_ready_unbalanced_min = CreateConVar("l4d_ready_unbalanced_min", "2", "Minimum of players in each team to allow a unbalanced start.", FCVAR_NOTIFY, true, 0.0); + l4d_ready_unready_limit = CreateConVar("l4d_ready_unready_limit", "0", "Limits the amount of unready a player can do in a single game. Set to 0 to disable.", FCVAR_NOTIFY, true, 0.0); // game convars - director_no_specials = FindConVar("director_no_specials"); - god = FindConVar("god"); - sb_stop = FindConVar("sb_stop"); - survivor_limit = FindConVar("survivor_limit"); - z_max_player_zombies = FindConVar("z_max_player_zombies"); - sv_infinite_primary_ammo = FindConVar("sv_infinite_primary_ammo"); + director_no_specials = FindConVar("director_no_specials"); + god = FindConVar("god"); + sb_stop = FindConVar("sb_stop"); + survivor_limit = FindConVar("survivor_limit"); + z_max_player_zombies = FindConVar("z_max_player_zombies"); + sv_infinite_primary_ammo = FindConVar("sv_infinite_primary_ammo"); } void SetupCommands() diff --git a/addons/sourcemod/scripting/survivor_mvp.sp b/addons/sourcemod/scripting/survivor_mvp.sp index 85d2d75f5..572e15136 100644 --- a/addons/sourcemod/scripting/survivor_mvp.sp +++ b/addons/sourcemod/scripting/survivor_mvp.sp @@ -1,45 +1,45 @@ #pragma semicolon 1 +#pragma newdecls required -#include +#include +#include #include #include -#include -#include +#include -#define TEAM_SPECTATOR 1 -#define TEAM_SURVIVOR 2 -#define TEAM_INFECTED 3 -#define FLAG_SPECTATOR (1 << TEAM_SPECTATOR) -#define FLAG_SURVIVOR (1 << TEAM_SURVIVOR) -#define FLAG_INFECTED (1 << TEAM_INFECTED) - -#define ZC_SMOKER 1 -#define ZC_BOOMER 2 -#define ZC_HUNTER 3 -#define ZC_SPITTER 4 -#define ZC_JOCKEY 5 -#define ZC_CHARGER 6 -#define ZC_WITCH 7 -#define ZC_TANK 8 - -#define BREV_SI 1 -#define BREV_CI 2 -#define BREV_FF 4 -#define BREV_RANK 8 +#define TEAM_SPECTATOR 1 +#define TEAM_SURVIVOR 2 +#define TEAM_INFECTED 3 +#define FLAG_SPECTATOR (1 << TEAM_SPECTATOR) +#define FLAG_SURVIVOR (1 << TEAM_SURVIVOR) +#define FLAG_INFECTED (1 << TEAM_INFECTED) + +#define ZC_SMOKER 1 +#define ZC_BOOMER 2 +#define ZC_HUNTER 3 +#define ZC_SPITTER 4 +#define ZC_JOCKEY 5 +#define ZC_CHARGER 6 +#define ZC_WITCH 7 +#define ZC_TANK 8 + +#define BREV_SI 1 +#define BREV_CI 2 +#define BREV_FF 4 +#define BREV_RANK 8 //#define BREV_??? 16 -#define BREV_PERCENT 32 -#define BREV_ABSOLUTE 64 +#define BREV_PERCENT 32 +#define BREV_ABSOLUTE 64 -#define CONBUFSIZE 1024 -#define CONBUFSIZELARGE 4096 - -#define CHARTHRESHOLD 160 // detecting unicode stuff +#define CONBUFSIZE 1024 +#define CONBUFSIZELARGE 4096 +#define CHARTHRESHOLD 160 // detecting unicode stuff /** -* Issues: -* - Add damage received from common -*/ + * Issues: + * - Add damage received from common + */ /* Changelog @@ -79,1244 +79,1265 @@ Brevity flags: 64 leave out absolutes */ - -public Plugin:myinfo = +public Plugin myinfo = { - name = "Survivor MVP notification", - author = "Tabun, Artifacial", - description = "Shows MVP for survivor team at end of round", - version = "0.3", - url = "https://github.com/alexberriman/l4d2_survivor_mvp" + name = "Survivor MVP notification", + author = "Tabun, Artifacial", + description = "Shows MVP for survivor team at end of round", + version = "0.4", + url = "https://github.com/alexberriman/l4d2_survivor_mvp" }; - -new Handle: hPluginEnabled = INVALID_HANDLE; - -new Handle: hCountTankDamage = INVALID_HANDLE; // whether we're tracking tank damage for MVP-selection -new Handle: hCountWitchDamage = INVALID_HANDLE; // whether we're tracking witch damage for MVP-selection -new Handle: hTrackFF = INVALID_HANDLE; // whether we're tracking friendly-fire damage (separate stat) -new Handle: hBrevityFlags = INVALID_HANDLE; // how verbose/brief the output should be: -new Handle: hRUPActive = INVALID_HANDLE; // whether the ready up mod is active - -new bool: bCountTankDamage; -new bool: bCountWitchDamage; -new bool: bTrackFF; -new iBrevityFlags; -new bool: bRUPActive; - -new Handle: hGameMode = INVALID_HANDLE; -new String: sGameMode[24] = "\0"; - -new String: sClientName[MAXPLAYERS + 1][64]; // which name is connected to the clientId? +ConVar + hPluginEnabled, + hCountTankDamage, // whether we're tracking tank damage for MVP-selection + hCountWitchDamage, // whether we're tracking witch damage for MVP-selection + hTrackFF, // whether we're tracking friendly-fire damage (separate stat) + hBrevityFlags, // how verbose/brief the output should be: + hRUPActive; // whether the ready up mod is active + +bool + bCountTankDamage, + bCountWitchDamage, + bTrackFF; +int + iBrevityFlags; +bool + bRUPActive; + +Handle + hGameMode = INVALID_HANDLE; +char + sGameMode[24] = "\0", + sClientName[MAXPLAYERS + 1][64]; // which name is connected to the clientId? // Basic statistics -new iGotKills[MAXPLAYERS + 1]; // SI kills track for each client -new iGotCommon[MAXPLAYERS + 1]; // CI kills -new iDidDamage[MAXPLAYERS + 1]; // SI only these are a bit redundant, but will keep anyway for now -new iDidDamageAll[MAXPLAYERS + 1]; // SI + tank + witch -new iDidDamageTank[MAXPLAYERS + 1]; // tank only -new iDidDamageWitch[MAXPLAYERS + 1]; // witch only -new iDidFF[MAXPLAYERS + 1]; // friendly fire damage +int + iGotKills[MAXPLAYERS + 1], // SI kills track for each client + iGotCommon[MAXPLAYERS + 1], // CI kills + iDidDamage[MAXPLAYERS + 1], // SI only these are a bit redundant, but will keep anyway for now + iDidDamageAll[MAXPLAYERS + 1], // SI + tank + witch + iDidDamageTank[MAXPLAYERS + 1], // tank only + iDidDamageWitch[MAXPLAYERS + 1], // witch only + iDidFF[MAXPLAYERS + 1]; // friendly fire damage // Detailed statistics -new iDidDamageClass[MAXPLAYERS + 1][ZC_TANK + 1]; // si classes -new timesPinned[MAXPLAYERS + 1][ZC_TANK + 1]; // times pinned -new totalPinned[MAXPLAYERS + 1]; // total times pinned -new pillsUsed[MAXPLAYERS + 1]; // total pills eaten -new boomerPops[MAXPLAYERS + 1]; // total boomer pops -new damageReceived[MAXPLAYERS + 1]; // Damage received +int + iDidDamageClass[MAXPLAYERS + 1][ZC_TANK + 1], // si classes + timesPinned[MAXPLAYERS + 1][ZC_TANK + 1], // times pinned + totalPinned[MAXPLAYERS + 1], // total times pinned + pillsUsed[MAXPLAYERS + 1], // total pills eaten + boomerPops[MAXPLAYERS + 1], // total boomer pops + damageReceived[MAXPLAYERS + 1]; // Damage received // Tank stats -new tankSpawned = false; // When tank is spawned -new commonKilledDuringTank[MAXPLAYERS + 1]; // Common killed during the tank -new ttlCommonKilledDuringTank = 0; // Common killed during the tank -new siDmgDuringTank[MAXPLAYERS + 1]; // SI killed during the tank -//new ttlSiDmgDuringTank = 0; // Total SI killed during the tank -new tankThrow; // Whether or not the tank has thrown a rock -new rocksEaten[MAXPLAYERS + 1]; // The amount of rocks a player 'ate'. -new rockIndex; // The index of the rock (to detect how many times we were rocked) -new ttlPinnedDuringTank[MAXPLAYERS + 1]; // The total times we were pinned when the tank was up - - -new iTotalKills; // prolly more efficient to store than to recalculate -new iTotalCommon; -//new iTotalDamage; -//new iTotalDamageTank; -//new iTotalDamageWitch; -new iTotalDamageAll; -new iTotalFF; - -new iRoundNumber; -new bInRound; -new bPlayerLeftStartArea; // used for tracking FF when RUP enabled - -new String: sTmpString[MAX_NAME_LENGTH]; // just used because I'm not going to break my head over why string assignment parameter passing doesn't work +bool + tankSpawned = false, // When tank is spawned + tankThrow; // Whether or not the tank has thrown a rock +int + commonKilledDuringTank[MAXPLAYERS + 1], // Common killed during the tank + ttlCommonKilledDuringTank = 0, // Common killed during the tank + siDmgDuringTank[MAXPLAYERS + 1], // SI killed during the tank + rocksEaten[MAXPLAYERS + 1], // The amount of rocks a player 'ate'. + ttlPinnedDuringTank[MAXPLAYERS + 1], // The total times we were pinned when the tank was up + rockIndex; // The index of the rock (to detect how many times we were rocked) + +int + iTotalKills, // prolly more efficient to store than to recalculate + iTotalCommon, + iTotalDamageAll, + iTotalFF; + +int + iRoundNumber; +bool + bInRound, + bPlayerLeftStartArea; // used for tracking FF when RUP enabled /* -* Natives -* ======= -*/ - -public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max) + * Natives + * ======= + */ +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) { - CreateNative("SURVMVP_GetMVP", Native_GetMVP); - CreateNative("SURVMVP_GetMVPDmgCount", Native_GetMVPDmgCount); - CreateNative("SURVMVP_GetMVPKills", Native_GetMVPKills); - CreateNative("SURVMVP_GetMVPDmgPercent", Native_GetMVPDmgPercent); - CreateNative("SURVMVP_GetMVPCI", Native_GetMVPCI); - CreateNative("SURVMVP_GetMVPCIKills", Native_GetMVPCIKills); - CreateNative("SURVMVP_GetMVPCIPercent", Native_GetMVPCIPercent); - - return APLRes_Success; + CreateNative("SURVMVP_GetMVP", Native_GetMVP); + CreateNative("SURVMVP_GetMVPDmgCount", Native_GetMVPDmgCount); + CreateNative("SURVMVP_GetMVPKills", Native_GetMVPKills); + CreateNative("SURVMVP_GetMVPDmgPercent", Native_GetMVPDmgPercent); + CreateNative("SURVMVP_GetMVPCI", Native_GetMVPCI); + CreateNative("SURVMVP_GetMVPCIKills", Native_GetMVPCIKills); + CreateNative("SURVMVP_GetMVPCIPercent", Native_GetMVPCIPercent); + RegPluginLibrary("survivor_mvp"); + return APLRes_Success; } +// ======================== +// Natives +// ======================== + // simply return current round MVP client -public Native_GetMVP(Handle:plugin, numParams) +public int Native_GetMVP(Handle plugin, int numParams) { - new client = findMVPSI(); - return _:client; + int client = findMVPSI(); + return client; } -// return damage percent of client -public Native_GetMVPDmgPercent(Handle:plugin, numParams) +// return damage of client +public int Native_GetMVPDmgCount(Handle plugin, int numParams) { - new client = GetNativeCell(1); - new Float: dmgprc = client && iTotalDamageAll > 0 ? (float(iDidDamageAll[client]) / float(iTotalDamageAll)) * 100 : 0.0; - return _:dmgprc; + int client = GetNativeCell(1); + int dmg = client && iTotalDamageAll > 0 ? iDidDamageAll[client] : 0; + return dmg; } -// return damage of client -public Native_GetMVPDmgCount(Handle:plugin, numParams) +// return SI kills of client +public int Native_GetMVPKills(Handle plugin, int numParams) { - new client = GetNativeCell(1); - new dmg = client && iTotalDamageAll > 0 ? iDidDamageAll[client] : 0; - return _:dmg; + int client = GetNativeCell(1); + int dmg = client && iTotalKills > 0 ? iGotKills[client] : 0; + return dmg; } -// return SI kills of client -public Native_GetMVPKills(Handle:plugin, numParams) +// return damage percent of client +public any Native_GetMVPDmgPercent(Handle plugin, int numParams) { - new client = GetNativeCell(1); - new dmg = client && iTotalKills > 0 ? iGotKills[client] : 0; - return _:dmg; + int client = GetNativeCell(1); + float dmgprc = client && iTotalDamageAll > 0 ? (float(iDidDamageAll[client]) / float(iTotalDamageAll)) * 100 : 0.0; + return dmgprc; } // simply return current round MVP client (Common) -public Native_GetMVPCI(Handle:plugin, numParams) +public int Native_GetMVPCI(Handle plugin, int numParams) { - new client = findMVPCommon(); - return _:client; + int client = findMVPCommon(); + return client; } // return common kills for client -public Native_GetMVPCIKills(Handle:plugin, numParams) +public int Native_GetMVPCIKills(Handle plugin, int numParams) { - new client = GetNativeCell(1); - new dmg = client && iTotalCommon > 0 ? iGotCommon[client] : 0; - return _:dmg; + int client = GetNativeCell(1); + int dmg = client && iTotalCommon > 0 ? iGotCommon[client] : 0; + return dmg; } // return CI percent of client -public Native_GetMVPCIPercent(Handle:plugin, numParams) +public any Native_GetMVPCIPercent(Handle plugin, int numParams) { - new client = GetNativeCell(1); - new Float: dmgprc = client && iTotalCommon > 0 ? (float(iGotCommon[client]) / float(iTotalCommon)) * 100 : 0.0; - return _:dmgprc; + int client = GetNativeCell(1); + float dmgprc = client && iTotalCommon > 0 ? (float(iGotCommon[client]) / float(iTotalCommon)) * 100 : 0.0; + return dmgprc; } - /* -* init -* ==== -*/ - -public OnPluginStart() + * init + * ==== + */ +public void OnPluginStart() { - // Round triggers - //HookEvent("door_close", DoorClose_Event); - //HookEvent("finale_vehicle_leaving", FinaleVehicleLeaving_Event, EventHookMode_PostNoCopy); - HookEvent("round_start", RoundStart_Event, EventHookMode_PostNoCopy); - HookEvent("round_end", RoundEnd_Event, EventHookMode_PostNoCopy); - HookEvent("map_transition", RoundEnd_Event, EventHookMode_PostNoCopy); - HookEvent("scavenge_round_start", ScavRoundStart, EventHookMode_PostNoCopy); - HookEvent("player_left_start_area", PlayerLeftStartArea, EventHookMode_PostNoCopy); - HookEvent("pills_used", pillsUsedEvent); - HookEvent("boomer_exploded", boomerExploded); - HookEvent("charger_carry_end", chargerCarryEnd); - HookEvent("jockey_ride", jockeyRide); - HookEvent("lunge_pounce", hunterLunged); - HookEvent("choke_start", smokerChoke); - HookEvent("tank_killed", tankKilled); - HookEvent("tank_spawn", tankSpawn); - HookEvent("ability_use", abilityUseEvent); - //HookEvent("tank_frustrated", tankFrustrated); - - // Catching data - HookEvent("player_hurt", PlayerHurt_Event, EventHookMode_Post); - HookEvent("player_death", PlayerDeath_Event, EventHookMode_Post); - HookEvent("infected_hurt" ,InfectedHurt_Event, EventHookMode_Post); - HookEvent("infected_death", InfectedDeath_Event, EventHookMode_Post); - - // check gamemode (for scavenge fix) - hGameMode = FindConVar("mp_gamemode"); - - // Cvars - hPluginEnabled = CreateConVar("sm_survivor_mvp_enabled", "1", "Enable display of MVP at end of round"); - hCountTankDamage = CreateConVar("sm_survivor_mvp_counttank", "0", "Damage on tank counts towards MVP-selection if enabled."); - hCountWitchDamage = CreateConVar("sm_survivor_mvp_countwitch", "0", "Damage on witch counts towards MVP-selection if enabled."); - hTrackFF = CreateConVar("sm_survivor_mvp_showff", "1", "Track Friendly-fire stat."); - hBrevityFlags = CreateConVar("sm_survivor_mvp_brevity", "0", "Flags for setting brevity of MVP report (hide 1:SI, 2:CI, 4:FF, 8:rank, 32:perc, 64:abs)."); - - bCountTankDamage = GetConVarBool(hCountTankDamage); - bCountWitchDamage = GetConVarBool(hCountWitchDamage); - bTrackFF = GetConVarBool(hTrackFF); - iBrevityFlags = GetConVarInt(hBrevityFlags); - - // for now, force FF tracking on: - bTrackFF = true; - - HookConVarChange(hCountTankDamage, ConVarChange_CountTankDamage); - HookConVarChange(hCountWitchDamage, ConVarChange_CountWitchDamage); - HookConVarChange(hTrackFF, ConVarChange_TrackFF); - HookConVarChange(hBrevityFlags, ConVarChange_BrevityFlags); - - if (!(iBrevityFlags & BREV_FF)) { bTrackFF = true; } // force tracking on if we're showing FF - - // RUP? - hRUPActive = FindConVar("l4d_ready_enabled"); - if (hRUPActive != INVALID_HANDLE) - { - // hook changes for this, and set state appropriately - bRUPActive = GetConVarBool(hRUPActive); - HookConVarChange(hRUPActive, ConVarChange_RUPActive); - } else { - // not loaded - bRUPActive = false; - } - bPlayerLeftStartArea = false; - - // Commands - RegConsoleCmd("sm_mvp", SurvivorMVP_Cmd, "Prints the current MVP for the survivor team"); - RegConsoleCmd("sm_mvpme", ShowMVPStats_Cmd, "Prints the client's own MVP-related stats"); - - RegConsoleCmd("say", Say_Cmd); - RegConsoleCmd("say_team", Say_Cmd); + // Translation + LoadTranslation("survivor_mvp.phrases"); + + // Round triggers + HookEvent("round_start", RoundStart_Event, EventHookMode_PostNoCopy); + HookEvent("round_end", RoundEnd_Event, EventHookMode_PostNoCopy); + HookEvent("map_transition", RoundEnd_Event, EventHookMode_PostNoCopy); + HookEvent("scavenge_round_start", ScavRoundStart, EventHookMode_PostNoCopy); + HookEvent("player_left_start_area", PlayerLeftStartArea, EventHookMode_PostNoCopy); + HookEvent("pills_used", pillsUsedEvent); + HookEvent("boomer_exploded", boomerExploded); + HookEvent("charger_carry_end", chargerCarryEnd); + HookEvent("jockey_ride", jockeyRide); + HookEvent("lunge_pounce", hunterLunged); + HookEvent("choke_start", smokerChoke); + HookEvent("tank_killed", tankKilled); + HookEvent("tank_spawn", tankSpawn); + HookEvent("ability_use", abilityUseEvent); + + // Catching data + HookEvent("player_hurt", PlayerHurt_Event, EventHookMode_Post); + HookEvent("player_death", PlayerDeath_Event, EventHookMode_Post); + HookEvent("infected_hurt", InfectedHurt_Event, EventHookMode_Post); + HookEvent("infected_death", InfectedDeath_Event, EventHookMode_Post); + + // check gamemode (for scavenge fix) + hGameMode = FindConVar("mp_gamemode"); + + // Cvars + hPluginEnabled = CreateConVar("sm_survivor_mvp_enabled", "1", "Enable display of MVP at end of round"); + hCountTankDamage = CreateConVar("sm_survivor_mvp_counttank", "0", "Damage on tank counts towards MVP-selection if enabled."); + hCountWitchDamage = CreateConVar("sm_survivor_mvp_countwitch", "0", "Damage on witch counts towards MVP-selection if enabled."); + hTrackFF = CreateConVar("sm_survivor_mvp_showff", "1", "Track Friendly-fire stat."); + hBrevityFlags = CreateConVar("sm_survivor_mvp_brevity", "0", "Flags for setting brevity of MVP report (hide 1:SI, 2:CI, 4:FF, 8:rank, 32:perc, 64:abs)."); + + bCountTankDamage = hCountTankDamage.BoolValue; + bCountWitchDamage = hCountWitchDamage.BoolValue; + bTrackFF = hTrackFF.BoolValue; + iBrevityFlags = hBrevityFlags.IntValue; + + // for now, force FF tracking on: + bTrackFF = true; + + HookConVarChange(hCountTankDamage, ConVarChange_CountTankDamage); + HookConVarChange(hCountWitchDamage, ConVarChange_CountWitchDamage); + HookConVarChange(hTrackFF, ConVarChange_TrackFF); + HookConVarChange(hBrevityFlags, ConVarChange_BrevityFlags); + + if (!(iBrevityFlags & BREV_FF)) { bTrackFF = true; } // force tracking on if we're showing FF + + // RUP? + hRUPActive = FindConVar("l4d_ready_enabled"); + if (hRUPActive != null) + { + // hook changes for this, and set state appropriately + bRUPActive = hRUPActive.BoolValue; + HookConVarChange(hRUPActive, ConVarChange_RUPActive); + } + else { + // not loaded + bRUPActive = false; + } + bPlayerLeftStartArea = false; + + // Commands + RegConsoleCmd("sm_mvp", SurvivorMVP_Cmd, "Prints the current MVP for the survivor team"); + RegConsoleCmd("sm_mvpme", ShowMVPStats_Cmd, "Prints the client's own MVP-related stats"); + + RegConsoleCmd("say", Say_Cmd); + RegConsoleCmd("say_team", Say_Cmd); } -/* -public OnPluginEnd() +void LoadTranslation(char[] sTranslation) { -// nothing + char + sPath[PLATFORM_MAX_PATH], + sName[64]; + + Format(sName, sizeof(sName), "translations/%s.txt", sTranslation); + BuildPath(Path_SM, sPath, sizeof(sPath), sName); + if (!FileExists(sPath)) + { + SetFailState("Missing translation file %s.txt", sTranslation); + } + LoadTranslations(sTranslation); } -*/ -public OnClientPutInServer(client) +public void OnClientPutInServer(int client) { - decl String:tmpBuffer[64]; - GetClientName(client, tmpBuffer, sizeof(tmpBuffer)); - - // if previously stored name for same client is not the same, delete stats & overwrite name - if (strcmp(tmpBuffer, sClientName[client], true) != 0) - { - iGotKills[client] = 0; - iGotCommon[client] = 0; - iDidDamage[client] = 0; - iDidDamageAll[client] = 0; - iDidDamageWitch[client] = 0; - iDidDamageTank[client] = 0; - iDidFF[client] = 0; - - - //@todo detailed statistics - set to 0 - for (new siClass = ZC_SMOKER; siClass <= ZC_TANK; siClass++) { - iDidDamageClass[client][siClass] = 0; - timesPinned[client][siClass] = 0; - } - pillsUsed[client] = 0; - boomerPops[client] = 0; - damageReceived[client] = 0; - totalPinned[client] = 0; - commonKilledDuringTank[client] = 0; - siDmgDuringTank[client] = 0; - rocksEaten[client] = 0; - ttlPinnedDuringTank[client] = 0; - - // store name for later reference - strcopy(sClientName[client], 64, tmpBuffer); - } + char tmpBuffer[128]; + GetClientName(client, tmpBuffer, sizeof(tmpBuffer)); + + // if previously stored name for same client is not the same, delete stats & overwrite name + if (strcmp(tmpBuffer, sClientName[client], true) != 0) + { + iGotKills[client] = 0; + iGotCommon[client] = 0; + iDidDamage[client] = 0; + iDidDamageAll[client] = 0; + iDidDamageWitch[client] = 0; + iDidDamageTank[client] = 0; + iDidFF[client] = 0; + + //@todo detailed statistics - set to 0 + for (int siClass = ZC_SMOKER; siClass <= ZC_TANK; siClass++) + { + iDidDamageClass[client][siClass] = 0; + timesPinned[client][siClass] = 0; + } + pillsUsed[client] = 0; + boomerPops[client] = 0; + damageReceived[client] = 0; + totalPinned[client] = 0; + commonKilledDuringTank[client] = 0; + siDmgDuringTank[client] = 0; + rocksEaten[client] = 0; + ttlPinnedDuringTank[client] = 0; + + // store name for later reference + strcopy(sClientName[client], sizeof(tmpBuffer), tmpBuffer); + } } /* -* convar changes -* ============== -*/ - -public ConVarChange_CountTankDamage(Handle:cvar, const String:oldValue[], const String:newValue[]) { - bCountTankDamage = StringToInt(newValue) != 0; + * convar changes + * ============== + */ +public void ConVarChange_CountTankDamage(Handle cvar, const char[] oldValue, const char[] newValue) +{ + bCountTankDamage = StringToInt(newValue) != 0; } -public ConVarChange_CountWitchDamage(Handle:cvar, const String:oldValue[], const String:newValue[]) { - bCountWitchDamage = StringToInt(newValue) != 0; + +public void ConVarChange_CountWitchDamage(Handle cvar, const char[] oldValue, const char[] newValue) +{ + bCountWitchDamage = StringToInt(newValue) != 0; } -public ConVarChange_TrackFF(Handle:cvar, const String:oldValue[], const String:newValue[]) { - //if (StringToInt(newValue) == 0) { bTrackFF = false; } else { bTrackFF = true; } - // for now, disable FF tracking toggle (always on) + +public void ConVarChange_TrackFF(Handle cvar, const char[] oldValue, const char[] newValue) +{ + // if (StringToInt(newValue) == 0) { bTrackFF = false; } else { bTrackFF = true; } + // for now, disable FF tracking toggle (always on) } -public ConVarChange_BrevityFlags(Handle:cvar, const String:oldValue[], const String:newValue[]) { - iBrevityFlags = StringToInt(newValue); - if (!(iBrevityFlags & BREV_FF)) { - bTrackFF = true; - } // force tracking on if we're showing FF + +public void ConVarChange_BrevityFlags(Handle cvar, const char[] oldValue, const char[] newValue) +{ + iBrevityFlags = StringToInt(newValue); + if (!(iBrevityFlags & BREV_FF)) + { + bTrackFF = true; + } // force tracking on if we're showing FF } -public ConVarChange_RUPActive(Handle:cvar, const String:oldValue[], const String:newValue[]) { - bRUPActive = StringToInt(newValue) != 0; +public void ConVarChange_RUPActive(Handle cvar, const char[] oldValue, const char[] newValue) +{ + bRUPActive = StringToInt(newValue) != 0; } /* -* map load / round start/end -* ========================== -*/ - -public Action:PlayerLeftStartArea(Handle:event, const String:name[], bool:dontBroadcast) + * map load / round start/end + * ========================== + */ +public Action PlayerLeftStartArea(Handle event, const char[] name, bool dontBroadcast) { - // if RUP active, now we can start tracking FF - bPlayerLeftStartArea = true; + // if RUP active, now we can start tracking FF + bPlayerLeftStartArea = true; + return Plugin_Continue; } -public OnMapStart() +public void OnMapStart() { - bPlayerLeftStartArea = false; - // get gamemode string for scavenge fix - GetConVarString(hGameMode, sGameMode, sizeof(sGameMode)); + bPlayerLeftStartArea = false; + // get gamemode string for scavenge fix + GetConVarString(hGameMode, sGameMode, sizeof(sGameMode)); } -public OnMapEnd() +public void OnMapEnd() { - iRoundNumber = 0; - bInRound = false; + iRoundNumber = 0; + bInRound = false; } -public void ScavRoundStart(Handle:event, const String:name[], bool:dontBroadcast) +public void ScavRoundStart(Handle event, const char[] name, bool dontBroadcast) { - // clear mvp stats - new i, maxplayers = MaxClients; - for (i = 1; i <= maxplayers; i++) - { - iGotKills[i] = 0; - iGotCommon[i] = 0; - iDidDamage[i] = 0; - iDidDamageAll[i] = 0; - iDidDamageWitch[i] = 0; - iDidDamageTank[i] = 0; - iDidFF[i] = 0; - - //@todo detailed statistics - set to 0 - for (new siClass = ZC_SMOKER; siClass <= ZC_TANK; siClass++) { - iDidDamageClass[i][siClass] = 0; - timesPinned[i][siClass] = 0; - } - pillsUsed[i] = 0; - boomerPops[i] = 0; - damageReceived[i] = 0; - totalPinned[i] = 0; - commonKilledDuringTank[i] = 0; - siDmgDuringTank[i] = 0; - rocksEaten[i] = 0; - ttlPinnedDuringTank[i] = 0; - } - iTotalKills = 0; - iTotalCommon = 0; - //iTotalDamage = 0; - //iTotalDamageTank = 0; - //iTotalDamageWitch = 0; - iTotalDamageAll = 0; - iTotalFF = 0; - //ttlSiDmgDuringTank = 0; - ttlCommonKilledDuringTank = 0; - tankThrow = false; - - bInRound = true; - tankSpawned = false; + // clear mvp stats + int + i, + maxplayers = MaxClients; + for (i = 1; i <= maxplayers; i++) + { + iGotKills[i] = 0; + iGotCommon[i] = 0; + iDidDamage[i] = 0; + iDidDamageAll[i] = 0; + iDidDamageWitch[i] = 0; + iDidDamageTank[i] = 0; + iDidFF[i] = 0; + + //@todo detailed statistics - set to 0 + for (int siClass = ZC_SMOKER; siClass <= ZC_TANK; siClass++) + { + iDidDamageClass[i][siClass] = 0; + timesPinned[i][siClass] = 0; + } + pillsUsed[i] = 0; + boomerPops[i] = 0; + damageReceived[i] = 0; + totalPinned[i] = 0; + commonKilledDuringTank[i] = 0; + siDmgDuringTank[i] = 0; + rocksEaten[i] = 0; + ttlPinnedDuringTank[i] = 0; + } + iTotalKills = 0; + iTotalCommon = 0; + iTotalDamageAll = 0; + iTotalFF = 0; + ttlCommonKilledDuringTank = 0; + tankThrow = false; + + bInRound = true; + tankSpawned = false; } -public RoundStart_Event(Handle:event, const String:name[], bool:dontBroadcast) +public void RoundStart_Event(Handle event, const char[] name, bool dontBroadcast) { - bPlayerLeftStartArea = false; - - if (!bInRound) - { - bInRound = true; - iRoundNumber++; - } - - // clear mvp stats - new i, maxplayers = MaxClients; - for (i = 1; i <= maxplayers; i++) - { - iGotKills[i] = 0; - iGotCommon[i] = 0; - iDidDamage[i] = 0; - iDidDamageAll[i] = 0; - iDidDamageWitch[i] = 0; - iDidDamageTank[i] = 0; - iDidFF[i] = 0; - - //@todo detailed statistics init to 0 - for (new siClass = ZC_SMOKER; siClass <= ZC_TANK; siClass++) { - iDidDamageClass[i][siClass] = 0; - timesPinned[i][siClass] = 0; - } - pillsUsed[i] = 0; - boomerPops[i] = 0; - damageReceived[i] = 0; - totalPinned[i] = 0; - commonKilledDuringTank[i] = 0; - siDmgDuringTank[i] = 0; - rocksEaten[i] = 0; - ttlPinnedDuringTank[i] = 0; - } - iTotalKills = 0; - iTotalCommon = 0; - //iTotalDamage = 0; - iTotalDamageAll = 0; - iTotalFF = 0; - //ttlSiDmgDuringTank = 0; - ttlCommonKilledDuringTank = 0; - //iTotalDamageTank = 0; - tankThrow = false; - - tankSpawned = false; + bPlayerLeftStartArea = false; + + if (!bInRound) + { + bInRound = true; + iRoundNumber++; + } + + // clear mvp stats + int i, maxplayers = MaxClients; + for (i = 1; i <= maxplayers; i++) + { + iGotKills[i] = 0; + iGotCommon[i] = 0; + iDidDamage[i] = 0; + iDidDamageAll[i] = 0; + iDidDamageWitch[i] = 0; + iDidDamageTank[i] = 0; + iDidFF[i] = 0; + + //@todo detailed statistics init to 0 + for (int siClass = ZC_SMOKER; siClass <= ZC_TANK; siClass++) + { + iDidDamageClass[i][siClass] = 0; + timesPinned[i][siClass] = 0; + } + pillsUsed[i] = 0; + boomerPops[i] = 0; + damageReceived[i] = 0; + totalPinned[i] = 0; + commonKilledDuringTank[i] = 0; + siDmgDuringTank[i] = 0; + rocksEaten[i] = 0; + ttlPinnedDuringTank[i] = 0; + } + iTotalKills = 0; + iTotalCommon = 0; + iTotalDamageAll = 0; + iTotalFF = 0; + ttlCommonKilledDuringTank = 0; + tankThrow = false; + + tankSpawned = false; } -public RoundEnd_Event(Handle:event, const String:name[], bool:dontBroadcast) +public void RoundEnd_Event(Handle event, const char[] name, bool dontBroadcast) { - if (StrEqual(sGameMode, "coop", false)) - { - if (bInRound) - { - if (GetConVarBool(hPluginEnabled)) - CreateTimer(0.01, delayedMVPPrint); // shorter delay for scavenge. - bInRound = false; - } - } - else - { - // versus or other - if (bInRound && !StrEqual(name, "map_transition", false)) - { - // only show / log stuff when the round is done "the first time" - if (GetConVarBool(hPluginEnabled)) - CreateTimer(2.0, delayedMVPPrint); - bInRound = false; - } - } - - tankSpawned = false; + if (StrEqual(sGameMode, "coop", false)) + { + if (bInRound) + { + if (hPluginEnabled.BoolValue) + CreateTimer(0.01, delayedMVPPrint); // shorter delay for scavenge. + bInRound = false; + } + } + else + { + // versus or other + if (bInRound && !StrEqual(name, "map_transition", false)) + { + // only show / log stuff when the round is done "the first time" + if (hPluginEnabled.BoolValue) + CreateTimer(2.0, delayedMVPPrint); + bInRound = false; + } + } + + tankSpawned = false; } - /* -* cmds / reports -* ============== -*/ - -public Action:Say_Cmd(client, args) + * cmds / reports + * ============== + */ +public Action Say_Cmd(int client, int args) { - if (!client) { return Plugin_Continue; } - - decl String:sMessage[MAX_NAME_LENGTH]; - GetCmdArg(1, sMessage, sizeof(sMessage)); - - if (StrEqual(sMessage, "!mvp") || StrEqual(sMessage, "!mvpme")) { return Plugin_Handled; } - - return Plugin_Continue; + if (!client) + { + return Plugin_Continue; + } + + char sMessage[MAX_NAME_LENGTH]; + GetCmdArg(1, sMessage, sizeof(sMessage)); + + if (StrEqual(sMessage, "!mvp") || StrEqual(sMessage, "!mvpme")) + { + return Plugin_Handled; + } + + return Plugin_Continue; } -public Action:SurvivorMVP_Cmd(client, args) +public Action SurvivorMVP_Cmd(int client, int args) { - decl String:printBuffer[4096]; - new String:strLines[8][192]; - - GetMVPString(printBuffer, sizeof(printBuffer)); - - // PrintToChat has a max length. Split it in to individual lines to output separately - new intPieces = ExplodeString(printBuffer, "\n", strLines, sizeof(strLines), sizeof(strLines[])); - - if (client && IsClientConnected(client)) - { - for (new i = 0; i < intPieces; i++) - { - CPrintToChat(client, "%s", strLines[i]); - } - } - PrintLoserz(true, client); + char + printBuffer[4096], + strLines[8][192]; + + GetMVPString(printBuffer, sizeof(printBuffer)); + + // PrintToChat has a max length. Split it in to individual lines to output separately + int intPieces = ExplodeString(printBuffer, "\n", strLines, sizeof(strLines), sizeof(strLines[])); + + if (client && IsClientConnected(client)) + { + for (int i = 0; i < intPieces; i++) + { + CPrintToChat(client, "%s", strLines[i]); + } + } + PrintLoserz(true, client); + return Plugin_Continue; } -public Action:ShowMVPStats_Cmd(client, args) +public Action ShowMVPStats_Cmd(int client, int args) { - PrintLoserz(true, client); + PrintLoserz(true, client); + return Plugin_Continue; } -public Action:delayedMVPPrint(Handle:timer) +public Action delayedMVPPrint(Handle timer) { - decl String:printBuffer[4096]; - new String:strLines[8][192]; - - GetMVPString(printBuffer, sizeof(printBuffer)); - - // PrintToChatAll has a max length. Split it in to individual lines to output separately - new intPieces = ExplodeString(printBuffer, "\n", strLines, sizeof(strLines), sizeof(strLines[])); - for (new i = 0; i < intPieces; i++) - { - for (new client = 1; client <= MaxClients; client++) - { - if (IsClientInGame(client)) CPrintToChat(client, "{default}%s", strLines[i]); - } - } - - CreateTimer(0.1, PrintLosers); + char + printBuffer[4096], + strLines[8][192]; + + GetMVPString(printBuffer, sizeof(printBuffer)); + + // PrintToChatAll has a max length. Split it in to individual lines to output separately + int intPieces = ExplodeString(printBuffer, "\n", strLines, sizeof(strLines), sizeof(strLines[])); + for (int i = 0; i < intPieces; i++) + { + for (int client = 1; client <= MaxClients; client++) + { + if (IsClientInGame(client)) CPrintToChat(client, "{default}%s", strLines[i]); + } + } + CreateTimer(0.1, PrintLosers); + return Plugin_Continue; } -public Action:PrintLosers(Handle:timer) +public Action PrintLosers(Handle timer) { - PrintLoserz(false, -1); + PrintLoserz(false, -1); + return Plugin_Continue; } -stock PrintLoserz(bool:bSolo, client) +stock void PrintLoserz(bool bSolo, int client) { - decl String:tmpBuffer[512]; - // also find the three non-mvp survivors and tell them they sucked - // tell them they sucked with SI - if (iTotalDamageAll > 0) - { - new mvp_SI = findMVPSI(); - new mvp_SI_losers[3]; - mvp_SI_losers[0] = findMVPSI(mvp_SI); // second place - mvp_SI_losers[1] = findMVPSI(mvp_SI, mvp_SI_losers[0]); // third - mvp_SI_losers[2] = findMVPSI(mvp_SI, mvp_SI_losers[0], mvp_SI_losers[1]); // fourth - - for (new i = 0; i <= 2; i++) - { - if (IsClientAndInGame(mvp_SI_losers[i]) && !IsFakeClient(mvp_SI_losers[i])) - { - if (bSolo) - { - if (mvp_SI_losers[i] == client) - { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}Your Rank {green}SI: {olive}#%d - {blue}({default}%d {green}dmg {blue}[{default}%.0f%%{blue}]{olive}, {default}%d {green}kills {blue}[{default}%.0f%%{blue}])", (i + 2), iDidDamageAll[mvp_SI_losers[i]], (float(iDidDamageAll[mvp_SI_losers[i]]) / float(iTotalDamageAll)) * 100, iGotKills[mvp_SI_losers[i]], (float(iGotKills[mvp_SI_losers[i]]) / float(iTotalKills)) * 100); - CPrintToChat(mvp_SI_losers[i], "%s", tmpBuffer); - } - } - else - { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}Your Rank {green}SI: {olive}#%d - {blue}({default}%d {green}dmg {blue}[{default}%.0f%%{blue}]{olive}, {default}%d {green}kills {blue}[{default}%.0f%%{blue}])", (i + 2), iDidDamageAll[mvp_SI_losers[i]], (float(iDidDamageAll[mvp_SI_losers[i]]) / float(iTotalDamageAll)) * 100, iGotKills[mvp_SI_losers[i]], (float(iGotKills[mvp_SI_losers[i]]) / float(iTotalKills)) * 100); - CPrintToChat(mvp_SI_losers[i], "%s", tmpBuffer); - } - } - } - } - - // tell them they sucked with Common - if (iTotalCommon > 0) - { - new mvp_CI = findMVPCommon(); - new mvp_CI_losers[3]; - mvp_CI_losers[0] = findMVPCommon(mvp_CI); // second place - mvp_CI_losers[1] = findMVPCommon(mvp_CI, mvp_CI_losers[0]); // third - mvp_CI_losers[2] = findMVPCommon(mvp_CI, mvp_CI_losers[0], mvp_CI_losers[1]); // fourth - - for (new i = 0; i <= 2; i++) - { - if (IsClientAndInGame(mvp_CI_losers[i]) && !IsFakeClient(mvp_CI_losers[i])) - { - if (bSolo) - { - if (mvp_CI_losers[i] == client) - { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}Your Rank {green}CI{default}: {olive}#%d {blue}({default}%d {green}common {blue}[{default}%.0f%%{blue}])", (i + 2), iGotCommon[mvp_CI_losers[i]], (float(iGotCommon[mvp_CI_losers[i]]) / float(iTotalCommon)) * 100); - CPrintToChat(mvp_CI_losers[i], "%s", tmpBuffer); - } - } - else - { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}Your Rank {green}CI{default}: {olive}#%d {blue}({default}%d {green}common {blue}[{default}%.0f%%{blue}])", (i + 2), iGotCommon[mvp_CI_losers[i]], (float(iGotCommon[mvp_CI_losers[i]]) / float(iTotalCommon)) * 100); - CPrintToChat(mvp_CI_losers[i], "%s", tmpBuffer); - } - } - } - } - - // tell them they were better with FF (I know, I know, losers = winners) - if (iTotalFF > 0) - { - new mvp_FF = findLVPFF(); - new mvp_FF_losers[3]; - mvp_FF_losers[0] = findLVPFF(mvp_FF); // second place - mvp_FF_losers[1] = findLVPFF(mvp_FF, mvp_FF_losers[0]); // third - mvp_FF_losers[2] = findLVPFF(mvp_FF, mvp_FF_losers[0], mvp_FF_losers[1]); // fourth - - for (new i = 0; i <= 2; i++) - { - if (IsClientAndInGame(mvp_FF_losers[i]) && !IsFakeClient(mvp_FF_losers[i])) - { - if (bSolo) - { - if (mvp_FF_losers[i] == client) - { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}Your Rank {green}FF{default}: {olive}#%d {blue}({default}%d {green}friendly fire {blue}[{default}%.0f%%{blue}])", (i + 2), iDidFF[mvp_FF_losers[i]], (float(iDidFF[mvp_FF_losers[i]]) / float(iTotalFF)) * 100); - CPrintToChat(mvp_FF_losers[i], "%s", tmpBuffer); - } - } - else - { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}Your Rank {green}FF{default}: {olive}#%d {blue}({default}%d {green}friendly fire {blue}[{default}%.0f%%{blue}])", (i + 2), iDidFF[mvp_FF_losers[i]], (float(iDidFF[mvp_FF_losers[i]]) / float(iTotalFF)) * 100); - CPrintToChat(mvp_FF_losers[i], "%s", tmpBuffer); - } - } - } - } + char tmpBuffer[512]; + // also find the three non-mvp survivors and tell them they sucked + // tell them they sucked with SI + if (iTotalDamageAll > 0) + { + int + mvp_SI = findMVPSI(), + mvp_SI_losers[3]; + mvp_SI_losers[0] = findMVPSI(mvp_SI); // second place + mvp_SI_losers[1] = findMVPSI(mvp_SI, mvp_SI_losers[0]); // third + mvp_SI_losers[2] = findMVPSI(mvp_SI, mvp_SI_losers[0], mvp_SI_losers[1]); // fourth + + for (int i = 0; i <= 2; i++) + { + if (IsClientAndInGame(mvp_SI_losers[i]) && !IsFakeClient(mvp_SI_losers[i])) + { + if (bSolo) + { + if (mvp_SI_losers[i] == client) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t", "YourRankSI", (i + 2), iDidDamageAll[mvp_SI_losers[i]], (float(iDidDamageAll[mvp_SI_losers[i]]) / float(iTotalDamageAll)) * 100, iGotKills[mvp_SI_losers[i]], (float(iGotKills[mvp_SI_losers[i]]) / float(iTotalKills)) * 100); + CPrintToChat(mvp_SI_losers[i], "%s", tmpBuffer); + } + } + else + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t", "YourRankSI", (i + 2), iDidDamageAll[mvp_SI_losers[i]], (float(iDidDamageAll[mvp_SI_losers[i]]) / float(iTotalDamageAll)) * 100, iGotKills[mvp_SI_losers[i]], (float(iGotKills[mvp_SI_losers[i]]) / float(iTotalKills)) * 100); + CPrintToChat(mvp_SI_losers[i], "%s", tmpBuffer); + } + } + } + } + + // tell them they sucked with Common + if (iTotalCommon > 0) + { + int + mvp_CI = findMVPCommon(), + mvp_CI_losers[3]; + mvp_CI_losers[0] = findMVPCommon(mvp_CI); // second place + mvp_CI_losers[1] = findMVPCommon(mvp_CI, mvp_CI_losers[0]); // third + mvp_CI_losers[2] = findMVPCommon(mvp_CI, mvp_CI_losers[0], mvp_CI_losers[1]); // fourth + + for (int i = 0; i <= 2; i++) + { + if (IsClientAndInGame(mvp_CI_losers[i]) && !IsFakeClient(mvp_CI_losers[i])) + { + if (bSolo) + { + if (mvp_CI_losers[i] == client) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t", "YourRankCI", (i + 2), iGotCommon[mvp_CI_losers[i]], (float(iGotCommon[mvp_CI_losers[i]]) / float(iTotalCommon)) * 100); + CPrintToChat(mvp_CI_losers[i], "%s", tmpBuffer); + } + } + else + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t", "YourRankCI", (i + 2), iGotCommon[mvp_CI_losers[i]], (float(iGotCommon[mvp_CI_losers[i]]) / float(iTotalCommon)) * 100); + CPrintToChat(mvp_CI_losers[i], "%s", tmpBuffer); + } + } + } + } + + // tell them they were better with FF (I know, I know, losers = winners) + if (iTotalFF > 0) + { + int + mvp_FF = findLVPFF(), + mvp_FF_losers[3]; + mvp_FF_losers[0] = findLVPFF(mvp_FF); // second place + mvp_FF_losers[1] = findLVPFF(mvp_FF, mvp_FF_losers[0]); // third + mvp_FF_losers[2] = findLVPFF(mvp_FF, mvp_FF_losers[0], mvp_FF_losers[1]); // fourth + + for (int i = 0; i <= 2; i++) + { + if (IsClientAndInGame(mvp_FF_losers[i]) && !IsFakeClient(mvp_FF_losers[i])) + { + if (bSolo) + { + if (mvp_FF_losers[i] == client) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t", "YourRankFF", (i + 2), iDidFF[mvp_FF_losers[i]], (float(iDidFF[mvp_FF_losers[i]]) / float(iTotalFF)) * 100); + CPrintToChat(mvp_FF_losers[i], "%s", tmpBuffer); + } + } + else + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t", "YourRankFF", (i + 2), iDidFF[mvp_FF_losers[i]], (float(iDidFF[mvp_FF_losers[i]]) / float(iTotalFF)) * 100); + CPrintToChat(mvp_FF_losers[i], "%s", tmpBuffer); + } + } + } + } } /** -* When an entity is created (which we use to track rocks) -* don't actually need this -*/ -public OnEntityCreated(entity, const String:classname[]) -{ - if(! tankThrow) { - return; - } - - if(StrEqual(classname, "tank_rock", true)) { - rockIndex = entity; - tankThrow = true; - } + * When an entity is created (which we use to track rocks) + * don't actually need this + */ +public void OnEntityCreated(int entity, const char[] classname) +{ + if (!tankThrow) + { + return; + } + + if (StrEqual(classname, "tank_rock", true)) + { + rockIndex = entity; + tankThrow = true; + } } /** -* When an entity has been destroyed (i.e. when a rock lands on someone) -*/ -public OnEntityDestroyed(entity) -{ - // The rock has been destroyed - if (rockIndex == entity) { - tankThrow = false; - } + * When an entity has been destroyed (i.e. when a rock lands on someone) + */ +public void OnEntityDestroyed(int entity) +{ + // The rock has been destroyed + if (rockIndex == entity) + { + tankThrow = false; + } } /** -* When an infected uses their ability -*/ -public Action:abilityUseEvent(Handle:event, const String:name[], bool:dontBroadcast) + * When an infected uses their ability + */ +public Action abilityUseEvent(Handle event, const char[] name, bool dontBroadcast) { - decl String:ability[32]; - GetEventString(event, "ability", ability, 32); - - // If tank is throwing a rock - if(StrEqual(ability, "ability_throw", true)) { - tankThrow = true; - } + char ability[32]; + GetEventString(event, "ability", ability, 32); + + // If tank is throwing a rock + if (StrEqual(ability, "ability_throw", true)) + { + tankThrow = true; + } + return Plugin_Continue; } /** -* Track pill usage -*/ -public pillsUsedEvent(Handle:event, const String:name[], bool:dontBroadcast) + * Track pill usage + */ +public void pillsUsedEvent(Handle event, const char[] name, bool dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "userid")); - if (client == 0 || ! IsClientInGame(client)) { - return; - } - - pillsUsed[client]++; + int client = GetClientOfUserId(GetEventInt(event, "userid")); + if (client == 0 || !IsClientInGame(client)) + { + return; + } + + pillsUsed[client]++; } /** -* Track boomer pops -*/ -public boomerExploded(Handle:event, const String:name[], bool:dontBroadcast) + * Track boomer pops + */ +public void boomerExploded(Handle event, const char[] name, bool dontBroadcast) { - // We only want to track pops where the boomer didn't bile anyone - new bool:biled = GetEventBool(event, "splashedbile"); - if (! biled) { - new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); - if (attacker == 0 || ! IsClientInGame(attacker)) { - return; - } - boomerPops[attacker]++; - } + // We only want to track pops where the boomer didn't bile anyone + bool biled = GetEventBool(event, "splashedbile"); + if (!biled) + { + int attacker = GetClientOfUserId(GetEventInt(event, "attacker")); + if (attacker == 0 || !IsClientInGame(attacker)) + { + return; + } + boomerPops[attacker]++; + } } - /** -* Track when someone gets charged (end of charge for level, or if someone shoots you off etc.) -*/ -public chargerCarryEnd(Handle:event, const String:name[], bool:dontBroadcast) + * Track when someone gets charged (end of charge for level, or if someone shoots you off etc.) + */ +public void chargerCarryEnd(Handle event, const char[] name, bool dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "victim")); - if (client == 0 || ! IsClientInGame(client)) { - return; - } - - timesPinned[client][ZC_CHARGER]++; - totalPinned[client]++; - - if (tankSpawned) { - ttlPinnedDuringTank[client]++; - } + int client = GetClientOfUserId(GetEventInt(event, "victim")); + if (client == 0 || !IsClientInGame(client)) + { + return; + } + + timesPinned[client][ZC_CHARGER]++; + totalPinned[client]++; + + if (tankSpawned) + { + ttlPinnedDuringTank[client]++; + } } /** -* Track when someone gets jockeyed. -*/ -public jockeyRide(Handle:event, const String:name[], bool:dontBroadcast) + * Track when someone gets jockeyed. + */ +public void jockeyRide(Handle event, const char[] name, bool dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "victim")); - if (client == 0 || ! IsClientInGame(client)) { - return; - } - - timesPinned[client][ZC_JOCKEY]++; - totalPinned[client]++; - - if (tankSpawned) { - ttlPinnedDuringTank[client]++; - } + int client = GetClientOfUserId(GetEventInt(event, "victim")); + if (client == 0 || !IsClientInGame(client)) + { + return; + } + + timesPinned[client][ZC_JOCKEY]++; + totalPinned[client]++; + + if (tankSpawned) + { + ttlPinnedDuringTank[client]++; + } } -/** -* Track when someone gets huntered. -*/ -public hunterLunged(Handle:event, const String:name[], bool:dontBroadcast) +/** + * Track when someone gets huntered. + */ +public void hunterLunged(Handle event, const char[] name, bool dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "victim")); - if (client == 0 || ! IsClientInGame(client)) { - return; - } - - timesPinned[client][ZC_HUNTER]++; - totalPinned[client]++; - - if (tankSpawned) { - ttlPinnedDuringTank[client]++; - } + int client = GetClientOfUserId(GetEventInt(event, "victim")); + if (client == 0 || !IsClientInGame(client)) + { + return; + } + + timesPinned[client][ZC_HUNTER]++; + totalPinned[client]++; + + if (tankSpawned) + { + ttlPinnedDuringTank[client]++; + } } /** -* Track when someone gets smoked (we track when they start getting smoked, because anyone can get smoked) -*/ -public smokerChoke(Handle:event, const String:name[], bool:dontBroadcast) + * Track when someone gets smoked (we track when they start getting smoked, because anyone can get smoked) + */ +public void smokerChoke(Handle event, const char[] name, bool dontBroadcast) { - new client = GetClientOfUserId(GetEventInt(event, "victim")); - if (client == 0 || ! IsClientInGame(client)) { - return; - } - - timesPinned[client][ZC_SMOKER]++; - totalPinned[client]++; - - if (tankSpawned) { - ttlPinnedDuringTank[client]++; - } + int client = GetClientOfUserId(GetEventInt(event, "victim")); + if (client == 0 || !IsClientInGame(client)) + { + return; + } + + timesPinned[client][ZC_SMOKER]++; + totalPinned[client]++; + + if (tankSpawned) + { + ttlPinnedDuringTank[client]++; + } } /** -* When the tank spawns -*/ -public tankSpawn(Handle:event, const String:name[], bool:dontBroadcast) { - tankSpawned = true; + * When the tank spawns + */ +public void tankSpawn(Handle event, const char[] name, bool dontBroadcast) +{ + tankSpawned = true; } /** -* When the tank is killed -*/ -public tankKilled(Handle:event, const String:name[], bool:dontBroadcast) { - tankSpawned = false; + * When the tank is killed + */ +public void tankKilled(Handle event, const char[] name, bool dontBroadcast) +{ + tankSpawned = false; } /* -* track damage/kills -* ================== -*/ - -public PlayerHurt_Event(Handle:event, const String:name[], bool:dontBroadcast) + * track damage/kills + * ================== + */ +public void PlayerHurt_Event(Handle event, const char[] name, bool dontBroadcast) { - new zombieClass = 0; - - // Victim details - new victimId = GetEventInt(event, "userid"); - new victim = GetClientOfUserId(victimId); - - // Attacker details - new attackerId = GetEventInt(event, "attacker"); - new attacker = GetClientOfUserId(attackerId); - - // Misc details - new damageDone = GetEventInt(event, "dmg_health"); - - // no world damage or flukes or whatevs, no bot attackers, no infected-to-infected damage - if (victimId && attackerId && IsClientAndInGame(victim) && IsClientAndInGame(attacker)) - { - // If a survivor is attacking infected - if (GetClientTeam(attacker) == TEAM_SURVIVOR && GetClientTeam(victim) == TEAM_INFECTED) - { - zombieClass = GetEntProp(victim, Prop_Send, "m_zombieClass"); - - // Increment the damage for that class to the total - iDidDamageClass[attacker][zombieClass] += damageDone; - //PrintToConsole(attacker, "Attacked: %d - Dmg: %d", zombieClass, damageDone); - //PrintToConsole(attacker, "Total damage for %d: %d", zombieClass, iDidDamageClass[attacker][zombieClass]); - - // separately store SI and tank damage - if (zombieClass >= ZC_SMOKER && zombieClass < ZC_WITCH) - { - // If the tank is up, let's store separately - if (tankSpawned) { - siDmgDuringTank[attacker] += damageDone; - //ttlSiDmgDuringTank += damageDone; - } - - iDidDamage[attacker] += damageDone; - iDidDamageAll[attacker] += damageDone; - // iTotalDamage += damageDone; - iTotalDamageAll += damageDone; - } - else if (zombieClass == ZC_TANK && damageDone != 5000) // For some reason the last attacker does 5k damage? - { - // We want to track tank damage even if we're not factoring it in to our mvp result - iDidDamageTank[attacker] += damageDone; - //iTotalDamageTank += damageDone; - - // If we're factoring it in, include it in our overall damage - if (bCountTankDamage) - { - iDidDamageAll[attacker] += damageDone; - iTotalDamageAll += damageDone; - } - } - } - - // Otherwise if friendly fire - else if (GetClientTeam(attacker) == TEAM_SURVIVOR && GetClientTeam(victim) == TEAM_SURVIVOR && bTrackFF) // survivor on survivor action == FF - { - if (!bRUPActive || GetEntityMoveType(victim) != MOVETYPE_NONE || bPlayerLeftStartArea) { - // but don't record while frozen in readyup / before leaving saferoom - iDidFF[attacker] += damageDone; - iTotalFF += damageDone; - } - } - - // Otherwise if infected are inflicting damage on a survivor - else if (GetClientTeam(attacker) == TEAM_INFECTED && GetClientTeam(victim) == TEAM_SURVIVOR) { - zombieClass = GetEntProp(attacker, Prop_Send, "m_zombieClass"); - - // If we got hit by a tank, let's see what type of damage it was - // If it was from a rock throw - if (tankThrow && zombieClass == ZC_TANK && damageDone == 24) { - rocksEaten[victim]++; - } - damageReceived[victim] += damageDone; - } - } + int + zombieClass = 0, + // Victim details + victimId = GetEventInt(event, "userid"), + victim = GetClientOfUserId(victimId), + // Attacker details + attackerId = GetEventInt(event, "attacker"), + attacker = GetClientOfUserId(attackerId), + // Misc details + damageDone = GetEventInt(event, "dmg_health"); + + // no world damage or flukes or whatevs, no bot attackers, no infected-to-infected damage + if (victimId && attackerId && IsClientAndInGame(victim) && IsClientAndInGame(attacker)) + { + // If a survivor is attacking infected + if (GetClientTeam(attacker) == TEAM_SURVIVOR && GetClientTeam(victim) == TEAM_INFECTED) + { + zombieClass = GetEntProp(victim, Prop_Send, "m_zombieClass"); + + // Increment the damage for that class to the total + iDidDamageClass[attacker][zombieClass] += damageDone; + + // separately store SI and tank damage + if (zombieClass >= ZC_SMOKER && zombieClass < ZC_WITCH) + { + // If the tank is up, let's store separately + if (tankSpawned) + { + siDmgDuringTank[attacker] += damageDone; + } + + iDidDamage[attacker] += damageDone; + iDidDamageAll[attacker] += damageDone; + iTotalDamageAll += damageDone; + } + else if (zombieClass == ZC_TANK && damageDone != 5000) // For some reason the last attacker does 5k damage? + { + // We want to track tank damage even if we're not factoring it in to our mvp result + iDidDamageTank[attacker] += damageDone; + + // If we're factoring it in, include it in our overall damage + if (bCountTankDamage) + { + iDidDamageAll[attacker] += damageDone; + iTotalDamageAll += damageDone; + } + } + } + + // Otherwise if friendly fire + else if (GetClientTeam(attacker) == TEAM_SURVIVOR && GetClientTeam(victim) == TEAM_SURVIVOR && bTrackFF) // survivor on survivor action == FF + { + if (!bRUPActive || GetEntityMoveType(victim) != MOVETYPE_NONE || bPlayerLeftStartArea) + { + // but don't record while frozen in readyup / before leaving saferoom + iDidFF[attacker] += damageDone; + iTotalFF += damageDone; + } + } + + // Otherwise if infected are inflicting damage on a survivor + else if (GetClientTeam(attacker) == TEAM_INFECTED && GetClientTeam(victim) == TEAM_SURVIVOR) + { + zombieClass = GetEntProp(attacker, Prop_Send, "m_zombieClass"); + + // If we got hit by a tank, let's see what type of damage it was + // If it was from a rock throw + if (tankThrow && zombieClass == ZC_TANK && damageDone == 24) + { + rocksEaten[victim]++; + } + damageReceived[victim] += damageDone; + } + } } -/** -* When the infected are hurt (i.e. when a survivor hurts an SI) -* We want to use this to track damage done to the witch. -*/ -public InfectedHurt_Event(Handle:event, const String:name[], bool:dontBroadcast) +/** + * When the infected are hurt (i.e. when a survivor hurts an SI) + * We want to use this to track damage done to the witch. + */ +public void InfectedHurt_Event(Handle event, const char[] name, bool dontBroadcast) { - // catch damage done to witch - new victimEntId = GetEventInt(event, "entityid"); - - if (IsWitch(victimEntId)) - { - new attackerId = GetEventInt(event, "attacker"); - new attacker = GetClientOfUserId(attackerId); - new damageDone = GetEventInt(event, "amount"); - - // no world damage or flukes or whatevs, no bot attackers - if (attackerId && IsClientAndInGame(attacker) && GetClientTeam(attacker) == TEAM_SURVIVOR) - { - // We want to track the witch damage regardless of whether we're counting it in our mvp stat - iDidDamageWitch[attacker] += damageDone; - //iTotalDamageWitch += damageDone; - - // If we're counting witch damage in our mvp stat, lets add the amount of damage done to the witch - if (bCountWitchDamage) - { - iDidDamageAll[attacker] += damageDone; - iTotalDamageAll += damageDone; - } - } - } + // catch damage done to witch + int victimEntId = GetEventInt(event, "entityid"); + + if (IsWitch(victimEntId)) + { + int + attackerId = GetEventInt(event, "attacker"), + attacker = GetClientOfUserId(attackerId), + damageDone = GetEventInt(event, "amount"); + + // no world damage or flukes or whatevs, no bot attackers + if (attackerId && IsClientAndInGame(attacker) && GetClientTeam(attacker) == TEAM_SURVIVOR) + { + // We want to track the witch damage regardless of whether we're counting it in our mvp stat + iDidDamageWitch[attacker] += damageDone; + + // If we're counting witch damage in our mvp stat, lets add the amount of damage done to the witch + if (bCountWitchDamage) + { + iDidDamageAll[attacker] += damageDone; + iTotalDamageAll += damageDone; + } + } + } } -public PlayerDeath_Event(Handle:event, const String:name[], bool:dontBroadcast) +public void PlayerDeath_Event(Handle event, const char[] name, bool dontBroadcast) { - // Get the victim details - new zombieClass = 0; - new victimId = GetEventInt(event, "userid"); - new victim = GetClientOfUserId(victimId); - - // Get the attacker details - new attackerId = GetEventInt(event, "attacker"); - new attacker = GetClientOfUserId(attackerId); - - // no world kills or flukes or whatevs, no bot attackers - if (victimId && attackerId && IsClientAndInGame(victim) && IsClientAndInGame(attacker) && GetClientTeam(attacker) == TEAM_SURVIVOR) - { - zombieClass = GetEntProp(victim, Prop_Send, "m_zombieClass"); - - // only SI, not the tank && only player-attackers - if (zombieClass >= ZC_SMOKER && zombieClass < ZC_WITCH) - { - // store kill to count for attacker id - iGotKills[attacker]++; - iTotalKills++; - } - } - - /** - * Are we tracking the tank? - * This is a secondary measure. For some reason when I test locally in PM, the - * tank_killed event is triggered, but when I test in a custom config, it's not. - * Hopefully this should fix it. - */ - if (victimId && IsClientAndInGame(victim)) { - zombieClass = GetEntProp(victim, Prop_Send, "m_zombieClass"); - if (zombieClass == ZC_TANK) { - tankSpawned = false; - } - } + // Get the victim details + int + zombieClass = 0, + victimId = GetEventInt(event, "userid"), + victim = GetClientOfUserId(victimId), + // Get the attacker details + attackerId = GetEventInt(event, "attacker"), + attacker = GetClientOfUserId(attackerId); + + // no world kills or flukes or whatevs, no bot attackers + if (victimId && attackerId && IsClientAndInGame(victim) && IsClientAndInGame(attacker) && GetClientTeam(attacker) == TEAM_SURVIVOR) + { + zombieClass = GetEntProp(victim, Prop_Send, "m_zombieClass"); + + // only SI, not the tank && only player-attackers + if (zombieClass >= ZC_SMOKER && zombieClass < ZC_WITCH) + { + // store kill to count for attacker id + iGotKills[attacker]++; + iTotalKills++; + } + } + + /** + * Are we tracking the tank? + * This is a secondary measure. For some reason when I test locally in PM, the + * tank_killed event is triggered, but when I test in a custom config, it's not. + * Hopefully this should fix it. + */ + if (victimId && IsClientAndInGame(victim)) + { + zombieClass = GetEntProp(victim, Prop_Send, "m_zombieClass"); + if (zombieClass == ZC_TANK) + { + tankSpawned = false; + } + } } // Was the zombie a hunter? -public bool:isHunter(zombieClass) { - return zombieClass == ZC_HUNTER; +public bool isHunter(int zombieClass) +{ + return zombieClass == ZC_HUNTER; } -public InfectedDeath_Event(Handle:event, const String:name[], bool:dontBroadcast) +public void InfectedDeath_Event(Handle event, const char[] name, bool dontBroadcast) { - new attackerId = GetEventInt(event, "attacker"); - new attacker = GetClientOfUserId(attackerId); - - if (attackerId && IsClientAndInGame(attacker) && GetClientTeam(attacker) == TEAM_SURVIVOR) - { - // If the tank is up, let's store separately - if (tankSpawned) { - commonKilledDuringTank[attacker]++; - ttlCommonKilledDuringTank++; - } - - iGotCommon[attacker]++; - iTotalCommon++; - // if victimType > 2, it's an "uncommon" (of some type or other) -- do nothing with this ftpresent. - } + int + attackerId = GetEventInt(event, "attacker"), + attacker = GetClientOfUserId(attackerId); + + if (attackerId && IsClientAndInGame(attacker) && GetClientTeam(attacker) == TEAM_SURVIVOR) + { + // If the tank is up, let's store separately + if (tankSpawned) + { + commonKilledDuringTank[attacker]++; + ttlCommonKilledDuringTank++; + } + + iGotCommon[attacker]++; + iTotalCommon++; + // if victimType > 2, it's an "uncommon" (of some type or other) -- do nothing with this ftpresent. + } } /* -* MVP string & 'sorting' -* ====================== -*/ + * MVP string & 'sorting' + * ====================== + */ void GetMVPString(char[] printBuffer, const int iSize) { - decl String:tmpBuffer[1024]; - printBuffer[0] = '\0'; - - decl String:tmpName[64]; - decl String:mvp_SI_name[64]; - decl String:mvp_Common_name[64]; - decl String:mvp_FF_name[64]; - - new mvp_SI = 0; - new mvp_Common = 0; - new mvp_FF = 0; - - // calculate MVP per category: - // 1. SI damage & SI kills + damage to tank/witch - // 2. common kills - - // SI MVP - if (!(iBrevityFlags & BREV_SI)) - { - mvp_SI = findMVPSI(); - if (mvp_SI > 0) - { - // get name from client if connected -- if not, use sClientName array - if (IsClientConnected(mvp_SI)) - { - GetClientName(mvp_SI, tmpName, sizeof(tmpName)); - if (IsFakeClient(mvp_SI)) - { - StrCat(tmpName, 64, " \x01[BOT]"); - } - } else { - strcopy(tmpName, 64, sClientName[mvp_SI]); - } - mvp_SI_name = tmpName; - } else { - mvp_SI_name = "(nobody)"; - } - } - - // Common MVP - if (!(iBrevityFlags & BREV_CI)) - { - mvp_Common = findMVPCommon(); - if (mvp_Common > 0) - { - // get name from client if connected -- if not, use sClientName array - if (IsClientConnected(mvp_Common)) - { - GetClientName(mvp_Common, tmpName, sizeof(tmpName)); - if (IsFakeClient(mvp_Common)) - { - StrCat(tmpName, 64, " \x01[BOT]"); - } - } else { - strcopy(tmpName, 64, sClientName[mvp_Common]); - } - mvp_Common_name = tmpName; - } else { - mvp_Common_name = "(nobody)"; - } - } - - // FF LVP - if (!(iBrevityFlags & BREV_FF) && bTrackFF) - { - mvp_FF = findLVPFF(); - if (mvp_FF > 0) - { - // get name from client if connected -- if not, use sClientName array - if (IsClientConnected(mvp_FF)) - { - GetClientName(mvp_FF, tmpName, sizeof(tmpName)); - if (IsFakeClient(mvp_FF)) - { - StrCat(tmpName, 64, " \x01[BOT]"); - } - } else { - strcopy(tmpName, 64, sClientName[mvp_FF]); - } - mvp_FF_name = tmpName; - } else { - mvp_FF_name = "(nobody)"; - } - } - - // report - - if (mvp_SI == 0 && mvp_Common == 0 && !(iBrevityFlags & BREV_SI && iBrevityFlags & BREV_CI)) - { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}[{default}MVP{blue}]{default} {blue}({default}not enough action yet{blue}){default}\n"); - StrCat(printBuffer, iSize, tmpBuffer); - } - else - { - if (!(iBrevityFlags & BREV_SI)) - { - if (mvp_SI > 0) - { - if (iBrevityFlags & BREV_PERCENT) { - Format(tmpBuffer, sizeof(tmpBuffer), "[MVP] SI:\x03 %s \x01(\x05%d \x01dmg,\x05 %d \x01kills)\n", mvp_SI_name, iDidDamageAll[mvp_SI], iGotKills[mvp_SI]); - } else if (iBrevityFlags & BREV_ABSOLUTE) { - Format(tmpBuffer, sizeof(tmpBuffer), "[MVP] SI:\x03 %s \x01(dmg \x04%2.0f%%\x01, kills \x04%.0f%%\x01)\n", mvp_SI_name, (float(iDidDamageAll[mvp_SI]) / float(iTotalDamageAll)) * 100, (float(iGotKills[mvp_SI]) / float(iTotalKills)) * 100); - } else { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}[{default}MVP{blue}] SI: {olive}%s {blue}({default}%d {green}dmg {blue}[{default}%.0f%%{blue}]{olive}, {default}%d {green}kills {blue}[{default}%.0f%%{blue}])\n", mvp_SI_name, iDidDamageAll[mvp_SI], (float(iDidDamageAll[mvp_SI]) / float(iTotalDamageAll)) * 100, iGotKills[mvp_SI], (float(iGotKills[mvp_SI]) / float(iTotalKills)) * 100); - } - StrCat(printBuffer, iSize, tmpBuffer); - } - else - { - StrCat(printBuffer, iSize, "{blue}[{default}MVP{blue}] SI: {blue}({default}nobody{blue}){default}\n"); - } - } - - if (!(iBrevityFlags & BREV_CI)) - { - if (mvp_Common > 0) - { - if (iBrevityFlags & BREV_PERCENT) { - Format(tmpBuffer, sizeof(tmpBuffer), "[MVP] CI:\x03 %s \x01(\x05%d \x01common)\n", mvp_Common_name, iGotCommon[mvp_Common]); - } else if (iBrevityFlags & BREV_ABSOLUTE) { - Format(tmpBuffer, sizeof(tmpBuffer), "[MVP] CI:\x03 %s \x01(\x04%.0f%%\x01)\n", mvp_Common_name, (float(iGotCommon[mvp_Common]) / float(iTotalCommon)) * 100); - } else { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}[{default}MVP{blue}] CI: {olive}%s {blue}({default}%d {green}common {blue}[{default}%.0f%%{blue}])\n", mvp_Common_name, iGotCommon[mvp_Common], (float(iGotCommon[mvp_Common]) / float(iTotalCommon)) * 100); - } - StrCat(printBuffer, iSize, tmpBuffer); - } - } - } - - // FF - if (!(iBrevityFlags & BREV_FF) && bTrackFF) - { - if (mvp_FF == 0) - { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}[{default}LVP{blue}] FF{default}: {green}no friendly fire at all!{default}\n"); - StrCat(printBuffer, iSize, tmpBuffer); - } - else - { - if (iBrevityFlags & BREV_PERCENT) { - Format(tmpBuffer, sizeof(tmpBuffer), "[LVP] FF:\x03 %s \x01(\x05%d \x01dmg)\n", mvp_FF_name, iDidFF[mvp_FF]); - } else if (iBrevityFlags & BREV_ABSOLUTE) { - Format(tmpBuffer, sizeof(tmpBuffer), "[LVP] FF:\x03 %s \x01(\x04%.0f%%\x01)\n", mvp_FF_name, (float(iDidFF[mvp_FF]) / float(iTotalFF)) * 100); - } else { - Format(tmpBuffer, sizeof(tmpBuffer), "{blue}[{default}LVP{blue}] FF{default}: {olive}%s {blue}({default}%d {green}friendly fire {blue}[{default}%.0f%%{blue}]){default}\n", mvp_FF_name, iDidFF[mvp_FF], (float(iDidFF[mvp_FF]) / float(iTotalFF)) * 100); - } - StrCat(printBuffer, iSize, tmpBuffer); - } - } + printBuffer[0] = '\0'; + char + tmpBuffer[1024], + tmpName[128], + botName[16], + nobodyName[16], + mvp_SI_name[128], + mvp_Common_name[128], + mvp_FF_name[128]; + + int + mvp_SI = 0, + mvp_Common = 0, + mvp_FF = 0; + + Format(botName, sizeof(botName), "%t", "BotName"); + Format(nobodyName, sizeof(nobodyName), "%t", "NobodyName"); + // calculate MVP per category: + // 1. SI damage & SI kills + damage to tank/witch + // 2. common kills + + // SI MVP + if (!(iBrevityFlags & BREV_SI)) + { + mvp_SI = findMVPSI(); + if (mvp_SI > 0) + { + // get name from client if connected -- if not, use sClientName array + if (IsClientConnected(mvp_SI)) + { + GetClientName(mvp_SI, tmpName, sizeof(tmpName)); + if (IsFakeClient(mvp_SI)) + { + StrCat(tmpName, sizeof(tmpName), botName); + } + } + else + { + strcopy(tmpName, sizeof(tmpName), sClientName[mvp_SI]); + } + mvp_SI_name = tmpName; + } + else + { + mvp_SI_name = nobodyName; + } + } + + // Common MVP + if (!(iBrevityFlags & BREV_CI)) + { + mvp_Common = findMVPCommon(); + if (mvp_Common > 0) + { + // get name from client if connected -- if not, use sClientName array + if (IsClientConnected(mvp_Common)) + { + GetClientName(mvp_Common, tmpName, sizeof(tmpName)); + if (IsFakeClient(mvp_Common)) + { + StrCat(tmpName, sizeof(tmpName), botName); + } + } + else + { + strcopy(tmpName, sizeof(tmpName), sClientName[mvp_Common]); + } + mvp_Common_name = tmpName; + } + else + { + mvp_Common_name = nobodyName; + } + } + + // FF LVP + if (!(iBrevityFlags & BREV_FF) && bTrackFF) + { + mvp_FF = findLVPFF(); + if (mvp_FF > 0) + { + // get name from client if connected -- if not, use sClientName array + if (IsClientConnected(mvp_FF)) + { + GetClientName(mvp_FF, tmpName, sizeof(tmpName)); + if (IsFakeClient(mvp_FF)) + { + StrCat(tmpName, sizeof(tmpName), botName); + } + } + else { + strcopy(tmpName, sizeof(tmpName), sClientName[mvp_FF]); + } + mvp_FF_name = tmpName; + } + else + { + mvp_FF_name = nobodyName; + } + } + + // report + + if (mvp_SI == 0 && mvp_Common == 0 && !(iBrevityFlags & BREV_SI && iBrevityFlags & BREV_CI)) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "NotEnoughAction"); + StrCat(printBuffer, iSize, tmpBuffer); + } + else + { + if (!(iBrevityFlags & BREV_SI)) + { + if (mvp_SI > 0) + { + if (iBrevityFlags & BREV_PERCENT) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportSI_Absolute", mvp_SI_name, iDidDamageAll[mvp_SI], iGotKills[mvp_SI]); + } + else if (iBrevityFlags & BREV_ABSOLUTE) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportSI_Percent", mvp_SI_name, (float(iDidDamageAll[mvp_SI]) / float(iTotalDamageAll)) * 100, (float(iGotKills[mvp_SI]) / float(iTotalKills)) * 100); + } + else + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportSI_Full", mvp_SI_name, iDidDamageAll[mvp_SI], (float(iDidDamageAll[mvp_SI]) / float(iTotalDamageAll)) * 100, iGotKills[mvp_SI], (float(iGotKills[mvp_SI]) / float(iTotalKills)) * 100); + } + StrCat(printBuffer, iSize, tmpBuffer); + } + else + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportSI_Nobody"); + StrCat(printBuffer, iSize, tmpBuffer); + } + } + + if (!(iBrevityFlags & BREV_CI)) + { + if (mvp_Common > 0) + { + if (iBrevityFlags & BREV_PERCENT) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportCI_Absolute", mvp_Common_name, iGotCommon[mvp_Common]); + } + else if (iBrevityFlags & BREV_ABSOLUTE) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportCI_Percent", mvp_Common_name, (float(iGotCommon[mvp_Common]) / float(iTotalCommon)) * 100); + } + else + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportCI_Full", mvp_Common_name, iGotCommon[mvp_Common], (float(iGotCommon[mvp_Common]) / float(iTotalCommon)) * 100); + } + StrCat(printBuffer, iSize, tmpBuffer); + } + } + } + + // FF + if (!(iBrevityFlags & BREV_FF) && bTrackFF) + { + if (mvp_FF == 0) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "NoFF"); + StrCat(printBuffer, iSize, tmpBuffer); + } + else + { + if (iBrevityFlags & BREV_PERCENT) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportFF_Absolute", mvp_FF_name, iDidFF[mvp_FF]); + } + else if (iBrevityFlags & BREV_ABSOLUTE) + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportFF_Percent", mvp_FF_name, (float(iDidFF[mvp_FF]) / float(iTotalFF)) * 100); + } + else + { + Format(tmpBuffer, sizeof(tmpBuffer), "%t %t\n", "Tag", "ReportFF_Full", mvp_FF_name, iDidFF[mvp_FF], (float(iDidFF[mvp_FF]) / float(iTotalFF)) * 100); + } + StrCat(printBuffer, iSize, tmpBuffer); + } + } } - -findMVPSI(excludeMeA = 0, excludeMeB = 0, excludeMeC = 0) +int findMVPSI(int excludeMeA = 0, int excludeMeB = 0, int excludeMeC = 0) { - new i, maxIndex = 0; - for(i = 1; i < sizeof(iDidDamageAll); i++) - { - if(iDidDamageAll[i] > iDidDamageAll[maxIndex] && i != excludeMeA && i != excludeMeB && i != excludeMeC) - maxIndex = i; - } - return maxIndex; + int + i, + maxIndex = 0; + for (i = 1; i < sizeof(iDidDamageAll); i++) + { + if (iDidDamageAll[i] > iDidDamageAll[maxIndex] && i != excludeMeA && i != excludeMeB && i != excludeMeC) + maxIndex = i; + } + return maxIndex; } -findMVPCommon(excludeMeA = 0, excludeMeB = 0, excludeMeC = 0) +int findMVPCommon(int excludeMeA = 0, int excludeMeB = 0, int excludeMeC = 0) { - new i, maxIndex = 0; - for(i = 1; i < sizeof(iGotCommon); i++) - { - if(iGotCommon[i] > iGotCommon[maxIndex] && i != excludeMeA && i != excludeMeB && i != excludeMeC) - maxIndex = i; - } - return maxIndex; + int + i, + maxIndex = 0; + for (i = 1; i < sizeof(iGotCommon); i++) + { + if (iGotCommon[i] > iGotCommon[maxIndex] && i != excludeMeA && i != excludeMeB && i != excludeMeC) + maxIndex = i; + } + return maxIndex; } -findLVPFF(excludeMeA = 0, excludeMeB = 0, excludeMeC = 0) +int findLVPFF(int excludeMeA = 0, int excludeMeB = 0, int excludeMeC = 0) { - new i, maxIndex = 0; - for(i = 1; i < sizeof(iDidFF); i++) - { - if(iDidFF[i] > iDidFF[maxIndex] && i != excludeMeA && i != excludeMeB && i != excludeMeC) - maxIndex = i; - } - return maxIndex; + int i, maxIndex = 0; + for (i = 1; i < sizeof(iDidFF); i++) + { + if (iDidFF[i] > iDidFF[maxIndex] && i != excludeMeA && i != excludeMeB && i != excludeMeC) + maxIndex = i; + } + return maxIndex; } - /* -* general functions -* ================= -*/ + * general functions + * ================= + */ - -stock bool:IsClientAndInGame(index) -{ - return (index > 0 && index <= MaxClients && IsClientInGame(index)); -} - -stock bool:IsSurvivor(client) -{ - return IsClientAndInGame(client) && GetClientTeam(client) == TEAM_SURVIVOR; -} - -stock bool:IsInfected(client) +stock bool IsClientAndInGame(int index) { - return IsClientAndInGame(client) && GetClientTeam(client) == TEAM_INFECTED; + return (index > 0 && index <= MaxClients && IsClientInGame(index)); } -stock bool:IsWitch(iEntity) +stock bool IsSurvivor(int client) { - if(iEntity > 0 && IsValidEntity(iEntity) && IsValidEdict(iEntity)) - { - decl String:strClassName[64]; - GetEdictClassname(iEntity, strClassName, sizeof(strClassName)); - return StrEqual(strClassName, "witch"); - } - return false; + return IsClientAndInGame(client) && GetClientTeam(client) == TEAM_SURVIVOR; } -stock getSurvivor(exclude[4]) +stock bool IsInfected(int client) { - for(new i=1; i <= MaxClients; i++) { - if (IsSurvivor(i)) { - new tagged = false; - // exclude already tagged survs - for (new j=0; j < 4; j++) { - if (exclude[j] == i) { tagged = true; } - } - if (!tagged) { - return i; - } - } - } - return 0; + return IsClientAndInGame(client) && GetClientTeam(client) == TEAM_INFECTED; } -public stripUnicode(String:testString[MAX_NAME_LENGTH]) +stock bool IsWitch(int iEntity) { - new const maxlength = MAX_NAME_LENGTH; - //strcopy(testString, maxlength, sTmpString); - sTmpString = testString; - - new uni=0; - new currentChar; - new tmpCharLength = 0; - //new iReplace[MAX_NAME_LENGTH]; // replace these chars - - for (new i=0; i < maxlength - 3 && sTmpString[i] != 0; i++) - { - // estimate current character value - if ((sTmpString[i]&0x80) == 0) // single byte character? - { - currentChar=sTmpString[i]; tmpCharLength = 0; - } else if (((sTmpString[i]&0xE0) == 0xC0) && ((sTmpString[i+1]&0xC0) == 0x80)) // two byte character? - { - currentChar=(sTmpString[i++] & 0x1f); currentChar=currentChar<<6; - currentChar+=(sTmpString[i] & 0x3f); - tmpCharLength = 1; - } else if (((sTmpString[i]&0xF0) == 0xE0) && ((sTmpString[i+1]&0xC0) == 0x80) && ((sTmpString[i+2]&0xC0) == 0x80)) // three byte character? - { - currentChar=(sTmpString[i++] & 0x0f); currentChar=currentChar<<6; - currentChar+=(sTmpString[i++] & 0x3f); currentChar=currentChar<<6; - currentChar+=(sTmpString[i] & 0x3f); - tmpCharLength = 2; - } else if (((sTmpString[i]&0xF8) == 0xF0) && ((sTmpString[i+1]&0xC0) == 0x80) && ((sTmpString[i+2]&0xC0) == 0x80) && ((sTmpString[i+3]&0xC0) == 0x80)) // four byte character? - { - currentChar=(sTmpString[i++] & 0x07); currentChar=currentChar<<6; - currentChar+=(sTmpString[i++] & 0x3f); currentChar=currentChar<<6; - currentChar+=(sTmpString[i++] & 0x3f); currentChar=currentChar<<6; - currentChar+=(sTmpString[i] & 0x3f); - tmpCharLength = 3; - } else - { - currentChar=CHARTHRESHOLD + 1; // reaching this may be caused by bug in sourcemod or some kind of bug using by the user - for unicode users I do assume last ... - tmpCharLength = 0; - } - - // decide if character is allowed - if (currentChar > CHARTHRESHOLD) - { - uni++; - // replace this character // 95 = _, 32 = space - for (new j=tmpCharLength; j >= 0; j--) { - sTmpString[i - j] = 95; - } - } - } + if (iEntity > 0 && IsValidEntity(iEntity) && IsValidEdict(iEntity)) + { + char strClassName[64]; + GetEdictClassname(iEntity, strClassName, sizeof(strClassName)); + return StrEqual(strClassName, "witch"); + } + return false; } -/* -stock bool:IsCommonInfected(iEntity) +stock int getSurvivor(int exclude[4]) { -if(iEntity > 0 && IsValidEntity(iEntity) && IsValidEdict(iEntity)) -{ -decl String:strClassName[64]; -GetEdictClassname(iEntity, strClassName, sizeof(strClassName)); -return StrEqual(strClassName, "infected"); -} -return false; + for (int i = 1; i <= MaxClients; i++) + { + if (IsSurvivor(i)) + { + bool tagged = false; + // exclude already tagged survs + for (int j = 0; j < 4; j++) + { + if (exclude[j] == i) + { + tagged = true; + } + } + if (!tagged) + { + return i; + } + } + } + return 0; } -*/ \ No newline at end of file diff --git a/addons/sourcemod/scripting/survivor_mvp_test.sp b/addons/sourcemod/scripting/survivor_mvp_test.sp new file mode 100644 index 000000000..3864656ec --- /dev/null +++ b/addons/sourcemod/scripting/survivor_mvp_test.sp @@ -0,0 +1,73 @@ +/** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * 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, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + */ + +#pragma semicolon 1 +#pragma newdecls required + +#include +#include +#include + +public Plugin myinfo = +{ + name = "Survivor MVP Test", + author = "Lechuga", + description = "Test MVP functions", + version = "1.0", + url = "" +}; + +public void OnPluginStart() +{ + RegConsoleCmd("sm_mvptest", Cmd_MVP, "Shows all available stats for Survivor MVP"); +} + +public Action Cmd_MVP(int client, int args) +{ + if( args < 0 ) + { + return Plugin_Handled; + } + + int + GetMVP = SURVMVP_GetMVP(), + GetMVPDmgCount = SURVMVP_GetMVPDmgCount(client), + GetMVPKills = SURVMVP_GetMVPKills(client), + GetMVPCI = SURVMVP_GetMVPCI(), + GetMVPCIKills = SURVMVP_GetMVPCIKills(client); + + float + GetMVPDmgPercent = SURVMVP_GetMVPDmgPercent(client), + GetMVPCIPercent = SURVMVP_GetMVPCIPercent(client); + + CPrintToChat(client, "Current round MVP: {olive}%N{default}", GetMVP); + CPrintToChat(client, "Damage of client: {olive}%d{default}", GetMVPDmgCount); + CPrintToChat(client, "SI kills of client: {olive}%d{default}", GetMVPKills); + CPrintToChat(client, "Damage percent of client: {olive}%f{default}", GetMVPDmgPercent); + CPrintToChat(client, "Current round MVP client (Common): {olive}%N{default}", GetMVPCI); + CPrintToChat(client, "Common kills for client: {olive}%d{default}", GetMVPCIKills); + CPrintToChat(client, "CI percent of client: {olive}%f{default}", GetMVPCIPercent); + return Plugin_Handled; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/teamflip.sp b/addons/sourcemod/scripting/teamflip.sp index 8cdc09155..8efe4a076 100644 --- a/addons/sourcemod/scripting/teamflip.sp +++ b/addons/sourcemod/scripting/teamflip.sp @@ -6,53 +6,108 @@ This version was made out of convenience */ - +#pragma semicolon 1 +#pragma newdecls required + #include #include +#include + +enum L4D2Team +{ + L4D2Team_None = 0, + L4D2Team_Spectator, + L4D2Team_Survivor, + L4D2Team_Infected, + + L4D2Team_Size //4 size +} -new result_int; -new String:client_name[32]; // Used to store the client_name of the player who calls teamflip -new previous_timeC = 0; // Used for teamflip -new current_timeC = 0; // Used for teamflip -new Handle:delay_time; // Handle for the teamflip_delay cvar +int + result_int, + previous_timeC = 0, // Used for teamflip + current_timeC = 0; // Used for teamflip +char + client_name[32]; // Used to store the client_name of the player who calls teamflip +ConVar + delay_time; // Handle for the teamflip_delay cvar +bool + swaptoIsAvailable; -public Plugin:myinfo = +public Plugin myinfo = { name = "Teamflip", author = "purpletreefactory, epilimic", description = "coinflip, but for teams!", - version = "1.0.1.0.1.0", + version = "1.0.1.0.1.0.1.0", url = "http://www.sourcemod.net/" } -public OnPluginStart() +public void OnPluginStart() { - delay_time = CreateConVar("teamflip_delay","-1", "Time delay in seconds between allowed teamflips. Set at -1 if no delay at all is desired."); + LoadTranslation("teamflip.phrases"); + delay_time = CreateConVar("teamflip_delay","-1", "Time delay in seconds between allowed teamflips. Set at -1 if no delay at all is desired.", FCVAR_NONE, true, -1.0); RegConsoleCmd("sm_teamflip", Command_teamflip); RegConsoleCmd("sm_tf", Command_teamflip); } -public Action:Command_teamflip(client, args) +public void OnAllPluginsLoaded() +{ + swaptoIsAvailable = CommandExists("sm_swapto"); +} + +void LoadTranslation(char[] sTranslation) +{ + char + sPath[PLATFORM_MAX_PATH], + sName[64]; + + Format(sName, sizeof(sName), "translations/%s.txt", sTranslation); + BuildPath(Path_SM, sPath, sizeof(sPath), sName); + if (!FileExists(sPath)) + { + SetFailState("Missing translation file %s.txt", sTranslation); + } + LoadTranslations(sTranslation); +} + +public Action Command_teamflip(int client, int args) { current_timeC = GetTime(); - if((current_timeC - previous_timeC) > GetConVarInt(delay_time)) // Only perform a teamflip if enough time has passed since the last one. This prevents spamming. + if((current_timeC - previous_timeC) > delay_time.IntValue) // Only perform a teamflip if enough time has passed since the last one. This prevents spamming. { result_int = GetURandomInt() % 2; // Gets a random integer and checks to see whether it's odd or even GetClientName(client, client_name, sizeof(client_name)); // Gets the client_name of the person using the command if(result_int == 0) - PrintToChatAll("\x01[\x05Teamflip\x01] \x03%s\x01 flipped a team and is on the \x03Survivor \x01team!", client_name); // Here {green} is actually yellow + { + CPrintToChatAll("%t %t", "Tag", "FlippedSurvivor", client_name); // Here {green} is actually yellow + if(swaptoIsAvailable && GetClientTeamEx(client) != L4D2Team_Survivor) + { + ServerCommand("sm_swapto 2 #%i", GetClientUserId(client)); + } + } else - PrintToChatAll("\x01[\x05Teamflip\x01] \x03%s\x01 flipped a team and is on the \x03Infected \x01team!", client_name); - + { + CPrintToChatAll("%t %t", "Tag", "FlippedInfected", client_name); + if(swaptoIsAvailable && GetClientTeamEx(client) != L4D2Team_Infected) + { + ServerCommand("sm_swapto 3 #%i", GetClientUserId(client)); + } + } previous_timeC = current_timeC; // Update the previous time } else { - PrintToConsole(client, "[Teamflip] Whoa there buddy, slow down. Wait at least %d seconds.", GetConVarInt(delay_time)); + PrintToConsole(client, "%t", "Wait", delay_time.IntValue); } return Plugin_Handled; +} + +stock L4D2Team GetClientTeamEx(int client) +{ + return view_as(GetClientTeam(client)); } \ No newline at end of file diff --git a/addons/sourcemod/scripting/weapon_loadout_vote.sp b/addons/sourcemod/scripting/weapon_loadout_vote.sp index 5af36b6c7..841561b6e 100644 --- a/addons/sourcemod/scripting/weapon_loadout_vote.sp +++ b/addons/sourcemod/scripting/weapon_loadout_vote.sp @@ -71,12 +71,13 @@ public Plugin myinfo = name = "Weapon Loadout", author = "Sir, A1m`", description = "Allows the Players to choose which weapons to play the mode in.", - version = "2.3", + version = "2.4", url = "https://github.com/SirPlease/L4D2-Competitive-Rework" }; public void OnPluginStart() { + LoadTranslation("weapon_loadout.phrases"); HookEvent("round_start", Event_RoundStart); HookEvent("player_team", Event_PlayerTeam); @@ -87,6 +88,21 @@ public void OnPluginStart() InitMenu(); } +void LoadTranslation(char[] sTranslation) +{ + char + sPath[PLATFORM_MAX_PATH], + sName[64]; + + Format(sName, sizeof(sName), "translations/%s.txt", sTranslation); + BuildPath(Path_SM, sPath, sizeof(sPath), sName); + if (!FileExists(sPath)) + { + SetFailState("Missing translation file %s.txt", sTranslation); + } + LoadTranslations(sTranslation); +} + void InitMenu() { g_hMenu = new Menu(Menu_VoteMenuHandler); @@ -158,7 +174,7 @@ public Action Cmd_VoteMode(int iClient, int iArgs) // We've already decided on a mode. if (!IsInReady() || InSecondHalfOfRound()) { - CPrintToChat(iClient, "{blue}[{green}Zone{blue}]{default}: You can only call for the vote during the first ready-up of a round"); + CPrintToChat(iClient, "%t %t", "Tag", "OnlyFirstReadyup"); return Plugin_Handled; } @@ -167,13 +183,13 @@ public Action Cmd_VoteMode(int iClient, int iArgs) // Is a new vote allowed? if (!IsNewBuiltinVoteAllowed()) { - CPrintToChat(iClient, "A vote cannot be called at this moment, try again in a second or five."); + CPrintToChat(iClient, "%t", "CannotCalled"); return Plugin_Handled; } // Check if all players are present, if not.. tell them about it. if (ReadyPlayers() != GetMaxPlayers()) { - CPrintToChat(iClient, "{blue}[{green}Zone{blue}]{default}: Both teams need to be full."); + CPrintToChat(iClient, "%t %t", "Tag", "NeedFull"); return Plugin_Handled; } @@ -193,7 +209,7 @@ public Action Cmd_ForceVoteMode(int iClient, int iArgs) // Is a new vote allowed? if (!IsNewBuiltinVoteAllowed()) { - CPrintToChat(iClient, "A vote cannot be called at this moment, try again in a second or five."); + CPrintToChat(iClient, "%t", "CannotCalled"); return Plugin_Handled; } @@ -204,10 +220,6 @@ public Action Cmd_ForceVoteMode(int iClient, int iArgs) void ShowMenu(int iClient) { - if (IsInReady()) { - FakeClientCommand(iClient, "sm_hide"); - } - g_hMenu.Display(iClient, MENU_TIME_FOREVER); } @@ -217,13 +229,13 @@ public int Menu_VoteMenuHandler(Menu hMenu, MenuAction iAction, int iClient, int case MenuAction_Select: { // Is a new vote allowed? if (!IsNewBuiltinVoteAllowed()) { - CPrintToChat(iClient, "A vote cannot be called at this moment, try again in a second or five."); + CPrintToChat(iClient, "%t", "CannotCalled"); return 0; } char sInfo[32], sVoteTitle[64]; if (hMenu.GetItem(iIndex, sInfo, sizeof(sInfo))) { - Format(sVoteTitle, sizeof(sVoteTitle), "Survivors get %s?", sInfo); + Format(sVoteTitle, sizeof(sVoteTitle), "%t", "SurvivorsGet", sInfo); g_iVotingMode = iIndex + 1; // Get all non-spectating players @@ -251,9 +263,6 @@ public int Menu_VoteMenuHandler(Menu hMenu, MenuAction iAction, int iClient, int FakeClientCommand(iClient, "Vote Yes"); } } - case MenuAction_Cancel: { - FakeClientCommand(iClient, "sm_show"); - } } return 0; @@ -274,7 +283,6 @@ public void BV_VoteActionHandler(Handle hVote, BuiltinVoteAction iAction, int iP public void BV_VoteResultHandler(Handle vote, int num_votes, int num_clients, const int[][] client_info, int num_items, const int[][] item_info) { - ReturnReadyUpPanel(); for (int i = 0; i < num_items; i++) { if (item_info[i][BUILTINVOTEINFO_ITEM_INDEX] == BUILTINVOTES_VOTE_YES) { @@ -283,12 +291,14 @@ public void BV_VoteResultHandler(Handle vote, int num_votes, int num_clients, co // Allow Admins though if (!IsInReady() && g_iCurrentMode != eUndecided && !g_bIsAdminVote) { DisplayBuiltinVoteFail(vote, BuiltinVoteFail_Loses); - CPrintToChatAll("{blue}[{green}Zone{blue}]{default}: Vote didn't pass before you left ready-up."); + CPrintToChatAll("%t %t", "Tag", "BeforeReadyup"); return; } g_bIsAdminVote = false; - DisplayBuiltinVotePass(vote, "Survivor Weapons Set!"); + char sBuffer[64]; + Format(sBuffer, sizeof(sBuffer), "%t", "WeaponsSet"); + DisplayBuiltinVotePass(vote, sBuffer); g_iCurrentMode = g_iVotingMode; GiveSurvivorsWeapons(); return; @@ -426,8 +436,8 @@ public Action Timer_InformPlayers(Handle hTimer) for (int i = 1; i <= MaxClients; i++) { if (IsClientInGame(i) && GetClientTeam(i) != L4D2Team_Spectator && !g_bVoteUnderstood[i]) { - CPrintToChat(i, "{blue}[{green}Zone{blue}]{default}: Welcome to {blue}Zone{green}Hunters{default}."); - CPrintToChat(i, "{blue}[{green}Zone{blue}]{default}: Type {olive}!mode {default}in chat to vote on weapons used."); + CPrintToChat(i, "%t %t", "Tag", "Welcome"); + CPrintToChat(i, "%t %t", "Tag", "Type"); } } @@ -435,15 +445,6 @@ public Action Timer_InformPlayers(Handle hTimer) return Plugin_Continue; } -void ReturnReadyUpPanel() -{ - for (int i = 1; i <= MaxClients; i++) { - if (IsClientInGame(i) && !IsFakeClient(i) && GetClientTeam(i) > L4D2Team_Spectator) { - FakeClientCommand(i, "sm_show"); - } - } -} - int GetMaxPlayers() { return FindConVar("survivor_limit").IntValue + FindConVar("z_max_player_zombies").IntValue; diff --git a/addons/sourcemod/translations/autopause.phrases.txt b/addons/sourcemod/translations/autopause.phrases.txt new file mode 100644 index 000000000..f74285705 --- /dev/null +++ b/addons/sourcemod/translations/autopause.phrases.txt @@ -0,0 +1,13 @@ +"Phrases" +{ + "Tag" + { + "en" "{blue}[{default}AutoPause{blue}]{default}" + } + "crashed" + { + "en" "{olive}%s{default} crashed." + "es" "{olive}%s{default} no responde." + "chi" "{olive}%s{default} 客户端崩溃." + } +} diff --git a/addons/sourcemod/translations/chi/caster_system.phrases.txt b/addons/sourcemod/translations/chi/caster_system.phrases.txt index 05edd496d..d52e2fba2 100644 --- a/addons/sourcemod/translations/chi/caster_system.phrases.txt +++ b/addons/sourcemod/translations/chi/caster_system.phrases.txt @@ -13,7 +13,7 @@ "SelfCast2" { - "chi" "{blue}[{default}Cast{blue}] 重连服务器以加载 MOD" + "chi" "{blue}[{default}Cast{blue}] 重连服务器来加载 MOD" } "RegCasterTarget" diff --git a/addons/sourcemod/translations/chi/coinflip.phrases.txt b/addons/sourcemod/translations/chi/coinflip.phrases.txt new file mode 100644 index 000000000..a19e75a0e --- /dev/null +++ b/addons/sourcemod/translations/chi/coinflip.phrases.txt @@ -0,0 +1,19 @@ +"Phrases" +{ + "Tag" + { + "chi" "[{olive}抛硬币{default}]" + } + "Heads" + { + "chi" "{lightgreen}%s{default} 抛了个硬币!\nIt's {green}正面{default}!" + } + "Tails" + { + "chi" "{lightgreen}%s{default} 抛了个硬币!\nIt's {green}反面{default}!" + } + "rolled" + { + "chi" "{lightgreen}%s{default} 挑选随机数字,最大为 {teamcolor}%d{default}!\n数字为 {green}%d{default}!" + } +} diff --git a/addons/sourcemod/translations/chi/l4d_tank_control_eq.phrases.txt b/addons/sourcemod/translations/chi/l4d_tank_control_eq.phrases.txt new file mode 100644 index 000000000..a13b3c58c --- /dev/null +++ b/addons/sourcemod/translations/chi/l4d_tank_control_eq.phrases.txt @@ -0,0 +1,35 @@ +"Phrases" +{ + "Tag_Selecion" + { + "chi" "{red}<{default}Tank 选择系统{red}>{default}" + } + "Tag_Rage" + { + "chi" "{red}<{default}Tank 控制权{red}>{default}" + } + "YouBecomeTank" + { + "chi" "{green}You{default} 将会成为 {red}Tank{default}!" + } + "BecomeTank" + { + "chi" "{olive}%s{default} 将会成为 {red}Tank{default}!" + } + "UnableGiveTank" + { + "chi" "[{olive}SM{default}] %s 不是感染者. 无法给予Tank" + } + "Hit_RageMeterRefilled" + { + "chi" "第一次控制权结束,第二次控制权开始" + } + "YouRageMeterRefilled" + { + "chi" "{olive}第一次控制权结束, {red}第二次控制权开始{default}" + } + "RageMeterRefilled" + { + "chi" "({green}%N{default}) {olive}第一次控制权结束, {red}第二次控制权开始" + } +} diff --git a/addons/sourcemod/translations/chi/l4d_tank_damage_announce.phrases.txt b/addons/sourcemod/translations/chi/l4d_tank_damage_announce.phrases.txt new file mode 100644 index 000000000..c618bdf18 --- /dev/null +++ b/addons/sourcemod/translations/chi/l4d_tank_damage_announce.phrases.txt @@ -0,0 +1,23 @@ +"Phrases" +{ + "Tag" + { + "chi" "[{green}!{default}]" + } + "AI" + { + "chi" "AI" + } + "HealthRemaining" + { + "chi" "{blue}Tank{default} ({olive}%s{default}) 剩余 {green}%d{default} 点血量" + } + "DealtToTank" + { + "chi" "对{blue}Tank{default} ({olive}%s{default}) 造成的{blue}伤害" + } + "PercentDamage" + { + "chi" "{blue}[{default}%d{blue}] ({default}%i%%{blue}) {olive}%N" + } +} diff --git a/addons/sourcemod/translations/chi/nodeathcamskip.phrases.txt b/addons/sourcemod/translations/chi/nodeathcamskip.phrases.txt new file mode 100644 index 000000000..835963535 --- /dev/null +++ b/addons/sourcemod/translations/chi/nodeathcamskip.phrases.txt @@ -0,0 +1,23 @@ +"Phrases" +{ + "Tag" + { + "chi" "{red}[{default}Exploit{red}]{default}" + } + "DeathTimer" + { + "chi" "{olive}%N{default} 尝试了跳过死亡时间." + } + "UnableToJoin" + { + "chi" "你在 {red}%.1f{default} 秒内将无法加入感染者团队." + } + "Moved" + { + "chi" "时间到了之后,将会自动将你移动到感染者团队." + } + "SlotsReserved" + { + "chi" "这个队伍目前有 {olive}保留名额{default}." + } +} diff --git a/addons/sourcemod/translations/chi/pause.phrases.txt b/addons/sourcemod/translations/chi/pause.phrases.txt index 2e10936df..cf93604a5 100644 --- a/addons/sourcemod/translations/chi/pause.phrases.txt +++ b/addons/sourcemod/translations/chi/pause.phrases.txt @@ -2,20 +2,26 @@ { "Tag" { - "chi" "{default}[{green}!{default}]" + "chi" "[{green}!{default}]" } "ClientFullyLoaded" { "chi" "{olive}%N {default}已经完全载入" } + "PauseCountFormat" + { + "#format" "{1:d},{2:d}" // 1:PauseCount(client), 2:pauseLimitCvar.IntValue + "chi" " [{green}{1}{default}/{green}{2}{default}]." + } "PauseCommand" { - "chi" "{olive}%N {blue}暂停游戏{default}." + "#format" "{1:N},{2:s}" // 1:client, 2:sPauseCount + "chi" "{olive}{1}{default} {blue}暂停游戏{default}{2}" } // PauseDelay_Timer "PauseAction" { - "chi" "{red}暂停游戏" + "chi" "{red}暂停游戏{default}" } "PauseDelay" { @@ -33,11 +39,13 @@ // Unpause_Cmd "UnpauseSurvivors" { - "chi" "{olive}%N %s{default}表示 {blue}%s {default}准备完毕." + "#format" "{1:N},{2:s},{3:s}" // 1:client, :2(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "chi" "{olive}{1} {2}{default} 表示 {blue}{3}{default} 准备完毕." } "UnpauseInfected" { - "chi" "{olive}%N %s{default}表示 {red}%s {default}准备完毕." + "#format" "{1:N},{2:s},{3:s}" // 1:client, :2(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "chi" "{olive}{1} {2}{default} 表示 {red}{3}{default} 准备完毕." } "UnpauseInitiator" { @@ -50,11 +58,13 @@ // Unready_Cmd "UnreadySurvivors" { - "chi" "{olive}%N %s{default}表示 {blue}%s {default}还未准备完毕." + "#format" "{1:N},{2:s},{3:s}" // 1:client, 2:(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "chi" "{olive}{1} {2}{default} 表示 {blue}{3}{default} 还未准备完毕." } "UnreadyInfected" { - "chi" "{olive}%N %s{default}表示 {red}%s {default}还未准备完毕." + "#format" "{1:N},{2:s},{3:s}" // 1:client, 2:(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "chi" "{olive}{1} {2}{default} 表示 {red}{3}{default} 还未准备完毕." } "UnreadyInitiator" { @@ -73,7 +83,7 @@ // AddPauseCount "PauseLimit" { - "chi" "你已经达到你能发起的暂停上限." + "chi" "你已经达到你的 {red}暂停上限{default} [{green}%d{default}]." } // AttemptPause "PauseDeferred" @@ -83,25 +93,22 @@ // Pause "PausePreventSpawn" { - "chi" "{default}你因为暂停 {red}被阻止生成" + "chi" "{default}你因为暂停被阻止{red}生成" } // Show_Cmd "PanelShow" { - "chi" "准备面板: [{blue}on{default}]." + "chi" "准备面板: [{blue}开启{default}]." } "PanelHide" { - "chi" "准备面板: [{red}off{default}]." + "chi" "准备面板: [{red}关闭{default}]." } // UpdatePanel "PanelSlots" { - "chi" "▸ 服务器: %s\n▸ 位置: %d/%d" - } - "PanelDate" - { - "chi" "▸ %m/%d/%Y - %I:%M%p" + "#format" "{1:s},{2:d},{3:d}" // 1:info, 2:GetSeriousClientCount(), 3:FindConVar("sv_maxplayers").IntValue + "chi" "▸ 服务器: {1}\n▸ 位置: {2}/{3}" } "PanelTitle" { diff --git a/addons/sourcemod/translations/chi/readyup.phrases.txt b/addons/sourcemod/translations/chi/readyup.phrases.txt index 1a7c27823..de49cccab 100644 --- a/addons/sourcemod/translations/chi/readyup.phrases.txt +++ b/addons/sourcemod/translations/chi/readyup.phrases.txt @@ -1,108 +1,128 @@ "Phrases" { -// The following uses bracket style color tags (see colors.inc) - "PanelHide" + "Tag" { - "chi" "[{olive}Readyup{default}] 准备面板已 {red}关闭{default}" + "chi" "[{green}!{default}]" } - - "PanelShow" + // readyup/action.inc + "LiveCountdownBegin" { - "chi" "[{olive}Readyup{default}] 准备面板已 {blue}开启{default}" + "chi" "比赛即将开始!\n输入 !unready / 按 F2 中断倒数" } - - "ForceStartAdmin" + "RoundIsLive" { - "#format" "{1:N}" - "chi" "[{green}!{default}] {blue}管理员 {default}({olive}{1}{default}) {green}强制{default}了{blue}游戏开始" + "chi" "比赛开始!" + } + "LiveCountdown" + { + "#format" "{1:d}" + "chi" "开始倒计时: {1}\n输入 !unready / 按 F2 中断倒数" } - - "VoteInProgress" + "AutoStartWaiting" { - "chi" "[{olive}Readyup{default}] 现在有{olive}投票{green}正在进行{default}" + "chi" "等待玩家加入..." } - - "VoteDelay" + "AutoStartWaiting" + { + "chi" "玩家数量不足..." + } + "InitiateAutoStart" + { + "chi" "游戏将会自动开始!" + } + "AutoStartCountdown" { "#format" "{1:d}" - "chi" "[{olive}Readyup{default}] 请等待 {blue}{1}秒 {default}以发起下一轮投票" + "chi" "游戏开始于:{1}" } - - "Player marked unready" + "LiveCountdownCancelled" { - "#format" "{1:N}" - "chi" "{default}[{green}!{default}] {green}倒数中止! {default}({teamcolor}{1} {green}取消了准备{default})" + "chi" "倒数中止!" } - - "Player switched team" + "CountUnReady" { - "#format" "{1:N}" - "chi" "{default}[{green}!{default}] {green}倒数中止! {default}({teamcolor}{1} {olive}切换了阵营{default})" + "#format" "{1:d}{2:d}" // 1:GetUnReadyCount(client), 2:l4d_ready_unready_limit.IntValue + "en" " [{green}{1}{default}/{green}{2}{default}]" } - - "Player disconnected" + "UnReadyLimit" { - "#format" "{1:N}" - "chi" "{default}[{green}!{default}] {green}倒数中止! {default}({teamcolor}{1} {green}离开了游戏{default})" + "chi" "你已经到达你的 {red}取消准备上限{default} [{green}%d{default}]" } - - "Admin aborted" + // readyup/command.inc + "ForceStartAdmin" { "#format" "{1:N}" - "chi" "{default}[{green}!{default}] {green}叫停强制开始! {default}({green}由 {olive}{1} {green}发起{default})" + "chi" "[{green}!{default}] {blue}管理员 {default}({olive}{1}{default}) {green}强制{default}了{blue}游戏开始" + } + "PanelHide" + { + "chi" "[{olive}Readyup{default}] 准备面板已 {red}关闭{default}" } - - -// The following are not allowed to use any color tag + "PanelShow" + { + "chi" "[{olive}Readyup{default}] 准备面板已 {blue}开启{default}" + } + // readyup/panel.inc "HintReady" { "chi" "你已经准备了\n输入 !unready / 按 F2 取消准备" } - "HintUnready" { "chi" "你还没有准备\n输入 !ready / 按 F1 确认准备" } - - "LiveCountdownBegin" + "PanelSlots" { - "chi" "比赛即将开始!\n输入 !unready / 按 F2 中断倒数" + "#format" "{1:s},{2:d},{3:d},{4:s}" // 1:ServerName, 2:GetSeriousClientCount(), 3:FindConVar("sv_maxplayers").IntValue, 4:cfgName + "chi" "▸ 服务器名字: {1} \n▸ 位置: {2}/{3}\n▸ 比赛配置: {4}" } - - "LiveCountdown" + "PanelCommands" { - "#format" "{1:d}" - "chi" "请各就各位:{1} \n输入 !unready / 按 F2 中断倒数" + "chi" "▸ 命令:" } - - "LiveCountdownCancelled" + "PanelSurvivors" { - "chi" "倒数中止!" + "#format" "{1:d},{2:s}" // 1:++textCount, 2:isTeamReadyMode ? teamReadySymbol[survivorReady] : "" + "chi" "->{1}. 生还者{2}" } - - "RoundIsLive" + "PanelInfected" { - "chi" "比赛开始!" - } - - "InitiateAutoStart" + "#format" "{1:d},{2:s}" // 1:++textCount, 2:isTeamReadyMode ? teamReadySymbol[survivorReady] : "" + "chi" "->{1}. 感染者{2}" + } + "PanelCaster" { - "chi" "游戏将会自动开始!" + "#format" "{1:d},{2:s}" // 1:++textCount, 2:casterCount > 1 ? "s" : "" + "chi" "->{1}. 裁判{2}" } - - "AutoStartCountdown" + "PanelSpectator" { - "#format" "{1:d}" - "chi" "游戏开始于:{1}" + "#format" "{1:d},{2:s}" // 1:++textCount, 2:specCount > 1 ? "s" : "" + "chi" "->{1}. 旁观者{2}" } - - "AutoStartWaiting" + "PanelMany" { - "chi" "等待玩家加入..." + "chi" "**很多** (%d)" } - - "AutoStartNotEnoughPlayers" + // g_sDisruptReason[] + "Player marked unready" { - "chi" "玩家数量不足..." + "#format" "{1:N}" + "chi" "{default}[{green}!{default}] {green}倒数中止! {default}({teamcolor}{1} {green}取消了准备{default})" + } + "Player switched team" + { + "#format" "{1:N}" + "chi" "{default}[{green}!{default}] {green}倒数中止! {default}({teamcolor}{1} {olive}切换了阵营{default})" + } + "Player disconnected" + { + "#format" "{1:N}" + "chi" "{default}[{green}!{default}] {green}倒数中止! {default}({teamcolor}{1} {green}离开了游戏{default})" + } + "Admin aborted" + { + "#format" "{1:N}" + "chi" "{default}[{green}!{default}] {green}叫停强制开始! {default}({green}由 {olive}{1} {green}发起{default})" } } \ No newline at end of file diff --git a/addons/sourcemod/translations/chi/survivor_mvp.phrases.txt b/addons/sourcemod/translations/chi/survivor_mvp.phrases.txt new file mode 100644 index 000000000..59d72bf05 --- /dev/null +++ b/addons/sourcemod/translations/chi/survivor_mvp.phrases.txt @@ -0,0 +1,75 @@ +"Phrases" +{ + "Tag" + { + "chi" "{blue}[{default}MVP{blue}]{default}" + } + "YourRankSI" + { + "chi" "{green}特感 {blue}排名: {olive}#%d {blue}({default}%d {green}伤害 {blue}[{default}%.0f%%{blue}]{default}, %d {green}kills {blue}[{default}%.0f%%{blue}])" + } + "YourRankCI" + { + "chi" "{green}丧尸 {blue}Rank: {olive}#%d {blue}({default}%d {green}丧尸 {blue}[{default}%.0f%%{blue}])" + } + "YourRankFF" + { + "chi" "{green}黑枪 {blue}Rank: {olive}#%d {blue}({default}%d {green}友伤 {blue}[{default}%.0f%%{blue}])" + } + "BotName" + { + "chi" "[BOT]" + } + "NobodyName" + { + "chi" "{blue}({default}没有人{blue})" + } + "NotEnoughAction" + { + "chi" "{blue}({default}还没有足够多的操作{blue})" + } + "ReportSI_Absolute" + { + "chi" "{green}特感: {olive}%s {blue}({default}%d {green}伤害{default}, %d {green}击杀{blue})" + } + "ReportSI_Percent" + { + "chi" "{green}特感: {olive}%s {blue}({green}伤害 {blue}[{default}%.0f%%{blue}]{default}, {green}击杀 {blue}[{default}%.0f%%{blue}])" + } + "ReportSI_Full" + { + "chi" "{green}特感: {olive}%s {blue}({default}%d {green}伤害 {blue}[{default}%.0f%%{blue}]{default}, %d {green}击杀 {blue}[{default}%.0f%%{blue}])" + } + "ReportSI_Nobody" + { + "chi" "{green}特感: {blue}({default}无{blue})" + } + "ReportCI_Absolute" + { + "chi" "{green}丧尸: {olive}%s {blue}({default}%d {green}丧尸{blue})" + } + "ReportCI_Percent" + { + "chi" "{green}丧尸: {olive}%s {blue}({green}丧尸 {blue}[{default}%.0f%%{blue}])" + } + "ReportCI_Full" + { + "chi" "{green}丧尸: {olive}%s {blue}({default}%d {green}丧尸 {blue}[{default}%.0f%%{blue}])" + } + "NoFF" + { + "chi" "{blue}({default}完全没有黑枪!{blue})" + } + "ReportFF_Absolute" + { + "chi" "{green}友伤: {olive}%s {blue}({default}%d {green}友伤{blue})" + } + "ReportFF_Percent" + { + "chi" "{green}友伤: {olive}%s {blue}({green}友伤 {blue}[{default}%.0f%%{blue}])" + } + "ReportFF_Full" + { + "chi" "{green}友伤: {olive}%s {blue}({default}%d {green}友伤 {blue}[{default}%.0f%%{blue}])" + } +} diff --git a/addons/sourcemod/translations/chi/teamflip.phrases.txt b/addons/sourcemod/translations/chi/teamflip.phrases.txt new file mode 100644 index 000000000..9727074d6 --- /dev/null +++ b/addons/sourcemod/translations/chi/teamflip.phrases.txt @@ -0,0 +1,19 @@ +"Phrases" +{ + "Tag" + { + "chi" "[{olive}Teamflip{default}]" + } + "FlippedSurvivor" + { + "chi" "{green}%s{default} 随机挑选了一个队伍,是 {blue}幸存者{default} 队伍!" + } + "FlippedInfected" + { + "chi" "{green}%s{default} 随机挑选了一个队伍,是 {red}感染者{default} 队伍!" + } + "Wait" + { + "chi" "[Teamflip] 哇,伙计,慢点。至少要等 %d 秒。" + } +} diff --git a/addons/sourcemod/translations/chi/weapon_loadout.phrases.txt b/addons/sourcemod/translations/chi/weapon_loadout.phrases.txt new file mode 100644 index 000000000..74f3ae139 --- /dev/null +++ b/addons/sourcemod/translations/chi/weapon_loadout.phrases.txt @@ -0,0 +1,39 @@ +"Phrases" +{ + "Tag" + { + "chi" "{blue}[{green}Zone{blue}]{default}:" + } + "OnlyFirstReadyup" + { + "chi" "你只能在第一回合Readyup前使用这个命令." + } + "CannotCalled" + { + "chi" "暂时无法发起一个投票,请稍等几秒钟..." + } + "NeedFull" + { + "chi" "所有队伍需要满人." + } + "SurvivorsGet" + { + "chi" "生还者获得 %s?" + } + "BeforeReadyup" + { + "chi" "准备完毕后无法使用." + } + "WeaponsSet" + { + "chi" "生还者武器设置完成!" + } + "Welcome" + { + "chi" "欢迎来到 {blue}Zone{green}Hunters模式{default}." + } + "Type" + { + "chi" "在聊天栏输入 {olive}!mode{default} 来投票选取武器的使用." + } +} diff --git a/addons/sourcemod/translations/coinflip.phrases.txt b/addons/sourcemod/translations/coinflip.phrases.txt new file mode 100644 index 000000000..986e26b49 --- /dev/null +++ b/addons/sourcemod/translations/coinflip.phrases.txt @@ -0,0 +1,19 @@ +"Phrases" +{ + "Tag" + { + "en" "[{olive}Coinflip{default}]" + } + "Heads" + { + "en" "{lightgreen}%s{default} flipped a coin!\nIt's {green}Heads{default}!" + } + "Tails" + { + "en" "{lightgreen}%s{default} flipped a coin!\nIt's {green}Tails{default}!" + } + "rolled" + { + "en" "{lightgreen}%s{default} rolled a {teamcolor}%d{default} sided die!\nIt's {green}%d{default}!" + } +} diff --git a/addons/sourcemod/translations/current.phrases.txt b/addons/sourcemod/translations/current.phrases.txt new file mode 100644 index 000000000..3a74b8e41 --- /dev/null +++ b/addons/sourcemod/translations/current.phrases.txt @@ -0,0 +1,9 @@ +"Phrases" +{ + "Current" + { + "en" "Current: {green}%d%%{default}" + "es" "Progreso: {green}%d%%{default}" + "chi" "当前进度: {green}%d%%{default}" + } +} diff --git a/addons/sourcemod/translations/es/coinflip.phrases.txt b/addons/sourcemod/translations/es/coinflip.phrases.txt new file mode 100644 index 000000000..012030b04 --- /dev/null +++ b/addons/sourcemod/translations/es/coinflip.phrases.txt @@ -0,0 +1,15 @@ +"Phrases" +{ + "Heads" + { + "es" "¡{lightgreen}%s{default} tiró una moneda!\n¡Es {green}Cara{default}!" + } + "Tails" + { + "es" "¡{lightgreen}%s{default} tiró una moneda!\n¡Es {green}Cruz{default}!" + } + "rolled" + { + "es" "!{lightgreen}%s{default} eligió un número del 1 al {teamcolor}%d{default}!\n¡Es {green}%d{default}!" + } +} diff --git a/addons/sourcemod/translations/es/l4d2_stats.phrases.txt b/addons/sourcemod/translations/es/l4d2_stats.phrases.txt index 4b8014c14..5f97db692 100644 --- a/addons/sourcemod/translations/es/l4d2_stats.phrases.txt +++ b/addons/sourcemod/translations/es/l4d2_stats.phrases.txt @@ -10,6 +10,19 @@ "#format" "{1:N},{2:N}" // 1:victim 2:attacker "es" "{olive}{2}{default} realizó un {blue}headshot{default} a {olive}{1}{default}" } + "assister" + { + "#format" "{1:N},{2:d},{3:d},{4:s}" // 1:assisters[0][0], 2:assisters[0][1], 3:g_iShotsDealt[victim][assisters[0][0]], 4:assist_shots == 1 ? AssistShotsSingular:AssistShotsPlural + "es" "{1} ({2}/{3} disparo{4})" + } + "AssistShotsSingular" + { + "es" "" + } + "AssistShotsPlural" + { + "es" "s" + } "TeamSkeeted" { "#format" "{1:N},{2:N},{3:d},{4:d},{5:s},{6:s}" // 1:attacker 2:victim 3:damage 4:shots 5:shots == 1 ? "" : "s" 6:assister_string diff --git a/addons/sourcemod/translations/es/l4d_tank_control_eq.phrases.txt b/addons/sourcemod/translations/es/l4d_tank_control_eq.phrases.txt new file mode 100644 index 000000000..aaa575f04 --- /dev/null +++ b/addons/sourcemod/translations/es/l4d_tank_control_eq.phrases.txt @@ -0,0 +1,35 @@ +"Phrases" +{ + "Tag_Selecion" + { + "es" "{red}<{default}Selección de Tank{red}>{default}" + } + "Tag_Rage" + { + "es" "{red}<{default}Ira del Tank{red}>{default}" + } + "YouBecomeTank" + { + "es" "¡{green}Tu{default} te convertirás en el {red}Tank{default}!" + } + "BecomeTank" + { + "es" "{olive}%s{default} se convertirá en el {red}Tank{default}!" + } + "UnableGiveTank" + { + "es" "[{olive}SM{default}] %s no es infectado. No se puede dar el Tank" + } + "Hit_RageMeterRefilled" + { + "es" "Medidor de ira Recargado" + } + "YouRageMeterRefilled" + { + "es" "{olive}Medidor de ira {red}Recargado{default}" + } + "RageMeterRefilled" + { + "es" "({green}%N{default}'s) {olive}Medidor de ira {red}Recargado" + } +} diff --git a/addons/sourcemod/translations/es/l4d_tank_damage_announce.phrases.txt b/addons/sourcemod/translations/es/l4d_tank_damage_announce.phrases.txt new file mode 100644 index 000000000..577c7204d --- /dev/null +++ b/addons/sourcemod/translations/es/l4d_tank_damage_announce.phrases.txt @@ -0,0 +1,19 @@ +"Phrases" +{ + "AI" + { + "es" "IA" + } + "HealthRemaining" + { + "es" "{blue}Tank{default} ({olive}%s{default}) tiene {green}%d{default} salud restante" + } + "DealtToTank" + { + "es" "{blue}Daño{default} infligido al {blue}Tank{default} ({olive}%s{default})" + } + "PercentDamage" + { + "es" "{blue}[{default}%d{blue}] ({default}%i%%{blue}) {olive}%N" + } +} diff --git a/addons/sourcemod/translations/es/nodeathcamskip.phrases.txt b/addons/sourcemod/translations/es/nodeathcamskip.phrases.txt new file mode 100644 index 000000000..a4da2e80a --- /dev/null +++ b/addons/sourcemod/translations/es/nodeathcamskip.phrases.txt @@ -0,0 +1,19 @@ +"Phrases" +{ + "DeathTimer" + { + "es" "{olive}%N{default} intentó evadir el cronómetro de muerte." + } + "UnableToJoin" + { + "es" "No podrás unirte al equipo por {red}%.1f{default} segundos." + } + "Moved" + { + "es" "Serás movido automáticamente." + } + "SlotsReserved" + { + "es" "Este equipo actualmente tiene espacios {olive}reservados{default}." + } +} diff --git a/addons/sourcemod/translations/es/pause.phrases.txt b/addons/sourcemod/translations/es/pause.phrases.txt index 4305b49c7..9957e97f5 100644 --- a/addons/sourcemod/translations/es/pause.phrases.txt +++ b/addons/sourcemod/translations/es/pause.phrases.txt @@ -2,151 +2,162 @@ { "ClientFullyLoaded" { - "es" "{olive}%N {default}ha cargado totalmente" + "es" "{olive}%N{default} ha cargado totalmente." + } + "PauseCountFormat" + { + "#format" "{1:d},{2:d}" // 1:PauseCount(client), 2:pauseLimitCvar.IntValue + "en" " [{green}{1}{default}/{green}{2}{default}]." } "PauseCommand" { - "es" "{olive}%N {default}a {blue} Pausado{default}." + "#format" "{1:N},{2:s}" // 1:client, 2:sPauseCount + "es" "{olive}{1}{default} a {blue}Pausado{default}{2}" } // PauseDelay_Timer "PauseAction" { - "es" "{red}PAUSA" + "es" "{red}PAUSA{default}" } "PauseDelay" { - "es" "{blue}Pausa en{default}: {olive}%d" + "es" "{blue}Pausa en{default}: {olive}%d{default}." } // ForcePause_Cmd "Crashed" { - "es" "{olive}El juego {default}se ha {green}puesto en pausa {default}porque un jugador se le ha {blue}cerrado{default}." + "es" "{olive}El juego{default} se ha {green}Pausado{default}, un jugador {blue}no responde{default}." } "ForcePause" { - "es" "Una pausa forzada {green}es emitida por {blue}Admin {default}({olive}%N{default})" + "es" "{green}Pausa forzada{default} por el {blue}Admin{default} ({olive}%N{default})" } // Unpause_Cmd "UnpauseSurvivors" { - "es" "{olive}%N %s{default}a marcado como {blue}%s {default}listo." + "#format" "{1:N},{2:s},{3:s}" // 1:client, :2(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "es" "{olive}{1} {2}{default} marco que los {blue}{3}{default} estan preparados." } "UnpauseInfected" { - "es" "{olive}%N %s{default}a marcado como {red}%s {default}listo." + "#format" "{1:N},{2:s},{3:s}" // 1:client, :2(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "es" "{olive}{1} {2}{default} marco que los {red}{3}{default} estan preparados." } "UnpauseInitiator" { - "es" "{olive}%N {default}a marcado como {green}Initiator {default}listo." + "es" "El jugador que {green}pauso{default} ({olive}%N{default}) marco que está preparado." } "UnpauseAdminConfirm" { - "es" "{olive}Los equipos {default}están listos. Espere a que {blue}Administrador {default} {green}confirme{default}." + "es" "{olive}Los equipos{default} están listos. Espere a que el {blue}Administrador{default} {green}confirme{default}." } // Unready_Cmd "UnreadySurvivors" { - "es" "{olive}%N %s{default}marcado {blue}%s {default}no listo." + "#format" "{1:N},{2:s},{3:s}" // 1:client, 2:(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "es" "{olive}{1} {2}{default} marco que los {blue}{3}{default} no estan preparados." } "UnreadyInfected" { - "es" "{olive}%N %s{default}marcado {red}%s {default}no listo." + "#format" "{1:N},{2:s},{3:s}" // 1:client, 2:(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "es" "{olive}{1} {2}{default} marco que los {red}{3}{default} no preparados." } "UnreadyInitiator" { - "es" "{olive}%N {default}marcó {green}Iniciador {default}no listo." + "es" "El jugador que {green}pauso{default} ({olive}%N{default}) marco que no está preparado." } // void AsInitiator() "AsInitiator" { - "es" "{default}como {green}Iniciador " + "es" "como {green}Iniciador{default}" } // ForceUnpause_Cmd "ForceUnpause" { - "es" "Un {green}forzar reanudación {default} es emitido por {blue}Administrador {default}({olive}%N{default})" + "es" "El {blue}Administrador{default} ({olive}%N{default}) {green}forzo la reanudación{default}." } // AddPauseCount "PauseLimit" { - "es" "Has alcanzado tu límite de pausa." + "es" "Has alcanzado tu {red}límite de pausas{default} [{green}%d{default}]." } // AttemptPause "PauseDeferred" { - "es" "{red}La pausa se ha retrasado debido a que un sobreviviente se está levantando." + "es" "{red}La pausa se ha retrasado debido a que un sobreviviente se está levantando{default}." } // Pause "PausePreventSpawn" { - "es" "{default}Tu {red}reaparición {default}ha sido impedido debido a la Pausa" + "es" "Tu{red} reaparición {default} fue impedida debido a la Pausa{default}." } // Show_Cmd "PanelShow" { - "es" "El panel ahora está {azul} activado {default}." + "es" "El panel ahora está {azul}activado{default}." } "PanelHide" { - "es" "El panel ahora está {rojo}desactivado{predeterminado}." + "es" "El panel ahora está {red}desactivado{predeterminado}." } // UpdatePanel "PanelSlots" { - "es" "▸ Servidor: %s\n▸ Espacios: %d/%d" + "#format" "{1:s},{2:d},{3:d}" // 1:info, 2:GetSeriousClientCount(), 3:FindConVar("sv_maxplayers").IntValue + "es" "▸ Servidor: {1}\n▸ Espacios: {2}/{3}" } "PanelTitle" { - "es" "▸ Estado" + "es" "▸ Estado" } "RequireAdmin" { - "es" "->0. Requerir que el administrador reanude la pausa" + "es" "->0. Requerir que el administrador reanude la pausa" } "SurvivorUnPaused" { - "es" "->1. Sobrevivientes: [√]" + "es" "->1. Sobrevivientes: [√]" } "SurvivorPaused" { - "es" "->1. Sobrevivientes: [X]" + "es" "->1. Sobrevivientes: [X]" } "InfectedUnPaused" { - "es" "->2. Infectado: [√]" + "es" "->2. Infectado: [√]" } "InfectedPaused" { - "es" "->2. Infectado: [X]" + "es" "->2. Infectado: [X]" } "InitiatorUnPaused" { - "es" "->0. Infectado: [√]" + "es" "->0. Infectado: [√]" } "InitiatorPaused" { - "es" "->0. Iniciador: [X]" + "es" "->0. Iniciador: [X]" } "AutoPauseCrash" { - "es" "▸ Pausa automática forzada -> Crash" + "es" "▸ Pausa automática forzada -> Crash" } "ForcePauseAdmin" { - "es" "▸ Forzar la pausa -> %s (Admin)" + "es" "▸ Forzar la pausa -> %s (Admin)" } "InitiatorPause" { - "es" "▸ Iniciador -> %s (%s)" + "es" "▸ Iniciador -> %s (%s)" } "DurationPause" { - "es" "▸ Duración: %02d:%02d" + "es" "▸ Duración: %02d:%02d" } // InitiateLiveCountdown "CountdownCancelNotify" { - "es" "Escriba {olive}!unready {default}para cancelar" + "es" "Escriba {olive}!unready{default} para cancelar" } "GameisLive" { @@ -159,7 +170,7 @@ // CancelFullReady "CountdownCancelled" { - "es" "{olive}%N {default}canceló la cuenta regresiva!" + "es" "{olive}%N{default} canceló la cuenta regresiva!" } // Callvote_Callback "CallvoteNoSpec" diff --git a/addons/sourcemod/translations/es/readyup.phrases.txt b/addons/sourcemod/translations/es/readyup.phrases.txt new file mode 100644 index 000000000..f1eef5fd0 --- /dev/null +++ b/addons/sourcemod/translations/es/readyup.phrases.txt @@ -0,0 +1,124 @@ +"Phrases" +{ + // readyup/action.inc + "LiveCountdownBegin" + { + "es" "¡Iniciando!\n ────────── \nPresiona F2|!nr para cancelar" + } + "RoundIsLive" + { + "es" "¡La ronda a comenzado!" + } + "LiveCountdown" + { + "#format" "{1:d}" + "es" "Iniciando en: {1}\nPresiona F2|!nr para cancelar" + } + "AutoStartNotEnoughPlayers" + { + "es" "Se requieren más jugadores..." + } + "AutoStartWaiting" + { + "es" "Esperando a los jugadores..." + } + "InitiateAutoStart" + { + "es" "¡El juego comenzara automaticamente!" + } + "AutoStartCountdown" + { + "#format" "{1:d}" + "es" "El juego comienza en: {1}" + } + "LiveCountdownCancelled" + { + "es" "¡Cuenta regresiva cancelada!" + } + "CountUnReady" + { + "#format" "{1:d}{2:d}" // 1:GetUnReadyCount(client), 2:l4d_ready_unready_limit.IntValue + "en" " [{green}{1}{default}/{green}{2}{default}]" + } + "UnReadyLimit" + { + "en" "Has alcanzado tu {red}límite de cancelaciones{default} [{green}%d{default}]" + } + // readyup/command.inc + "ForceStartAdmin" + { + "#format" "{1:N}" + "es" "El {blue}inicio del juego{default} es {green}forzado{default} por el {blue}Admin{default} ({olive}{1}{default})" + } + "PanelHide" + { + "es" "El panel ahora esta {red}desactivado{default}" + } + "PanelShow" + { + "es" "El panel ahora esta {blue}activado{default}" + } + // readyup/panel.inc + "HintReady" + { + "es" "Estás preparado\n ────────── \nPresiona F2|!nr para cancelar" + } + "HintUnready" + { + "es" "No estás preparado\n ────────── \nPresiona F1|!r para confirmar" + } + "PanelSlots" + { + "#format" "{1:s},{2:d},{3:d},{4:s}" // 1:ServerName, 2:GetSeriousClientCount(), 3:FindConVar("sv_maxplayers").IntValue, 4:cfgName + "es" "▸ Servidor: {1} \n▸ Espacios: {2}/{3}\n▸ Config: {4}" + } + "PanelCommands" + { + "es" "▸ Comandos:" + } + "PanelSurvivors" + { + "#format" "{1:d},{2:s}" // 1:++textCount, 2:isTeamReadyMode ? teamReadySymbol[survivorReady] : "" + "es" "->{1}. Superviviente{2}" + } + "PanelInfected" + { + "#format" "{1:d},{2:s}" // 1:++textCount, 2:isTeamReadyMode ? teamReadySymbol[survivorReady] : "" + "es" "->{1}. Infectado{2}" + } + "PanelCaster" + { + "#format" "{1:d},{2:s}" // 1:++textCount, 2:casterCount > 1 ? "s" : "" + "es" "->{1}. Comentador{2}" + } + "PanelSpectator" + { + "#format" "{1:d},{2:s}" // 1:++textCount, 2:specCount > 1 ? "s" : "" + "es" "->{1}. Espectador{2}" + } + "PanelMany" + { + "es" "**Muchos** (%d)" + } + // g_sDisruptReason[] + "Player marked unready" + { + "#format" "{1:N}{2:s}" + "es" "{green}¡Cuenta regresiva cancelada!{default} ({teamcolor}{1}{default}){2}" + } + "Player switched team" + { + "#format" "{1:N}" + "es" "{green}¡Cuenta regresiva cancelada!{default} ({teamcolor}{1} {olive}se cambio de equipo{default})" + } + "Player disconnected" + { + "#format" "{1:N}" + "es" "{green}¡Cuenta regresiva cancelada!{default} ({teamcolor}{1} {green}se a desconectado{default})" + } + "Admin aborted" + { + "#format" "{1:N}" + "es" "{green}¡El inicio forzado fue cancelado!{default} ({olive}{1}{default})" + } +} \ No newline at end of file diff --git a/addons/sourcemod/translations/es/survivor_mvp.phrases.txt b/addons/sourcemod/translations/es/survivor_mvp.phrases.txt new file mode 100644 index 000000000..cffe93119 --- /dev/null +++ b/addons/sourcemod/translations/es/survivor_mvp.phrases.txt @@ -0,0 +1,71 @@ +"Phrases" +{ + "YourRankSI" + { + "es" "{blue}Rango {green}Especial: {olive}#%d {blue}({default}%d {green}daño {blue}[{default}%.0f%%{blue}]{default}, %d {green}muertes {blue}[{default}%.0f%%{blue}])" + } + "YourRankCI" + { + "es" "{blue}Rango {green}Común: {olive}#%d {blue}({default}%d {green}comúnes {blue}[{default}%.0f%%{blue}])" + } + "YourRankFF" + { + "es" "{blue}Rango {green}Fuego Amigo: {olive}#%d {blue}({default}%d {green}fuego amigo {blue}[{default}%.0f%%{blue}])" + } + "BotName" + { + "es" "[BOT]" + } + "NobodyName" + { + "es" "{blue}({default}nadie{blue})" + } + "NotEnoughAction" + { + "es" "{blue}({default}no hay suficiente acción todavía{blue})" + } + "ReportSI_Absolute" + { + "es" "{green}SI: {olive}%s {blue}({default}%d {green}daño{default}, %d {green}muertes{blue})" + } + "ReportSI_Percent" + { + "es" "{green}SI: {olive}%s {blue}({green}daño {blue}[{default}%.0f%%{blue}]{default}, {green}muertes {blue}[{default}%.0f%%{blue}])" + } + "ReportSI_Full" + { + "es" "{green}Especial: {olive}%s {blue}({default}%d {green}daño {blue}[{default}%.0f%%{blue}]{default}, %d {green}muertes {blue}[{default}%.0f%%{blue}])" + } + "ReportSI_Nobody" + { + "es" "{green}SI: {blue}({default}Nadie{blue})" + } + "ReportCI_Absolute" + { + "es" "{green}CI: {olive}%s {blue}({default}%d {green}comúnes{blue})" + } + "ReportCI_Percent" + { + "es" "{green}CI: {olive}%s {blue}({green}comúnes {blue}[{default}%.0f%%{blue}])" + } + "ReportCI_Full" + { + "es" "{green}Comun: {olive}%s {blue}({default}%d {green}muertes {blue}[{default}%.0f%%{blue}])" + } + "NoFF" + { + "es" "{blue}({default}No hay fuego amigo en absoluto!{blue})" + } + "ReportFF_Absolute" + { + "es" "{green}FF: {olive}%s {blue}({default}%d {green}fuego amigo{blue})" + } + "ReportFF_Percent" + { + "es" "{green}FF: {olive}%s {blue}({green}fuego amigo {blue}[{default}%.0f%%{blue}])" + } + "ReportFF_Full" + { + "es" "{green}Fuego Amigo: {olive}%s {blue}({default}%d {green}daño {blue}[{default}%.0f%%{blue}])" + } +} diff --git a/addons/sourcemod/translations/es/teamflip.phrases.txt b/addons/sourcemod/translations/es/teamflip.phrases.txt new file mode 100644 index 000000000..8107cb983 --- /dev/null +++ b/addons/sourcemod/translations/es/teamflip.phrases.txt @@ -0,0 +1,15 @@ +"Phrases" +{ + "FlippedSurvivor" + { + "es" "¡{green}%s{default} lanzo una moneda para elegir equipo y le salió {blue}Superviviente{default}!" + } + "FlippedInfected" + { + "es" "¡{green}%s{default} lanzo una moneda para elegir equipo y le salió {blue}Infectado{default}!" + } + "Wait" + { + "es" "[Teamflip] Vaya, reduce la velocidad. Espere al menos %d segundos." + } +} diff --git a/addons/sourcemod/translations/es/weapon_loadout.phrases.txt b/addons/sourcemod/translations/es/weapon_loadout.phrases.txt new file mode 100644 index 000000000..d16b3925e --- /dev/null +++ b/addons/sourcemod/translations/es/weapon_loadout.phrases.txt @@ -0,0 +1,35 @@ +"Phrases" +{ + "OnlyFirstReadyup" + { + "es" "Solo puede llamar a votación durante la primer ready-up de una ronda." + } + "CannotCalled" + { + "es" "No se puede convocar una votación en este momento, inténtelo de nuevo en un segundo o cinco." + } + "NeedFull" + { + "es" "Ambos equipos necesitan estar completos." + } + "SurvivorsGet" + { + "es" "Los supervivientes obtienen %s?" + } + "BeforeReadyup" + { + "es" "La votación no pasó antes del ready-up." + } + "WeaponsSet" + { + "es" "¡Los supervivientes obtuvieron sus armas!" + } + "Welcome" + { + "es" "Bienvenido a {blue}Zone{green}Hunters{default}." + } + "Type" + { + "es" "Escribe {olive}!mode{default} en el chat para votar que armas se usaran." + } +} diff --git a/addons/sourcemod/translations/l4d_tank_control_eq.phrases.txt b/addons/sourcemod/translations/l4d_tank_control_eq.phrases.txt new file mode 100644 index 000000000..fa2dfe6d6 --- /dev/null +++ b/addons/sourcemod/translations/l4d_tank_control_eq.phrases.txt @@ -0,0 +1,35 @@ +"Phrases" +{ + "Tag_Selecion" + { + "en" "{red}<{default}Tank Selection{red}>{default}" + } + "Tag_Rage" + { + "en" "{red}<{default}Tank Rage{red}>{default}" + } + "YouBecomeTank" + { + "en" "{green}You{default} will become the {red}Tank{default}!" + } + "BecomeTank" + { + "en" "{olive}%s{default} will become the {red}Tank{default}!" + } + "UnableGiveTank" + { + "en" "[{olive}SM{default}] %s not on infected. Unable to give tank" + } + "Hit_RageMeterRefilled" + { + "en" "Rage Meter Refilled" + } + "YouRageMeterRefilled" + { + "en" "{olive}Rage Meter {red}Refilled{default}" + } + "RageMeterRefilled" + { + "en" "({green}%N{default}'s) {olive}Rage Meter {red}Refilled" + } +} diff --git a/addons/sourcemod/translations/l4d_tank_damage_announce.phrases.txt b/addons/sourcemod/translations/l4d_tank_damage_announce.phrases.txt new file mode 100644 index 000000000..477746741 --- /dev/null +++ b/addons/sourcemod/translations/l4d_tank_damage_announce.phrases.txt @@ -0,0 +1,23 @@ +"Phrases" +{ + "Tag" + { + "en" "[{green}!{default}]" + } + "AI" + { + "en" "AI" + } + "HealthRemaining" + { + "en" "{blue}Tank{default} ({olive}%s{default}) had {green}%d{default} health remaining" + } + "DealtToTank" + { + "en" "{blue}Damage{default} dealt to {blue}Tank{default} ({olive}%s{default})" + } + "PercentDamage" + { + "en" "{blue}[{default}%d{blue}] ({default}%i%%{blue}) {olive}%N" + } +} diff --git a/addons/sourcemod/translations/nodeathcamskip.phrases.txt b/addons/sourcemod/translations/nodeathcamskip.phrases.txt new file mode 100644 index 000000000..6e84fed6b --- /dev/null +++ b/addons/sourcemod/translations/nodeathcamskip.phrases.txt @@ -0,0 +1,23 @@ +"Phrases" +{ + "Tag" + { + "en" "{red}[{default}Exploit{red}]{default}" + } + "DeathTimer" + { + "en" "{olive}%N{default} tried skipping the Death Timer." + } + "UnableToJoin" + { + "en" "You will be unable to join the Team for {red}%.1f{default} Seconds." + } + "Moved" + { + "en" "You will be moved automatically." + } + "SlotsReserved" + { + "en" "This team currently has slots {olive}reserved{default}." + } +} diff --git a/addons/sourcemod/translations/pause.phrases.txt b/addons/sourcemod/translations/pause.phrases.txt index 914d44009..e5985b2cf 100644 --- a/addons/sourcemod/translations/pause.phrases.txt +++ b/addons/sourcemod/translations/pause.phrases.txt @@ -2,159 +2,166 @@ { "Tag" { - "en" "{default}[{green}!{default}]" + "en" "[{green}!{default}]" } "ClientFullyLoaded" { - "en" "{olive}%N {default}has fully loaded" + "en" "{olive}%N{default} has fully loaded." + } + "PauseCountFormat" + { + "#format" "{1:d},{2:d}" // 1:PauseCount(client), 2:pauseLimitCvar.IntValue + "en" " [{green}{1}{default}/{green}{2}{default}]." } "PauseCommand" { - "en" "{olive}%N {blue}Paused{default}." + "#format" "{1:N},{2:s}" // 1:client, 2:sPauseCount + "en" "{olive}{1}{default} {blue}Paused{default}{2}" } // PauseDelay_Timer "PauseAction" { - "en" "{red}PAUSED" + "en" "{red}PAUSED{default}" } "PauseDelay" { - "en" "{blue}Pausing in{default}: {olive}%d" + "en" "{blue}Pausing in{default}: {olive}%d{default}." } // ForcePause_Cmd "Crashed" { - "en" "{olive}Game {default}was {green}force paused {default}because a player has {blue}crashed{default}." + "en" "{olive}Game{default} was {green}force paused{default} because a player has {blue}crashed{default}." } "ForcePause" { - "en" "A {green}force pause {default}is issued by {blue}Admin {default}({olive}%N{default})" + "en" "A {green}force pause{default} is issued by {blue}Admin{default} ({olive}%N{default})" } // Unpause_Cmd "UnpauseSurvivors" { - "en" "{olive}%N %s{default}marked {blue}%s {default}ready." + "#format" "{1:N},{2:s},{3:s}" // 1:client, :2(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "en" "{olive}{1} {2}{default} marked {blue}{3}{default} ready." } "UnpauseInfected" { - "en" "{olive}%N %s{default}marked {red}%s {default}ready." + "#format" "{1:N},{2:s},{3:s}" // 1:client, :2(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "en" "{olive}{1} {2}{default} marked {red}{3}{default} ready." } "UnpauseInitiator" { - "en" "{olive}%N {default}marked {green}Initiator {default}ready." + "en" "{olive}%N{default} marked {green}Initiator{default} ready." } "UnpauseAdminConfirm" { - "en" "{olive}Teams {default}are ready. Wait for {blue}Admin {default}to {green}confirm{default}." + "en" "{olive}Teams{default} are ready. Wait for {blue}Admin{default} to {green}confirm{default}." } // Unready_Cmd "UnreadySurvivors" { - "en" "{olive}%N %s{default}marked {blue}%s {default}not ready." + "#format" "{1:N},{2:s},{3:s}" // 1:client, 2:(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "en" "{olive}{1} {2}{default} marked {blue}{3}{default} not ready." } "UnreadyInfected" { - "en" "{olive}%N %s{default}marked {red}%s {default}not ready." + "#format" "{1:N},{2:s},{3:s}" // 1:client, 2:(initiatorReady && client == initiator) ? AsInitiator() : "", 3:L4D2_TeamName[clientTeam] + "en" "{olive}{1} {2}{default} marked {red}{3}{default} not ready." } "UnreadyInitiator" { - "en" "{olive}%N {default}marked {green}Initiator {default}not ready." + "en" "{olive}%N{default} marked {green}Initiator{default} not ready." } // void AsInitiator() "AsInitiator" { - "en" "{default}as {green}Initiator " + "en" "as {green}Initiator{default} " } // ForceUnpause_Cmd "ForceUnpause" { - "en" "A {green}force unpause {default}is issued by {blue}Admin {default}({olive}%N{default})" + "en" "A {green}force unpause{default} is issued by {blue}Admin{default} ({olive}%N{default})" } // AddPauseCount "PauseLimit" { - "en" "You have reached your pause limit." + "en" "You have reached your {red}pause limit{default} [{green}%d{default}]." } // AttemptPause "PauseDeferred" { - "en" "{red}Pause has been delayed due to a pick-up in progress!" + "en" "{red}Pause has been delayed due to a pick-up in progress!" } // Pause "PausePreventSpawn" { - "en" "{default}Your {red}Spawn {default}has been prevented because of the Pause" + "en" "Your {red}Spawn{default} has been prevented because of the Pause." } // Show_Cmd "PanelShow" { - "en" "Panel is now {blue}on{default}." + "en" "Panel is now {blue}on{default}." } "PanelHide" { - "en" "Panel is now {red}off{default}." + "en" "Panel is now {red}off{default}." } // UpdatePanel "PanelSlots" { - "en" "▸ Server: %s\n▸ Slots: %d/%d" - } - "PanelDate" - { - "en" "▸ %m/%d/%Y - %I:%M%p" + "#format" "{1:s},{2:d},{3:d}" // 1:info, 2:GetSeriousClientCount(), 3:FindConVar("sv_maxplayers").IntValue + "en" "▸ Server: {1}\n▸ Slots: {2}/{3}" } "PanelTitle" { - "en" "▸ Ready Status" + "en" "▸ Ready Status" } "RequireAdmin" { - "en" "->0. Require Admin to Unpause" + "en" "->0. Require Admin to Unpause" } "SurvivorUnPaused" { - "en" "->1. Survivors: [√]" + "en" "->1. Survivors: [√]" } "SurvivorPaused" { - "en" "->1. Survivors: [X]" + "en" "->1. Survivors: [X]" } "InfectedUnPaused" { - "en" "->2. Infected: [√]" + "en" "->2. Infected: [√]" } "InfectedPaused" { - "en" "->2. Infected: [X]" + "en" "->2. Infected: [X]" } "InitiatorUnPaused" { - "en" "->0. Initiator: [√]" + "en" "->0. Initiator: [√]" } "InitiatorPaused" { - "en" "->0. Initiator: [X]" + "en" "->0. Initiator: [X]" } "AutoPauseCrash" { - "en" "▸ Forced AutoPause -> Crash" + "en" "▸ Forced AutoPause -> Crash" } "ForcePauseAdmin" { - "en" "▸ Force Pause -> %s (Admin)" + "en" "▸ Force Pause -> %s (Admin)" } "InitiatorPause" { - "en" "▸ Initiator -> %s (%s)" + "en" "▸ Initiator -> %s (%s)" } "DurationPause" { - "en" "▸ Duration: %02d:%02d" + "en" "▸ Duration: %02d:%02d" } // InitiateLiveCountdown "CountdownCancelNotify" { - "en" "Say {olive}!unready {default}to cancel" + "en" "Say {olive}!unready{default} to cancel" } "GameisLive" { @@ -167,7 +174,7 @@ // CancelFullReady "CountdownCancelled" { - "en" "{olive}%N {default}cancelled the countdown!" + "en" "{olive}%N{default} cancelled the countdown!" } // Callvote_Callback "CallvoteNoSpec" diff --git a/addons/sourcemod/translations/readyup.phrases.txt b/addons/sourcemod/translations/readyup.phrases.txt index 62efbbeb4..c59505ec8 100644 --- a/addons/sourcemod/translations/readyup.phrases.txt +++ b/addons/sourcemod/translations/readyup.phrases.txt @@ -1,108 +1,128 @@ "Phrases" { -// The following uses bracket style color tags (see colors.inc) - "PanelHide" + "Tag" { - "en" "[{olive}Readyup{default}] Panel is now {red}off{default}" + "en" "[{green}!{default}]" } - - "PanelShow" + // readyup/action.inc + "LiveCountdownBegin" { - "en" "[{olive}Readyup{default}] Panel is now {blue}on{default}" + "en" "Going live!\nSay !unready / Press F2 to cancel" } - - "ForceStartAdmin" + "RoundIsLive" { - "#format" "{1:N}" - "en" "[{green}!{default}] {blue}Game {default}start is {green}forced {default}by {blue}Admin {default}({olive}{1}{default})" + "en" "Round is live!" + } + "LiveCountdown" + { + "#format" "{1:d}" + "en" "Live in: {1}\nSay !unready / Press F2 to cancel" + } + "AutoStartNotEnoughPlayers" + { + "en" "More players are required..." + } + "AutoStartWaiting" + { + "en" "Waiting for loading players..." } - - "VoteInProgress" + "InitiateAutoStart" { - "en" "[{olive}Readyup{default}] There's {olive}a vote {green}in progress{default}." + "en" "Game will automatically start!" } - - "VoteDelay" + "AutoStartCountdown" { "#format" "{1:d}" - "en" "[{olive}Readyup{default}] Wait for another {blue}{1}s {default}to call a vote." + "en" "Game starts in: {1}" } - - "Player marked unready" + "LiveCountdownCancelled" { - "#format" "{1:N}" - "en" "{default}[{green}!{default}] {green}Countdown Cancelled! {default}({teamcolor}{1} {green}marked unready{default})" + "en" "Countdown Cancelled!" } - - "Player switched team" + "CountUnReady" { - "#format" "{1:N}" - "en" "{default}[{green}!{default}] {green}Countdown Cancelled! {default}({teamcolor}{1} {olive}switched team{default})" + "#format" "{1:d}{2:d}" // 1:GetUnReadyCount(client), 2:l4d_ready_unready_limit.IntValue + "en" " [{green}{1}{default}/{green}{2}{default}]" } - - "Player disconnected" + "UnReadyLimit" { - "#format" "{1:N}" - "en" "{default}[{green}!{default}] {green}Countdown Cancelled! {default}({teamcolor}{1} {green}disconnected{default})" + "en" "You have reached your {red}unready limit{default} [{green}%d{default}]" } - - "Admin aborted" + // readyup/command.inc + "ForceStartAdmin" { "#format" "{1:N}" - "en" "{default}[{green}!{default}] {green}Force Start Aborted! {default}({olive}{1} {green}issued{default})" + "en" "{blue}Game{default} start is {green}forced{default} by {blue}Admin{default} ({olive}{1}{default})" + } + "PanelHide" + { + "en" "Panel is now {red}off{default}" + } + "PanelShow" + { + "en" "Panel is now {blue}on{default}" } - - -// The following are not allowed to use any color tag + // readyup/panel.inc "HintReady" { "en" "You are ready.\nSay !unready / Press F2 to unready." } - "HintUnready" { "en" "You are not ready.\nSay !ready / Press F1 to ready up." } - - "LiveCountdownBegin" + "PanelSlots" { - "en" "Going live!\nSay !unready / Press F2 to cancel" + "#format" "{1:s},{2:d},{3:d},{4:s}" // 1:ServerName, 2:GetSeriousClientCount(), 3:FindConVar("sv_maxplayers").IntValue, 4:cfgName + "en" "▸ Server: {1} \n▸ Slots: {2}/{3}\n▸ Config: {4}" } - - "LiveCountdown" + "PanelCommands" { - "#format" "{1:d}" - "en" "Live in: {1}\nSay !unready / Press F2 to cancel" + "en" "▸ Commands:" } - - "LiveCountdownCancelled" + "PanelSurvivors" { - "en" "Countdown Cancelled!" + "#format" "{1:d},{2:s}" // 1:++textCount, 2:isTeamReadyMode ? teamReadySymbol[survivorReady] : "" + "en" "->{1}. Survivors{2}" } - - "RoundIsLive" + "PanelInfected" { - "en" "Round is live!" + "#format" "{1:d},{2:s}" // 1:++textCount, 2:isTeamReadyMode ? teamReadySymbol[survivorReady] : "" + "en" "->{1}. Infected{2}" } - - "InitiateAutoStart" + "PanelCaster" { - "en" "Game will automatically start!" + "#format" "{1:d},{2:s}" // 1:++textCount, 2:casterCount > 1 ? "s" : "" + "en" "->{1}. Caster{2}" } - - "AutoStartCountdown" + "PanelSpectator" { - "#format" "{1:d}" - "en" "Game starts in: {1}" + "#format" "{1:d},{2:s}" // 1:++textCount, 2:specCount > 1 ? "s" : "" + "en" "->{1}. Spectator{2}" } - - "AutoStartWaiting" + "PanelMany" { - "en" "Waiting for loading players..." + "en" "**Many** (%d)" } - - "AutoStartNotEnoughPlayers" + // g_sDisruptReason[] + "Player marked unready" { - "en" "More players are required..." + "#format" "{1:N}{2:s}" + "en" "{green}Countdown Cancelled!{default} ({teamcolor}{1}{green} marked unready{default}){2}" + } + "Player switched team" + { + "#format" "{1:N}" + "en" "{green}Countdown Cancelled!{default} ({teamcolor}{1}{olive} switched team{default})" + } + "Player disconnected" + { + "#format" "{1:N}" + "en" "{green}Countdown Cancelled!{default} ({teamcolor}{1}{green} disconnected{default})" + } + "Admin aborted" + { + "#format" "{1:N}" + "en" "{green}Force Start Aborted!{default} ({olive}{1}{green} issued{default})" } } \ No newline at end of file diff --git a/addons/sourcemod/translations/survivor_mvp.phrases.txt b/addons/sourcemod/translations/survivor_mvp.phrases.txt new file mode 100644 index 000000000..133e2a218 --- /dev/null +++ b/addons/sourcemod/translations/survivor_mvp.phrases.txt @@ -0,0 +1,75 @@ +"Phrases" +{ + "Tag" + { + "en" "{blue}[{default}MVP{blue}]{default}" + } + "YourRankSI" + { + "en" "{blue}Rank {green}SI: {olive}#%d {blue}({default}%d {green}dmg {blue}[{default}%.0f%%{blue}]{default}, %d {green}kills {blue}[{default}%.0f%%{blue}])" + } + "YourRankCI" + { + "en" "{blue}Rank {green}CI: {olive}#%d {blue}({default}%d {green}common {blue}[{default}%.0f%%{blue}])" + } + "YourRankFF" + { + "en" "{blue}Rank {green}FF: {olive}#%d {blue}({default}%d {green}friendly fire {blue}[{default}%.0f%%{blue}])" + } + "BotName" + { + "en" "[BOT]" + } + "NobodyName" + { + "en" "{blue}({default}nobody{blue})" + } + "NotEnoughAction" + { + "en" "{blue}({default}not enough action yet{blue})" + } + "ReportSI_Absolute" + { + "en" "{green}SI: {olive}%s {blue}({default}%d {green}dmg{default}, %d {green}kills{blue})" + } + "ReportSI_Percent" + { + "en" "{green}SI: {olive}%s {blue}({green}dmg {blue}[{default}%.0f%%{blue}]{default}, {green}kills {blue}[{default}%.0f%%{blue}])" + } + "ReportSI_Full" + { + "en" "{green}SI: {olive}%s {blue}({default}%d {green}dmg {blue}[{default}%.0f%%{blue}]{default}, %d {green}kills {blue}[{default}%.0f%%{blue}])" + } + "ReportSI_Nobody" + { + "en" "{green}SI: {blue}({default}Nobody{blue})" + } + "ReportCI_Absolute" + { + "en" "{green}CI: {olive}%s {blue}({default}%d {green}common{blue})" + } + "ReportCI_Percent" + { + "en" "{green}CI: {olive}%s {blue}({green}common {blue}[{default}%.0f%%{blue}])" + } + "ReportCI_Full" + { + "en" "{green}CI: {olive}%s {blue}({default}%d {green}common {blue}[{default}%.0f%%{blue}])" + } + "NoFF" + { + "en" "{blue}({default}No friendly fire at all!{blue})" + } + "ReportFF_Absolute" + { + "en" "{green}FF: {olive}%s {blue}({default}%d {green}friendly fire{blue})" + } + "ReportFF_Percent" + { + "en" "{green}FF: {olive}%s {blue}({green}friendly fire {blue}[{default}%.0f%%{blue}])" + } + "ReportFF_Full" + { + "en" "{green}FF: {olive}%s {blue}({default}%d {green}friendly fire {blue}[{default}%.0f%%{blue}])" + } +} diff --git a/addons/sourcemod/translations/teamflip.phrases.txt b/addons/sourcemod/translations/teamflip.phrases.txt new file mode 100644 index 000000000..8dce379d5 --- /dev/null +++ b/addons/sourcemod/translations/teamflip.phrases.txt @@ -0,0 +1,19 @@ +"Phrases" +{ + "Tag" + { + "en" "[{olive}Teamflip{default}]" + } + "FlippedSurvivor" + { + "en" "{green}%s{default} flipped a team and is on the {blue}Survivor{default} team!" + } + "FlippedInfected" + { + "en" "{green}%s{default} flipped a team and is on the {red}Infected{default} team!" + } + "Wait" + { + "en" "[Teamflip] Whoa there buddy, slow down. Wait at least %d seconds." + } +} diff --git a/addons/sourcemod/translations/weapon_loadout.phrases.txt b/addons/sourcemod/translations/weapon_loadout.phrases.txt new file mode 100644 index 000000000..5ddc01443 --- /dev/null +++ b/addons/sourcemod/translations/weapon_loadout.phrases.txt @@ -0,0 +1,39 @@ +"Phrases" +{ + "Tag" + { + "en" "{blue}[{green}Zone{blue}]{default}:" + } + "OnlyFirstReadyup" + { + "en" "You can only call for the vote during the first ready-up of a round." + } + "CannotCalled" + { + "en" "A vote cannot be called at this moment, try again in a second or five." + } + "NeedFull" + { + "en" "Both teams need to be full." + } + "SurvivorsGet" + { + "en" "Survivors get %s?" + } + "BeforeReadyup" + { + "en" "Vote didn't pass before you left ready-up." + } + "WeaponsSet" + { + "en" "Survivor Weapons Set!" + } + "Welcome" + { + "en" "Welcome to {blue}Zone{green}Hunters{default}." + } + "Type" + { + "en" "Type {olive}!mode{default} in chat to vote on weapons used." + } +}