diff --git a/CELT_VOICE/scripting/nosteam_celt_audio.sp b/CELT_VOICE/scripting/nosteam_celt_audio.sp index 4d185aa..d69c682 100644 --- a/CELT_VOICE/scripting/nosteam_celt_audio.sp +++ b/CELT_VOICE/scripting/nosteam_celt_audio.sp @@ -3,6 +3,7 @@ #include #include #include +#include #include #pragma semicolon 1 @@ -34,6 +35,21 @@ public void OnPluginEnd() } } +public void set_webclient_listen_override(int client) +{ + for (int j = 1; j <= MaxClients; j++) + { + if (!IsValidClient(j) || client == j || IsFakeClient(j)) + continue; + if (!PM_IsPlayerSteam(client) && PM_IsPlayerSteam(j)) + { + //the nosteam client is not allowed to hear the steam client because broadcastvoicedata would ear rape them. + //LogMessage("%N has muted %N", client, j); + SetListenOverride(client, j, Listen_No); + } + } +} + public Action check_mutes(Handle timer, any data) { for (int i = 1; i <= MaxClients; i++) @@ -44,9 +60,10 @@ public Action check_mutes(Handle timer, any data) } if (!g_bWasChecked[i]) { + //this exists for the webclient. the webclient is skipping all connection related forwards. hence a manual check like this is needed for the webclient. char dummy[64]; OnClientAuthorized(i, dummy); - g_bWasChecked[i] = true; + set_webclient_listen_override(i); } for (int j = 1; j <= MaxClients; j++) { @@ -54,11 +71,10 @@ public Action check_mutes(Handle timer, any data) { continue; } - //i = muter, j = mutee - bool isMuted = GetListenOverride(i, j) == Listen_No; + bool isMuted = BaseComm_IsClientMuted(j); if (!isMuted) { - isMuted = BaseComm_IsClientMuted(j); + isMuted = SelfMute_IsIgnoring(i, j); } //PrintToChatAll("i: %N. j: %N. isMuted: %i", i, j, isMuted); ClientMutedOtherClient(i, j, isMuted); diff --git a/SelfMute/scripting/SelfMute_codec_transcode.sp b/SelfMute/scripting/SelfMute_codec_transcode.sp new file mode 100644 index 0000000..d49713e --- /dev/null +++ b/SelfMute/scripting/SelfMute_codec_transcode.sp @@ -0,0 +1,1718 @@ +#pragma semicolon 1 + +#include +#include +#include +#include +#include +#include + +#undef REQUIRE_PLUGIN +#include +#include +#tryinclude +#include +#define REQUIRE_PLUGIN + +#undef REQUIRE_EXTENSIONS +#tryinclude +#define REQUIRE_EXTENSIONS + +#pragma newdecls required + +bool g_Plugin_ccc = false; +bool g_Plugin_zombiereloaded = false; +bool g_Plugin_voiceannounce_ex = false; +bool g_Plugin_AdvancedTargeting = false; +bool g_Extension_Voice = false; +bool g_bIsProtoBuf = false; + +Handle g_hCookieTorchMuted = null; + + +Database g_hDatabase; + +#define PLUGIN_VERSION "2.5" +//may 20th 2024 jenz edit to add option for perm sm, stored in database. +public Plugin myinfo = +{ + name = "SelfMute", + author = "BotoX", + description = "Ignore other players in text and voicechat.", + version = PLUGIN_VERSION, + url = "" +}; + +enum +{ + MUTE_NONE = 0, + MUTE_SPEC = 1, + MUTE_CT = 2, + MUTE_T = 4, + MUTE_DEAD = 8, + MUTE_ALIVE = 16, + MUTE_NOTFRIENDS = 32, + MUTE_ALL = 64, + MUTE_LAST = 64 +}; + +bool g_Ignored[(MAXPLAYERS + 1) * (MAXPLAYERS + 1)]; +bool g_Exempt[MAXPLAYERS + 1][MAXPLAYERS + 1]; +int g_SpecialMutes[MAXPLAYERS + 1]; + +char g_PlayerNames[MAXPLAYERS+1][MAX_NAME_LENGTH]; + +/* + CREATE TABLE SelfMute.unloze_selfmute ( + `client_name` varchar(64) NOT NULL, + `client_steamid` varchar(32) NOT NULL, + `target_name` varchar(64) NOT NULL, + `target_steamid` varchar(32) NOT NULL, + PRIMARY KEY (`client_steamid`, `target_steamid`) +) + +CREATE TABLE SelfMute.is_online ( + `client_name` varchar(64) NOT NULL, + `client_steamid` varchar(32) NOT NULL, + PRIMARY KEY (`client_steamid`) +) +*/ + +public void SQL_OnDatabaseConnect(Database db, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Database error: %s", error); + return; + } + g_hDatabase = db; + + char sQuery[512]; + Format(sQuery, sizeof(sQuery), "truncate table `is_online`"); + g_hDatabase.Query(SQL_OnQueryCompletedTruncate, sQuery); +} + +public void SQL_OnQueryCompletedTruncate(Database db, DBResultSet results, const char[] error, int iSerial) +{ + if (!db || strlen(error)) + { + delete results; + LogError("Query error 3: %s", error); + return; + } + delete results; + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && !IsFakeClient(i)) + { + OnClientPostAdminCheck(i); + } + } +} + +public void ReadClientsToPermMuteForClient(int client) +{ + char csSID[64]; + GetClientAuthId(client, AuthId_Steam2, csSID, sizeof(csSID)); + char sQuery[512]; + //limits this way to only select online clients to apply self mute for. + Format(sQuery, sizeof(sQuery), "select target_steamid from `unloze_selfmute` where client_steamid = '%s' and target_steamid in (select client_steamid from `is_online`)", csSID); + g_hDatabase.Query(SQL_GetClientsToSelfMuteForClient, sQuery, GetClientSerial(client), DBPrio_High); +} + +public void SQL_GetClientsToSelfMuteForClient(Database db, DBResultSet results, const char[] error, int iSerial) +{ + if (!db || strlen(error)) + { + delete results; + LogError("Query error 3: %s", error); + return; + } + int client; + if ((client = GetClientFromSerial(iSerial)) == 0) + { + delete results; + return; + } + + while (results.RowCount && results.FetchRow()) + { + char cSID[64]; + results.FetchString(0, cSID, sizeof(cSID)); + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && !IsFakeClient(i)) + { + char sAuth[64]; + GetClientAuthId(i, AuthId_Steam2, sAuth, sizeof(sAuth)); + if (StrEqual(cSID, sAuth)) + { + Ignore(client, i); + //PrintToChat(client, "Player you permanent muted connected: %N", i); + UpdateIgnored(); //no clue if it needs to update that often. + } + } + } + } + delete results; +} + +public void OnClientPostAdminCheck(int client) +{ + if(!IsValidClient(client) || IsFakeClient(client)) + return; + if (!g_hDatabase) + { + return; + } + insert_client_as_online(client); + + //using last connect forward to assure PM_IsPlayerSteam check cant fail due to client not being ingame yet. + for (int j = 1; j <= MaxClients; j++) + { + if (!IsValidClient(j) || client == j || IsFakeClient(j)) + continue; + if (!PM_IsPlayerSteam(client) && PM_IsPlayerSteam(j)) + { + //the nosteam client is not allowed to hear the steam client because broadcastvoicedata would ear rape them. + //LogMessage("%N has muted %N", client, j); + SetListenOverride(client, j, Listen_No); + } + if (PM_IsPlayerSteam(client) && !PM_IsPlayerSteam(j)) + { + //the nosteam client is not allowed to hear the steam client because broadcastvoicedata would ear rape them. + //LogMessage("%N has muted %N", j, client); + SetListenOverride(j, client, Listen_No); + } + } +} + +public void delete_client_from_online(int client) +{ + char csSID[64]; + GetClientAuthId(client, AuthId_Steam2, csSID, sizeof(csSID)); + char sQuery[512]; + Format(sQuery, sizeof(sQuery), "delete from `is_online` where client_steamid = '%s'", csSID); + g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low); +} + +public void insert_client_as_online(int client) +{ + char csSID[64]; + GetClientAuthId(client, AuthId_Steam2, csSID, sizeof(csSID)); + char sName[MAX_NAME_LENGTH]; + GetClientName(client, sName, sizeof(sName)); + int size2 = 2 * strlen(sName) + 1; + char[] sEscapedName = new char[size2 + 1]; + g_hDatabase.Escape(sName, sEscapedName, size2 + 1); + char sQuery[512]; + Format(sQuery, sizeof(sQuery), "INSERT IGNORE INTO `is_online` (`client_name`, `client_steamid`) VALUES ('%s', '%s')", sEscapedName, csSID); + g_hDatabase.Query(SQL_FinishedQueryUpdateMutes, sQuery, _, DBPrio_High); +} + +public void SQL_FinishedQueryUpdateMutes(Database db, DBResultSet results, const char[] error, any data) +{ + if (!db || strlen(error)) + { + LogError("Query error 3: %s", error); + } + delete results; + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && !IsFakeClient(i)) + { + ReadClientsToPermMuteForClient(i); + } + } +} + +public void SQL_FinishedQuery(Database db, DBResultSet results, const char[] error, any data) +{ + if (!db || strlen(error)) + { + LogError("Query error 3: %s", error); + } + delete results; +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char [] error, int err_max) +{ + CreateNative("SelfMute_IsIgnoring", Native_IsIgnoring); + return APLRes_Success; +} + +public int Native_IsIgnoring(Handle plugin, int numParams) +{ + int client = GetNativeCell(1); + int target = GetNativeCell(2); + return GetIgnored(client, target) ? 1 : 0; +} + +public void OnPluginStart() +{ + if (!g_hDatabase) + { + Database.Connect(SQL_OnDatabaseConnect, "SelfMute"); + } + else + { + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && !IsFakeClient(i)) + { + OnClientPostAdminCheck(i); + } + } + } + LoadTranslations("common.phrases"); + + CreateConVar("sm_selfmute_version", PLUGIN_VERSION, "Version of Self-Mute", FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); + + RegConsoleCmd("sm_sm", Command_SelfMute, "Mute player by typing !sm [playername]"); + RegConsoleCmd("sm_psm", Command_SelfMutePerm, "Mute player by typing !psm [playername] but permanently"); + RegConsoleCmd("sm_su", Command_SelfUnMute, "Unmute player by typing !su [playername]"); + RegConsoleCmd("sm_cm", Command_CheckMutes, "Check who you have self-muted"); + RegAdminCmd("sm_debugtorch", Command_CheckPermaTorchMutes, ADMFLAG_GENERIC, "Check who has permanently self-muted Torch"); + + HookEvent("round_start", Event_Round); + HookEvent("round_end", Event_Round); + HookEvent("player_team", Event_TeamChange); + + if(GetFeatureStatus(FeatureType_Native, "GetUserMessageType") == FeatureStatus_Available && GetUserMessageType() == UM_Protobuf) + g_bIsProtoBuf = true; + + UserMsg RadioText = GetUserMessageId("RadioText"); + if(RadioText == INVALID_MESSAGE_ID) + SetFailState("This game doesn't support RadioText user messages."); + + HookUserMessage(RadioText, Hook_UserMessageRadioText, true); + + UserMsg SendAudio = GetUserMessageId("SendAudio"); + if(SendAudio == INVALID_MESSAGE_ID) + SetFailState("This game doesn't support SendAudio user messages."); + + HookUserMessage(SendAudio, Hook_UserMessageSendAudio, true); + + g_hCookieTorchMuted = RegClientCookie("torch_muted", "is torch muted", CookieAccess_Protected); +} + +public void OnAllPluginsLoaded() +{ + g_Plugin_ccc = LibraryExists("ccc"); + g_Plugin_zombiereloaded = LibraryExists("zombiereloaded"); + g_Plugin_voiceannounce_ex = LibraryExists("voiceannounce_ex"); + g_Plugin_AdvancedTargeting = LibraryExists("AdvancedTargeting"); + g_Extension_Voice = LibraryExists("Voice"); + + LogMessage("SelfMute capabilities:\nProtoBuf: %s\nCCC: %s\nZombieReloaded: %s\nVoiceAnnounce: %s\nAdvancedTargeting: %s\nVoice: %s", + (g_bIsProtoBuf ? "yes" : "no"), + (g_Plugin_ccc ? "loaded" : "not loaded"), + (g_Plugin_zombiereloaded ? "loaded" : "not loaded"), + (g_Plugin_voiceannounce_ex ? "loaded" : "not loaded"), + (g_Plugin_AdvancedTargeting ? "loaded" : "not loaded"), + (g_Extension_Voice ? "loaded" : "not loaded")); +} + +void OnLibrary(const char[] name, bool added) +{ + if(StrEqual(name, "ccc")) + g_Plugin_ccc = added; + else if(StrEqual(name, "zombiereloaded")) + g_Plugin_zombiereloaded = added; + else if(StrEqual(name, "voiceannounce_ex")) + g_Plugin_voiceannounce_ex = added; + else if(StrEqual(name, "AdvancedTargeting")) + g_Plugin_AdvancedTargeting = added; + else if(StrEqual(name, "Voice")) + g_Extension_Voice = added; + +} + +public void OnLibraryAdded(const char[] name) { OnLibrary(name, true); } +public void OnLibraryRemoved(const char[] name) { OnLibrary(name, false); } + +public void OnClientPutInServer(int client) +{ + g_SpecialMutes[client] = MUTE_NONE; + for(int i = 1; i <= MaxClients; i++) + { + SetIgnored(client, i, false); + SetExempt(client, i, false); + + SetIgnored(i, client, false); + SetExempt(i, client, false); + } + + UpdateSpecialMutesOtherClients(client); + UpdateIgnored(); + + GetCookiesForTorch(client); +} + +public void OnMapEnd() +{ + char sQuery[512]; + Format(sQuery, sizeof(sQuery), "truncate table `is_online`"); + g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low); +} + +public void OnClientDisconnect(int client) +{ + if (!IsFakeClient(client)) + { + delete_client_from_online(client); + } + g_SpecialMutes[client] = MUTE_NONE; + for(int i = 1; i <= MaxClients; i++) + { + SetIgnored(client, i, false); + SetExempt(client, i, false); + + SetIgnored(i, client, false); + SetExempt(i, client, false); + + if(IsClientInGame(i) && i != client) + SetListenOverride(i, client, Listen_Yes); + } + + UpdateIgnored(); +} + +public void GetCookiesForTorch(int client) +{ + char sBuffer[2]; + + GetClientCookie(client, g_hCookieTorchMuted, sBuffer, sizeof(sBuffer)); + if(sBuffer[0] != '\0') + { + for(int i = 1; i <= MaxClients; i++) + { + if(IsClientInGame(i) && IsClientSourceTV(i)) + Ignore(client, i); + } + } + + UpdateIgnored(); +} + +public void Event_Round(Handle event, const char[] name, bool dontBroadcast) +{ + for(int i = 1; i <= MaxClients; i++) + { + if(IsClientInGame(i)) + UpdateSpecialMutesThisClient(i); + } +} + +public void Event_TeamChange(Handle event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(GetEventInt(event, "userid")); + + UpdateSpecialMutesOtherClients(client); +} + +public void ZR_OnClientInfected(int client, int attacker, bool motherInfect, bool respawnOverride, bool respawn) +{ + UpdateSpecialMutesOtherClients(client); +} + +public void ZR_OnClientHumanPost(int client, bool respawn, bool protect) +{ + UpdateSpecialMutesOtherClients(client); +} + +/* + * Mutes this client on other players +*/ +void UpdateSpecialMutesOtherClients(int client) +{ + bool Alive = IsPlayerAlive(client); + int Team = GetClientTeam(client); + + for(int i = 1; i <= MaxClients; i++) + { + if(i == client || !IsClientInGame(i)) + continue; + + int Flags = MUTE_NONE; + + if(g_SpecialMutes[i] & MUTE_SPEC && Team == CS_TEAM_SPECTATOR) + Flags |= MUTE_SPEC; + + else if(g_SpecialMutes[i] & MUTE_CT && Alive && + ((g_Plugin_zombiereloaded && ZR_IsClientHuman(client)) || (!g_Plugin_zombiereloaded && Team == CS_TEAM_CT))) + Flags |= MUTE_CT; + + else if(g_SpecialMutes[i] & MUTE_T && Alive && + ((g_Plugin_zombiereloaded && ZR_IsClientZombie(client)) || (!g_Plugin_zombiereloaded && Team == CS_TEAM_T))) + Flags |= MUTE_T; + + else if(g_SpecialMutes[i] & MUTE_DEAD && !Alive) + Flags |= MUTE_DEAD; + + else if(g_SpecialMutes[i] & MUTE_ALIVE && Alive) + Flags |= MUTE_ALIVE; + + else if(g_SpecialMutes[i] & MUTE_NOTFRIENDS && + g_Plugin_AdvancedTargeting && IsClientFriend(i, client) == 0) + Flags |= MUTE_NOTFRIENDS; + + else if(g_SpecialMutes[i] & MUTE_ALL) + Flags |= MUTE_ALL; + + if(Flags && !GetExempt(i, client)) + { + SetListenOverride(i, client, Listen_No); + //LogMessage("selfmuted 1: i: %N. client: %N", i, client); + } + else if(!GetIgnored(i, client) && PM_IsPlayerSteam(i)) //dont allows nosteamers to have it overwritten to listen yes to stop broadcastvoice data when using wrong audio codecs for nosteamers. + SetListenOverride(i, client, Listen_Yes); + } +} + +/* + * Mutes other players on this client +*/ +void UpdateSpecialMutesThisClient(int client) +{ + for(int i = 1; i <= MaxClients; i++) + { + if(i == client || !IsClientInGame(i)) + continue; + + bool Alive = IsPlayerAlive(i); + int Team = GetClientTeam(i); + + int Flags = MUTE_NONE; + + if(g_SpecialMutes[client] & MUTE_SPEC && Team == CS_TEAM_SPECTATOR) + Flags |= MUTE_SPEC; + + else if(g_SpecialMutes[client] & MUTE_CT && Alive && + ((g_Plugin_zombiereloaded && ZR_IsClientHuman(i) || (!g_Plugin_zombiereloaded) && Team == CS_TEAM_CT))) + Flags |= MUTE_CT; + + else if(g_SpecialMutes[client] & MUTE_T && Alive && + ((g_Plugin_zombiereloaded && ZR_IsClientZombie(i) || (!g_Plugin_zombiereloaded) && Team == CS_TEAM_T))) + Flags |= MUTE_T; + + else if(g_SpecialMutes[client] & MUTE_DEAD && !Alive) + Flags |= MUTE_DEAD; + + else if(g_SpecialMutes[client] & MUTE_ALIVE && Alive) + Flags |= MUTE_ALIVE; + + else if(g_SpecialMutes[client] & MUTE_NOTFRIENDS && + g_Plugin_AdvancedTargeting && IsClientFriend(client, i) == 0) + Flags |= MUTE_NOTFRIENDS; + + else if(g_SpecialMutes[client] & MUTE_ALL) + Flags |= MUTE_ALL; + + if(Flags && !GetExempt(client, i)) + { + SetListenOverride(client, i, Listen_No); + //LogMessage("selfmuted 2: client: %N. i: %N", client, i); + } + else if(!GetIgnored(client, i) && PM_IsPlayerSteam(i)) //dont allows nosteamers to have it overwritten to listen yes to stop broadcastvoice data when using wrong audio codecs for nosteamers. + SetListenOverride(client, i, Listen_Yes); + } +} + +int GetSpecialMutesFlags(char[] Argument) +{ + int SpecialMute = MUTE_NONE; + if(StrEqual(Argument, "@spec", false) || StrEqual(Argument, "@!ct", false) || StrEqual(Argument, "@!t", false)) + SpecialMute |= MUTE_SPEC; + if(StrEqual(Argument, "@ct", false) || StrEqual(Argument, "@!t", false) || StrEqual(Argument, "@!spec", false)) + SpecialMute |= MUTE_CT; + if(StrEqual(Argument, "@t", false) || StrEqual(Argument, "@!ct", false) || StrEqual(Argument, "@!spec", false)) + SpecialMute |= MUTE_T; + if(StrEqual(Argument, "@dead", false) || StrEqual(Argument, "@!alive", false)) + SpecialMute |= MUTE_DEAD; + if(StrEqual(Argument, "@alive", false) || StrEqual(Argument, "@!dead", false)) + SpecialMute |= MUTE_ALIVE; + if(g_Plugin_AdvancedTargeting && StrEqual(Argument, "@!friends", false)) + SpecialMute |= MUTE_NOTFRIENDS; + if(StrEqual(Argument, "@all", false)) + SpecialMute |= MUTE_ALL; + + return SpecialMute; +} + +void FormatSpecialMutes(int SpecialMute, char[] aBuf, int BufLen) +{ + if(!SpecialMute) + { + StrCat(aBuf, BufLen, "none"); + return; + } + + bool Status = false; + if(SpecialMute & MUTE_ALL) + { + StrCat(aBuf, BufLen, "Everyone, "); + Status = true; + } + if(SpecialMute & MUTE_SPEC) + { + StrCat(aBuf, BufLen, "Spectators, "); + Status = true; + } + if(SpecialMute & MUTE_CT) + { + StrCat(aBuf, BufLen, "Counter-Terrorists, "); + Status = true; + } + if(SpecialMute & MUTE_T) + { + StrCat(aBuf, BufLen, "Terrorists, "); + Status = true; + } + if(SpecialMute & MUTE_DEAD) + { + StrCat(aBuf, BufLen, "Dead players, "); + Status = true; + } + if(SpecialMute & MUTE_ALIVE) + { + StrCat(aBuf, BufLen, "Alive players, "); + Status = true; + } + if(SpecialMute & MUTE_NOTFRIENDS) + { + StrCat(aBuf, BufLen, "Not Steam friends, "); + Status = true; + } + + // Cut off last ', ' + if(Status) + aBuf[strlen(aBuf) - 2] = 0; +} + +bool MuteSpecial(int client, char[] Argument) +{ + bool RetValue = false; + int SpecialMute = GetSpecialMutesFlags(Argument); + + if(SpecialMute & MUTE_NOTFRIENDS && g_Plugin_AdvancedTargeting && ReadClientFriends(client) != 1) + { + PrintToChat(client, "\x04[Self-Mute]\x01 Could not read your friendslist, your profile must be set to public!"); + SpecialMute &= ~MUTE_NOTFRIENDS; + RetValue = true; + } + + if(SpecialMute) + { + if(SpecialMute & MUTE_ALL || g_SpecialMutes[client] & MUTE_ALL) + { + g_SpecialMutes[client] = MUTE_ALL; + SpecialMute = MUTE_ALL; + } + else + g_SpecialMutes[client] |= SpecialMute; + + UpdateSpecialMutesThisClient(client); + + char aBuf[128]; + FormatSpecialMutes(SpecialMute, aBuf, sizeof(aBuf)); + + PrintToChat(client, "\x04[Self-Mute]\x01 You have self-muted group:\x04 %s", aBuf); + RetValue = true; + } + + return RetValue; +} + +bool UnMuteSpecial(int client, char[] Argument) +{ + int SpecialMute = GetSpecialMutesFlags(Argument); + + if(SpecialMute) + { + if(SpecialMute & MUTE_ALL) + { + if(g_SpecialMutes[client]) + { + SpecialMute = g_SpecialMutes[client]; + g_SpecialMutes[client] = MUTE_NONE; + } + else + { + for(int i = 1; i <= MaxClients; i++) + { + if(IsClientInGame(i) && !IsClientSourceTV(i)) + UnIgnore(client, i); + + PrintToChat(client, "\x04[Self-Mute]\x01 You have self-unmuted:\x04 all players"); + return true; + } + } + } + else + g_SpecialMutes[client] &= ~SpecialMute; + + UpdateSpecialMutesThisClient(client); + + char aBuf[256]; + FormatSpecialMutes(SpecialMute, aBuf, sizeof(aBuf)); + + PrintToChat(client, "\x04[Self-Mute]\x01 You have self-unmuted group:\x04 %s", aBuf); + return true; + } + + return false; +} + +void Ignore(int client, int target) +{ + SetIgnored(client, target, true); + SetListenOverride(client, target, Listen_No); + //LogMessage("selfmuted 3: client: %N. target: %N", client, target); +} + +void UnIgnore(int client, int target) +{ + SetIgnored(client, target, false); + SetListenOverride(client, target, Listen_Yes); +} + +void Exempt(int client, int target) +{ + SetExempt(client, target, true); + UpdateSpecialMutesThisClient(client); +} + +void UnExempt(int client, int target) +{ + SetExempt(client, target, false); + UpdateSpecialMutesThisClient(client); +} + +/* + * CHAT COMMANDS +*/ + +public Action Command_CheckPermaTorchMutes(int client, int args) +{ + int iTorchPermMuted; + int iPlayers; + char sBuffer[2]; + + for(int i = 1; i <= MaxClients; i++) + { + if(!IsClientInGame(i) || IsFakeClient(i)) + continue; + + GetClientCookie(i, g_hCookieTorchMuted, sBuffer, sizeof(sBuffer)); + + if(sBuffer[0] != '\0') + iTorchPermMuted++; + + iPlayers++; + } + + ReplyToCommand(client, "[SM] There are currently %d out of %d Players whove got Torch permanently self-muted.", iTorchPermMuted, iPlayers); + + return Plugin_Handled; +} + +public Action Command_SelfMutePerm(int client, int args) +{ + if(client == 0) + { + PrintToServer("[SM] Cannot use command from server console."); + return Plugin_Handled; + } + + if(args < 1) + { + PrintToChat(client, "\x04[Self-Mute]\x01 Permanent mutes are dangerous. You need to specify the name of the target to permanently self mute."); + return Plugin_Handled; + } + + char Argument[65]; + GetCmdArg(1, Argument, sizeof(Argument)); + + char Filtered[65]; + strcopy(Filtered, sizeof(Filtered), Argument); + StripQuotes(Filtered); + TrimString(Filtered); + + if(MuteSpecial(client, Filtered)) + return Plugin_Handled; + + char sTargetName[MAX_TARGET_LENGTH]; + int aTargetList[MAXPLAYERS]; + int TargetCount; + bool TnIsMl; + + if((TargetCount = ProcessTargetString( + Argument, + client, + aTargetList, + MAXPLAYERS, + COMMAND_FILTER_CONNECTED|COMMAND_FILTER_NO_IMMUNITY, + sTargetName, + sizeof(sTargetName), + TnIsMl)) <= 0) + { + ReplyToTargetError(client, TargetCount); + return Plugin_Handled; + } + + if(TargetCount == 1) + { + if(aTargetList[0] == client) + { + PrintToChat(client, "\x04[Self-Mute]\x01 You can't mute yourself, don't be silly."); + return Plugin_Handled; + } + + if(IsClientSourceTV(aTargetList[0])) + { + Ignore(client, aTargetList[0]); + SetClientCookie(client, g_hCookieTorchMuted, "1"); + PrintToChat(client, "\x04[Self-Mute]\x01 You have permanently self-muted:\x04 %s", sTargetName); + return Plugin_Handled; + } + + if(GetExempt(client, aTargetList[0])) + { + UnExempt(client, aTargetList[0]); + PrintToChat(client, "\x04[Self-Mute]\x01 You have removed exempt from self-mute:\x04 %s", sTargetName); + return Plugin_Handled; + } + } + + for(int i = 0; i < TargetCount; i++) + { + if(aTargetList[i] == client) + continue; + + Ignore(client, aTargetList[i]); + if (!IsFakeClient(aTargetList[i])) + { + AddClientMutingClient(client, aTargetList[i]); + } + } + UpdateIgnored(); + + PrintToChat(client, "\x04[Self-Mute]\x01 You have permanently self-muted:\x04 %s. !su can revert this decision.", sTargetName); + + return Plugin_Handled; +} + +public void AddClientMutingClient(int client, int target) +{ + char csSID[64]; + GetClientAuthId(client, AuthId_Steam2, csSID, sizeof(csSID)); + char csSIDTarget[64]; + GetClientAuthId(target, AuthId_Steam2, csSIDTarget, sizeof(csSIDTarget)); + + char sName[MAX_NAME_LENGTH]; + GetClientName(client, sName, sizeof(sName)); + int size2 = 2 * strlen(sName) + 1; + char[] sEscapedName = new char[size2 + 1]; + g_hDatabase.Escape(sName, sEscapedName, size2 + 1); + + GetClientName(target, sName, sizeof(sName)); + size2 = 2 * strlen(sName) + 1; + char[] sEscapedNameTarget = new char[size2 + 1]; + g_hDatabase.Escape(sName, sEscapedNameTarget, size2 + 1); + + char sQuery[512]; + + Format(sQuery, sizeof(sQuery), "insert ignore into `unloze_selfmute` (`client_name`, `client_steamid`, `target_name`, `target_steamid`) VALUES ('%s', '%s', '%s', '%s')", sEscapedName, csSID, sEscapedNameTarget, csSIDTarget); + g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low); +} + +public void delete_client_from_permMute(int client, int target) +{ + if (IsFakeClient(target)) + { + return; + } + char csSID[64]; + GetClientAuthId(client, AuthId_Steam2, csSID, sizeof(csSID)); + + char csSIDTarget[64]; + GetClientAuthId(target, AuthId_Steam2, csSIDTarget, sizeof(csSIDTarget)); + + char sQuery[512]; + Format(sQuery, sizeof(sQuery), "delete from `unloze_selfmute` where client_steamid = '%s' and target_steamid = '%s'", csSID, csSIDTarget); + g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low); +} + +public Action Command_SelfMute(int client, int args) +{ + if(client == 0) + { + PrintToServer("[SM] Cannot use command from server console."); + return Plugin_Handled; + } + + if(args < 1) + { + DisplayMuteMenu(client); + return Plugin_Handled; + } + + char Argument[65]; + GetCmdArg(1, Argument, sizeof(Argument)); + + char Filtered[65]; + strcopy(Filtered, sizeof(Filtered), Argument); + StripQuotes(Filtered); + TrimString(Filtered); + + if(MuteSpecial(client, Filtered)) + return Plugin_Handled; + + char sTargetName[MAX_TARGET_LENGTH]; + int aTargetList[MAXPLAYERS]; + int TargetCount; + bool TnIsMl; + + if((TargetCount = ProcessTargetString( + Argument, + client, + aTargetList, + MAXPLAYERS, + COMMAND_FILTER_CONNECTED|COMMAND_FILTER_NO_IMMUNITY, + sTargetName, + sizeof(sTargetName), + TnIsMl)) <= 0) + { + ReplyToTargetError(client, TargetCount); + return Plugin_Handled; + } + + if(TargetCount == 1) + { + if(aTargetList[0] == client) + { + PrintToChat(client, "\x04[Self-Mute]\x01 You can't mute yourself, don't be silly."); + return Plugin_Handled; + } + + if(IsClientSourceTV(aTargetList[0])) + { + Ignore(client, aTargetList[0]); + SetClientCookie(client, g_hCookieTorchMuted, "1"); + PrintToChat(client, "\x04[Self-Mute]\x01 You have permanently self-muted:\x04 %s", sTargetName); + return Plugin_Handled; + } + + if(GetExempt(client, aTargetList[0])) + { + UnExempt(client, aTargetList[0]); + + PrintToChat(client, "\x04[Self-Mute]\x01 You have removed exempt from self-mute:\x04 %s", sTargetName); + + return Plugin_Handled; + } + } + + for(int i = 0; i < TargetCount; i++) + { + if(aTargetList[i] == client) + continue; + + Ignore(client, aTargetList[i]); + } + UpdateIgnored(); + + PrintToChat(client, "\x04[Self-Mute]\x01 You have self-muted:\x04 %s. \x01 You can use !psm for permanent self mute now.", sTargetName); + + return Plugin_Handled; +} + +public Action Command_SelfUnMute(int client, int args) +{ + if(client == 0) + { + PrintToServer("[SM] Cannot use command from server console."); + return Plugin_Handled; + } + + if(args < 1) + { + DisplayUnMuteMenu(client); + return Plugin_Handled; + } + + char Argument[65]; + GetCmdArg(1, Argument, sizeof(Argument)); + + char Filtered[65]; + strcopy(Filtered, sizeof(Filtered), Argument); + StripQuotes(Filtered); + TrimString(Filtered); + + if(UnMuteSpecial(client, Filtered)) + return Plugin_Handled; + + char sTargetName[MAX_TARGET_LENGTH]; + int aTargetList[MAXPLAYERS]; + int TargetCount; + bool TnIsMl; + + if((TargetCount = ProcessTargetString( + Argument, + client, + aTargetList, + MAXPLAYERS, + COMMAND_FILTER_CONNECTED|COMMAND_FILTER_NO_IMMUNITY, + sTargetName, + sizeof(sTargetName), + TnIsMl)) <= 0) + { + ReplyToTargetError(client, TargetCount); + return Plugin_Handled; + } + + if(TargetCount == 1) + { + if(aTargetList[0] == client) + { + PrintToChat(client, "\x04[Self-Mute]\x01 Unmuting wont work either."); + return Plugin_Handled; + } + + if(IsClientSourceTV(aTargetList[0])) + { + UnIgnore(client, aTargetList[0]); + SetClientCookie(client, g_hCookieTorchMuted, ""); + PrintToChat(client, "\x04[Self-Mute]\x01 You have permanently self-unmuted:\x04 %s", sTargetName); + return Plugin_Handled; + } + + if(!GetIgnored(client, aTargetList[0])) + { + Exempt(client, aTargetList[0]); + + PrintToChat(client, "\x04[Self-Mute]\x01 You have exempted from self-mute:\x04 %s", sTargetName); + + return Plugin_Handled; + } + } + + for(int i = 0; i < TargetCount; i++) + { + if(aTargetList[i] == client) + continue; + + UnIgnore(client, aTargetList[i]); + delete_client_from_permMute(client, aTargetList[i]); + } + UpdateIgnored(); + + PrintToChat(client, "\x04[Self-Mute]\x01 You have self-unmuted:\x04 %s", sTargetName); + + return Plugin_Handled; +} + +public Action Command_CheckMutes(int client, int args) +{ + if(client == 0) + { + PrintToServer("[SM] Cannot use command from server console."); + return Plugin_Handled; + } + + char aMuted[1024]; + char aExempted[1024]; + char aName[MAX_NAME_LENGTH]; + for(int i = 1; i <= MaxClients; i++) + { + if(!IsClientInGame(i)) + continue; + + GetClientName(i, aName, sizeof(aName)); + + if(GetIgnored(client, i)) + { + StrCat(aMuted, sizeof(aMuted), aName); + StrCat(aMuted, sizeof(aMuted), ", "); + } + + if(GetExempt(client, i)) + { + StrCat(aExempted, sizeof(aExempted), aName); + StrCat(aExempted, sizeof(aExempted), ", "); + } + } + + if(strlen(aMuted)) + { + aMuted[strlen(aMuted) - 2] = 0; + PrintToChat(client, "\x04[Self-Mute]\x01 You have self-muted:\x04 %s", aMuted); + } + + if(g_SpecialMutes[client] != MUTE_NONE) + { + aMuted[0] = 0; + FormatSpecialMutes(g_SpecialMutes[client], aMuted, sizeof(aMuted)); + PrintToChat(client, "\x04[Self-Mute]\x01 You have self-muted group:\x04 %s", aMuted); + } + else if(!strlen(aMuted) && !strlen(aExempted)) + PrintToChat(client, "\x04[Self-Mute]\x01 You have not self-muted anyone!"); + + if(strlen(aExempted)) + { + aExempted[strlen(aExempted) - 2] = 0; + PrintToChat(client, "\x04[Self-Mute]\x01 You have exempted from self-mute:\x04 %s", aExempted); + } + + return Plugin_Handled; +} + +stock bool _IsClientSpeaking(int client) +{ + #if defined _voiceannounceex_included_ + if(g_Plugin_voiceannounce_ex) + return IsClientSpeaking(client); + #endif + + #if defined _voice_included + if(g_Extension_Voice) + return IsClientTalking(client); + #endif + + return false; +} + +/* + * MENU +*/ +void DisplayMuteMenu(int client) +{ + Menu menu = new Menu(MenuHandler_MuteMenu, MenuAction_Select|MenuAction_Cancel|MenuAction_End|MenuAction_DrawItem|MenuAction_DisplayItem); + menu.ExitButton = true; + + int[] aClients = new int[MaxClients + 1]; + + { + // Count talking players and insert id's into aClients array + int CurrentlyTalking = 0; + for(int i = 1; i <= MaxClients; i++) + { + if(i != client && IsClientInGame(i) && _IsClientSpeaking(i)) + aClients[CurrentlyTalking++] = i; + } + + if(CurrentlyTalking > 0) + { + // insert player names into g_PlayerNames array + for(int i = 0; i < CurrentlyTalking; i++) + GetClientName(aClients[i], g_PlayerNames[aClients[i]], sizeof(g_PlayerNames[])); + + // sort aClients array by player name + SortCustom1D(aClients, CurrentlyTalking, SortByPlayerName); + + // insert players sorted + char aBuf[12]; + for(int i = 0; i < CurrentlyTalking; i++) + { + IntToString(GetClientUserId(aClients[i]), aBuf, sizeof(aBuf)); + menu.AddItem(aBuf, g_PlayerNames[aClients[i]]); + } + + // insert spacers + int Entries = 7 - CurrentlyTalking % 7; + while(Entries--) + menu.AddItem("", "", ITEMDRAW_RAWLINE); + } + } + + menu.AddItem("@all", "Everyone"); + menu.AddItem("@spec", "Spectators"); + menu.AddItem("@ct", "Counter-Terrorists"); + menu.AddItem("@t", "Terrorists"); + menu.AddItem("@dead", "Dead players"); + menu.AddItem("@alive", "Alive players"); + if(g_Plugin_AdvancedTargeting) + menu.AddItem("@!friends", "Not Steam friends"); + else + menu.AddItem("", "", ITEMDRAW_RAWLINE); + + // Count valid players and insert id's into aClients array + int Players = 0; + for(int i = 1; i <= MaxClients; i++) + { + if(i != client && IsClientInGame(i)) + aClients[Players++] = i; + } + + // insert player names into g_PlayerNames array + for(int i = 0; i < Players; i++) + GetClientName(aClients[i], g_PlayerNames[aClients[i]], sizeof(g_PlayerNames[])); + + // sort aClients array by player name + SortCustom1D(aClients, Players, SortByPlayerName); + + // insert players sorted + char aBuf[12]; + for(int i = 0; i < Players; i++) + { + IntToString(GetClientUserId(aClients[i]), aBuf, sizeof(aBuf)); + menu.AddItem(aBuf, g_PlayerNames[aClients[i]]); + } + + menu.Display(client, MENU_TIME_FOREVER); +} + +public int MenuHandler_MuteMenu(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_End: + { + if(param1 != MenuEnd_Selected) + CloseHandle(menu); + } + case MenuAction_Select: + { + int Style; + char aItem[32]; + char aDisp[MAX_NAME_LENGTH + 4]; + menu.GetItem(param2, aItem, sizeof(aItem), Style, aDisp, sizeof(aDisp)); + + if(Style != ITEMDRAW_DEFAULT || !aItem[0]) + { + PrintToChat(param1, "Internal error: aItem[0] -> %d | Style -> %d", aItem[0], Style); + return 0; + } + + if(aItem[0] == '@') + { + int Flag = GetSpecialMutesFlags(aItem); + if(Flag && g_SpecialMutes[param1] & Flag) + UnMuteSpecial(param1, aItem); + else + MuteSpecial(param1, aItem); + + menu.DisplayAt(param1, GetMenuSelectionPosition(), MENU_TIME_FOREVER); + return 0; + } + + int UserId = StringToInt(aItem); + int client = GetClientOfUserId(UserId); + if(!client) + { + PrintToChat(param1, "\x04[Self-Mute]\x01 Player no longer available."); + menu.DisplayAt(param1, GetMenuSelectionPosition(), MENU_TIME_FOREVER); + return 0; + } + + if(GetIgnored(param1, client)) + { + if(IsClientSourceTV(client)) + { + UnIgnore(param1, client); + SetClientCookie(param1, g_hCookieTorchMuted, ""); + PrintToChat(param1, "\x04[Self-Mute]\x01 You have permanently self-unmuted:\x04 %N", client); + } + else + { + UnIgnore(param1, client); + PrintToChat(param1, "\x04[Self-Mute]\x01 You have self-unmuted:\x04 %N", client); + delete_client_from_permMute(param1, client); + } + } + else if(GetExempt(param1, client)) + { + UnExempt(param1, client); + PrintToChat(param1, "\x04[Self-Mute]\x01 You have removed exempt from self-mute:\x04 %N", client); + } + else + { + if(IsClientSourceTV(client)) + { + Ignore(param1, client); + SetClientCookie(param1, g_hCookieTorchMuted, "1"); + PrintToChat(param1, "\x04[Self-Mute]\x01 You have permanently self-muted:\x04 %N", client); + } + else + { + Ignore(param1, client); + PrintToChat(param1, "\x04[Self-Mute]\x01 You have self-muted:\x04 %N. \x01 You can now use !psm to permanent self mute a player.", client); + } + } + menu.DisplayAt(param1, GetMenuSelectionPosition(), MENU_TIME_FOREVER); + return 0; + } + case MenuAction_DrawItem: + { + int Style; + char aItem[32]; + menu.GetItem(param2, aItem, sizeof(aItem), Style); + + if(!aItem[0]) + return ITEMDRAW_DISABLED; + + if(aItem[0] == '@') + { + int Flag = GetSpecialMutesFlags(aItem); + if(Flag & MUTE_ALL) + return Style; + else if(g_SpecialMutes[param1] & MUTE_ALL) + return ITEMDRAW_DISABLED; + + return Style; + } + + int UserId = StringToInt(aItem); + int client = GetClientOfUserId(UserId); + if(!client) // Player disconnected + return ITEMDRAW_DISABLED; + + return Style; + } + case MenuAction_DisplayItem: + { + int Style; + char aItem[32]; + char aDisp[MAX_NAME_LENGTH + 4]; + menu.GetItem(param2, aItem, sizeof(aItem), Style, aDisp, sizeof(aDisp)); + + // Start of current page + if((param2 + 1) % 7 == 1) + { + if(aItem[0] == '@') + menu.SetTitle("[Self-Mute] Groups"); + else if(param2 == 0) + menu.SetTitle("[Self-Mute] Talking players"); + else + menu.SetTitle("[Self-Mute] All players"); + } + + if(!aItem[0]) + return 0; + + if(aItem[0] == '@') + { + int Flag = GetSpecialMutesFlags(aItem); + if(Flag && g_SpecialMutes[param1] & Flag) + { + char aBuf[32] = "[M] "; + FormatSpecialMutes(Flag, aBuf, sizeof(aBuf)); + if(!StrEqual(aDisp, aBuf)) + return RedrawMenuItem(aBuf); + } + + return 0; + } + + int UserId = StringToInt(aItem); + int client = GetClientOfUserId(UserId); + if(!client) // Player disconnected + { + char aBuf[MAX_NAME_LENGTH + 4] = "[D] "; + StrCat(aBuf, sizeof(aBuf), aDisp); + if(!StrEqual(aDisp, aBuf)) + return RedrawMenuItem(aBuf); + } + + if(GetIgnored(param1, client)) + { + char aBuf[MAX_NAME_LENGTH + 4] = "[M] "; + GetClientName(client, g_PlayerNames[client], sizeof(g_PlayerNames[])); + StrCat(aBuf, sizeof(aBuf), g_PlayerNames[client]); + if(!StrEqual(aDisp, aBuf)) + return RedrawMenuItem(aBuf); + } + else if(GetExempt(param1, client)) + { + char aBuf[MAX_NAME_LENGTH + 4] = "[E] "; + GetClientName(client, g_PlayerNames[client], sizeof(g_PlayerNames[])); + StrCat(aBuf, sizeof(aBuf), g_PlayerNames[client]); + if(!StrEqual(aDisp, aBuf)) + return RedrawMenuItem(aBuf); + } + else + { + GetClientName(client, g_PlayerNames[client], sizeof(g_PlayerNames[])); + if(!StrEqual(aDisp, g_PlayerNames[client])) + return RedrawMenuItem(g_PlayerNames[client]); + } + + return 0; + } + } + + return 0; +} + +void DisplayUnMuteMenu(int client) +{ + Menu menu = new Menu(MenuHandler_UnMuteMenu, MenuAction_Select|MenuAction_Cancel|MenuAction_End|MenuAction_DrawItem|MenuAction_DisplayItem); + menu.SetTitle("[Self-UnMute]"); + menu.ExitButton = true; + + if(g_SpecialMutes[client] & MUTE_ALL) + menu.AddItem("@all", "Everyone"); + if(g_SpecialMutes[client] & MUTE_SPEC) + menu.AddItem("@spec", "Spectators"); + if(g_SpecialMutes[client] & MUTE_CT) + menu.AddItem("@ct", "Counter-Terrorists"); + if(g_SpecialMutes[client] & MUTE_T) + menu.AddItem("@t", "Terrorists"); + if(g_SpecialMutes[client] & MUTE_DEAD) + menu.AddItem("@dead", "Dead players"); + if(g_SpecialMutes[client] & MUTE_ALIVE) + menu.AddItem("@alive", "Alive players"); + if(g_SpecialMutes[client] & MUTE_NOTFRIENDS) + menu.AddItem("@!friends", "Not Steam friends"); + if(g_SpecialMutes[client]) + menu.AddItem("", "", ITEMDRAW_RAWLINE); + + int[] aClients = new int[MaxClients + 1]; + + // Count valid players and insert ids into aClients array + int Players = 0; + for(int i = 1; i <= MaxClients; i++) + { + if(i != client && IsClientInGame(i) && (GetIgnored(client, i) || GetExempt(client, i))) + aClients[Players++] = i; + } + + // insert player names into g_PlayerNames array + for(int i = 0; i < Players; i++) + { + GetClientName(aClients[i], g_PlayerNames[aClients[i]], sizeof(g_PlayerNames[])); + } + + // sort aClients array by player name + SortCustom1D(aClients, Players, SortByPlayerName); + + // insert players sorted + char aBuf[12]; + for(int i = 0; i < Players; i++) + { + IntToString(GetClientUserId(aClients[i]), aBuf, sizeof(aBuf)); + menu.AddItem(aBuf, g_PlayerNames[aClients[i]]); + } + + if(!menu.ItemCount) + { + delete menu; + PrintToChat(client, "\x04[Self-Mute]\x01 You haven't muted or exempted anyone."); + return; + } + + menu.Display(client, MENU_TIME_FOREVER); +} + + +public int MenuHandler_UnMuteMenu(Menu menu, MenuAction action, int param1, int param2) +{ + switch(action) + { + case MenuAction_End: + { + if(param1 != MenuEnd_Selected) + CloseHandle(menu); + } + case MenuAction_Select: + { + int Style; + char aItem[32]; + char aDisp[MAX_NAME_LENGTH + 4]; + menu.GetItem(param2, aItem, sizeof(aItem), Style, aDisp, sizeof(aDisp)); + + if(Style != ITEMDRAW_DEFAULT || !aItem[0]) + { + PrintToChat(param1, "Internal error: aItem[0] -> %d | Style -> %d", aItem[0], Style); + return 0; + } + + if(aItem[0] == '@') + { + int Flag = GetSpecialMutesFlags(aItem); + if(Flag && g_SpecialMutes[param1] & Flag) + UnMuteSpecial(param1, aItem); + + menu.RemoveItem(GetMenuSelectionPosition()); + menu.DisplayAt(param1, GetMenuSelectionPosition(), MENU_TIME_FOREVER); + return 0; + } + + int UserId = StringToInt(aItem); + int client = GetClientOfUserId(UserId); + if(!client) + { + PrintToChat(param1, "\x04[Self-Mute]\x01 Player no longer available."); + menu.DisplayAt(param1, GetMenuSelectionPosition(), MENU_TIME_FOREVER); + return 0; + } + + if(GetIgnored(param1, client)) + { + if(IsClientSourceTV(client)) + { + UnIgnore(param1, client); + SetClientCookie(param1, g_hCookieTorchMuted, ""); + PrintToChat(param1, "\x04[Self-Mute]\x01 You have permanently self-unmuted:\x04 %N", client); + } + else + { + UnIgnore(param1, client); + PrintToChat(param1, "\x04[Self-Mute]\x01 You have self-unmuted:\x04 %N", client); + delete_client_from_permMute(param1, client); + } + } + else if(GetExempt(param1, client)) + { + UnExempt(param1, client); + PrintToChat(param1, "\x04[Self-Mute]\x01 You have removed exempt from self-mute:\x04 %N", client); + } + + menu.RemoveItem(GetMenuSelectionPosition()); + menu.DisplayAt(param1, GetMenuSelectionPosition(), MENU_TIME_FOREVER); + return 0; + } + case MenuAction_DrawItem: + { + int Style; + char aItem[32]; + menu.GetItem(param2, aItem, sizeof(aItem), Style); + + if(!aItem[0]) + return ITEMDRAW_DISABLED; + + if(aItem[0] == '@') + return Style; + + int UserId = StringToInt(aItem); + int client = GetClientOfUserId(UserId); + if(!client) // Player disconnected + return ITEMDRAW_DISABLED; + + return Style; + } + case MenuAction_DisplayItem: + { + int Style; + char aItem[32]; + char aDisp[MAX_NAME_LENGTH + 4]; + menu.GetItem(param2, aItem, sizeof(aItem), Style, aDisp, sizeof(aDisp)); + + if(!aItem[0]) + return 0; + + int UserId = StringToInt(aItem); + int client = GetClientOfUserId(UserId); + if(!client) // Player disconnected + { + char aBuf[MAX_NAME_LENGTH + 4] = "[D] "; + StrCat(aBuf, sizeof(aBuf), aDisp); + if(!StrEqual(aDisp, aBuf)) + return RedrawMenuItem(aBuf); + } + + if(GetExempt(param1, client)) + { + char aBuf[MAX_NAME_LENGTH + 4] = "[E] "; + GetClientName(client, g_PlayerNames[client], sizeof(g_PlayerNames[])); + StrCat(aBuf, sizeof(aBuf), g_PlayerNames[client]); + if(!StrEqual(aDisp, aBuf)) + return RedrawMenuItem(aBuf); + } + + return 0; + } + } + + return 0; +} + +/* + * HOOKS +*/ +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_bIsProtoBuf) + { + g_MsgDest = PbReadInt(bf, "msg_dst"); + g_MsgClient = PbReadInt(bf, "client"); + PbReadString(bf, "msg_name", g_MsgName, sizeof(g_MsgName)); + PbReadString(bf, "params", g_MsgParam1, sizeof(g_MsgParam1), 0); + PbReadString(bf, "params", g_MsgParam2, sizeof(g_MsgParam2), 1); + PbReadString(bf, "params", g_MsgParam3, sizeof(g_MsgParam3), 2); + PbReadString(bf, "params", g_MsgParam4, sizeof(g_MsgParam4), 3); + } + else + { + 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); + } + + // Check which clients need to be excluded. + g_MsgPlayersNum = 0; + for(int i = 0; i < playersNum; 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; +} + +public Action Hook_UserMessageSendAudio(UserMsg msg_id, Handle bf, const int[] players, int playersNum, bool reliable, bool init) +{ + if(g_MsgClient == -1) + return Plugin_Continue; + else if(g_MsgClient == -2) + return Plugin_Handled; + + if(g_bIsProtoBuf) + PbReadString(bf, "radio_sound", g_MsgRadioSound, sizeof(g_MsgRadioSound)); + else + BfReadString(bf, g_MsgRadioSound, sizeof(g_MsgRadioSound), false); + + if(StrEqual(g_MsgRadioSound, "radio.locknload")) + return Plugin_Continue; + + 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); + + for(int i = 0; i < g_MsgPlayersNum; i++) + pack.WriteCell(g_MsgPlayers[i]); + + RequestFrame(OnPlayerRadio, pack); + + return Plugin_Handled; +} + +public void OnPlayerRadio(DataPack pack) +{ + 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(); + + int playersNum = 0; + for(int i = 0; i < g_MsgPlayersNum; i++) + { + int client_ = pack.ReadCell(); + if(IsClientInGame(client_)) + g_MsgPlayers[playersNum++] = client_; + } + CloseHandle(pack); + + Handle RadioText = StartMessage("RadioText", g_MsgPlayers, playersNum, USERMSG_RELIABLE); + if(g_bIsProtoBuf) + { + PbSetInt(RadioText, "msg_dst", g_MsgDest); + PbSetInt(RadioText, "client", g_MsgClient); + PbSetString(RadioText, "msg_name", g_MsgName); + PbSetString(RadioText, "params", g_MsgParam1, 0); + PbSetString(RadioText, "params", g_MsgParam2, 1); + PbSetString(RadioText, "params", g_MsgParam3, 2); + PbSetString(RadioText, "params", g_MsgParam4, 3); + } + else + { + 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 SendAudio = StartMessage("SendAudio", g_MsgPlayers, playersNum, USERMSG_RELIABLE); + if(g_bIsProtoBuf) + PbSetString(SendAudio, "radio_sound", g_MsgRadioSound); + else + BfWriteString(SendAudio, g_MsgRadioSound); + EndMessage(); +} + +/* + * HELPERS +*/ +void UpdateIgnored() +{ + if(g_Plugin_ccc) + CCC_UpdateIgnoredArray(g_Ignored); +} + +public int SortByPlayerName(int elem1, int elem2, const int[] array, Handle hndl) +{ + return strcmp(g_PlayerNames[elem1], g_PlayerNames[elem2], false); +} + +bool GetIgnored(int client, int target) +{ + return g_Ignored[(client * (MAXPLAYERS + 1) + target)]; +} + +void SetIgnored(int client, int target, bool ignored) +{ + g_Ignored[(client * (MAXPLAYERS + 1) + target)] = ignored; +} + +bool GetExempt(int client, int target) +{ + return g_Exempt[client][target]; +} + +void SetExempt(int client, int target, bool exempt) +{ + g_Exempt[client][target] = exempt; +} + +stock bool IsValidClient(int client) +{ + if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client)) + return true; + return false; +} diff --git a/SelfMute/scripting/include/selfmute.inc b/SelfMute/scripting/include/selfmute.inc new file mode 100644 index 0000000..ee5a6f2 --- /dev/null +++ b/SelfMute/scripting/include/selfmute.inc @@ -0,0 +1,6 @@ +#if defined _selfmute_included_ + #endinput +#endif +#define _selfmute_included_ + +native bool SelfMute_IsIgnoring(int client, int target);