diff --git a/AdminCheats/scripting/AdminCheats.sp b/AdminCheats/scripting/AdminCheats.sp index 1fe6ab0b..03b5e9e0 100644 --- a/AdminCheats/scripting/AdminCheats.sp +++ b/AdminCheats/scripting/AdminCheats.sp @@ -74,6 +74,9 @@ public void UpdateClients() public void OnClientPutInServer(int client) { + if(IsFakeClient(client)) + return; + SendConVarValue(client, g_CVar_sv_cheats, "0"); } diff --git a/PlayerVisibility/scripting/PlayerVisibility.sp b/PlayerVisibility/scripting/PlayerVisibility.sp new file mode 100644 index 00000000..5bc32d13 --- /dev/null +++ b/PlayerVisibility/scripting/PlayerVisibility.sp @@ -0,0 +1,149 @@ +#pragma semicolon 1 + +#include +#include +#include + +public Plugin myinfo = +{ + name = "PlayerVisibility", + author = "BotoX", + description = "Fades players away when you get close to them.", + version = "1.0", + url = "" +}; + +int g_Client_Alpha[MAXPLAYERS + 1] = {255, ...}; + +public void OnPluginStart() +{ + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client)) + OnClientPutInServer(client); + } +} + +public void OnPluginEnd() +{ + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client)) + { + if(g_Client_Alpha[client] != 255.0) + SetEntityRenderMode(client, RENDER_NORMAL); + + OnClientDisconnect(client); + } + } +} + +public void OnClientPutInServer(int client) +{ + SDKHook(client, SDKHook_PostThink, OnPostThink); +} + +public void OnClientDisconnect(int client) +{ + SDKUnhook(client, SDKHook_PostThink, OnPostThink); +} + +public void OnPostThink(client) +{ + if(!IsPlayerAlive(client)) + return; + + if(!ZR_IsClientHuman(client)) + { + if(g_Client_Alpha[client] != 255) + { + g_Client_Alpha[client] = 255; + if(GetEntityRenderMode(client) != RENDER_NONE) + ToolsSetEntityAlpha(client, 255); + } + return; + } + + if(GetEntityRenderMode(client) == RENDER_NONE) + { + g_Client_Alpha[client] = 255; + return; + } + + float fAlpha = 255.0; + for(int i = 1; i <= MaxClients; i++) + { + if(i == client || !IsClientInGame(i) || !IsPlayerAlive(i)) + continue; + + if(!ZR_IsClientHuman(i)) + continue; + + static float fVec1[3]; + static float fVec2[3]; + GetClientAbsOrigin(client, fVec1); + GetClientAbsOrigin(i, fVec2); + + float fMaxDistance = 150.0; + float fDistance = GetVectorDistance(fVec1, fVec2, false); + + if(fDistance <= fMaxDistance) + { + float fFactor = fDistance / fMaxDistance; + if(fFactor < 0.75) + fFactor = 0.75; + + fAlpha *= fFactor; + } + } + + if(fAlpha < 100.0) + fAlpha = 100.0; + + int Alpha = RoundToNearest(fAlpha); + int LastAlpha = g_Client_Alpha[client]; + g_Client_Alpha[client] = Alpha; + + if(Alpha == LastAlpha) + return; + + ToolsSetEntityAlpha(client, Alpha); +} + +void ToolsSetEntityAlpha(int client, int Alpha) +{ + if(Alpha == 255) + { + SetEntityRenderMode(client, RENDER_NORMAL); + return; + } + + int aColor[4]; + ToolsGetEntityColor(client, aColor); + + SetEntityRenderMode(client, RENDER_TRANSCOLOR); + SetEntityRenderColor(client, aColor[0], aColor[1], aColor[2], g_Client_Alpha[client]); +} + +stock ToolsGetEntityColor(int entity, int aColor[4]) +{ + static bool s_GotConfig = false; + static char s_sProp[32]; + + if(!s_GotConfig) + { + Handle GameConf = LoadGameConfigFile("core.games"); + bool Exists = GameConfGetKeyValue(GameConf, "m_clrRender", s_sProp, sizeof(s_sProp)); + CloseHandle(GameConf); + + if(!Exists) + strcopy(s_sProp, sizeof(s_sProp), "m_clrRender"); + + s_GotConfig = true; + } + + int Offset = GetEntSendPropOffs(entity, s_sProp); + + for(int i = 0; i < 4; i++) + aColor[i] = GetEntData(entity, Offset + i, 1); +} diff --git a/SelfMute/scripting/SelfMute.sp b/SelfMute/scripting/SelfMute.sp index 6e9db8be..655db581 100644 --- a/SelfMute/scripting/SelfMute.sp +++ b/SelfMute/scripting/SelfMute.sp @@ -19,7 +19,7 @@ bool g_Plugin_zombiereloaded = false; bool g_Plugin_voiceannounce_ex = false; bool g_Plugin_AdvancedTargeting = false; -#define PLUGIN_VERSION "2.0.1" +#define PLUGIN_VERSION "2.1" public Plugin myinfo = { @@ -78,10 +78,10 @@ public void OnPluginStart() public void OnAllPluginsLoaded() { g_Plugin_ccc = LibraryExists("ccc"); - g_Plugin_zombiereloaded = true;//LibraryExists("zombiereloaded"); + g_Plugin_zombiereloaded = LibraryExists("zombiereloaded"); g_Plugin_voiceannounce_ex = LibraryExists("voiceannounce_ex"); g_Plugin_AdvancedTargeting = LibraryExists("AdvancedTargeting"); - PrintToServer("CCC: %s\nZombieReloaded: %s\nVoiceAnnounce: %s\nAdvancedTargeting: %s", + LogMessage("CCC: %s\nZombieReloaded: %s\nVoiceAnnounce: %s\nAdvancedTargeting: %s", (g_Plugin_ccc ? "loaded" : "not loaded"), (g_Plugin_zombiereloaded ? "loaded" : "not loaded"), (g_Plugin_voiceannounce_ex ? "loaded" : "not loaded"), @@ -805,94 +805,111 @@ void DisplayUnMuteMenu(int client) /* * HOOKS */ -#define MAX_MESSAGES 8 - -int g_MsgDest[MAX_MESSAGES]; -int g_MsgClient[MAX_MESSAGES] = {-1, ...}; -char g_MsgName[MAX_MESSAGES][256]; -char g_MsgParam1[MAX_MESSAGES][256]; -char g_MsgParam2[MAX_MESSAGES][256]; -char g_MsgParam3[MAX_MESSAGES][256]; -char g_MsgParam4[MAX_MESSAGES][256]; -int g_MsgPlayersNum[MAX_MESSAGES]; -int g_MsgPlayers[MAX_MESSAGES][MAXPLAYERS + 1]; - -int g_NumMessages = 0; +int g_MsgDest; +int g_MsgClient; +char g_MsgName[256]; +char g_MsgParam1[256]; +char g_MsgParam2[256]; +char g_MsgParam3[256]; +char g_MsgParam4[256]; +char g_MsgRadioSound[256]; +int g_MsgPlayersNum; +int g_MsgPlayers[MAXPLAYERS + 1]; public Action Hook_UserMessageRadioText(UserMsg msg_id, Handle bf, const int[] players, int playersNum, bool reliable, bool init) { - if(g_NumMessages >= MAX_MESSAGES) - return Plugin_Handled; // Silently drop + g_MsgDest = BfReadByte(bf); + g_MsgClient = BfReadByte(bf); + BfReadString(bf, g_MsgName, sizeof(g_MsgName), false); + BfReadString(bf, g_MsgParam1, sizeof(g_MsgParam1), false); + BfReadString(bf, g_MsgParam2, sizeof(g_MsgParam2), false); + BfReadString(bf, g_MsgParam3, sizeof(g_MsgParam3), false); + BfReadString(bf, g_MsgParam4, sizeof(g_MsgParam4), false); - g_MsgDest[g_NumMessages] = BfReadByte(bf); - g_MsgClient[g_NumMessages] = BfReadByte(bf); - BfReadString(bf, g_MsgName[g_NumMessages], sizeof(g_MsgName[]), false); - BfReadString(bf, g_MsgParam1[g_NumMessages], sizeof(g_MsgParam1[]), false); - BfReadString(bf, g_MsgParam2[g_NumMessages], sizeof(g_MsgParam2[]), false); - BfReadString(bf, g_MsgParam3[g_NumMessages], sizeof(g_MsgParam3[]), false); - BfReadString(bf, g_MsgParam4[g_NumMessages], sizeof(g_MsgParam4[]), false); - - g_MsgPlayersNum[g_NumMessages] = playersNum; + // Check which clients need to be excluded. + g_MsgPlayersNum = 0; for(int i = 0; i < playersNum; i++) - g_MsgPlayers[g_NumMessages][i] = players[i]; + { + int client = players[i]; + if(!GetIgnored(client, g_MsgClient)) + g_MsgPlayers[g_MsgPlayersNum++] = client; + } + + // No clients were excluded. + if(g_MsgPlayersNum == playersNum) + { + g_MsgClient = -1; + return Plugin_Continue; + } + else if(g_MsgPlayersNum == 0) // All clients were excluded and there is no need to broadcast. + { + g_MsgClient = -2; + return Plugin_Handled; + } return Plugin_Handled; } -char g_MsgRadioSound[MAX_MESSAGES][256]; - public Action Hook_UserMessageSendAudio(UserMsg msg_id, Handle bf, const int[] players, int playersNum, bool reliable, bool init) { - if(g_NumMessages >= MAX_MESSAGES) - return Plugin_Handled; // Silently drop + if(g_MsgClient == -1) + return Plugin_Continue; + else if(g_MsgClient == -2) + return Plugin_Handled; - BfReadString(bf, g_MsgRadioSound[g_NumMessages], sizeof(g_MsgRadioSound[]), false); + BfReadString(bf, g_MsgRadioSound, sizeof(g_MsgRadioSound), false); - if(!g_NumMessages) - CreateTimer(0.1, Timer_PlayerRadio); + DataPack pack = new DataPack(); + pack.WriteCell(g_MsgDest); + pack.WriteCell(g_MsgClient); + pack.WriteString(g_MsgName); + pack.WriteString(g_MsgParam1); + pack.WriteString(g_MsgParam2); + pack.WriteString(g_MsgParam3); + pack.WriteString(g_MsgParam4); + pack.WriteString(g_MsgRadioSound); + pack.WriteCell(g_MsgPlayersNum); - g_NumMessages++; + ArrayList aPlayers = new ArrayList(g_MsgPlayersNum, 1); + aPlayers.SetArray(0, g_MsgPlayers, g_MsgPlayersNum); + pack.WriteCell(aPlayers); + + RequestFrame(OnPlayerRadio, pack); return Plugin_Handled; } -public Action Timer_PlayerRadio(Handle timer) +public void OnPlayerRadio(DataPack pack) { - for(int NumMsg = 0; NumMsg < g_NumMessages; NumMsg++) - { - if(g_MsgClient[NumMsg] == -1) - continue; + pack.Reset(); + g_MsgDest = pack.ReadCell(); + g_MsgClient = pack.ReadCell(); + pack.ReadString(g_MsgName, sizeof(g_MsgName)); + pack.ReadString(g_MsgParam1, sizeof(g_MsgParam1)); + pack.ReadString(g_MsgParam2, sizeof(g_MsgParam2)); + pack.ReadString(g_MsgParam3, sizeof(g_MsgParam3)); + pack.ReadString(g_MsgParam4, sizeof(g_MsgParam4)); + pack.ReadString(g_MsgRadioSound, sizeof(g_MsgRadioSound)); + g_MsgPlayersNum = pack.ReadCell(); + ArrayList aPlayers = pack.ReadCell(); + CloseHandle(pack); - int[] players = new int[g_MsgPlayersNum[NumMsg] + 1]; - int playersNum = 0; + aPlayers.GetArray(0, g_MsgPlayers, g_MsgPlayersNum); + delete aPlayers; - for(int i = 0; i < g_MsgPlayersNum[NumMsg]; i++) - { - int client = g_MsgPlayers[NumMsg][i]; - if(IsClientInGame(client) && !GetIgnored(client, g_MsgClient[NumMsg])) - players[playersNum++] = client; - } + Handle RadioText = StartMessage("RadioText", g_MsgPlayers, g_MsgPlayersNum, USERMSG_RELIABLE | USERMSG_BLOCKHOOKS); + BfWriteByte(RadioText, g_MsgDest); + BfWriteByte(RadioText, g_MsgClient); + BfWriteString(RadioText, g_MsgName); + BfWriteString(RadioText, g_MsgParam1); + BfWriteString(RadioText, g_MsgParam2); + BfWriteString(RadioText, g_MsgParam3); + BfWriteString(RadioText, g_MsgParam4); + EndMessage(); - Handle RadioText = StartMessage("RadioText", players, playersNum, USERMSG_RELIABLE | USERMSG_BLOCKHOOKS); - BfWriteByte(RadioText, g_MsgDest[NumMsg]); - BfWriteByte(RadioText, g_MsgClient[NumMsg]); - BfWriteString(RadioText, g_MsgName[NumMsg]); - BfWriteString(RadioText, g_MsgParam1[NumMsg]); - BfWriteString(RadioText, g_MsgParam2[NumMsg]); - BfWriteString(RadioText, g_MsgParam3[NumMsg]); - BfWriteString(RadioText, g_MsgParam4[NumMsg]); - EndMessage(); - - Handle SendAudio = StartMessage("SendAudio", players, playersNum, USERMSG_RELIABLE | USERMSG_BLOCKHOOKS); - BfWriteString(SendAudio, g_MsgRadioSound[NumMsg]); - EndMessage(); - - g_MsgClient[NumMsg] = -1; - } - - g_NumMessages = 0; - - return Plugin_Stop; + Handle SendAudio = StartMessage("SendAudio", g_MsgPlayers, g_MsgPlayersNum, USERMSG_RELIABLE | USERMSG_BLOCKHOOKS); + BfWriteString(SendAudio, g_MsgRadioSound); + EndMessage(); } /* diff --git a/SprayManager/scripting/SprayManager.sp b/SprayManager/scripting/SprayManager.sp new file mode 100644 index 00000000..bb498da4 --- /dev/null +++ b/SprayManager/scripting/SprayManager.sp @@ -0,0 +1,2144 @@ +#pragma semicolon 1 + +#include +#include +#include + +#undef REQUIRE_PLUGIN + +#include + +#pragma newdecls required + +enum +{ + AABBMinX = 0, + AABBMaxX = 1, + AABBMinY = 2, + AABBMaxY = 3, + AABBMinZ = 4, + AABBMaxZ = 5, + AABBTotalPoints = 6 +} + +Handle g_hDatabase = null; +Handle g_hTraceTimer = null; +Handle g_hTopMenu = null; +ConVar g_cvarHookedDecalFrequency = null; +ConVar g_cvarDecalFrequency = null; +ConVar g_cvarUseProximityCheck = null; + +bool g_bLoadedLate; +bool g_bAllowSpray; +bool g_bSQLite; +bool g_bGotBans; +bool g_bGotBlacklist; +bool g_bFullyConnected; + +char g_sBanIssuer[MAXPLAYERS + 1][64]; +char g_sBanIssuerSID[MAXPLAYERS + 1][32]; +char g_sBanReason[MAXPLAYERS + 1][32]; +char g_sSprayHash[MAXPLAYERS + 1][16]; + +bool g_bSprayBanned[MAXPLAYERS + 1]; +bool g_bSprayHashBanned[MAXPLAYERS + 1]; +bool g_bInvokedThroughTopMenu[MAXPLAYERS + 1]; +bool g_bInvokedThroughListMenu[MAXPLAYERS + 1]; + +int g_iSprayLifetime[MAXPLAYERS + 1]; +int g_iSprayBanTimestamp[MAXPLAYERS + 1]; +int g_iSprayUnbanTimestamp[MAXPLAYERS + 1] = { -1, ... }; +int g_iSprayBanTarget[MAXPLAYERS + 1]; +int g_iSprayUnbanTarget[MAXPLAYERS + 1]; +int g_iSprayTraceTarget[MAXPLAYERS + 1]; +int g_iBanTarget[MAXPLAYERS + 1]; + +float g_fNextSprayTime[MAXPLAYERS + 1]; +float g_vecSprayOrigin[MAXPLAYERS + 1][3]; +float g_SprayAABB[MAXPLAYERS + 1][AABBTotalPoints]; + +public Plugin myinfo = +{ + name = "Spray Manager", + description = "A plugin to help manage player sprays.", + author = "Obus", + version = "1.0", + url = "" +} + +public APLRes AskPluginLoad2(Handle hThis, bool bLate, char[] err, int iErrLen) +{ + g_bLoadedLate = bLate; + + return APLRes_Success; +} + +public void OnPluginStart() +{ + LoadTranslations("common.phrases"); + + RegAdminCmd("sm_spray", Command_AdminSpray, 0, "Spray a clients spray"); + RegAdminCmd("sm_sprayban", Command_SprayBan, ADMFLAG_GENERIC, "Ban a client from spraying"); + RegAdminCmd("sm_sprayunban", Command_SprayUnban, ADMFLAG_GENERIC, "Unban a client and allow them to spray"); + RegAdminCmd("sm_banspray", Command_BanSpray, ADMFLAG_GENERIC, "Ban a clients spray from being sprayed (Note: This will not spray-ban the client, it will only ban the spray which they are currently using)"); + RegAdminCmd("sm_unbanspray", Command_UnbanSpray, ADMFLAG_GENERIC, "Unban a clients spray (Note: This will not spray-unban the client, it will only unban the spray which they are currently using)"); + RegAdminCmd("sm_tracespray", Command_TraceSpray, ADMFLAG_GENERIC, "Finds a spray under your crosshair"); + RegAdminCmd("sm_spraytrace", Command_TraceSpray, ADMFLAG_GENERIC, "Finds a spray under your crosshair"); + RegAdminCmd("sm_removespray", Command_RemoveSpray, ADMFLAG_GENERIC, "Finds and removes a spray under your crosshair"); + RegAdminCmd("sm_spraymanagerupdatedb", Command_SprayManager_UpdateInfo, ADMFLAG_CHEATS, "Updates all clients info"); + RegAdminCmd("sm_spraymanagerrefreshdb", Command_SprayManager_UpdateInfo, ADMFLAG_CHEATS, "Updates all clients info"); + RegAdminCmd("sm_spraymanagerreloaddb", Command_SprayManager_UpdateInfo, ADMFLAG_CHEATS, "Updates all clients info"); + + AddTempEntHook("Player Decal", HookDecal); + AddNormalSoundHook(HookSprayer); + + TopMenu hTopMenu; + + if (LibraryExists("adminmenu") && ((hTopMenu = GetAdminTopMenu()) != INVALID_HANDLE)) + OnAdminMenuReady(hTopMenu); + + if (g_cvarHookedDecalFrequency != null) + delete g_cvarHookedDecalFrequency; + + if (g_cvarDecalFrequency != null) + delete g_cvarDecalFrequency; + + if (g_cvarUseProximityCheck != null) + delete g_cvarUseProximityCheck; + + g_cvarHookedDecalFrequency = FindConVar("decalfrequency"); + g_cvarHookedDecalFrequency.IntValue = 0; + + g_cvarDecalFrequency = CreateConVar("sm_decalfrequency", "10", "Controls how often clients can spray", FCVAR_NOTIFY); + + HookConVarChange(g_cvarHookedDecalFrequency, CVarHook_DecalFrequency); + + g_cvarUseProximityCheck = CreateConVar("sm_spraymanager_blockoverspraying", "1", "Allows or disallows people to overspray other people.", FCVAR_NOTIFY); + + AutoExecConfig(true, "plugin.spraymanager"); + + if (g_hDatabase != null) + delete g_hDatabase; + + g_hTraceTimer = CreateTimer(0.25, PerformPlayerTraces, _, TIMER_REPEAT); + + InitializeSQL(); +} + +public void OnPluginEnd() +{ + RemoveTempEntHook("Player Decal", HookDecal); + RemoveNormalSoundHook(HookSprayer); + + if (g_hDatabase != null) + { + SQL_UnlockDatabase(g_hDatabase); + delete g_hDatabase; + } + + if (g_hTraceTimer != null) + KillTimer(g_hTraceTimer); +} + +public void OnClientPostAdminCheck(int client) +{ + if (g_hDatabase != null) + { + ClearPlayerInfo(client); + UpdatePlayerInfo(client); + UpdateSprayHashInfo(client); + } +} + +public void OnClientDisconnect(int client) +{ + SprayClientDecal(client, 0, NULL_VECTOR); + ClearPlayerInfo(client); +} + +public Action CS_OnTerminateRound(float &fDelay, CSRoundEndReason &reason) +{ + for (int i = 1; i <= MaxClients; i++) + { + if (!IsValidClient(i)) + continue; + + if (g_vecSprayOrigin[i][0] != 0.0) + g_iSprayLifetime[i]++; + + if (g_iSprayLifetime[i] >= 2) + { + g_bAllowSpray = true; + SprayClientDecal(i, 0, NULL_VECTOR); + } + } +} + +public Action OnPlayerRunCmd(int client, int &buttons, int &impulse) +{ + if (!impulse || impulse != 201) + return Plugin_Continue; + + if (CheckCommandAccess(client, "sm_sprayban", ADMFLAG_GENERIC)) + { + if (!g_bSprayBanned[client] && !g_bSprayHashBanned[client]) + { + if (TracePlayerAnglesRanged(client, 128.0)) + return Plugin_Continue; + + ForceSpray(client, client, false); + g_fNextSprayTime[client] = 0.0; + } + } + + return Plugin_Continue; +} + +public void OnAdminMenuReady(Handle hAdminMenu) +{ + if (hAdminMenu == g_hTopMenu) + return; + + g_hTopMenu = CloneHandle(hAdminMenu); + + TopMenuObject hMenuObj = AddToTopMenu(g_hTopMenu, "SprayManagerCommands", TopMenuObject_Category, TopMenu_Main_Handler, INVALID_TOPMENUOBJECT); + + if (hMenuObj == INVALID_TOPMENUOBJECT) + return; + + AddToTopMenu(g_hTopMenu, "SprayManager_Spraybanlist", TopMenuObject_Item, Handler_SprayBanList, hMenuObj); + AddToTopMenu(g_hTopMenu, "SprayManager_Tracespray", TopMenuObject_Item, Handler_TraceSpray, hMenuObj, "sm_tracespray", ADMFLAG_GENERIC); + AddToTopMenu(g_hTopMenu, "SprayManager_Sprayban", TopMenuObject_Item, Handler_SprayBan, hMenuObj, "sm_sprayban", ADMFLAG_GENERIC); + AddToTopMenu(g_hTopMenu, "SprayManager_Sprayunban", TopMenuObject_Item, Handler_SprayUnban, hMenuObj, "sm_sprayunban", ADMFLAG_GENERIC); + AddToTopMenu(g_hTopMenu, "SprayManager_Banspray", TopMenuObject_Item, Handler_BanSpray, hMenuObj, "sm_banspray", ADMFLAG_GENERIC); + AddToTopMenu(g_hTopMenu, "SprayManager_Unbanspray", TopMenuObject_Item, Handler_UnbanSpray, hMenuObj, "sm_unbanspray", ADMFLAG_GENERIC); +} + +public void OnLibraryRemoved(const char[] sLibraryName) +{ + if (StrEqual(sLibraryName, "adminmenu")) + delete g_hTopMenu; +} + +public void TopMenu_Main_Handler(Handle hMenu, TopMenuAction hAction, TopMenuObject hObjID, int iParam1, char[] sBuffer, int iBufflen) +{ + if (hAction == TopMenuAction_DisplayOption) + Format(sBuffer, iBufflen, "%s", "SprayManager Commands", iParam1); + else if (hAction == TopMenuAction_DisplayTitle) + Format(sBuffer, iBufflen, "%s", "SprayManager Commands:", iParam1); +} + +public void Handler_SprayBanList(Handle hMenu, TopMenuAction hAction, TopMenuObject hObjID, int iParam1, char[] sBuffer, int iBufflen) +{ + if (hAction == TopMenuAction_DisplayOption) + Format(sBuffer, iBufflen, "%s", "List Spray Banned Clients", iParam1); + else if (hAction == TopMenuAction_SelectOption) + Menu_ListBans(iParam1); +} + +public void Handler_TraceSpray(Handle hMenu, TopMenuAction hAction, TopMenuObject hObjID, int iParam1, char[] sBuffer, int iBufflen) +{ + if (hAction == TopMenuAction_DisplayOption) + Format(sBuffer, iBufflen, "%s", "Trace a Spray", iParam1); + else if (hAction == TopMenuAction_SelectOption) + { + float vecEndPos[3]; + + if (TracePlayerAngles(iParam1, vecEndPos)) + { + for (int i = 1; i <= MaxClients; i++) + { + if (IsPointInsideAABB(vecEndPos, g_SprayAABB[i])) + { + g_bInvokedThroughTopMenu[iParam1] = true; + Menu_Trace(iParam1, i); + + return; + } + } + } + + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Trace did not hit any sprays."); + + if (g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + } +} + +public void Handler_SprayBan(Handle hMenu, TopMenuAction hAction, TopMenuObject hObjID, int iParam1, char[] sBuffer, int iBufflen) +{ + if (hAction == TopMenuAction_DisplayOption) + Format(sBuffer, iBufflen, "%s", "Spray Ban a Client", iParam1); + else if (hAction == TopMenuAction_SelectOption) + Menu_SprayBan(iParam1); +} + +public void Handler_SprayUnban(Handle hMenu, TopMenuAction hAction, TopMenuObject hObjID, int iParam1, char[] sBuffer, int iBufflen) +{ + if (hAction == TopMenuAction_DisplayOption) + Format(sBuffer, iBufflen, "%s", "Spray Unban a Client", iParam1); + else if (hAction == TopMenuAction_SelectOption) + Menu_SprayUnban(iParam1); +} + +public void Handler_BanSpray(Handle hMenu, TopMenuAction hAction, TopMenuObject hObjID, int iParam1, char[] sBuffer, int iBufflen) +{ + if (hAction == TopMenuAction_DisplayOption) + Format(sBuffer, iBufflen, "%s", "Ban a Client's Spray", iParam1); + else if (hAction == TopMenuAction_SelectOption) + Menu_BanSpray(iParam1); +} + +public void Handler_UnbanSpray(Handle hMenu, TopMenuAction hAction, TopMenuObject hObjID, int iParam1, char[] sBuffer, int iBufflen) +{ + if (hAction == TopMenuAction_DisplayOption) + Format(sBuffer, iBufflen, "%s", "Unban a Client's Spray", iParam1); + else if (hAction == TopMenuAction_SelectOption) + Menu_UnbanSpray(iParam1); +} + +void Menu_ListBans(int client) +{ + if (!IsValidClient(client)) + return; + + int iBannedClients; + + Menu ListMenu = new Menu(MenuHandler_Menu_ListBans); + ListMenu.SetTitle("[SprayManager] Banned Clients:"); + ListMenu.ExitBackButton = true; + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsValidClient(i)) + continue; + + if (g_bSprayBanned[i] || g_bSprayHashBanned[i]) + { + char sUserID[16]; + char sBuff[64]; + int iUserID = GetClientUserId(i); + + Format(sBuff, sizeof(sBuff), "%N (#%i)", i, iUserID); + Format(sUserID, sizeof(sUserID), "%d", iUserID); + + ListMenu.AddItem(sUserID, sBuff); + iBannedClients++; + } + } + + if (!iBannedClients) + ListMenu.AddItem("", "No Banned Clients.", ITEMDRAW_DISABLED); + + ListMenu.Display(client, MENU_TIME_FOREVER); +} + +int MenuHandler_Menu_ListBans(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + } + + case MenuAction_Select: + { + char sOption[32]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = GetClientOfUserId(StringToInt(sOption)); + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + if (g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + else + CloseHandle(hMenu); + } + else + { + g_bInvokedThroughListMenu[iParam1] = true; + Menu_ListBans_Target(iParam1, target); + } + } + } +} + +void Menu_Trace(int client, int target) +{ + char sSteamID[32]; + GetClientAuthId(target, AuthId_Steam2, sSteamID, sizeof(sSteamID)); + + Menu TraceMenu = new Menu(MenuHandler_Menu_Trace); + TraceMenu.SetTitle("Sprayed by: %N (%s)", target, sSteamID); + + if (g_bInvokedThroughTopMenu[client]) + TraceMenu.ExitBackButton = true; + + TraceMenu.AddItem("1", "Warn Client"); + TraceMenu.AddItem("2", "Slap and Warn Client"); + TraceMenu.AddItem("3", "Kick Client"); + TraceMenu.AddItem("4", "Spray Ban Client"); + TraceMenu.AddItem("5", "Ban Clients Spray"); + TraceMenu.AddItem("", "", ITEMDRAW_SPACER); + TraceMenu.AddItem("6", "Ban Client"); + + g_iSprayTraceTarget[client] = target; + + TraceMenu.Display(client, MENU_TIME_FOREVER); +} + +int MenuHandler_Menu_Trace(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + } + + case MenuAction_Select: + { + char sOption[2]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = g_iSprayTraceTarget[iParam1]; + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + g_bInvokedThroughTopMenu[iParam1] = false; + + if (g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + else + CloseHandle(hMenu); + } + else + { + switch (StringToInt(sOption)) + { + case 1: + { + PrintToChat(target, "\x01\x04[SprayManager]\x01 Your spray is not allowed, change it."); + Menu_Trace(iParam1, target); + } + + case 2: + { + SlapPlayer(target, 0); + PrintToChat(target, "\x01\x04[SprayManager]\x01 Your spray is not allowed, change it."); + Menu_Trace(iParam1, target); + } + + case 3: + { + g_bInvokedThroughTopMenu[iParam1] = false; + KickClient(target, "Your spray is not allowed, change it"); + } + + case 4: + { + Menu TraceSpraySprayBan = new Menu(MenuHandler_Menu_Trace_SprayBan); + TraceSpraySprayBan.SetTitle("[SprayManager] Select a Spray Ban Length for %N (#%i)", target, GetClientUserId(target)); + TraceSpraySprayBan.ExitBackButton = true; + + TraceSpraySprayBan.AddItem("10", "10 Minutes"); + TraceSpraySprayBan.AddItem("30", "30 Minutes"); + TraceSpraySprayBan.AddItem("60", "1 Hour"); + TraceSpraySprayBan.AddItem("1440", "1 Day"); + TraceSpraySprayBan.AddItem("10080", "1 Week"); + TraceSpraySprayBan.AddItem("40320", "1 Month"); + TraceSpraySprayBan.AddItem("0", "Permanent"); + + g_iSprayBanTarget[iParam1] = target; + + TraceSpraySprayBan.Display(iParam1, MENU_TIME_FOREVER); + } + + case 5: + { + if (BanClientSpray(target)) + PrintToChatAll("\x01\x04[SprayManager] %N\x01 banned \x04%N\x01's spray.", iParam1, target); + else + PrintToChat(iParam1, "\x01\x04[SprayManager] %N\x01's spray is already blacklisted.", target); + } + + case 6: + { + Menu TraceSprayBan = new Menu(MenuHandler_Menu_Trace_Ban); + TraceSprayBan.SetTitle("[SprayManager] Select a Ban Length for %N (#%i)", target, GetClientUserId(target)); + TraceSprayBan.ExitBackButton = true; + + TraceSprayBan.AddItem("10", "10 Minutes"); + TraceSprayBan.AddItem("30", "30 Minutes"); + TraceSprayBan.AddItem("60", "1 Hour"); + TraceSprayBan.AddItem("1440", "1 Day"); + TraceSprayBan.AddItem("10080", "1 Week"); + TraceSprayBan.AddItem("40320", "1 Month"); + TraceSprayBan.AddItem("0", "Permanent"); + + g_iBanTarget[iParam1] = target; + + TraceSprayBan.Display(iParam1, MENU_TIME_FOREVER); + } + } + } + } + } +} + +int MenuHandler_Menu_Trace_SprayBan(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack) + { + if (IsValidClient(g_iSprayBanTarget[iParam1])) + Menu_Trace(iParam1, g_iSprayBanTarget[iParam1]); + else if (g_hTopMenu != INVALID_HANDLE) + { + g_bInvokedThroughTopMenu[iParam1] = false; + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + } + else + { + g_bInvokedThroughTopMenu[iParam1] = false; + CloseHandle(hMenu); + } + } + } + + case MenuAction_Select: + { + char sOption[8]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = g_iSprayBanTarget[iParam1]; + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + g_iSprayBanTarget[iParam1] = 0; + g_bInvokedThroughTopMenu[iParam1] = false; + + if (g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + else + CloseHandle(hMenu); + } + else + { + if (SprayBanClient(iParam1, target, StringToInt(sOption), "Inappropriate Spray")) + PrintToChatAll("\x01\x04[SprayManager] %N\x01 spray banned \x04%N\x01.", iParam1, target); + + g_iSprayBanTarget[iParam1] = 0; + g_bInvokedThroughTopMenu[iParam1] = false; + } + } + } +} + +int MenuHandler_Menu_Trace_Ban(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack) + { + if (IsValidClient(g_iBanTarget[iParam1])) + Menu_Trace(iParam1, g_iBanTarget[iParam1]); + else if (g_hTopMenu != INVALID_HANDLE) + { + g_bInvokedThroughTopMenu[iParam1] = false; + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + } + else + { + g_bInvokedThroughTopMenu[iParam1] = false; + CloseHandle(hMenu); + } + } + } + + case MenuAction_Select: + { + char sOption[8]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = g_iBanTarget[iParam1]; + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + g_iBanTarget[iParam1] = 0; + g_bInvokedThroughTopMenu[iParam1] = false; + + if (g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + else + CloseHandle(hMenu); + } + else + { + FakeClientCommandEx(iParam1, "sm_ban \"#%i\" \"%s\" \"Inappropriate spray\"", GetClientUserId(g_iBanTarget[iParam1]), sOption); + g_iBanTarget[iParam1] = 0; + g_bInvokedThroughTopMenu[iParam1] = false; + } + } + } +} + +void Menu_SprayBan(int client) +{ + if (!IsValidClient(client)) + return; + + Menu SprayBanMenu = new Menu(MenuHandler_Menu_SprayBan); + SprayBanMenu.SetTitle("[SprayManager] Select a Client to Spray Ban:"); + SprayBanMenu.ExitBackButton = true; + + int iClientsToDisplay; + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && !g_bSprayBanned[i]) + { + char sUserID[16]; + char sBuff[64]; + int iUserID = GetClientUserId(i); + + Format(sBuff, sizeof(sBuff), "%N (#%i)", i, iUserID); + Format(sUserID, sizeof(sUserID), "%d", iUserID); + + SprayBanMenu.AddItem(sUserID, sBuff); + iClientsToDisplay++; + } + } + + if (!iClientsToDisplay) + SprayBanMenu.AddItem("", "No Clients to Display.", ITEMDRAW_DISABLED); + + SprayBanMenu.Display(client, MENU_TIME_FOREVER); +} + +int MenuHandler_Menu_SprayBan(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + } + + case MenuAction_Select: + { + char sOption[32]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = GetClientOfUserId(StringToInt(sOption)); + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + if (g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + else + CloseHandle(hMenu); + } + else + { + Menu SprayBanLengthMenu = new Menu(MenuHandler_Menu_SprayBan_Length); + SprayBanLengthMenu.SetTitle("[SprayManager] Choose a Spray Ban Length for %N (#%i)", target, GetClientUserId(target)); + SprayBanLengthMenu.ExitBackButton = true; + + SprayBanLengthMenu.AddItem("10", "10 Minutes"); + SprayBanLengthMenu.AddItem("30", "30 Minutes"); + SprayBanLengthMenu.AddItem("60", "1 Hour"); + SprayBanLengthMenu.AddItem("1440", "1 Day"); + SprayBanLengthMenu.AddItem("10080", "1 Week"); + SprayBanLengthMenu.AddItem("40320", "1 Month"); + SprayBanLengthMenu.AddItem("0", "Permanent"); + + g_iSprayBanTarget[iParam1] = target; + + SprayBanLengthMenu.Display(iParam1, MENU_TIME_FOREVER); + } + } + } +} + +int MenuHandler_Menu_SprayBan_Length(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack) + Menu_SprayBan(iParam1); + } + + case MenuAction_Select: + { + char sOption[8]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = g_iSprayBanTarget[iParam1]; + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + g_iSprayBanTarget[iParam1] = 0; + + Menu_SprayBan(iParam1); + } + else + { + if (SprayBanClient(iParam1, target, StringToInt(sOption), "Inappropriate Spray")) + PrintToChatAll("\x01\x04[SprayManager] %N\x01 spray banned \x04%N\x01.", iParam1, target); + + g_iSprayBanTarget[iParam1] = 0; + } + } + } +} + +void Menu_SprayUnban(int client) +{ + if (!IsValidClient(client)) + return; + + int iBannedClients; + + Menu SprayUnbanMenu = new Menu(MenuHandler_Menu_SprayUnban); + SprayUnbanMenu.SetTitle("[SprayManager] Select a Client to Unban:"); + SprayUnbanMenu.ExitBackButton = true; + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsValidClient(i)) + continue; + + if (g_bSprayBanned[i] || g_bSprayHashBanned[i]) + { + char sUserID[16]; + char sBuff[64]; + int iUserID = GetClientUserId(i); + + Format(sBuff, sizeof(sBuff), "%N (#%i)", i, iUserID); + Format(sUserID, sizeof(sUserID), "%d", iUserID); + + SprayUnbanMenu.AddItem(sUserID, sBuff); + iBannedClients++; + } + } + + if (!iBannedClients) + SprayUnbanMenu.AddItem("", "No Banned Clients.", ITEMDRAW_DISABLED); + + SprayUnbanMenu.Display(client, MENU_TIME_FOREVER); +} + +int MenuHandler_Menu_SprayUnban(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + } + + case MenuAction_Select: + { + char sOption[32]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = GetClientOfUserId(StringToInt(sOption)); + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + g_iSprayUnbanTarget[iParam1] = 0; + + Menu_SprayUnban(iParam1); + } + else + { + g_bInvokedThroughListMenu[iParam1] = false; + Menu_ListBans_Target(iParam1, target); + } + } + } +} + +void Menu_BanSpray(int client) +{ + if (!IsValidClient(client)) + return; + + int iClientsToDisplay; + + Menu BanSprayMenu = new Menu(MenuHandler_Menu_BanSpray); + BanSprayMenu.SetTitle("[SprayManager] Select a Client to Ban their Spray:"); + BanSprayMenu.ExitBackButton = true; + + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && !g_bSprayHashBanned[i]) + { + char sUserID[16]; + char sBuff[64]; + int iUserID = GetClientUserId(i); + + Format(sBuff, sizeof(sBuff), "%N (#%i)", i, iUserID); + Format(sUserID, sizeof(sUserID), "%d", iUserID); + + BanSprayMenu.AddItem(sUserID, sBuff); + iClientsToDisplay++; + } + } + + if (!iClientsToDisplay) + BanSprayMenu.AddItem("", "No Clients to Display.", ITEMDRAW_DISABLED); + + BanSprayMenu.Display(client, MENU_TIME_FOREVER); +} + +int MenuHandler_Menu_BanSpray(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + } + + case MenuAction_Select: + { + char sOption[32]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = GetClientOfUserId(StringToInt(sOption)); + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + Menu_BanSpray(iParam1); + } + else + { + if (BanClientSpray(target)) + PrintToChatAll("\x01\x04[SprayManager] %N\x01 banned \x04%N\x01's spray.", iParam1, target); + else + PrintToChat(iParam1, "\x01\x04[SprayManager] %N\x01's spray is already blacklisted.", target); + } + } + } +} + +void Menu_UnbanSpray(int client) +{ + if (!IsValidClient(client)) + return; + + Menu UnbanSprayMenu = new Menu(MenuHandler_Menu_UnbanSpray); + UnbanSprayMenu.SetTitle("[SprayManager] Select a Client to Unban their Spray:"); + UnbanSprayMenu.ExitBackButton = true; + + int iBannedClients; + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && g_bSprayHashBanned[i]) + { + char sUserID[16]; + char sBuff[64]; + int iUserID = GetClientUserId(i); + + Format(sBuff, sizeof(sBuff), "%N (#%i)", i, iUserID); + Format(sUserID, sizeof(sUserID), "%d", iUserID); + + UnbanSprayMenu.AddItem(sUserID, sBuff); + iBannedClients++; + } + } + + if (!iBannedClients) + UnbanSprayMenu.AddItem("", "No Banned Clients.", ITEMDRAW_DISABLED); + + UnbanSprayMenu.Display(client, MENU_TIME_FOREVER); +} + +int MenuHandler_Menu_UnbanSpray(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack && g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + } + + case MenuAction_Select: + { + char sOption[32]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = GetClientOfUserId(StringToInt(sOption)); + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + Menu_UnbanSpray(iParam1); + } + else + { + if (UnbanClientSpray(target)) + PrintToChatAll("\x01\x04[SprayManager] %N\x01 unbanned \x04%N\x01's spray.", iParam1, target); + else + PrintToChat(iParam1, "\x01\x04[SprayManager] %N\x01's spray is not blacklisted.", target); + } + } + } +} + +void Menu_ListBans_Target(int client, int target) +{ + Menu ListTargetMenu = new Menu(MenuHandler_Menu_ListBans_Target); + ListTargetMenu.SetTitle("[SprayManager] Banned Client: %N (#%i)", target, GetClientUserId(target)); + ListTargetMenu.ExitBackButton = true; + + char sBanType[32]; + char sUserID[32]; + int iUserID = GetClientUserId(target); + + Format(sUserID, sizeof(sUserID), "%d", iUserID); + + if (g_bSprayHashBanned[target] && !g_bSprayBanned[target]) + { + strcopy(sBanType, sizeof(sBanType), "Type: Hash"); + + ListTargetMenu.AddItem("", sBanType, ITEMDRAW_DISABLED); + ListTargetMenu.AddItem("", "", ITEMDRAW_SPACER); + + ListTargetMenu.AddItem(sUserID, "Unban Client?"); + + ListTargetMenu.Display(client, MENU_TIME_FOREVER); + return; + } + + char sBanExpiryDate[64]; + char sBanIssuedDate[64]; + char sBanDuration[64]; + char sBannedBy[128]; + char sBanReason[64]; + int iBanExpiryDate = g_iSprayUnbanTimestamp[target]; + int iBanIssuedDate = g_iSprayBanTimestamp[target]; + int iBanDuration = iBanExpiryDate ? ((iBanExpiryDate - iBanIssuedDate) / 60) : 0; + + if (iBanExpiryDate) + { + FormatTime(sBanExpiryDate, sizeof(sBanExpiryDate), NULL_STRING, iBanExpiryDate); + Format(sBanDuration, sizeof(sBanDuration), "%i %s", iBanDuration, SingularOrMultiple(iBanDuration) ? "Minutes" : "Minute"); + } + else + { + strcopy(sBanExpiryDate, sizeof(sBanExpiryDate), "Never"); + strcopy(sBanDuration, sizeof(sBanDuration), "Permanent"); + } + + FormatTime(sBanIssuedDate, sizeof(sBanIssuedDate), NULL_STRING, iBanIssuedDate); + Format(sBannedBy, sizeof(sBannedBy), "Banned by: %s (%s)", g_sBanIssuer[target], g_sBanIssuerSID[target]); + Format(sBanDuration, sizeof(sBanDuration), "Duration: %s", sBanDuration); + Format(sBanExpiryDate, sizeof(sBanExpiryDate), "Expires: %s", sBanExpiryDate); + Format(sBanIssuedDate, sizeof(sBanIssuedDate), "Issued on: %s", sBanIssuedDate); + Format(sBanReason, sizeof(sBanReason), "Reason: %s", g_sBanReason[target]); + + if (g_bSprayBanned[target] && g_bSprayHashBanned[target]) + strcopy(sBanType, sizeof(sBanType), "Type: Spray & Hash"); + else if (g_bSprayBanned[target]) + strcopy(sBanType, sizeof(sBanType), "Type: Spray"); + + ListTargetMenu.AddItem("", sBanType, ITEMDRAW_DISABLED); + ListTargetMenu.AddItem("", sBannedBy, ITEMDRAW_DISABLED); + ListTargetMenu.AddItem("", sBanIssuedDate, ITEMDRAW_DISABLED); + ListTargetMenu.AddItem("", sBanExpiryDate, ITEMDRAW_DISABLED); + ListTargetMenu.AddItem("", sBanDuration, ITEMDRAW_DISABLED); + ListTargetMenu.AddItem("", sBanReason, ITEMDRAW_DISABLED); + + ListTargetMenu.AddItem(sUserID, "Unban Client?"); + + ListTargetMenu.Display(client, MENU_TIME_FOREVER); +} + +int MenuHandler_Menu_ListBans_Target(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack) + { + if (g_bInvokedThroughListMenu[iParam1]) + Menu_ListBans(iParam1); + else + Menu_SprayUnban(iParam1); + } + } + + case MenuAction_Select: + { + char sOption[32]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + int target = GetClientOfUserId(StringToInt(sOption)); + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + Menu_ListBans(iParam1); + } + else + { + Menu MenuConfirmUnban = new Menu(MenuHandler_Menu_ConfirmUnban); + MenuConfirmUnban.SetTitle("[SprayManager] Unban %N?", target); + MenuConfirmUnban.ExitBackButton = true; + + MenuConfirmUnban.AddItem("Y", "Yes."); + MenuConfirmUnban.AddItem("N", "No."); + + g_iSprayUnbanTarget[iParam1] = target; + + MenuConfirmUnban.Display(iParam1, MENU_TIME_FOREVER); + } + } + } +} + +int MenuHandler_Menu_ConfirmUnban(Menu hMenu, MenuAction action, int iParam1, int iParam2) +{ + switch (action) + { + case MenuAction_End: + CloseHandle(hMenu); + + case MenuAction_Cancel: + { + if (iParam2 == MenuCancel_ExitBack) + { + if (IsValidClient(g_iSprayUnbanTarget[iParam1])) + Menu_ListBans_Target(iParam1, g_iSprayUnbanTarget[iParam1]); + else if (g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + else + CloseHandle(hMenu); + } + } + + case MenuAction_Select: + { + char sOption[2]; + hMenu.GetItem(iParam2, sOption, sizeof(sOption)); + + int target = g_iSprayUnbanTarget[iParam1]; + + if (!IsValidClient(target)) + { + PrintToChat(iParam1, "\x01\x04[SprayManager]\x01 Target no longer available."); + + g_iSprayUnbanTarget[iParam1] = 0; + + if (g_hTopMenu != INVALID_HANDLE) + DisplayTopMenu(g_hTopMenu, iParam1, TopMenuPosition_LastCategory); + else + CloseHandle(hMenu); + } + else + { + if (sOption[0] == 'Y') + { + if (g_bSprayHashBanned[target] && g_bSprayBanned[target]) + { + PrintToChatAll("\x01\x04[SprayManager] %N\x01 spray unbanned \x04%N\x01.", iParam1, target); + SprayUnbanClient(target); + UnbanClientSpray(target); + } + else if (g_bSprayBanned[target]) + { + PrintToChatAll("\x01\x04[SprayManager] %N\x01 spray unbanned \x04%N\x01.", iParam1, target); + SprayUnbanClient(target); + } + else if (g_bSprayHashBanned[target]) + { + PrintToChatAll("\x01\x04[SprayManager] %N\x01 unbanned \x04%N\x01's spray.", iParam1, target); + UnbanClientSpray(target); + } + + g_iSprayUnbanTarget[iParam1] = 0; + } + else if (sOption[0] == 'N') + { + Menu_ListBans_Target(iParam1, g_iSprayUnbanTarget[iParam1]); + g_iSprayUnbanTarget[iParam1] = 0; + } + } + } + } +} + +public Action Command_AdminSpray(int client, int argc) +{ + if (!client) + { + PrintToServer("[SprayManager] Cannot use command from server console."); + return Plugin_Handled; + } + + if (argc > 0) + { + char sArgs[64]; + char sTargetName[MAX_TARGET_LENGTH]; + int iTargets[MAXPLAYERS]; + int iTargetCount; + bool bIsML; + + GetCmdArg(1, sArgs, sizeof(sArgs)); + + if (!(iTargetCount = ProcessTargetString(sArgs, client, iTargets, MAXPLAYERS, 0, sTargetName, sizeof(sTargetName), bIsML))) + { + ReplyToTargetError(client, iTargetCount); + return Plugin_Handled; + } + + float vecEndPos[3]; + TracePlayerAngles(client, vecEndPos); + + for (int i = 0; i < iTargetCount; i++) + { + g_bAllowSpray = true; + ForceSpray(client, iTargets[i]); + } + + PrintToChat(client, "\x01\x04[SprayManager]\x01 Sprayed \x04%s\x01's spray(s).", sTargetName); + + return Plugin_Handled; + } + else + { + float vecEndPos[3]; + TracePlayerAngles(client, vecEndPos); + + g_bAllowSpray = true; + ForceSpray(client, client); + + PrintToChat(client, "\x01\x04[SprayManager]\x01 Sprayed your own spray."); + } + + return Plugin_Handled; +} + +public Action Command_SprayBan(int client, int argc) +{ + if (argc < 1) + { + ReplyToCommand(client, "[SprayManager] Usage: sm_sprayban "); + return Plugin_Handled; + } + + int iTarget; + char sTarget[32]; + char sLength[32]; + char sReason[32]; + + GetCmdArg(1, sTarget, sizeof(sTarget)); + + if (argc > 1) + { + GetCmdArg(2, sLength, sizeof(sLength)); + + if (argc > 2) + GetCmdArg(3, sReason, sizeof(sReason)); + } + + if (!(iTarget = FindTarget(client, sTarget))) + return Plugin_Handled; + + if (SprayBanClient(client, iTarget, StringToInt(sLength), sReason)) + PrintToChatAll("\x01\x04[SprayManager] %N\x01 spray banned \x04%N\x01.", client, iTarget); + + return Plugin_Handled; +} + +public Action Command_SprayUnban(int client, int argc) +{ + if (argc < 1) + { + ReplyToCommand(client, "[SprayManager] Usage: sm_sprayunban "); + return Plugin_Handled; + } + + int iTarget; + char sTarget[32]; + + GetCmdArg(1, sTarget, sizeof(sTarget)); + + if (!(iTarget = FindTarget(client, sTarget))) + return Plugin_Handled; + + if (!SprayUnbanClient(iTarget)) + { + ReplyToCommand(client, "[SprayManager] %N is not spray banned.", iTarget); + return Plugin_Handled; + } + + PrintToChatAll("\x01\x04[SprayManager] %N\x01 spray unbanned \x04%N\x01.", client, iTarget); + + return Plugin_Handled; +} + +public Action Command_BanSpray(int client, int argc) +{ + if (argc < 1) + { + ReplyToCommand(client, "[SprayManager] Usage: sm_banspray "); + return Plugin_Handled; + } + + int iTarget; + char sTarget[32]; + + GetCmdArg(1, sTarget, sizeof(sTarget)); + + if (!(iTarget = FindTarget(client, sTarget))) + return Plugin_Handled; + + if (!BanClientSpray(iTarget)) + { + ReplyToCommand(client, "[SprayManager] %N's spray is already blacklisted.", iTarget); + return Plugin_Handled; + } + + PrintToChatAll("\x01\x04[SprayManager] %N\x01 banned \x04%N\x01's spray.", client, iTarget); + + return Plugin_Handled; +} + +public Action Command_UnbanSpray(int client, int argc) +{ + if (argc < 1) + { + ReplyToCommand(client, "[SprayManager] Usage: sm_unbanspray "); + return Plugin_Handled; + } + + int iTarget; + char sTarget[32]; + + GetCmdArg(1, sTarget, sizeof(sTarget)); + + if (!(iTarget = FindTarget(client, sTarget))) + return Plugin_Handled; + + if (!UnbanClientSpray(iTarget)) + { + ReplyToCommand(client, "[SprayManager] %N's spray is not blacklisted.", iTarget); + return Plugin_Handled; + } + + PrintToChatAll("\x01\x04[SprayManager] %N\x01 unbanned \x04%N\x01's spray.", client, iTarget); + + return Plugin_Handled; +} + +public Action Command_TraceSpray(int client, int argc) +{ + if (!client) + { + PrintToServer("[SprayManager] Cannot use command from server console."); + return Plugin_Handled; + } + + float vecEndPos[3]; + if (TracePlayerAngles(client, vecEndPos)) + { + for (int i = 1; i <= MaxClients; i++) + { + if (IsPointInsideAABB(vecEndPos, g_SprayAABB[i])) + { + g_bInvokedThroughTopMenu[client] = false; + Menu_Trace(client, i); + + return Plugin_Handled; + } + } + } + + PrintToChat(client, "\x01\x04[SprayManager]\x01 Trace did not hit any sprays."); + + return Plugin_Handled; +} + +public Action Command_RemoveSpray(int client, int argc) +{ + if (!client) + { + PrintToServer("[SprayManager] Cannot use command from server console."); + return Plugin_Handled; + } + + float vecEndPos[3]; + if (TracePlayerAngles(client, vecEndPos)) + { + for (int i = 1; i <= MaxClients; i++) + { + if (IsPointInsideAABB(vecEndPos, g_SprayAABB[i])) + { + g_bAllowSpray = true; + SprayClientDecal(i, 0, NULL_VECTOR); + + PrintToChat(client, "\x01\x04[SprayManager]\x01 You have successfully removed \x04%N\x01's spray.", i); + + return Plugin_Handled; + } + } + } + + PrintToChat(client, "\x01\x04[SprayManager]\x01 No spray could be found."); + + return Plugin_Handled; +} + +public Action Command_SprayManager_UpdateInfo(int client, int argc) +{ + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i)) + { + UpdatePlayerInfo(i); + UpdateSprayHashInfo(i); + } + } + + ReplyToCommand(client, "[SprayManager] Refreshed database."); +} + +public Action HookDecal(const char[] sTEName, const int[] iClients, int iNumClients, float fSendDelay) +{ + int client = TE_ReadNum("m_nPlayer"); + + if (!IsValidClient(client)) + return Plugin_Continue; + + float vecOrigin[3]; + float AABBTemp[AABBTotalPoints]; + + TE_ReadVector("m_vecOrigin", vecOrigin); + + AABBTemp[AABBMinX] = vecOrigin[0] - 32.0; + AABBTemp[AABBMaxX] = vecOrigin[0] + 32.0; + AABBTemp[AABBMinY] = vecOrigin[1] - 32.0; + AABBTemp[AABBMaxY] = vecOrigin[1] + 32.0; + AABBTemp[AABBMinZ] = vecOrigin[2] - 32.0; + AABBTemp[AABBMaxZ] = vecOrigin[2] + 32.0; + + if (!g_bAllowSpray) + { + if (g_bSprayHashBanned[client]) + { + PrintToChat(client, "\x01\x04[SprayManager]\x01 Your spray is blacklisted, change it."); + return Plugin_Handled; + } + + if (g_iSprayUnbanTimestamp[client] != 0 && g_iSprayUnbanTimestamp[client] != -1) + { + if (g_iSprayUnbanTimestamp[client] < GetTime()) + SprayUnbanClient(client); + } + + if (g_bSprayBanned[client]) + { + char sRemainingTime[512]; + + FormatRemainingTime(g_iSprayUnbanTimestamp[client], sRemainingTime, sizeof(sRemainingTime)); + + PrintToChat(client, "\x01\x04[SprayManager]\x01 You are currently spray banned. (\x04%s\x01)", sRemainingTime); + + return Plugin_Handled; + } + + if (g_fNextSprayTime[client] > GetGameTime()) + return Plugin_Handled; + + if (!CheckCommandAccess(client, "sm_sprayban", ADMFLAG_GENERIC)) + { + if (g_cvarUseProximityCheck.IntValue >= 1) + { + for (int i = 1; i <= MaxClients; i++) + { + if (!IsValidClient(i) || i == client) + continue; + + if (IsVectorZero(g_vecSprayOrigin[i])) + continue; + + if (!CheckForAABBCollision(AABBTemp, g_SprayAABB[i])) + continue; + + if (CheckCommandAccess(i, "", ADMFLAG_CUSTOM1, true) || CheckCommandAccess(i, "sm_sprayban", ADMFLAG_GENERIC)) + { + PrintToChat(client, "\x01\x04[SprayManager]\x01 Your spray is too close to \x04%N\x01's spray.", i); + + return Plugin_Handled; + } + } + } + + if (CheckCommandAccess(client, "", ADMFLAG_CUSTOM1)) + g_fNextSprayTime[client] = GetGameTime() + (g_cvarDecalFrequency.FloatValue / 2); + else + g_fNextSprayTime[client] = GetGameTime() + g_cvarDecalFrequency.FloatValue; + } + } + + g_bAllowSpray = false; + + g_vecSprayOrigin[client][0] = vecOrigin[0]; + g_vecSprayOrigin[client][1] = vecOrigin[1]; + g_vecSprayOrigin[client][2] = vecOrigin[2]; + + g_SprayAABB[client][AABBMinX] = AABBTemp[AABBMinX]; + g_SprayAABB[client][AABBMaxX] = AABBTemp[AABBMaxX]; + g_SprayAABB[client][AABBMinY] = AABBTemp[AABBMinY]; + g_SprayAABB[client][AABBMaxY] = AABBTemp[AABBMaxY]; + g_SprayAABB[client][AABBMinZ] = AABBTemp[AABBMinZ]; + g_SprayAABB[client][AABBMaxZ] = AABBTemp[AABBMaxZ]; + + ArrayList PosArray = new ArrayList(3, 0); + + PosArray.PushArray(vecOrigin, 3); + + RequestFrame(FrameAfterSpray, PosArray); + + return Plugin_Continue; +} + +public void FrameAfterSpray(ArrayList Data) +{ + float vecPos[3]; + Data.GetArray(0, vecPos, 3); + + EmitSoundToAll("player/sprayer.wav", SOUND_FROM_WORLD, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, _, _, _, vecPos); + + delete Data; +} + +public Action HookSprayer(int iClients[MAXPLAYERS], int &iNumClients, char sSoundName[PLATFORM_MAX_PATH], + int &iEntity, int &iChannel, float &flVolume, int &iLevel, int &iPitch, int &iFlags, + char sSoundEntry[PLATFORM_MAX_PATH], int &seed) +{ + if (StrEqual(sSoundName, "player/sprayer.wav") && iEntity > 0) + return Plugin_Handled; + + return Plugin_Continue; +} + +public Action PerformPlayerTraces(Handle hTimer) +{ + static bool bLookingatSpray[MAXPLAYERS + 1]; + static bool bOnce[MAXPLAYERS + 1]; + float vecPos[3]; + + for (int i = 1; i <= MaxClients; i++) + { + if (!IsValidClient(i) || IsFakeClient(i)) + continue; + + if (!TracePlayerAngles(i, vecPos)) + continue; + + for (int a = 1; a <= MaxClients; a++) + { + if (!IsValidClient(a)) + continue; + + if (IsPointInsideAABB(vecPos, g_SprayAABB[a])) + { + char sSteamID[32]; + GetClientAuthId(a, AuthId_Steam2, sSteamID, sizeof(sSteamID)); + + PrintHintText(i, "Sprayed by: %N (%s)", a, sSteamID); + StopSound(i, SNDCHAN_STATIC, "UI/hint.wav"); + + bLookingatSpray[i] = true; + bOnce[i] = false; + + break; + } + else + bLookingatSpray[i] = false; + } + } + + for (int x = 1; x <= MaxClients; x++) + { + if (!IsValidClient(x) || IsFakeClient(x)) + continue; + + if (!bLookingatSpray[x] && !bOnce[x]) + { + PrintHintText(x, ""); + StopSound(x, SNDCHAN_STATIC, "UI/hint.wav"); + + bOnce[x] = true; + } + } +} + +void InitializeSQL() +{ + if (g_hDatabase != null) + delete g_hDatabase; + + if (SQL_CheckConfig("spraymanager")) + SQL_TConnect(OnSQLConnected, "spraymanager"); + else + SetFailState("Could not find \"spraymanager\" entry in databases.cfg."); +} + +public void OnSQLConnected(Handle hParent, Handle hChild, const char[] err, any data) +{ + if (hChild == null) + { + LogError("Failed to connect to database, retrying in 10 seconds. (%s)", err); + + if (CreateTimer(10.0, ReconnectSQL) == null) + { + LogError("Failed to create re-connector timer, trying to reconnect now."); + InitializeSQL(); + } + + return; + } + + char sDriver[16]; + g_hDatabase = CloneHandle(hChild); + SQL_GetDriverIdent(hParent, sDriver, sizeof(sDriver)); + + if (!strncmp(sDriver, "my", 2, false)) + { + SQL_TQuery(g_hDatabase, DummyCallback, "SET NAMES \"UTF8\""); + + SQL_TQuery(g_hDatabase, OnSQLTableCreated, "CREATE TABLE IF NOT EXISTS `spraymanager` (`steamid` VARCHAR(32) NOT NULL, `name` VARCHAR(32) NOT NULL, `unbantime` INT, `issuersteamid` VARCHAR(32), `issuername` VARCHAR(32) NOT NULL, `issuedtime` INT, `issuedreason` VARCHAR(64) NOT NULL, PRIMARY KEY(steamid)) CHARACTER SET utf8 COLLATE utf8_general_ci;"); + SQL_TQuery(g_hDatabase, OnSQLSprayBlacklistCreated, "CREATE TABLE IF NOT EXISTS `sprayblacklist` (`sprayhash` VARCHAR(16) NOT NULL, `sprayer` VARCHAR(32) NOT NULL, `sprayersteamid` VARCHAR(32), PRIMARY KEY(sprayhash)) CHARACTER SET utf8 COLLATE utf8_general_ci;"); + + g_bSQLite = false; + } + else + { + SQL_TQuery(g_hDatabase, OnSQLTableCreated, "CREATE TABLE IF NOT EXISTS `spraymanager` (`steamid` TEXT NOT NULL, `name` TEXT DEFAULT 'unknown', `unbantime` INTEGER, `issuersteamid` TEXT, `issuername` TEXT DEFAULT 'unknown', `issuedtime` INTEGER NOT NULL, `issuedreason` TEXT DEFAULT 'none', PRIMARY KEY(steamid));"); + SQL_TQuery(g_hDatabase, OnSQLSprayBlacklistCreated, "CREATE TABLE IF NOT EXISTS `sprayblacklist` (`sprayhash` TEXT NOT NULL, `sprayer` TEXT DEFAULT 'unknown', `sprayersteamid` TEXT, PRIMARY KEY(sprayhash));"); + + g_bSQLite = true; + } +} + +public Action ReconnectSQL(Handle hTimer) +{ + InitializeSQL(); + + return Plugin_Handled; +} + +public void OnSQLTableCreated(Handle hParent, Handle hChild, const char[] err, any data) +{ + if (hChild == null) + { + LogError("Database error while creating/checking for \"spraymanager\" table, retrying in 10 seconds. (%s)", err); + + if (CreateTimer(10.0, RetryMainTableCreation) == null) + { + LogError("Failed to create re-query timer, trying to query now."); + + if (g_bSQLite) + SQL_TQuery(g_hDatabase, OnSQLTableCreated, "CREATE TABLE IF NOT EXISTS `spraymanager` (`steamid` TEXT NOT NULL, `name` TEXT DEFAULT 'unknown', `unbantime` INTEGER, `issuersteamid` TEXT, `issuername` TEXT DEFAULT 'unknown', `issuedtime` INTEGER NOT NULL, `issuedreason` TEXT DEFAULT 'none', PRIMARY KEY(steamid));"); + else + SQL_TQuery(g_hDatabase, OnSQLTableCreated, "CREATE TABLE IF NOT EXISTS `spraymanager` (`steamid` VARCHAR(32) NOT NULL, `name` VARCHAR(32) NOT NULL, `unbantime` INT, `issuersteamid` VARCHAR(32), `issuername` VARCHAR(32) NOT NULL, `issuedtime` INT, `issuedreason` VARCHAR(64) NOT NULL, PRIMARY KEY(steamid)) CHARACTER SET utf8 COLLATE utf8_general_ci;"); + } + + return; + } + + g_bGotBans = true; + + if (g_bGotBlacklist) + { + // TODO: Obus fix this. + if (g_bLoadedLate) + { + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i)) + OnClientPostAdminCheck(i); + } + } + + LogMessage("Successfully connected to %s database!", g_bSQLite ? "SQLite" : "mySQL"); + + g_bFullyConnected = true; + } +} + +public Action RetryMainTableCreation(Handle hTimer) +{ + if (g_bSQLite) + SQL_TQuery(g_hDatabase, OnSQLTableCreated, "CREATE TABLE IF NOT EXISTS `spraymanager` (`steamid` TEXT NOT NULL, `name` TEXT DEFAULT 'unknown', `unbantime` INTEGER, `issuersteamid` TEXT, `issuername` TEXT DEFAULT 'unknown', `issuedtime` INTEGER NOT NULL, `issuedreason` TEXT DEFAULT 'none', PRIMARY KEY(steamid));"); + else + SQL_TQuery(g_hDatabase, OnSQLTableCreated, "CREATE TABLE IF NOT EXISTS `spraymanager` (`steamid` VARCHAR(32) NOT NULL, `name` VARCHAR(32) NOT NULL, `unbantime` INT, `issuersteamid` VARCHAR(32), `issuername` VARCHAR(32) NOT NULL, `issuedtime` INT, `issuedreason` VARCHAR(64) NOT NULL, PRIMARY KEY(steamid)) CHARACTER SET utf8 COLLATE utf8_general_ci;"); +} + +public void OnSQLSprayBlacklistCreated(Handle hParent, Handle hChild, const char[] err, any data) +{ + if (hChild == null) + { + LogError("Database error while creating/checking for \"sprayblacklist\" table, retrying in 10 seconds. (%s)", err); + + if (CreateTimer(10.0, RetryBlacklistTableCreation) == null) + { + LogError("Failed to create re-query timer, trying to query now."); + + if (g_bSQLite) + SQL_TQuery(g_hDatabase, OnSQLSprayBlacklistCreated, "CREATE TABLE IF NOT EXISTS `sprayblacklist` (`sprayhash` TEXT NOT NULL, `sprayer` TEXT DEFAULT 'unknown', `sprayersteamid` TEXT NOT NULL, PRIMARY KEY(sprayhash));"); + else + SQL_TQuery(g_hDatabase, OnSQLSprayBlacklistCreated, "CREATE TABLE IF NOT EXISTS `sprayblacklist` (`sprayhash` VARCHAR(16) NOT NULL, `sprayer` VARCHAR(32) NOT NULL, `sprayersteamid` VARCHAR(32) NOT NULL, PRIMARY KEY(sprayhash)) CHARACTER SET utf8 COLLATE utf8_general_ci;"); + } + + return; + } + + g_bGotBlacklist = true; + + if (g_bGotBans) + { + // TODO: Obus fix this. + if (g_bLoadedLate) + { + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i)) + OnClientPostAdminCheck(i); + } + } + + LogMessage("Successfully connected to %s database!", g_bSQLite ? "SQLite" : "mySQL"); + + g_bFullyConnected = true; + } +} + +public Action RetryBlacklistTableCreation(Handle hTimer) +{ + if (g_bSQLite) + SQL_TQuery(g_hDatabase, OnSQLSprayBlacklistCreated, "CREATE TABLE IF NOT EXISTS `sprayblacklist` (`sprayhash` TEXT NOT NULL, `sprayer` TEXT DEFAULT 'unknown', `sprayersteamid` TEXT NOT NULL, PRIMARY KEY(sprayhash));"); + else + SQL_TQuery(g_hDatabase, OnSQLSprayBlacklistCreated, "CREATE TABLE IF NOT EXISTS `sprayblacklist` (`sprayhash` VARCHAR(16) NOT NULL, `sprayer` VARCHAR(32) NOT NULL, `sprayersteamid` VARCHAR(32) NOT NULL, PRIMARY KEY(sprayhash)) CHARACTER SET utf8 COLLATE utf8_general_ci;"); +} + +public void CVarHook_DecalFrequency(ConVar cvar, const char[] sOldValue, const char[] sNewValue) +{ + if (cvar == g_cvarHookedDecalFrequency) + { + if (StringToInt(sNewValue) != 0) + { + LogMessage("ConVar \"decalfrequency\" needs to be 0 at all times, please use sm_decalfrequency instead."); + cvar.IntValue = 0; + } + } +} + +bool SprayBanClient(int client, int target, int iBanLength, const char[] sReason) +{ + if (!IsValidClient(target)) + { + ReplyToCommand(client, "[SprayManager] Target is no longer valid."); + return false; + } + + if (g_hDatabase == null || !g_bFullyConnected) + { + ReplyToCommand(client, "[SprayManager] Database is not connected."); + return false; + } + + if (g_bSprayBanned[target]) + { + ReplyToCommand(client, "[SprayManager] %N is already spray banned.", target); + return false; + } + + char sQuery[512]; + char sAdminName[64]; + char sTargetName[64]; + char sTargetSteamID[32]; + char sAdminSteamID[32]; + + Format(sAdminName, sizeof(sAdminName), "%N", client); + GetClientName(target, sTargetName, sizeof(sTargetName)); + + if (client) + GetClientAuthId(client, AuthId_Steam2, sAdminSteamID, sizeof(sAdminSteamID)); + else + strcopy(sAdminSteamID, sizeof(sAdminSteamID), "STEAM_ID_SERVER"); + + GetClientAuthId(target, AuthId_Steam2, sTargetSteamID, sizeof(sTargetSteamID)); + + char[] sSafeAdminName = new char[2 * strlen(sAdminName) + 1]; + char[] sSafeTargetName = new char[2 * strlen(sTargetName) + 1]; + char[] sSafeReason = new char[2 * strlen(sReason) + 1]; + SQL_EscapeString(g_hDatabase, sAdminName, sSafeAdminName, 2 * strlen(sAdminName) + 1); + SQL_EscapeString(g_hDatabase, sTargetName, sSafeTargetName, 2 * strlen(sTargetName) + 1); + SQL_EscapeString(g_hDatabase, sReason, sSafeReason, 2 * strlen(sReason) + 1); + + Format(sQuery, sizeof(sQuery), "INSERT INTO `spraymanager` (`steamid`, `name`, `unbantime`, `issuersteamid`, `issuername`, `issuedtime`, `issuedreason`) VALUES ('%s', '%s', '%i', '%s', '%s', '%i', '%s');", + sTargetSteamID, sSafeTargetName, iBanLength ? (GetTime() + (iBanLength * 60)) : 0, + sAdminSteamID, sSafeAdminName, GetTime(), strlen(sSafeReason) > 1 ? sSafeReason : "none"); + + SQL_TQuery(g_hDatabase, DummyCallback, sQuery); + + strcopy(g_sBanIssuer[target], sizeof(g_sBanIssuer[]), sAdminName); + strcopy(g_sBanIssuerSID[target], sizeof(g_sBanIssuerSID[]), sAdminSteamID); + strcopy(g_sBanReason[target], sizeof(g_sBanReason[]), strlen(sReason) ? sReason : "none"); + g_bSprayBanned[target] = true; + g_iSprayBanTimestamp[target] = GetTime(); + g_iSprayUnbanTimestamp[target] = iBanLength ? (GetTime() + (iBanLength * 60)) : 0; + g_fNextSprayTime[target] = 0.0; + + g_bAllowSpray = true; + SprayClientDecal(target, 0, NULL_VECTOR); + + return true; +} + +bool SprayUnbanClient(int client) +{ + if (!IsValidClient(client)) + return false; + + if (g_hDatabase == null || !g_bFullyConnected) + return false; + + if (!g_bSprayBanned[client]) + return false; + + char sQuery[128]; + char sClientSteamID[32]; + + GetClientAuthId(client, AuthId_Steam2, sClientSteamID, sizeof(sClientSteamID)); + Format(sQuery, sizeof(sQuery), "DELETE FROM `spraymanager` WHERE steamid = '%s';", sClientSteamID); + + SQL_TQuery(g_hDatabase, DummyCallback, sQuery); + + strcopy(g_sBanIssuer[client], sizeof(g_sBanIssuer[]), ""); + strcopy(g_sBanIssuerSID[client], sizeof(g_sBanIssuerSID[]), ""); + strcopy(g_sBanReason[client], sizeof(g_sBanReason[]), ""); + g_bSprayBanned[client] = false; + g_iSprayBanTimestamp[client] = 0; + g_iSprayUnbanTimestamp[client] = -1; + g_fNextSprayTime[client] = 0.0; + + return true; +} + +bool BanClientSpray(int client) +{ + if (!IsValidClient(client)) + return false; + + if (g_hDatabase == null || !g_bFullyConnected) + return false; + + if (g_bSprayHashBanned[client]) + return false; + + char sQuery[256]; + char sTargetName[64]; + char sTargetSteamID[32]; + + GetClientName(client, sTargetName, sizeof(sTargetName)); + GetClientAuthId(client, AuthId_Steam2, sTargetSteamID, sizeof(sTargetSteamID)); + + char[] sSafeTargetName = new char[2 * strlen(sTargetName) + 1]; + SQL_EscapeString(g_hDatabase, sTargetName, sSafeTargetName, 2 * strlen(sTargetName) + 1); + + Format(sQuery, sizeof(sQuery), "INSERT INTO `sprayblacklist` (`sprayhash`, `sprayer`, `sprayersteamid`) VALUES ('%s', '%s', '%s');", + g_sSprayHash[client], sSafeTargetName, sTargetSteamID); + + SQL_TQuery(g_hDatabase, DummyCallback, sQuery); + + g_bSprayHashBanned[client] = true; + + g_bAllowSpray = true; + SprayClientDecal(client, 0, NULL_VECTOR); + + return true; +} + +bool UnbanClientSpray(int client) +{ + if (!IsValidClient(client)) + return false; + + if (g_hDatabase == null || !g_bFullyConnected) + return false; + + if (!g_bSprayHashBanned[client]) + return false; + + char sQuery[128]; + Format(sQuery, sizeof(sQuery), "DELETE FROM `sprayblacklist` WHERE `sprayhash` = '%s';", g_sSprayHash[client]); + + SQL_TQuery(g_hDatabase, DummyCallback, sQuery); + + g_bSprayHashBanned[client] = false; + + return true; +} + +void UpdatePlayerInfo(int client) +{ + if (!IsValidClient(client)) + return; + + if (g_hDatabase == null || !g_bFullyConnected) + return; + + char sSteamID[32]; + char sQuery[128]; + + GetClientAuthId(client, AuthId_Steam2, sSteamID, sizeof(sSteamID)); + Format(sQuery, sizeof(sQuery), "SELECT * FROM `spraymanager` WHERE `steamid` = '%s';", sSteamID); + + SQL_TQuery(g_hDatabase, OnSQLCheckBanQuery, sQuery, client, DBPrio_High); +} + +void UpdateSprayHashInfo(int client) +{ + if (!IsValidClient(client)) + return; + + if (g_hDatabase == null || !g_bFullyConnected) + return; + + char sSprayQuery[128]; + + GetPlayerDecalFile(client, g_sSprayHash[client], sizeof(g_sSprayHash[])); + Format(sSprayQuery, sizeof(sSprayQuery), "SELECT * FROM `sprayblacklist` WHERE `sprayhash` = '%s';", g_sSprayHash[client]); + + SQL_TQuery(g_hDatabase, OnSQLCheckSprayHashBanQuery, sSprayQuery, client, DBPrio_High); +} + +public void DummyCallback(Handle hOwner, Handle hChild, const char[] err, any data) +{ + if (hOwner == null || hChild == null) + LogError("Query error. (%s)", err); +} + +public void OnSQLCheckBanQuery(Handle hParent, Handle hChild, const char[] err, any client) +{ + if (!IsValidClient(client)) + return; + + if (hChild == null) + { + LogError("An error occurred while querying the database for a user ban, retrying in 10 seconds. (%s)", err); + + if (CreateTimer(10.0, RetryPlayerInfoUpdate, client) == null) + { + LogError("Failed to create query timer, trying to query now."); + UpdatePlayerInfo(client); + } + + return; + } + + if (SQL_FetchRow(hChild)) + { + g_bSprayBanned[client] = true; + g_iSprayUnbanTimestamp[client] = SQL_FetchInt(hChild, 2); + g_iSprayBanTimestamp[client] = SQL_FetchInt(hChild, 5); + + SQL_FetchString(hChild, 3, g_sBanIssuerSID[client], sizeof(g_sBanIssuerSID[])); + SQL_FetchString(hChild, 4, g_sBanIssuer[client], sizeof(g_sBanIssuer[])); + SQL_FetchString(hChild, 6, g_sBanReason[client], sizeof(g_sBanReason[])); + } +} + +public void OnSQLCheckSprayHashBanQuery(Handle hParent, Handle hChild, const char[] err, any client) +{ + if (!IsValidClient(client)) + return; + + if (hChild == null) + { + LogError("An error occurred while querying the database for a spray ban, retrying in 10 seconds. (%s)", err); + + if (CreateTimer(10.0, RetrySprayHashUpdate, client) == null) + { + LogError("Failed to create spray query timer, trying to query now."); + UpdateSprayHashInfo(client); + } + + return; + } + + if (SQL_FetchRow(hChild)) + g_bSprayHashBanned[client] = true; +} + +public Action RetryPlayerInfoUpdate(Handle hTimer, any client) +{ + UpdatePlayerInfo(client); +} + +public Action RetrySprayHashUpdate(Handle hTimer, any client) +{ + UpdateSprayHashInfo(client); +} + +bool ForceSpray(int client, int target, bool bPlaySound=true) +{ + if (!IsValidClient(target)) + return false; + + float vecEndPos[3]; + if (TracePlayerAngles(client, vecEndPos)) + { + SprayClientDecal(target, 0, vecEndPos); + + if (bPlaySound) + EmitSoundToAll("player/sprayer.wav", SOUND_FROM_WORLD, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, _, _, _, vecEndPos); + + return true; + } + + PrintToChat(client, "\x01\x04[SprayManager]\x01 Could not spray here, try somewhere else."); + + return false; +} + +bool SprayClientDecal(int client, int iEntity, float vecOrigin[3]) +{ + if (!IsValidClient(client)) + return false; + + TE_Start("Player Decal"); + TE_WriteVector("m_vecOrigin", vecOrigin); + TE_WriteNum("m_nEntity", iEntity); + TE_WriteNum("m_nPlayer", client); + TE_SendToAll(); + + return true; +} + +bool TracePlayerAngles(int client, float vecResult[3]) +{ + if (!IsValidClient(client)) + return false; + + float vecEyeAngles[3]; + float vecEyeOrigin[3]; + + GetClientEyeAngles(client, vecEyeAngles); + GetClientEyePosition(client, vecEyeOrigin); + + Handle hTraceRay = TR_TraceRayFilterEx(vecEyeOrigin, vecEyeAngles, MASK_SHOT_HULL, RayType_Infinite, TraceFilterEntities); + + if (TR_DidHit(hTraceRay)) + { + TR_GetEndPosition(vecResult, hTraceRay); + CloseHandle(hTraceRay); + + return true; + } + + CloseHandle(hTraceRay); + + return false; +} + +bool TracePlayerAnglesRanged(int client, float fMaxDistance) +{ + if (!IsValidClient(client)) + return false; + + float vecEyeAngles[3]; + float vecEyeOrigin[3]; + float vecDirection[3]; + float vecEndPos[3]; + + GetClientEyeAngles(client, vecEyeAngles); + GetClientEyePosition(client, vecEyeOrigin); + GetAngleVectors(vecEyeAngles, vecDirection, NULL_VECTOR, NULL_VECTOR); + + vecEndPos[0] = vecEyeOrigin[0] + (vecDirection[0] * fMaxDistance); + vecEndPos[1] = vecEyeOrigin[1] + (vecDirection[1] * fMaxDistance); + vecEndPos[2] = vecEyeOrigin[2] + (vecDirection[2] * fMaxDistance); + + Handle hTraceRay = TR_TraceRayFilterEx(vecEyeOrigin, vecEndPos, MASK_SHOT_HULL, RayType_EndPoint, TraceFilterEntities); + + if (TR_DidHit(hTraceRay)) + { + CloseHandle(hTraceRay); + + return true; + } + + return false; +} + +void ClearPlayerInfo(int client) +{ + if (!IsValidClient(client)) + return; + + strcopy(g_sBanIssuer[client], sizeof(g_sBanIssuer[]), ""); + strcopy(g_sBanIssuerSID[client], sizeof(g_sBanIssuerSID[]), ""); + strcopy(g_sBanReason[client], sizeof(g_sBanReason[]), ""); + strcopy(g_sSprayHash[client], sizeof(g_sSprayHash[]), ""); + g_bSprayBanned[client] = false; + g_bSprayHashBanned[client] = false; + g_iSprayBanTimestamp[client] = 0; + g_iSprayUnbanTimestamp[client] = -1; + g_fNextSprayTime[client] = 0.0; + g_vecSprayOrigin[client] = NULL_VECTOR; +} + +void FormatRemainingTime(int iTimestamp, char[] sBuffer, int iBuffSize) +{ + if (!iTimestamp) + { + Format(sBuffer, iBuffSize, "Permanent"); + return; + } + + int tstamp = (iTimestamp - GetTime()); + + int days = (tstamp / 86400); + int hours = ((tstamp / 3600) % 24); + int minutes = ((tstamp / 60) % 60); + int seconds = (tstamp % 60); + + if (tstamp > 86400) + { + Format(sBuffer, iBuffSize, "%d %s, %d %s, %d %s, %d %s", days, SingularOrMultiple(days) ? "Days" : "Day", + hours, SingularOrMultiple(hours) ? "Hours" : "Hour", minutes, SingularOrMultiple(minutes) ? "Minutes" : "Minute", + seconds, SingularOrMultiple(seconds)?"Seconds":"Second"); + } + else if (tstamp > 3600) + { + Format(sBuffer, iBuffSize, "%d %s, %d %s, %d %s", hours, SingularOrMultiple(hours) ? "Hours" : "Hour", + minutes, SingularOrMultiple(minutes) ? "Minutes" : "Minute", seconds, SingularOrMultiple(seconds) ? "Seconds" : "Second"); + } + else if (tstamp > 60) + { + Format(sBuffer, iBuffSize, "%d %s, %d %s", minutes, SingularOrMultiple(minutes) ? "Minutes" : "Minute", + seconds, SingularOrMultiple(seconds) ? "Seconds" : "Second"); + } + else + Format(sBuffer, iBuffSize, "%d %s", seconds, SingularOrMultiple(seconds)?"Seconds":"Second"); +} + +bool IsPointInsideAABB(float vecPoint[3], float AABB[6]) +{ + if (vecPoint[0] >= AABB[AABBMinX] && vecPoint[0] <= AABB[AABBMaxX] && + vecPoint[1] >= AABB[AABBMinY] && vecPoint[1] <= AABB[AABBMaxY] && + vecPoint[2] >= AABB[AABBMinZ] && vecPoint[2] <= AABB[AABBMaxZ]) + { + return true; + } + + return false; +} + +bool CheckForAABBCollision(float AABB1[6], float AABB2[6]) +{ + if (AABB1[AABBMinX] > AABB2[AABBMaxX]) return false; + if (AABB1[AABBMinY] > AABB2[AABBMaxY]) return false; + if (AABB1[AABBMinZ] > AABB2[AABBMaxZ]) return false; + if (AABB1[AABBMaxX] < AABB2[AABBMinX]) return false; + if (AABB1[AABBMaxY] < AABB2[AABBMinY]) return false; + if (AABB1[AABBMaxZ] < AABB2[AABBMinZ]) return false; + + return true; +} + +stock bool IsVectorZero(float vecPos[3]) +{ + return ((vecPos[0] == 0.0) && (vecPos[1] == 0.0) && (vecPos[2] == 0.0)); +} + +stock bool SingularOrMultiple(int num) +{ + if (!num || num > 1) + return true; + + return false; +} + +stock bool TraceFilterEntities(int entity, int contentsMask) +{ + return false; +} + +stock bool IsValidClient(int client) +{ + if (client <= 0 || client > MaxClients || !IsClientInGame(client)) + return false; + + return IsClientAuthorized(client); +} diff --git a/StopSound/scripting/StopSound.sp b/StopSound/scripting/StopSound.sp index 3c02d98c..1cbab971 100644 --- a/StopSound/scripting/StopSound.sp +++ b/StopSound/scripting/StopSound.sp @@ -2,40 +2,36 @@ #include #include -#include +#include "morecolors.inc" +#undef REQUIRE_PLUGIN -#define PLUGIN_NAME "Toggle Weapon Sounds" -#define PLUGIN_VERSION "1.2.0" +#pragma newdecls required +#define PLUGIN_VERSION "1.3.0" -#define UPDATE_URL "http://godtony.mooo.com/stopsound/stopsound.txt" +bool g_bStopSound[MAXPLAYERS+1]; +bool g_bHooked; +static char g_sKVPATH[PLATFORM_MAX_PATH]; +KeyValues g_hWepSounds; -new bool:g_bStopSound[MAXPLAYERS+1], bool:g_bHooked; -static String:g_sKVPATH[PLATFORM_MAX_PATH]; -new Handle:g_hWepSounds; - -public Plugin:myinfo = +public Plugin myinfo = { - name = PLUGIN_NAME, - author = "GoD-Tony, edit by id/Obus", + name = "Toggle Weapon Sounds", + author = "GoD-Tony, edit by Obus + BotoX", description = "Allows clients to stop hearing weapon sounds", version = PLUGIN_VERSION, url = "http://www.sourcemod.net/" }; -public OnPluginStart() +public void OnPluginStart() { // Detect game and hook appropriate tempent. - decl String:sGame[32]; + static char sGame[32]; GetGameFolderName(sGame, sizeof(sGame)); - if (StrEqual(sGame, "cstrike")) - { + if(StrEqual(sGame, "cstrike")) AddTempEntHook("Shotgun Shot", CSS_Hook_ShotgunShot); - } - else if (StrEqual(sGame, "dod")) - { + else if(StrEqual(sGame, "dod")) AddTempEntHook("FireBullets", DODS_Hook_FireBullets); - } // TF2/HL2:DM and misc weapon sounds will be caught here. AddNormalSoundHook(Hook_NormalSound); @@ -43,62 +39,81 @@ public OnPluginStart() CreateConVar("sm_stopsound_version", PLUGIN_VERSION, "Toggle Weapon Sounds", FCVAR_NOTIFY|FCVAR_DONTRECORD|FCVAR_REPLICATED); RegConsoleCmd("sm_stopsound", Command_StopSound, "Toggle hearing weapon sounds"); - if (g_hWepSounds != INVALID_HANDLE) - { - CloseHandle(g_hWepSounds); - } - - g_hWepSounds = CreateKeyValues("WeaponSounds"); + g_hWepSounds = new KeyValues("WeaponSounds"); BuildPath(Path_SM, g_sKVPATH, sizeof(g_sKVPATH), "data/playerprefs.WepSounds.txt"); + g_hWepSounds.ImportFromFile(g_sKVPATH); - FileToKeyValues(g_hWepSounds, g_sKVPATH); + // Suppress reload sound effects + UserMsg ReloadEffect = GetUserMessageId("ReloadEffect"); + if(ReloadEffect != INVALID_MESSAGE_ID) + HookUserMessage(ReloadEffect, Hook_ReloadEffect, true); - // Updater. - //if (LibraryExists("updater")) - //{ - // Updater_AddPlugin(UPDATE_URL); - //} + // Late load + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client) && IsClientAuthorized(client)) + { + static char sAuth[32]; + GetClientAuthId(client, AuthId_Steam2, sAuth, sizeof(sAuth)); + OnClientAuthorized(client, sAuth); + } + } } -/*public OnLibraryAdded(const String:name[]) +public void OnPluginEnd() { - if (StrEqual(name, "updater")) + for(int client = 1; client <= MaxClients; client++) { - Updater_AddPlugin(UPDATE_URL); + if(IsClientInGame(client)) + OnClientDisconnect_Post(client); } -}*/ -public Action:Command_StopSound(client, args) + // Detect game and unhook appropriate tempent. + static char sGame[32]; + GetGameFolderName(sGame, sizeof(sGame)); + + if(StrEqual(sGame, "cstrike")) + RemoveTempEntHook("Shotgun Shot", CSS_Hook_ShotgunShot); + else if(StrEqual(sGame, "dod")) + RemoveTempEntHook("FireBullets", DODS_Hook_FireBullets); + + // TF2/HL2:DM and misc weapon sounds were caught here. + RemoveNormalSoundHook(Hook_NormalSound); + + UserMsg ReloadEffect = GetUserMessageId("ReloadEffect"); + if(ReloadEffect != INVALID_MESSAGE_ID) + UnhookUserMessage(ReloadEffect, Hook_ReloadEffect, true); +} + +public Action Command_StopSound(int client, int args) { - if (client == 0) + if(client == 0) { PrintToServer("[SM] Cannot use command from server console."); return Plugin_Handled; } - if (args > 0) + if(args > 0) { - decl String:Arguments[32]; + static char Arguments[32]; GetCmdArg(1, Arguments, sizeof(Arguments)); - if (StrEqual(Arguments, "save")) + static char SID[32]; + GetClientAuthId(client, AuthId_Steam2, SID, sizeof(SID)); + + if(StrEqual(Arguments, "save")) { - KvRewind(g_hWepSounds); + g_hWepSounds.Rewind(); - decl String:SID[32]; - GetClientAuthId(client, AuthId_Steam2, SID, sizeof(SID)); - - if (KvJumpToKey(g_hWepSounds, SID, true)) + if(g_hWepSounds.JumpToKey(SID, true)) { - new disabled; - disabled = KvGetNum(g_hWepSounds, "disabled", 0); - - if (!disabled) + int disabled = g_hWepSounds.GetNum("disabled", 0); + if(!disabled) { //CPrintToChat(client, "[StopSound] Saved entry for STEAMID({green}%s{default}) {green}successfully{default}.", SID); - KvSetNum(g_hWepSounds, "disabled", 1); - KvRewind(g_hWepSounds); - KeyValuesToFile(g_hWepSounds, g_sKVPATH); + g_hWepSounds.SetNum("disabled", 1); + g_hWepSounds.Rewind(); + g_hWepSounds.ExportToFile(g_sKVPATH); g_bStopSound[client] = true; CReplyToCommand(client, "{green}[StopSound]{default} Weapon sounds {red}disabled{default} - {green}entry saved{default}."); @@ -109,9 +124,9 @@ public Action:Command_StopSound(client, args) else { //CPrintToChat(client, "[StopSound] Entry for STEAMID({green}%s{default}) {green}successfully deleted{default}.", SID); - KvDeleteThis(g_hWepSounds); - KvRewind(g_hWepSounds); - KeyValuesToFile(g_hWepSounds, g_sKVPATH); + g_hWepSounds.DeleteThis(); + g_hWepSounds.Rewind(); + g_hWepSounds.ExportToFile(g_sKVPATH); g_bStopSound[client] = false; CReplyToCommand(client, "{green}[StopSound]{default} Weapon sounds {green}enabled{default} - {red}entry deleted{default}."); @@ -121,24 +136,21 @@ public Action:Command_StopSound(client, args) } } - KvRewind(g_hWepSounds); + g_hWepSounds.Rewind(); } - else if (StrEqual(Arguments, "delete")) + else if(StrEqual(Arguments, "delete")) { - KvRewind(g_hWepSounds); + g_hWepSounds.Rewind(); - decl String:SID[32]; - GetClientAuthId(client, AuthId_Steam2, SID, sizeof(SID)); - - if (KvJumpToKey(g_hWepSounds, SID, false)) + if(g_hWepSounds.JumpToKey(SID, false)) { g_bStopSound[client] = false; CReplyToCommand(client, "{green}[StopSound]{default} Weapon sounds {green}enabled{default} - {red}entry deleted{default}."); CheckHooks(); - KvDeleteThis(g_hWepSounds); - KvRewind(g_hWepSounds); - KeyValuesToFile(g_hWepSounds, g_sKVPATH); + g_hWepSounds.DeleteThis(); + g_hWepSounds.Rewind(); + g_hWepSounds.ExportToFile(g_sKVPATH); return Plugin_Handled; } @@ -162,41 +174,34 @@ public Action:Command_StopSound(client, args) return Plugin_Handled; } -public OnClientPutInServer(client) +public void OnClientAuthorized(int client, const char[] auth) { - KvRewind(g_hWepSounds); + g_hWepSounds.Rewind(); - decl String:SID[32]; - GetClientAuthId(client, AuthId_Steam2, SID, sizeof(SID)); - - if (KvJumpToKey(g_hWepSounds, SID, false)) + if(KvJumpToKey(g_hWepSounds, auth, false)) { - new disabled; - disabled = KvGetNum(g_hWepSounds, "disabled", 0); - - if (disabled) - { + int disabled = g_hWepSounds.GetNum("disabled", 0); + if(disabled) g_bStopSound[client] = true; - } } CheckHooks(); - KvRewind(g_hWepSounds); + g_hWepSounds.Rewind(); } -public OnClientDisconnect_Post(client) +public void OnClientDisconnect_Post(int client) { g_bStopSound[client] = false; CheckHooks(); } -CheckHooks() +void CheckHooks() { - new bool:bShouldHook = false; + bool bShouldHook = false; - for (new i = 1; i <= MaxClients; i++) + for(int i = 1; i <= MaxClients; i++) { - if (g_bStopSound[i]) + if(g_bStopSound[i]) { bShouldHook = true; break; @@ -207,25 +212,22 @@ CheckHooks() g_bHooked = bShouldHook; } -public Action:Hook_NormalSound(clients[64], &numClients, String:sample[PLATFORM_MAX_PATH], &entity, &channel, &Float:volume, &level, &pitch, &flags) +public Action Hook_NormalSound(int clients[MAXPLAYERS], int &numClients, char sample[PLATFORM_MAX_PATH], + int &entity, int &channel, float &volume, int &level, int &pitch, int &flags, + char soundEntry[PLATFORM_MAX_PATH], int &seed) { // Ignore non-weapon sounds. - if (!g_bHooked || !(strncmp(sample, "weapons", 7) == 0 || strncmp(sample[1], "weapons", 7) == 0)) - { + if(!g_bHooked || !(strncmp(sample, "weapons", 7) == 0 || strncmp(sample[1], "weapons", 7) == 0)) return Plugin_Continue; - } - decl i, j; - - for (i = 0; i < numClients; i++) + for(int i = 0; i < numClients; i++) { - if (g_bStopSound[clients[i]]) + int client = clients[i]; + if(g_bStopSound[client]) { // Remove the client from the array. - for (j = i; j < numClients - 1; j++) - { + for(int j = i; j < numClients - 1; j++) clients[j] = clients[j + 1]; - } numClients--; i--; @@ -235,39 +237,30 @@ public Action:Hook_NormalSound(clients[64], &numClients, String:sample[PLATFORM_ return (numClients > 0) ? Plugin_Changed : Plugin_Stop; } -public Action:CSS_Hook_ShotgunShot(const String:te_name[], const Players[], numClients, Float:delay) +public Action CSS_Hook_ShotgunShot(const char[] te_name, const int[] Players, int numClients, float delay) { - if (!g_bHooked) - { + if(!g_bHooked) return Plugin_Continue; - } // Check which clients need to be excluded. - decl newClients[MaxClients], client, i; - new newTotal = 0; + int[] newClients = new int[numClients]; + int newTotal = 0; - for (i = 0; i < numClients; i++) + for(int i = 0; i < numClients; i++) { - client = Players[i]; - - if (!g_bStopSound[client]) - { + int client = Players[i]; + if(!g_bStopSound[client]) newClients[newTotal++] = client; - } } // No clients were excluded. - if (newTotal == numClients) - { + if(newTotal == numClients) return Plugin_Continue; - } - else if (newTotal == 0) // All clients were excluded and there is no need to broadcast. - { + else if(newTotal == 0) // All clients were excluded and there is no need to broadcast. return Plugin_Stop; - } // Re-broadcast to clients that still need it. - decl Float:vTemp[3]; + float vTemp[3]; TE_Start("Shotgun Shot"); TE_ReadVector("m_vecOrigin", vTemp); TE_WriteVector("m_vecOrigin", vTemp); @@ -284,39 +277,30 @@ public Action:CSS_Hook_ShotgunShot(const String:te_name[], const Players[], numC return Plugin_Stop; } -public Action:DODS_Hook_FireBullets(const String:te_name[], const Players[], numClients, Float:delay) +public Action DODS_Hook_FireBullets(const char[] te_name, const int[] Players, int numClients, float delay) { - if (!g_bHooked) - { + if(!g_bHooked) return Plugin_Continue; - } // Check which clients need to be excluded. - decl newClients[MaxClients], client, i; - new newTotal = 0; + int[] newClients = new int[numClients]; + int newTotal = 0; - for (i = 0; i < numClients; i++) + for(int i = 0; i < numClients; i++) { - client = Players[i]; - - if (!g_bStopSound[client]) - { + int client = Players[i]; + if(!g_bStopSound[client]) newClients[newTotal++] = client; - } } // No clients were excluded. - if (newTotal == numClients) - { + if(newTotal == numClients) return Plugin_Continue; - } - else if (newTotal == 0)// All clients were excluded and there is no need to broadcast. - { + else if(newTotal == 0)// All clients were excluded and there is no need to broadcast. return Plugin_Stop; - } // Re-broadcast to clients that still need it. - decl Float:vTemp[3]; + float vTemp[3]; TE_Start("FireBullets"); TE_ReadVector("m_vecOrigin", vTemp); TE_WriteVector("m_vecOrigin", vTemp); @@ -330,4 +314,61 @@ public Action:DODS_Hook_FireBullets(const String:te_name[], const Players[], num TE_Send(newClients, newTotal, delay); return Plugin_Stop; -} \ No newline at end of file +} + +public Action Hook_ReloadEffect(UserMsg msg_id, BfRead msg, const int[] players, int playersNum, bool reliable, bool init) +{ + if(!g_bHooked) + return Plugin_Continue; + + int client = msg.ReadShort(); + + // Check which clients need to be excluded. + int[] newClients = new int[playersNum]; + int newTotal = 0; + + for(int i = 0; i < playersNum; i++) + { + int client_ = players[i]; + if(IsClientInGame(client_) && !g_bStopSound[client_]) + newClients[newTotal++] = client_; + } + + // No clients were excluded. + if(newTotal == playersNum) + return Plugin_Continue; + else if(newTotal == 0) // All clients were excluded and there is no need to broadcast. + return Plugin_Handled; + + DataPack pack = new DataPack(); + pack.WriteCell(client); + pack.WriteCell(newTotal); + + ArrayList aPlayers = new ArrayList(newTotal, 1); + aPlayers.SetArray(0, newClients, newTotal); + pack.WriteCell(aPlayers); + + RequestFrame(OnReloadEffect, pack); + + return Plugin_Handled; +} + +public void OnReloadEffect(DataPack pack) +{ + pack.Reset(); + int client = pack.ReadCell(); + int playersNum = pack.ReadCell(); + ArrayList aPlayers = pack.ReadCell(); + CloseHandle(pack); + + int[] players = new int[playersNum]; + aPlayers.GetArray(0, players, playersNum); + delete aPlayers; + + Handle ReloadEffect = StartMessage("ReloadEffect", players, playersNum, USERMSG_RELIABLE | USERMSG_BLOCKHOOKS); + if(GetFeatureStatus(FeatureType_Native, "GetUserMessageType") == FeatureStatus_Available && GetUserMessageType() == UM_Protobuf) + PbSetInt(ReloadEffect, "entidx", client); + else + BfWriteShort(ReloadEffect, client); + EndMessage(); +} diff --git a/WeaponCleaner/scripting/WeaponCleaner.sp b/WeaponCleaner/scripting/WeaponCleaner.sp index eed570f4..ad7fc74e 100644 --- a/WeaponCleaner/scripting/WeaponCleaner.sp +++ b/WeaponCleaner/scripting/WeaponCleaner.sp @@ -100,6 +100,9 @@ public void OnClientDisconnect(int client) SDKUnhook(client, SDKHook_WeaponDropPost, OnWeaponDrop); SDKUnhook(client, SDKHook_WeaponEquipPost, OnWeaponEquip); + if(!IsClientInGame(client)) + return; + // Simulate dropping all equipped weapons for(int i = 0; i < 5; i++) {