diff --git a/addons/sourcemod/plugins/HNS-Anti-Frag.smx b/addons/sourcemod/plugins/HNS-Anti-Frag.smx new file mode 100644 index 0000000..0e23906 Binary files /dev/null and b/addons/sourcemod/plugins/HNS-Anti-Frag.smx differ diff --git a/addons/sourcemod/scripting/HNS-Anti-Frag.sp b/addons/sourcemod/scripting/HNS-Anti-Frag.sp new file mode 100644 index 0000000..c2ecf16 --- /dev/null +++ b/addons/sourcemod/scripting/HNS-Anti-Frag.sp @@ -0,0 +1,467 @@ +#pragma semicolon 1 +#pragma newdecls required + +#include +#include +#include +#include + +#define PLUGIN_VERSION "1.0.2" + +ConVar h_enable_plugin; +ConVar h_e_cooldown_all; +ConVar h_knife_damage; +ConVar g_transparent; +ConVar g_ctransparent; +ConVar g_cbodyR; +ConVar g_cbodyG; +ConVar g_cbodyB; +ConVar g_notify; +ConVar g_notify2; +ConVar h_cooldown; +ConVar gcv_force = null; + +Handle g_bTimer[MAXPLAYERS + 1]; +Handle g_bTimer2[MAXPLAYERS + 1]; + +bool RoundEnd; +bool h_benable_plugin = false; +bool g_btransparent = false; +bool g_bLateLoaded = false; + +float h_fknife_damage; +float h_bcooldown; + +int GetHealth[MAXPLAYERS + 1]; +int g_bctransparent; +int g_bcbodyR; +int g_bcbodyG; +int g_bcbodyB; +int g_bnotify = 0; +int g_bnotify2 = 0; +int h_be_cooldown_all = 0; + +public Plugin myinfo = +{ + name = "[HNS] Anti Frag", + author = "Gold KingZ ", + description = "Modify Knife Damage + Cooldown From Stabbing T's", + version = PLUGIN_VERSION, + url = "https://github.com/oqyh" +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int length) +{ + g_bLateLoaded = late; + return APLRes_Success; +} + +public void OnPluginStart() +{ + LoadTranslations( "HNS-Anti-Frag.phrases" ); + + CreateConVar("hns_f_version", PLUGIN_VERSION, "[HNS] Anti Frag Plugin Version", FCVAR_NOTIFY|FCVAR_DONTRECORD); + + h_enable_plugin = CreateConVar("hns_f_enable_plugin", "1", "Enable Anti-Frag Plugin\n1= Yes\n0= No", _, true, 0.0, true, 1.0); + h_knife_damage = CreateConVar("hns_f_knife_damage", "50.0", "How Much Knife Damage To T's\nDefault: 50 HP"); + h_cooldown = CreateConVar("hns_f_knife_cooldown", "5.0", "(in sec) Cooldown Between Knife Stabs"); + h_e_cooldown_all = CreateConVar("hns_f_ct_cooldown", "1", "How Would You Like Cooldown Will Be For Attacker (CT)\n2= Give Attacker (CT) Cooldown From Stabbing To All T's\n1= Give Victim (T) Who Got Stabbed God Mode(Cooldown From Getting Stabbed) \n0= No (Disable Cooldown)", _, true, 0.0, true, 2.0); + g_transparent = CreateConVar("hns_f_enable_transparent", "0", "Enable Transparent After Damage\n1= Yes\n0= No", _, true, 0.0, true, 1.0); + g_ctransparent = CreateConVar("hns_f_transparent", "120", "How Much Transparent After Hit\n0= Invisible\n120= Transparent\n255=None"); + g_cbodyR = CreateConVar("hns_f_color_r", "255", "Body Red Code Color Pick Here https://www.rapidtables.com/web/color/RGB_Color.html"); + g_cbodyG = CreateConVar("hns_f_color_g", "0", "Body Green Code Color Pick Here https://www.rapidtables.com/web/color/RGB_Color.html"); + g_cbodyB = CreateConVar("hns_f_color_b", "0", "Body Blue Code Color Pick Here https://www.rapidtables.com/web/color/RGB_Color.html"); + g_notify = CreateConVar("hns_f_notify", "1", "Enable Notification Message Chat After Damage For\n3= Both Attacker (CT) And Victim (T)\n2= Victim (T)\n1= Attacker (CT)\n0= No Disable Notify Message", _, true, 0.0, true, 3.0); + g_notify2 = CreateConVar("hns_f_notify_annoc", "0", "Do You Like The Notification Message To Be Announced To All Players About Who Got Stabbed+Killed\n2= Yes With Hp Left\n1= Yes\n0= No Disable Announcer", _, true, 0.0, true, 2.0); + gcv_force = FindConVar("sv_disable_immunity_alpha"); + gcv_force.AddChangeHook(Onchanged); + + HookConVarChange(h_enable_plugin, OnSettingsChanged); + HookConVarChange(h_knife_damage, OnSettingsChanged); + HookConVarChange(h_cooldown, OnSettingsChanged); + HookConVarChange(g_transparent, OnSettingsChanged); + HookConVarChange(g_ctransparent, OnSettingsChanged); + HookConVarChange(g_cbodyR, OnSettingsChanged); + HookConVarChange(g_cbodyG, OnSettingsChanged); + HookConVarChange(g_cbodyB, OnSettingsChanged); + HookConVarChange(g_notify, OnSettingsChanged); + HookConVarChange(g_notify2, OnSettingsChanged); + HookConVarChange(h_e_cooldown_all, OnSettingsChanged); + + HookEvent("round_end", Event_RoundEnd); + HookEvent("round_start", Event_RoundStart); + HookEvent("player_death", Event_player_death); + + if (g_bLateLoaded) + { + for (int i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i)) + { + OnClientPutInServer(i); + } + } + } + + AutoExecConfig(true, "HNS-Anti-Frag"); +} + +public void Onchanged(ConVar convar, const char[] oldValue, const char[] newValue) +{ + if(g_btransparent == true) + { + if(StrEqual (newValue, "0")){ + gcv_force.BoolValue = true; + } + } +} + +public void OnConfigsExecuted() +{ + h_benable_plugin = GetConVarBool(h_enable_plugin); + h_fknife_damage = GetConVarFloat(h_knife_damage); + h_bcooldown = GetConVarFloat(h_cooldown); + g_btransparent = GetConVarBool(g_transparent); + g_bctransparent = GetConVarInt(g_ctransparent); + g_bcbodyR = GetConVarInt(g_cbodyR); + g_bcbodyG = GetConVarInt(g_cbodyG); + g_bcbodyB = GetConVarInt(g_cbodyB); + g_bnotify = GetConVarInt(g_notify); + g_bnotify2 = GetConVarInt(g_notify2); + h_be_cooldown_all = GetConVarInt(h_e_cooldown_all); +} + +public int OnSettingsChanged(Handle convar, const char[] oldValue, const char[] newValue) +{ + if(convar == h_enable_plugin) + { + h_benable_plugin = h_enable_plugin.BoolValue; + } + + if(convar == h_knife_damage) + { + h_fknife_damage = h_knife_damage.FloatValue; + } + + if(convar == h_cooldown) + { + h_bcooldown = h_cooldown.FloatValue; + } + + if(convar == g_transparent) + { + ServerCommand("sv_disable_immunity_alpha 1"); + g_btransparent = g_transparent.BoolValue; + } + + if(convar == g_ctransparent) + { + g_bctransparent = g_ctransparent.IntValue; + } + + if(convar == g_cbodyR) + { + g_bcbodyR = g_cbodyR.IntValue; + } + + if(convar == g_cbodyG) + { + g_bcbodyG = g_cbodyG.IntValue; + } + + if(convar == g_cbodyB) + { + g_bcbodyB = g_cbodyB.IntValue; + } + + if(convar == g_notify) + { + g_bnotify = g_notify.IntValue; + } + + if(convar == g_notify2) + { + g_bnotify2 = g_notify2.IntValue; + } + + if(convar == h_e_cooldown_all) + { + h_be_cooldown_all = h_e_cooldown_all.IntValue; + } + + return 0; +} + +public void OnClientPutInServer(int client) +{ + SDKHook(client, SDKHook_OnTakeDamage, OneHitDamage); +} + +public void OnClientDisconnect(int client) +{ + GetHealth[client] =0; + + if (g_bTimer[client] != INVALID_HANDLE) + { + delete g_bTimer[client]; + } + + if (g_bTimer2[client] != INVALID_HANDLE) + { + delete g_bTimer2[client]; + } +} +public Action Event_player_death(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(GetEventInt(event, "userid")); + + if(IsValidClient(client)) + { + GetHealth[client] =0; + + SetEntityRenderMode(client, RENDER_NORMAL); + SetEntityRenderColor(client, 255, 255, 255, 255); + + if (g_bTimer[client] != INVALID_HANDLE) + { + delete g_bTimer[client]; + } + + if (g_bTimer2[client] != INVALID_HANDLE) + { + delete g_bTimer2[client]; + } + } + return Plugin_Continue; +} +public Action Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) +{ + RoundEnd = true; + + for (int i = 1; i <= MaxClients; i++) + { + if(IsValidClient(i)) + { + GetHealth[i] =0; + + SetEntityRenderMode(i, RENDER_NORMAL); + SetEntityRenderColor(i, 255, 255, 255, 255); + + if (g_bTimer[i] != INVALID_HANDLE) + { + delete g_bTimer[i]; + } + + if (g_bTimer2[i] != INVALID_HANDLE) + { + delete g_bTimer2[i]; + } + + } + } + return Plugin_Continue; +} + +public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) +{ + RoundEnd = false; +} + +public Action OneHitDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype) +{ + if (!h_benable_plugin || !IsValidClient(victim) || !IsValidClient(attacker)) + { + return Plugin_Continue; + } + + if(g_bTimer[victim] != INVALID_HANDLE || g_bTimer2[attacker] != INVALID_HANDLE) + return Plugin_Handled; + + if(IsValidClient(victim) && IsValidClient(attacker)) + { + char weapon[64]; + GetClientWeapon(attacker, weapon, sizeof(weapon)); + if ((damagetype & DMG_SLASH) && GetClientTeam(attacker) == CS_TEAM_CT && GetClientTeam(victim) == CS_TEAM_T && RoundEnd == false) + { + if(h_fknife_damage <= 5.0) + { + damage = h_fknife_damage + 1.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 1; + }else if(h_fknife_damage <= 11.0) + { + damage = h_fknife_damage + 2.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 2; + }else if(h_fknife_damage <= 17.0) + { + damage = h_fknife_damage + 3.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 3; + }else if(h_fknife_damage <= 22.0) + { + damage = h_fknife_damage + 4.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 4; + }else if(h_fknife_damage <= 27.0) + { + damage = h_fknife_damage + 5.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 5; + }else if(h_fknife_damage <= 32.0) + { + damage = h_fknife_damage + 6.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 6; + }else if(h_fknife_damage <= 38.0) + { + damage = h_fknife_damage + 7.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 7; + }else if(h_fknife_damage <= 44.0) + { + damage = h_fknife_damage + 8.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 8; + }else if(h_fknife_damage <= 50.0) + { + damage = h_fknife_damage + 9.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 9; + }else if(h_fknife_damage <= 56.0) + { + damage = h_fknife_damage + 10.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 10; + }else if(h_fknife_damage <= 62.0) + { + damage = h_fknife_damage + 11.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 11; + }else if(h_fknife_damage <= 68.0) + { + damage = h_fknife_damage + 12.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 12; + }else if(h_fknife_damage <= 73.0) + { + damage = h_fknife_damage + 13.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 13; + }else if(h_fknife_damage <= 78.0) + { + damage = h_fknife_damage + 14.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 14; + }else if(h_fknife_damage <= 84.0) + { + damage = h_fknife_damage + 15.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 15; + }else if(h_fknife_damage <= 90.0) + { + damage = h_fknife_damage + 16.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 16; + }else if(h_fknife_damage <= 96.0) + { + damage = h_fknife_damage + 17.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 17; + }else if(h_fknife_damage <= 102.0) + { + damage = h_fknife_damage + 18.0; + GetHealth[victim] = GetClientHealth(victim) - RoundToFloor(damage) + 18; + } + + float cooldown = h_bcooldown; + + if(g_bnotify == 1) + { + if(h_be_cooldown_all == 1) + { + CPrintToChat(attacker, " %t","CooldownCTNotify", cooldown, victim); + }else if(h_be_cooldown_all == 2) + { + CPrintToChat(attacker, " %t","CooldownCTNotifyTeamT", cooldown); + } + }else if(g_bnotify == 2) + { + if(h_be_cooldown_all == 1 || h_be_cooldown_all == 2) + { + CPrintToChat(victim, " %t", "CooldownTNotify", cooldown); + } + }else if(g_bnotify == 3) + { + if(h_be_cooldown_all == 1) + { + CPrintToChat(victim, " %t", "CooldownTNotify", cooldown); + CPrintToChat(attacker, " %t","CooldownCTNotify", cooldown, victim); + }else if(h_be_cooldown_all == 2) + { + CPrintToChat(victim, " %t", "CooldownTNotify", cooldown); + CPrintToChat(attacker, " %t","CooldownCTNotifyTeamT", cooldown); + } + } + + if(g_bnotify2 == 1) + { + if(GetHealth[victim] >= 1) + { + CPrintToChatAll(" %t","CooldownCTAnnouncedWithoutHP", attacker, victim); + }else + { + CPrintToChatAll(" %t","CooldownCTAnnouncedWithoutHPDead", attacker, victim); + } + }else if(g_bnotify2 == 2) + { + if(GetHealth[victim] >= 1) + { + CPrintToChatAll(" %t","CooldownCTAnnouncedWithHP", attacker, victim, GetHealth[victim]); + }else + { + CPrintToChatAll(" %t","CooldownCTAnnouncedWithHPDead", attacker, victim); + } + } + + if(h_be_cooldown_all == 1) + { + g_bTimer[victim] = CreateTimer(cooldown, Time_Disable, victim); + }else if(h_be_cooldown_all == 2) + { + g_bTimer2[attacker] = CreateTimer(cooldown, Time_Disable2, attacker); + g_bTimer[victim] = CreateTimer(cooldown, Time_Disable, victim); + } + + if(g_btransparent && h_be_cooldown_all == 2 || g_btransparent && h_be_cooldown_all == 1){ + SetEntityRenderMode(victim, RENDER_TRANSALPHA); + SetEntityRenderColor(victim, g_bcbodyR, g_bcbodyG, g_bcbodyB, g_bctransparent); + }else if(!g_btransparent){ + SetEntityRenderMode(victim, RENDER_TRANSALPHA); + SetEntityRenderColor(victim, g_bcbodyR, g_bcbodyG, g_bcbodyB, 255); + } + return Plugin_Changed; + } + } + return Plugin_Continue; +} + + +public Action Time_Disable2(Handle timer, any attacker) +{ + if(IsValidClient(attacker)) + { + if (g_bTimer2[attacker] != INVALID_HANDLE) + { + g_bTimer2[attacker] = INVALID_HANDLE; + delete g_bTimer2[attacker]; + } + } + return Plugin_Continue; +} + +public Action Time_Disable(Handle timer, any victim) +{ + if(IsValidClient(victim)) + { + SetEntityRenderMode(victim, RENDER_NORMAL); + SetEntityRenderColor(victim, 255, 255, 255, 255); + if (g_bTimer[victim] != INVALID_HANDLE) + { + g_bTimer[victim] = INVALID_HANDLE; + delete g_bTimer[victim]; + } + } + return Plugin_Continue; +} + +static bool IsValidClient( int client ) +{ + if ( !( 1 <= client <= MaxClients ) || !IsClientInGame(client)) + return false; + + return true; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/include/multicolors.inc b/addons/sourcemod/scripting/include/multicolors.inc new file mode 100644 index 0000000..9bbfc10 --- /dev/null +++ b/addons/sourcemod/scripting/include/multicolors.inc @@ -0,0 +1,461 @@ +#if defined _multicolors_included + #endinput +#endif +#define _multicolors_included + +#define MuCo_VERSION "2.1.2" + +#include "multicolors/morecolors" +#include "multicolors/colors" + +/* +* +* Credits: +* - Popoklopsi +* - Powerlord +* - exvel +* - Dr. McKay +* +* Based on stamm-colors +* - https://github.com/popoklopsi/Stamm/blob/master/include/stamm/stamm-colors.inc +* +*/ + + + +#define PREFIX_MAX_LENGTH 64 +#define PREFIX_SEPARATOR "{default} " + +/* Global var to check whether colors are fixed or not */ +static bool g_bCFixColors; + +static char g_sCPrefix[PREFIX_MAX_LENGTH]; + +/** + * Add a chat prefix before all chat msg + * + * @param sPrefix Prefix + */ +stock void CSetPrefix(const char[] sPrefix, any ...) { + if (!sPrefix[0]) { + return; + } + + SetGlobalTransTarget(LANG_SERVER); + VFormat(g_sCPrefix, sizeof(g_sCPrefix) - strlen(PREFIX_SEPARATOR), sPrefix, 2); + + // Add ending space + Format(g_sCPrefix, sizeof(g_sCPrefix), "%s%s", g_sCPrefix, PREFIX_SEPARATOR); +} + +/** + * Add a chat prefix before all chat msg + * + * @param sPrefix Prefix + */ +stock void CClearPrefix() { + g_sCPrefix[0] = '\0'; +} + +/** + * Writes a message to a client with the correct stock for the game. + * + * @param client Client index. + * @param message Message (formatting rules). + * + * @error If the client is not connected an error will be thrown. + */ +stock void CPrintToChat(int client, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_PrintToChat(client, "%s%s", g_sCPrefix, buffer); + } + else { + MC_PrintToChat(client, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param message Message (formatting rules) + */ +stock void CPrintToChatAll(const char[] message, any ...) { + if (!g_bCFixColors) { + CFixColors(); + } + + char buffer[MAX_BUFFER_LENGTH]; + if (!IsSource2009()) { + for (int i = 1; i <= MaxClients; ++i) { + if (IsClientInGame(i) && !IsFakeClient(i) && !C_SkipList[i]) { + SetGlobalTransTarget(i); + VFormat(buffer, sizeof(buffer), message, 2); + + C_PrintToChat(i, "%s", buffer); + } + + C_SkipList[i] = false; + } + } + else { + MC_CheckTrie(); + + char buffer2[MAX_BUFFER_LENGTH]; + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || MC_SkipList[i]) { + MC_SkipList[i] = false; + continue; + } + + SetGlobalTransTarget(i); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 2); + + MC_ReplaceColorCodes(buffer2); + MC_SendMessage(i, buffer2); + } + } +} + +/** + * Writes a message to all of a client's observers. + * + * @param target Client index. + * @param message Message (formatting rules). + */ +stock void CPrintToChatObservers(int target, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + for (int client = 1; client <= MaxClients; client++) { + if (IsClientInGame(client) && !IsPlayerAlive(client) && !IsFakeClient(client)) { + int observee = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); + int ObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode"); + + if (observee == target && (ObserverMode == 4 || ObserverMode == 5)) { + CPrintToChat(client, buffer); + } + } + } +} + +/** + * Writes a message to a client with the correct stock for the game. + * + * @param client Client index. + * @param author Author index. + * @param message Message (formatting rules). + * + * @error If the client is not connected an error will be thrown. + */ +stock void CPrintToChatEx(int client, int author, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_PrintToChatEx(client, author, "%s%s", g_sCPrefix, buffer); + } + else { + MC_PrintToChatEx(client, author, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Writes a message to all clients with the correct stock for the game. + * + * @param author Author index. + * @param message Message (formatting rules). + */ +stock void CPrintToChatAllEx(int author, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_PrintToChatAllEx(author, "%s%s", g_sCPrefix, buffer); + } + else { + MC_PrintToChatAllEx(author, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Writes a message to all of a client's observers with the correct + * game stock. + * + * @param target Client index. + * @param message Message (formatting rules). + */ +stock void CPrintToChatObserversEx(int target, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + for (int client = 1; client <= MaxClients; client++) { + if (IsClientInGame(client) && !IsPlayerAlive(client) && !IsFakeClient(client)) { + int observee = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); + int ObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode"); + + if (observee == target && (ObserverMode == 4 || ObserverMode == 5)) { + CPrintToChatEx(client, target, buffer); + } + } + } +} + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param message Message (formatting rules) + */ +stock void CReplyToCommand(int client, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ReplyToCommand(client, "%s%s", g_sCPrefix, buffer); + } + else { + MC_ReplyToCommand(client, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param author Client to use for {teamcolor} + * @param message Message (formatting rules) + */ +stock void CReplyToCommandEx(int client, int author, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ReplyToCommandEx(client, author, "%s%s", g_sCPrefix, buffer); + } + else { + MC_ReplyToCommandEx(client, author, "%s%s", g_sCPrefix, buffer); + } +} + +/** + * Remove all tags and print to server + * + * @param message Message (formatting rules) + */ +stock void CPrintToServer(const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + char prefixBuffer[PREFIX_MAX_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 2); + strcopy(prefixBuffer, sizeof(prefixBuffer), g_sCPrefix); + + if (!g_bCFixColors) { + CFixColors(); + } + + CRemoveTags(buffer, sizeof(buffer)); + CRemoveTags(prefixBuffer, sizeof(prefixBuffer)); + + PrintToServer("%s%s", prefixBuffer, buffer); +} + +/** + * Displays usage of an admin command to users depending on the + * setting of the sm_show_activity cvar. + * + * This version does not display a message to the originating client + * if used from chat triggers or menus. If manual replies are used + * for these cases, then this function will suffice. Otherwise, + * CShowActivity2() is slightly more useful. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * + * @error + */ +stock void CShowActivity(int author, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 3); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ShowActivity(author, "%s", buffer); + } + else { + MC_ShowActivity(author, "%s", buffer); + } +} + +/** + * Same as C_ShowActivity(), except the tag parameter is used instead of "[SM] " (note that you must supply any spacing). + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to display with. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * + * @error + */ +stock void CShowActivityEx(int author, const char[] tag, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ShowActivityEx(author, tag, "%s", buffer); + } + else { + MC_ShowActivityEx(author, tag, "%s", buffer); + } +} + +/** + * Displays usage of an admin command to users depending on the setting of the sm_show_activity cvar. + * All users receive a message in their chat text, except for the originating client, + * who receives the message based on the current ReplySource. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to prepend to the message. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * + * @error + */ + stock void CShowActivity2(int author, const char[] tag, const char[] message, any ...) { + char buffer[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(LANG_SERVER); + VFormat(buffer, sizeof(buffer), message, 4); + + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + C_ShowActivity2(author, tag, "%s", buffer); + } + else { + MC_ShowActivity2(author, tag, "%s", buffer); + } +} + + +/** + * Replaces color tags in a string with color codes + * + * @param message String. + * @param maxlength Maximum length of the string buffer. + */ +stock void CFormatColor(char[] message, int maxlength, int author = -1) { + if (!g_bCFixColors) { + CFixColors(); + } + + if (!IsSource2009()) { + if (author == 0) { + author = -1; + } + + C_Format(message, maxlength, author); + } + else { + if (author == -1) { + author = 0; + } + + MC_ReplaceColorCodes(message, author, false, maxlength); + } +} + +/** + * Removes color tags from a message + * + * @param message Message to remove tags from + * @param maxlen Maximum buffer length + */ +stock void CRemoveTags(char[] message, int maxlen) { + if (!IsSource2009()) { + C_RemoveTags(message, maxlen); + } + else { + MC_RemoveTags(message, maxlen); + } +} + +/** + * Fixes missing Lightgreen color. + */ +stock void CFixColors() { + g_bCFixColors = true; + + // Replace lightgreen if not exists + if (!C_ColorAllowed(Color_Lightgreen)) { + if (C_ColorAllowed(Color_Lime)) { + C_ReplaceColor(Color_Lightgreen, Color_Lime); + } + else if (C_ColorAllowed(Color_Olive)) { + C_ReplaceColor(Color_Lightgreen, Color_Olive); + } + } +} + +stock bool IsSource2009() { + return (GetEngineVersion() == Engine_CSS + || GetEngineVersion() == Engine_HL2DM + || GetEngineVersion() == Engine_DODS + || GetEngineVersion() == Engine_TF2 + || GetEngineVersion() == Engine_SDK2013); +} diff --git a/addons/sourcemod/scripting/include/multicolors/colors.inc b/addons/sourcemod/scripting/include/multicolors/colors.inc new file mode 100644 index 0000000..170ec97 --- /dev/null +++ b/addons/sourcemod/scripting/include/multicolors/colors.inc @@ -0,0 +1,905 @@ +/************************************************************************** + * * + * Colored Chat Functions * + * Author: exvel, Editor: Popoklopsi, Powerlord, Bara * + * Version: 2.0.0-MC * + * * + **************************************************************************/ + + +#if defined _colors_included + #endinput +#endif +#define _colors_included + +#define MAX_MESSAGE_LENGTH 250 +#define MAX_COLORS 18 + +#define SERVER_INDEX 0 +#define NO_INDEX -1 +#define NO_PLAYER -2 + +enum C_Colors { + Color_Default = 0, + Color_Darkred, + Color_Green, + Color_Lightgreen, + Color_Red, + Color_Blue, + Color_Olive, + Color_Lime, + Color_Lightred, + Color_Purple, + Color_Grey, + Color_Yellow, + Color_Orange, + Color_Bluegrey, + Color_Lightblue, + Color_Darkblue, + Color_Grey2, + Color_Orchid, + Color_Lightred2 +} + +/* C_Colors' properties */ +char C_Tag[][] = {"{default}", "{darkred}", "{green}", "{lightgreen}", "{red}", "{blue}", "{olive}", "{lime}", "{lightred}", "{purple}", "{grey}", "{yellow}", "{orange}", "{bluegrey}", "{lightblue}", "{darkblue}", "{grey2}", "{orchid}", "{lightred2}"}; +char C_TagCode[][] = {"\x01", "\x02", "\x04", "\x03", "\x03", "\x03", "\x05", "\x06", "\x07", "\x03", "\x08", "\x09", "\x10", "\x0A", "\x0B", "\x0C", "\x0D", "\x0E", "\x0F"}; +bool C_TagReqSayText2[] = {false, false, false, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false}; +bool C_EventIsHooked; +bool C_SkipList[MAXPLAYERS+1]; + +/* Game default profile */ +bool C_Profile_Colors[] = {true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}; +int C_Profile_TeamIndex[] = {NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX}; +bool C_Profile_SayText2; + +static ConVar sm_show_activity; + +/** + * Prints a message to a specific client in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param szMessage Message (formatting rules). + * @return No return + * + * On error/Errors: If the client is not connected an error will be thrown. + */ +stock void C_PrintToChat(int client, const char[] szMessage, any ...) { + if (client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %d", client); + } + + if (!IsClientInGame(client)) { + ThrowError("Client %d is not in game", client); + } + + char szBuffer[MAX_MESSAGE_LENGTH]; + char szCMessage[MAX_MESSAGE_LENGTH]; + + SetGlobalTransTarget(client); + + Format(szBuffer, sizeof(szBuffer), "\x01%s", szMessage); + VFormat(szCMessage, sizeof(szCMessage), szBuffer, 3); + + int index = C_Format(szCMessage, sizeof(szCMessage)); + + if (index == NO_INDEX) { + PrintToChat(client, "%s", szCMessage); + } + else { + C_SayText2(client, index, szCMessage); + } +} + +/** + * Reples to a message in a command. A client index of 0 will use PrintToServer(). + * If the command was from the console, PrintToConsole() is used. If the command was from chat, C_PrintToChat() is used. + * Supports color tags. + * + * @param client Client index, or 0 for server. + * @param szMessage Formatting rules. + * @param ... Variable number of format parameters. + * @return No return + * + * On error/Errors: If the client is not connected or invalid. + */ +stock void C_ReplyToCommand(int client, const char[] szMessage, any ...) { + char szCMessage[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(szCMessage, sizeof(szCMessage), szMessage, 3); + + if (client == 0) { + C_RemoveTags(szCMessage, sizeof(szCMessage)); + PrintToServer("%s", szCMessage); + } + else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE) { + C_RemoveTags(szCMessage, sizeof(szCMessage)); + PrintToConsole(client, "%s", szCMessage); + } + else { + C_PrintToChat(client, "%s", szCMessage); + } +} + +/** + * Reples to a message in a command. A client index of 0 will use PrintToServer(). + * If the command was from the console, PrintToConsole() is used. If the command was from chat, C_PrintToChat() is used. + * Supports color tags. + * + * @param client Client index, or 0 for server. + * @param author Author index whose color will be used for teamcolor tag. + * @param szMessage Formatting rules. + * @param ... Variable number of format parameters. + * @return No return + * + * On error/Errors: If the client is not connected or invalid. + */ +stock void C_ReplyToCommandEx(int client, int author, const char[] szMessage, any ...) { + char szCMessage[MAX_MESSAGE_LENGTH]; + SetGlobalTransTarget(client); + VFormat(szCMessage, sizeof(szCMessage), szMessage, 4); + + if (client == 0) { + C_RemoveTags(szCMessage, sizeof(szCMessage)); + PrintToServer("%s", szCMessage); + } + else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE) { + C_RemoveTags(szCMessage, sizeof(szCMessage)); + PrintToConsole(client, "%s", szCMessage); + } + else { + C_PrintToChatEx(client, author, "%s", szCMessage); + } +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param szMessage Message (formatting rules) + * @return No return + */ +stock void C_PrintToChatAll(const char[] szMessage, any ...) { + char szBuffer[MAX_MESSAGE_LENGTH]; + + for (int i = 1; i <= MaxClients; ++i) { + if (IsClientInGame(i) && !IsFakeClient(i) && !C_SkipList[i]) { + SetGlobalTransTarget(i); + VFormat(szBuffer, sizeof(szBuffer), szMessage, 2); + + C_PrintToChat(i, "%s", szBuffer); + } + + C_SkipList[i] = false; + } +} + +/** + * Prints a message to a specific client in the chat area. + * Supports color tags and teamcolor tag. + * + * @param client Client index. + * @param author Author index whose color will be used for teamcolor tag. + * @param szMessage Message (formatting rules). + * @return No return + * + * On error/Errors: If the client or author are not connected an error will be thrown. + */ +stock void C_PrintToChatEx(int client, int author, const char[] szMessage, any ...) { + if (client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %d", client); + } + + if (!IsClientInGame(client)) { + ThrowError("Client %d is not in game", client); + } + + if (author < 0 || author > MaxClients) { + ThrowError("Invalid client index %d", author); + } + + char szBuffer[MAX_MESSAGE_LENGTH]; + char szCMessage[MAX_MESSAGE_LENGTH]; + + SetGlobalTransTarget(client); + + Format(szBuffer, sizeof(szBuffer), "\x01%s", szMessage); + VFormat(szCMessage, sizeof(szCMessage), szBuffer, 4); + + int index = C_Format(szCMessage, sizeof(szCMessage), author); + + if (index == NO_INDEX) { + PrintToChat(client, "%s", szCMessage); + } + else { + C_SayText2(client, author, szCMessage); + } +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags and teamcolor tag. + * + * @param author Author index whos color will be used for teamcolor tag. + * @param szMessage Message (formatting rules). + * @return No return + * + * On error/Errors: If the author is not connected an error will be thrown. + */ +stock void C_PrintToChatAllEx(int author, const char[] szMessage, any ...) { + if (author < 0 || author > MaxClients) { + ThrowError("Invalid client index %d", author); + } + + if (!IsClientInGame(author)) { + ThrowError("Client %d is not in game", author); + } + + char szBuffer[MAX_MESSAGE_LENGTH]; + + for (int i = 1; i <= MaxClients; ++i) { + if (IsClientInGame(i) && !IsFakeClient(i) && !C_SkipList[i]) { + SetGlobalTransTarget(i); + VFormat(szBuffer, sizeof(szBuffer), szMessage, 3); + + C_PrintToChatEx(i, author, "%s", szBuffer); + } + + C_SkipList[i] = false; + } +} + +/** + * Removes color tags from the string. + * + * @param szMessage String. + * @return No return + */ +stock void C_RemoveTags(char[] szMessage, int maxlength) { + for (int i = 0; i < MAX_COLORS; i++) { + ReplaceString(szMessage, maxlength, C_Tag[i], "", false); + } + + ReplaceString(szMessage, maxlength, "{teamcolor}", "", false); +} + +/** + * Checks whether a color is allowed or not + * + * @param tag Color Tag. + * @return True when color is supported, otherwise false + */ +stock bool C_ColorAllowed(C_Colors color) { + if (!C_EventIsHooked) { + C_SetupProfile(); + + C_EventIsHooked = true; + } + + return C_Profile_Colors[color]; +} + +/** + * Replace the color with another color + * Handle with care! + * + * @param color color to replace. + * @param newColor color to replace with. + * @noreturn + */ +stock void C_ReplaceColor(C_Colors color, C_Colors newColor) { + if (!C_EventIsHooked) { + C_SetupProfile(); + + C_EventIsHooked = true; + } + + C_Profile_Colors[color] = C_Profile_Colors[newColor]; + C_Profile_TeamIndex[color] = C_Profile_TeamIndex[newColor]; + + C_TagReqSayText2[color] = C_TagReqSayText2[newColor]; + Format(C_TagCode[color], sizeof(C_TagCode[]), C_TagCode[newColor]); +} + +/** + * This function should only be used right in front of + * C_PrintToChatAll or C_PrintToChatAllEx and it tells + * to those funcions to skip specified client when printing + * message to all clients. After message is printed client will + * no more be skipped. + * + * @param client Client index + * @return No return + */ +stock void C_SkipNextClient(int client) { + if (client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %d", client); + } + + C_SkipList[client] = true; +} + +/** + * Replaces color tags in a string with color codes + * + * @param szMessage String. + * @param maxlength Maximum length of the string buffer. + * @return Client index that can be used for SayText2 author index + * + * On error/Errors: If there is more then one team color is used an error will be thrown. + */ +stock int C_Format(char[] szMessage, int maxlength, int author = NO_INDEX) { + /* Hook event for auto profile setup on map start */ + if (!C_EventIsHooked) { + C_SetupProfile(); + HookEvent("server_spawn", C_Event_MapStart, EventHookMode_PostNoCopy); + + C_EventIsHooked = true; + } + + int iRandomPlayer = NO_INDEX; + + // On CS:GO set invisible precolor + if (GetEngineVersion() == Engine_CSGO) { + Format(szMessage, maxlength, " %s", szMessage); + } + + /* If author was specified replace {teamcolor} tag */ + if (author != NO_INDEX) { + if (C_Profile_SayText2) { + ReplaceString(szMessage, maxlength, "{teamcolor}", "\x03", false); + + iRandomPlayer = author; + } + /* If saytext2 is not supported by game replace {teamcolor} with green tag */ + else { + ReplaceString(szMessage, maxlength, "{teamcolor}", C_TagCode[Color_Green], false); + } + } + else { + ReplaceString(szMessage, maxlength, "{teamcolor}", "", false); + } + + /* For other color tags we need a loop */ + for (int i = 0; i < MAX_COLORS; i++) { + /* If tag not found - skip */ + if (StrContains(szMessage, C_Tag[i], false) == -1) { + continue; + } + + /* If tag is not supported by game replace it with green tag */ + else if (!C_Profile_Colors[i]) { + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[Color_Green], false); + } + + /* If tag doesn't need saytext2 simply replace */ + else if (!C_TagReqSayText2[i]) { + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[i], false); + } + + /* Tag needs saytext2 */ + else { + /* If saytext2 is not supported by game replace tag with green tag */ + if (!C_Profile_SayText2) { + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[Color_Green], false); + } + + /* Game supports saytext2 */ + else { + /* If random player for tag wasn't specified replace tag and find player */ + if (iRandomPlayer == NO_INDEX) { + /* Searching for valid client for tag */ + iRandomPlayer = C_FindRandomPlayerByTeam(C_Profile_TeamIndex[i]); + + /* If player not found replace tag with green color tag */ + if (iRandomPlayer == NO_PLAYER) { + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[Color_Green], false); + } + + /* If player was found simply replace */ + else { + ReplaceString(szMessage, maxlength, C_Tag[i], C_TagCode[i], false); + } + + } + /* If found another team color tag throw error */ + else { + //ReplaceString(szMessage, maxlength, C_Tag[i], ""); + ThrowError("Using two team colors in one message is not allowed"); + } + } + } + } + + return iRandomPlayer; +} + +/** + * Finds a random player with specified team + * + * @param color_team Client team. + * @return Client index or NO_PLAYER if no player found + */ +stock int C_FindRandomPlayerByTeam(int color_team) { + if (color_team == SERVER_INDEX) { + return 0; + } + + int[] players = new int[MaxClients]; + int count; + + for (int i = 1; i <= MaxClients; ++i) { + if (IsClientInGame(i) && GetClientTeam(i) == color_team) { + players[count++] = i; + } + } + + if (count) { + return players[GetRandomInt(0, count-1)]; + } + + return NO_PLAYER; +} + +/** + * Sends a SayText2 usermessage to a client + * + * @param szMessage Client index + * @param maxlength Author index + * @param szMessage Message + * @return No return. + */ +stock void C_SayText2(int client, int author, const char[] szMessage) { + Handle hBuffer = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS); + + if (GetFeatureStatus(FeatureType_Native, "GetUserMessageType") == FeatureStatus_Available && GetUserMessageType() == UM_Protobuf) { + Protobuf pb = UserMessageToProtobuf(hBuffer); + pb.SetInt("ent_idx", author); + pb.SetBool("chat", true); + pb.SetString("msg_name", szMessage); + pb.AddString("params", ""); + pb.AddString("params", ""); + pb.AddString("params", ""); + pb.AddString("params", ""); + } + else { + BfWrite bf = UserMessageToBfWrite(hBuffer); + bf.WriteByte(author); + bf.WriteByte(true); + bf.WriteString(szMessage); + } + + EndMessage(); +} + +/** + * Creates game color profile + * This function must be edited if you want to add more games support + * + * @return No return. + */ +stock void C_SetupProfile() { + EngineVersion engine = GetEngineVersion(); + + if (engine == Engine_CSS) { + C_Profile_Colors[Color_Lightgreen] = true; + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; + C_Profile_TeamIndex[Color_Red] = 2; + C_Profile_TeamIndex[Color_Blue] = 3; + C_Profile_SayText2 = true; + } + else if (engine == Engine_CSGO) { + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_Colors[Color_Darkred] = true; + C_Profile_Colors[Color_Lime] = true; + C_Profile_Colors[Color_Lightred] = true; + C_Profile_Colors[Color_Purple] = true; + C_Profile_Colors[Color_Grey] = true; + C_Profile_Colors[Color_Yellow] = true; + C_Profile_Colors[Color_Orange] = true; + C_Profile_Colors[Color_Bluegrey] = true; + C_Profile_Colors[Color_Lightblue] = true; + C_Profile_Colors[Color_Darkblue] = true; + C_Profile_Colors[Color_Grey2] = true; + C_Profile_Colors[Color_Orchid] = true; + C_Profile_Colors[Color_Lightred2] = true; + C_Profile_TeamIndex[Color_Red] = 2; + C_Profile_TeamIndex[Color_Blue] = 3; + C_Profile_SayText2 = true; + } + else if (engine == Engine_TF2) { + C_Profile_Colors[Color_Lightgreen] = true; + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; + C_Profile_TeamIndex[Color_Red] = 2; + C_Profile_TeamIndex[Color_Blue] = 3; + C_Profile_SayText2 = true; + } + else if (engine == Engine_Left4Dead || engine == Engine_Left4Dead2) { + C_Profile_Colors[Color_Lightgreen] = true; + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; + C_Profile_TeamIndex[Color_Red] = 3; + C_Profile_TeamIndex[Color_Blue] = 2; + C_Profile_SayText2 = true; + } + else if (engine == Engine_HL2DM) { + /* hl2mp profile is based on mp_teamplay convar */ + if (GetConVarBool(FindConVar("mp_teamplay"))) { + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_Colors[Color_Olive] = true; + C_Profile_TeamIndex[Color_Red] = 3; + C_Profile_TeamIndex[Color_Blue] = 2; + C_Profile_SayText2 = true; + } + else { + C_Profile_SayText2 = false; + C_Profile_Colors[Color_Olive] = true; + } + } + else if (engine == Engine_DODS) { + C_Profile_Colors[Color_Olive] = true; + C_Profile_SayText2 = false; + } + /* Profile for other games */ + else { + if (GetUserMessageId("SayText2") == INVALID_MESSAGE_ID) { + C_Profile_SayText2 = false; + } + else { + C_Profile_Colors[Color_Red] = true; + C_Profile_Colors[Color_Blue] = true; + C_Profile_TeamIndex[Color_Red] = 2; + C_Profile_TeamIndex[Color_Blue] = 3; + C_Profile_SayText2 = true; + } + } +} + +public void C_Event_MapStart(Event event, const char[] name, bool dontBroadcast) { + C_SetupProfile(); + + for (int i = 1; i <= MaxClients; ++i) { + C_SkipList[i] = false; + } +} + +/** + * Displays usage of an admin command to users depending on the + * setting of the sm_show_activity cvar. + * + * This version does not display a message to the originating client + * if used from chat triggers or menus. If manual replies are used + * for these cases, then this function will suffice. Otherwise, + * C_ShowActivity2() is slightly more useful. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock int C_ShowActivity(int client, const char[] format, any ...) { + if (sm_show_activity == null) { + sm_show_activity = FindConVar("sm_show_activity"); + } + + char tag[] = "[SM] "; + + char szBuffer[MAX_MESSAGE_LENGTH]; + //char szCMessage[MAX_MESSAGE_LENGTH]; + int value = sm_show_activity.IntValue; + ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + bool display_in_chat = false; + if (client != 0) { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) { + ThrowError("Client index %d is invalid", client); + } + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID || !GetAdminFlag(id, Admin_Generic, Access_Effective)) { + sign = "PLAYER"; + } + + /* Display the message to the client? */ + if (replyto == SM_REPLY_TO_CONSOLE) { + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToConsole(client, "%s%s", tag, szBuffer); + display_in_chat = true; + } + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s", tag, szBuffer); + } + + if (!value) { + return 1; + } + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || IsFakeClient(i) || (display_in_chat && i == client)) { + continue; + } + + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID || !GetAdminFlag(id, Admin_Generic, Access_Effective)) { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 2) || (i == client)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else { + /* Treat this as an admin user */ + bool is_root = GetAdminFlag(id, Admin_Root, Access_Effective); + if ((value & 4) || (value & 8) || ((value & 16) && is_root)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 8) || ((value & 16) && is_root) || (i == client)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Same as C_ShowActivity(), except the tag parameter is used instead of "[SM] " (note that you must supply any spacing). + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to display with. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock int C_ShowActivityEx(int client, const char[] tag, const char[] format, any ...) { + if (sm_show_activity == null) { + sm_show_activity = FindConVar("sm_show_activity"); + } + + char szTag[MAX_MESSAGE_LENGTH]; + strcopy(szTag, sizeof(szTag), tag); + MC_RemoveTags(szTag, sizeof(szTag)); + + char szBuffer[MAX_MESSAGE_LENGTH]; + //char szCMessage[MAX_MESSAGE_LENGTH]; + int value = sm_show_activity.IntValue; + ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + bool display_in_chat = false; + if (client != 0) { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) { + ThrowError("Client index %d is invalid", client); + } + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID || !GetAdminFlag(id, Admin_Generic, Access_Effective)) { + sign = "PLAYER"; + } + + /* Display the message to the client? */ + if (replyto == SM_REPLY_TO_CONSOLE) { + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToConsole(client, "%s%s", szTag, szBuffer); + display_in_chat = true; + } + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s", szTag, szBuffer); + } + + if (!value) { + return 1; + } + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || IsFakeClient(i) || (display_in_chat && i == client)) { + continue; + } + + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID || !GetAdminFlag(id, Admin_Generic, Access_Effective)) { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 2) || (i == client)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else { + /* Treat this as an admin user */ + bool is_root = GetAdminFlag(id, Admin_Root, Access_Effective); + if ((value & 4) || (value & 8) || ((value & 16) && is_root)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 8) || ((value & 16) && is_root) || (i == client)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Displays usage of an admin command to users depending on the setting of the sm_show_activity cvar. + * All users receive a message in their chat text, except for the originating client, + * who receives the message based on the current ReplySource. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to prepend to the message. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + * @error + */ +stock int C_ShowActivity2(int client, const char[] tag, const char[] format, any ...) { + if (sm_show_activity == null) { + sm_show_activity = FindConVar("sm_show_activity"); + } + + char szTag[MAX_MESSAGE_LENGTH]; + strcopy(szTag, sizeof(szTag), tag); + MC_RemoveTags(szTag, sizeof(szTag)); + + char szBuffer[MAX_MESSAGE_LENGTH]; + //char szCMessage[MAX_MESSAGE_LENGTH]; + int value = sm_show_activity.IntValue; + // ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + if (client != 0) { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) { + ThrowError("Client index %d is invalid", client); + } + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID || !GetAdminFlag(id, Admin_Generic, Access_Effective)) { + sign = "PLAYER"; + } + + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + /* We don't display directly to the console because the chat text + * simply gets added to the console, so we don't want it to print + * twice. + */ + C_PrintToChatEx(client, client, "%s%s", szTag, szBuffer); + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s", szTag, szBuffer); + } + + if (!value) { + return 1; + } + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || IsFakeClient(i) || i == client) { + continue; + } + + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID + || !GetAdminFlag(id, Admin_Generic, Access_Effective)) { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 2)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else { + /* Treat this as an admin user */ + bool is_root = GetAdminFlag(id, Admin_Root, Access_Effective); + if ((value & 4) || (value & 8) || ((value & 16) && is_root)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 8) || ((value & 16) && is_root)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} diff --git a/addons/sourcemod/scripting/include/multicolors/morecolors.inc b/addons/sourcemod/scripting/include/multicolors/morecolors.inc new file mode 100644 index 0000000..b1a6285 --- /dev/null +++ b/addons/sourcemod/scripting/include/multicolors/morecolors.inc @@ -0,0 +1,998 @@ +// MOAR COLORS +// By Dr. McKay +// Inspired by: https://forums.alliedmods.net/showthread.php?t=96831 + +#if defined _more_colors_included + #endinput +#endif +#define _more_colors_included + +#pragma newdecls optional +#include + +#define MORE_COLORS_VERSION "2.0.0-MC" +#define MC_MAX_MESSAGE_LENGTH 256 +#define MAX_BUFFER_LENGTH (MC_MAX_MESSAGE_LENGTH * 4) + +#define MCOLOR_RED 0xFF4040 +#define MCOLOR_BLUE 0x99CCFF +#define MCOLOR_GRAY 0xCCCCCC +#define MCOLOR_GREEN 0x3EFF3E + +#define MC_GAME_DODS 0 + +bool MC_SkipList[MAXPLAYERS+1]; +StringMap MC_Trie; +int MC_TeamColors[][] = {{0xCCCCCC, 0x4D7942, 0xFF4040}}; // Multi-dimensional array for games that don't support SayText2. First index is the game index (as defined by the GAME_ defines), second index is team. 0 = spectator, 1 = team1, 2 = team2 + +static ConVar sm_show_activity; + +/** + * Prints a message to a specific client in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param message Message (formatting rules). + * + * On error/Errors: If the client is not connected an error will be thrown. + */ +stock void MC_PrintToChat(int client, const char[] message, any ...) { + MC_CheckTrie(); + + if (client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %i", client); + } + + if (!IsClientInGame(client)) { + ThrowError("Client %i is not in game", client); + } + + char buffer[MAX_BUFFER_LENGTH]; + char buffer2[MAX_BUFFER_LENGTH]; + + SetGlobalTransTarget(client); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 3); + + MC_ReplaceColorCodes(buffer2); + MC_SendMessage(client, buffer2); +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags. + * + * @param client Client index. + * @param message Message (formatting rules). + */ +stock void MC_PrintToChatAll(const char[] message, any ...) { + MC_CheckTrie(); + + char buffer[MAX_BUFFER_LENGTH], buffer2[MAX_BUFFER_LENGTH]; + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || MC_SkipList[i]) { + MC_SkipList[i] = false; + continue; + } + + SetGlobalTransTarget(i); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 2); + + MC_ReplaceColorCodes(buffer2); + MC_SendMessage(i, buffer2); + } +} + +/** + * Prints a message to a specific client in the chat area. + * Supports color tags and teamcolor tag. + * + * @param client Client index. + * @param author Author index whose color will be used for teamcolor tag. + * @param message Message (formatting rules). + * + * On error/Errors: If the client or author are not connected an error will be thrown + */ +stock void MC_PrintToChatEx(int client, int author, const char[] message, any ...) { + MC_CheckTrie(); + + if (client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %i", client); + } + + if (!IsClientInGame(client)) { + ThrowError("Client %i is not in game", client); + } + + if (author < 0 || author > MaxClients) { + ThrowError("Invalid client index %i", author); + } + + if ((author != 0) && !IsClientInGame(author)) { + ThrowError("Client %i is not in game", author); + } + + char buffer[MAX_BUFFER_LENGTH], buffer2[MAX_BUFFER_LENGTH]; + SetGlobalTransTarget(client); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 4); + MC_ReplaceColorCodes(buffer2, author); + MC_SendMessage(client, buffer2, author); +} + +/** + * Prints a message to all clients in the chat area. + * Supports color tags and teamcolor tag. + * + * @param author Author index whose color will be used for teamcolor tag. + * @param message Message (formatting rules). + * + * On error/Errors: If the author is not connected an error will be thrown. + */ +stock void MC_PrintToChatAllEx(int author, const char[] message, any ...) { + MC_CheckTrie(); + + if (author < 0 || author > MaxClients) { + ThrowError("Invalid client index %i", author); + } + + if ((author != 0) && !IsClientInGame(author)) { + ThrowError("Client %i is not in game", author); + } + + char buffer[MAX_BUFFER_LENGTH]; + char buffer2[MAX_BUFFER_LENGTH]; + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || MC_SkipList[i]) { + MC_SkipList[i] = false; + continue; + } + + SetGlobalTransTarget(i); + Format(buffer, sizeof(buffer), "\x01%s", message); + VFormat(buffer2, sizeof(buffer2), buffer, 3); + + MC_ReplaceColorCodes(buffer2, author); + MC_SendMessage(i, buffer2, author); + } +} + +/** + * Sends a SayText2 usermessage + * + * @param client Client to send usermessage to + * @param message Message to send + */ +stock void MC_SendMessage(int client, const char[] message, int author = 0) { + if (author == 0) { + author = client; + } + + char buffer[MC_MAX_MESSAGE_LENGTH]; + strcopy(buffer, sizeof(buffer), message); + + UserMsg index = GetUserMessageId("SayText2"); + if (index == INVALID_MESSAGE_ID) { + if (GetEngineVersion() == Engine_DODS) { + int team = GetClientTeam(author); + if (team == 0) { + ReplaceString(buffer, sizeof(buffer), "\x03", "\x04", false); // Unassigned gets green + } + else { + char temp[16]; + Format(temp, sizeof(temp), "\x07%06X", MC_TeamColors[MC_GAME_DODS][team - 1]); + ReplaceString(buffer, sizeof(buffer), "\x03", temp, false); + } + } + + PrintToChat(client, "%s", buffer); + return; + } + + Handle buf = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS); + if (GetFeatureStatus(FeatureType_Native, "GetUserMessageType") == FeatureStatus_Available && GetUserMessageType() == UM_Protobuf) { + Protobuf pb = UserMessageToProtobuf(buf); + pb.SetInt("ent_idx", author); + pb.SetBool("chat", true); + pb.SetString("msg_name", buffer); + pb.AddString("params", ""); + pb.AddString("params", ""); + pb.AddString("params", ""); + pb.AddString("params", ""); + } + else { + BfWrite bf = UserMessageToBfWrite(buf); + bf.WriteByte(author); // Message author + bf.WriteByte(true); // Chat message + bf.WriteString(buffer); // Message text + } + + EndMessage(); +} + +/** + * This function should only be used right in front of + * MC_PrintToChatAll or MC_PrintToChatAllEx. It causes those functions + * to skip the specified client when printing the message. + * After printing the message, the client will no longer be skipped. + * + * @param client Client index + */ +stock void MC_SkipNextClient(int client) { + if (client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %i", client); + } + + MC_SkipList[client] = true; +} + +/** + * Checks if the colors trie is initialized and initializes it if it's not (used internally) + * + * @return No return + */ +stock void MC_CheckTrie() { + if (MC_Trie == null) { + MC_Trie = MC_InitColorTrie(); + } +} + +/** + * Replaces color tags in a string with color codes (used internally by MC_PrintToChat, MC_PrintToChatAll, MC_PrintToChatEx, and MC_PrintToChatAllEx + * + * @param buffer String. + * @param author Optional client index to use for {teamcolor} tags, or 0 for none + * @param removeTags Optional boolean value to determine whether we're replacing tags with colors, or just removing tags, used by MC_RemoveTags + * @param maxlen Optional value for max buffer length, used by MC_RemoveTags + * + * On error/Errors: If the client index passed for author is invalid or not in game. + */ +stock void MC_ReplaceColorCodes(char[] buffer, int author = 0, bool removeTags = false, int maxlen = MAX_BUFFER_LENGTH) { + MC_CheckTrie(); + if (!removeTags) { + ReplaceString(buffer, maxlen, "{default}", "\x01", false); + } + else { + ReplaceString(buffer, maxlen, "{default}", "", false); + ReplaceString(buffer, maxlen, "{teamcolor}", "", false); + } + + if (author != 0 && !removeTags) { + if (author < 0 || author > MaxClients) { + ThrowError("Invalid client index %i", author); + } + + if (!IsClientInGame(author)) { + ThrowError("Client %i is not in game", author); + } + + ReplaceString(buffer, maxlen, "{teamcolor}", "\x03", false); + } + + int cursor = 0; + int value; + char tag[32], buff[32]; + char[] output = new char[maxlen]; + + strcopy(output, maxlen, buffer); + // Since the string's size is going to be changing, output will hold the replaced string and we'll search buffer + + Regex regex = new Regex("{[#a-zA-Z0-9]+}"); + for (int i = 0; i < 1000; i++) { // The RegEx extension is quite flaky, so we have to loop here :/. This loop is supposed to be infinite and broken by return, but conditions have been added to be safe. + if (regex.Match(buffer[cursor]) < 1) { + delete regex; + strcopy(buffer, maxlen, output); + return; + } + + regex.GetSubString(0, tag, sizeof(tag)); + MC_StrToLower(tag); + cursor = StrContains(buffer[cursor], tag, false) + cursor + 1; + strcopy(buff, sizeof(buff), tag); + ReplaceString(buff, sizeof(buff), "{", ""); + ReplaceString(buff, sizeof(buff), "}", ""); + + if (buff[0] == '#') { + if (strlen(buff) == 7) { + Format(buff, sizeof(buff), "\x07%s", buff[1]); + } + else if (strlen(buff) == 9) { + Format(buff, sizeof(buff), "\x08%s", buff[1]); + } + else { + continue; + } + + if (removeTags) { + ReplaceString(output, maxlen, tag, "", false); + } + else { + ReplaceString(output, maxlen, tag, buff, false); + } + } + else if (!MC_Trie.GetValue(buff, value)) { + continue; + } + + if (removeTags) { + ReplaceString(output, maxlen, tag, "", false); + } + else { + Format(buff, sizeof(buff), "\x07%06X", value); + ReplaceString(output, maxlen, tag, buff, false); + } + } + LogError("[MORE COLORS] Infinite loop broken."); +} + +/** + * Gets a part of a string + * + * @param input String to get the part from + * @param output Buffer to write to + * @param maxlen Max length of output buffer + * @param start Position to start at + * @param numChars Number of characters to return, or 0 for the end of the string + */ +stock void CSubString(const char[] input, char[] output, int maxlen, int start, int numChars = 0) { + int i = 0; + for (;;) { + if (i == maxlen - 1 || i >= numChars || input[start + i] == '\0') { + output[i] = '\0'; + return; + } + + output[i] = input[start + i]; + i++; + } +} + +/** + * Converts a string to lowercase + * + * @param buffer String to convert + */ +stock void MC_StrToLower(char[] buffer) { + int len = strlen(buffer); + for (int i = 0; i < len; i++) { + buffer[i] = CharToLower(buffer[i]); + } +} + +/** + * Adds a color to the colors trie + * + * @param name Color name, without braces + * @param color Hexadecimal representation of the color (0xRRGGBB) + * @return True if color was added successfully, false if a color already exists with that name + */ +stock bool MC_AddColor(const char[] name, int color) { + MC_CheckTrie(); + + int value; + + if (MC_Trie.GetValue(name, value)) { + return false; + } + + char newName[64]; + strcopy(newName, sizeof(newName), name); + + MC_StrToLower(newName); + MC_Trie.SetValue(newName, color); + return true; +} + +/** + * Removes color tags from a message + * + * @param message Message to remove tags from + * @param maxlen Maximum buffer length + */ +stock void MC_RemoveTags(char[] message, int maxlen) { + MC_ReplaceColorCodes(message, 0, true, maxlen); +} + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param message Message (formatting rules) + */ +stock void MC_ReplyToCommand(int client, const char[] message, any ...) { + char buffer[MAX_BUFFER_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 3); + + if (client == 0) { + MC_RemoveTags(buffer, sizeof(buffer)); + PrintToServer("%s", buffer); + } + else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE) { + MC_RemoveTags(buffer, sizeof(buffer)); + PrintToConsole(client, "%s", buffer); + } + else { + MC_PrintToChat(client, "%s", buffer); + } +} + +/** + * Replies to a command with colors + * + * @param client Client to reply to + * @param author Client to use for {teamcolor} + * @param message Message (formatting rules) + */ +stock void MC_ReplyToCommandEx(int client, int author, const char[] message, any ...) { + char buffer[MAX_BUFFER_LENGTH]; + SetGlobalTransTarget(client); + VFormat(buffer, sizeof(buffer), message, 4); + + if (client == 0) { + MC_RemoveTags(buffer, sizeof(buffer)); + PrintToServer("%s", buffer); + } + else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE) { + MC_RemoveTags(buffer, sizeof(buffer)); + PrintToConsole(client, "%s", buffer); + } + else { + MC_PrintToChatEx(client, author, "%s", buffer); + } +} + +/** + * Displays usage of an admin command to users depending on the + * setting of the sm_show_activity cvar. + * + * This version does not display a message to the originating client + * if used from chat triggers or menus. If manual replies are used + * for these cases, then this function will suffice. Otherwise, + * MC_ShowActivity2() is slightly more useful. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error + */ +stock int MC_ShowActivity(int client, const char[] format, any ...) { + if (sm_show_activity == null) { + sm_show_activity = FindConVar("sm_show_activity"); + } + + char tag[] = "[SM] "; + + char szBuffer[MC_MAX_MESSAGE_LENGTH]; + //char szCMessage[MC_MAX_MESSAGE_LENGTH]; + int value = sm_show_activity.IntValue; + ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + bool display_in_chat = false; + if (client != 0) { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) + ThrowError("Client index %d is invalid", client); + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID || !id.HasFlag(Admin_Generic, Access_Effective)) { + sign = "PLAYER"; + } + + /* Display the message to the client? */ + if (replyto == SM_REPLY_TO_CONSOLE) { + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToConsole(client, "%s%s", tag, szBuffer); + display_in_chat = true; + } + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s", tag, szBuffer); + } + + if (!value) { + return 1; + } + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || IsFakeClient(i) || (display_in_chat && i == client)) { + continue; + } + + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID || !id.HasFlag(Admin_Generic, Access_Effective)) { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 2) || (i == client)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else { + /* Treat this as an admin user */ + bool is_root = id.HasFlag(Admin_Root, Access_Effective); + if ((value & 4) || (value & 8) || ((value & 16) && is_root)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 8) || ((value & 16) && is_root) || (i == client)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Same as MC_ShowActivity(), except the tag parameter is used instead of "[SM] " (note that you must supply any spacing). + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to display with. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error + */ +stock int MC_ShowActivityEx(int client, const char[] tag, const char[] format, any ...) { + if (sm_show_activity == null) { + sm_show_activity = FindConVar("sm_show_activity"); + } + + char szTag[MC_MAX_MESSAGE_LENGTH]; + strcopy(szTag, sizeof(szTag), tag); + MC_RemoveTags(szTag, sizeof(szTag)); + + char szBuffer[MC_MAX_MESSAGE_LENGTH]; + //char szCMessage[MC_MAX_MESSAGE_LENGTH]; + int value = sm_show_activity.IntValue; + ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + bool display_in_chat = false; + if (client != 0) { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) { + ThrowError("Client index %d is invalid", client); + } + + GetClientName(client, name, sizeof(name)); + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID || !id.HasFlag(Admin_Generic, Access_Effective)) { + sign = "PLAYER"; + } + + /* Display the message to the client? */ + if (replyto == SM_REPLY_TO_CONSOLE) { + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToConsole(client, "%s%s", szTag, szBuffer); + display_in_chat = true; + } + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s", szTag, szBuffer); + } + + if (!value) { + return 1; + } + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || IsFakeClient(i) || (display_in_chat && i == client)) { + continue; + } + + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID || !id.HasFlag(Admin_Generic, Access_Effective)) { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 2) || (i == client)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else { + /* Treat this as an admin user */ + bool is_root = id.HasFlag(Admin_Root, Access_Effective); + if ((value & 4) || (value & 8) || ((value & 16) && is_root)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 8) || ((value & 16) && is_root) || (i == client)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Displays usage of an admin command to users depending on the setting of the sm_show_activity cvar. + * All users receive a message in their chat text, except for the originating client, + * who receives the message based on the current ReplySource. + * Supports color tags. + * + * @param client Client index doing the action, or 0 for server. + * @param tags Tag to prepend to the message. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @error + */ +stock int MC_ShowActivity2(int client, const char[] tag, const char[] format, any ...) { + if (sm_show_activity == null) { + sm_show_activity = FindConVar("sm_show_activity"); + } + + char szTag[MC_MAX_MESSAGE_LENGTH]; + strcopy(szTag, sizeof(szTag), tag); + MC_RemoveTags(szTag, sizeof(szTag)); + + char szBuffer[MC_MAX_MESSAGE_LENGTH]; + //char szCMessage[MC_MAX_MESSAGE_LENGTH]; + int value = sm_show_activity.IntValue; + // ReplySource replyto = GetCmdReplySource(); + + char name[MAX_NAME_LENGTH] = "Console"; + char sign[MAX_NAME_LENGTH] = "ADMIN"; + + if (client != 0) { + if (client < 0 || client > MaxClients || !IsClientConnected(client)) { + ThrowError("Client index %d is invalid", client); + } + + GetClientName(client, name, sizeof(name)); + + AdminId id = GetUserAdmin(client); + if (id == INVALID_ADMIN_ID || !id.HasFlag(Admin_Generic, Access_Effective)) { + sign = "PLAYER"; + } + + SetGlobalTransTarget(client); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + /* We don't display directly to the console because the chat text + * simply gets added to the console, so we don't want it to print + * twice. + */ + MC_PrintToChatEx(client, client, "%s%s", szTag, szBuffer); + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s", szTag, szBuffer); + } + + if (!value) { + return 1; + } + + for (int i = 1; i <= MaxClients; ++i) { + if (!IsClientInGame(i) || IsFakeClient(i) || i == client) { + continue; + } + + AdminId id = GetUserAdmin(i); + SetGlobalTransTarget(i); + if (id == INVALID_ADMIN_ID || !id.HasFlag(Admin_Generic, Access_Effective)) { + /* Treat this as a normal user. */ + if ((value & 1) | (value & 2)) { + char newsign[MAX_NAME_LENGTH]; + + if ((value & 2)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + else { + /* Treat this as an admin user */ + bool is_root = id.HasFlag(Admin_Root, Access_Effective); + if ((value & 4) || (value & 8) || ((value & 16) && is_root)) { + char newsign[MAX_NAME_LENGTH]; + + + if ((value & 8) || ((value & 16) && is_root)) { + newsign = name; + } + else { + newsign = sign; + } + + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_PrintToChatEx(i, client, "%s%s: %s", tag, newsign, szBuffer); + } + } + } + + return 1; +} + +/** + * Determines whether a color name exists + * + * @param color The color name to check + * @return True if the color exists, false otherwise + */ +stock bool CColorExists(const char[] color) { + MC_CheckTrie(); + int temp; + return MC_Trie.GetValue(color, temp); +} + +/** + * Returns the hexadecimal representation of a client's team color (will NOT initialize the trie) + * + * @param client Client to get the team color for + * @return Client's team color in hexadecimal, or green if unknown + * On error/Errors: If the client index passed is invalid or not in game. + */ +stock int CGetTeamColor(int client) { + if (client <= 0 || client > MaxClients) { + ThrowError("Invalid client index %i", client); + } + + if (!IsClientInGame(client)) { + ThrowError("Client %i is not in game", client); + } + + int value; + switch(GetClientTeam(client)) { + case 1: { + value = MCOLOR_GRAY; + } + case 2: { + value = MCOLOR_RED; + } + case 3: { + value = MCOLOR_BLUE; + } + default: { + value = MCOLOR_GREEN; + } + } + + return value; +} + +stock StringMap MC_InitColorTrie() { + StringMap hTrie = new StringMap(); + hTrie.SetValue("aliceblue", 0xF0F8FF); + hTrie.SetValue("allies", 0x4D7942); // same as Allies team in DoD:S + hTrie.SetValue("ancient", 0xEB4B4B); // same as Ancient item rarity in Dota 2 + hTrie.SetValue("antiquewhite", 0xFAEBD7); + hTrie.SetValue("aqua", 0x00FFFF); + hTrie.SetValue("aquamarine", 0x7FFFD4); + hTrie.SetValue("arcana", 0xADE55C); // same as Arcana item rarity in Dota 2 + hTrie.SetValue("axis", 0xFF4040); // same as Axis team in DoD:S + hTrie.SetValue("azure", 0x007FFF); + hTrie.SetValue("beige", 0xF5F5DC); + hTrie.SetValue("bisque", 0xFFE4C4); + hTrie.SetValue("black", 0x000000); + hTrie.SetValue("blanchedalmond", 0xFFEBCD); + hTrie.SetValue("blue", 0x99CCFF); // same as BLU/Counter-Terrorist team color + hTrie.SetValue("blueviolet", 0x8A2BE2); + hTrie.SetValue("brown", 0xA52A2A); + hTrie.SetValue("burlywood", 0xDEB887); + hTrie.SetValue("cadetblue", 0x5F9EA0); + hTrie.SetValue("chartreuse", 0x7FFF00); + hTrie.SetValue("chocolate", 0xD2691E); + hTrie.SetValue("collectors", 0xAA0000); // same as Collector's item quality in TF2 + hTrie.SetValue("common", 0xB0C3D9); // same as Common item rarity in Dota 2 + hTrie.SetValue("community", 0x70B04A); // same as Community item quality in TF2 + hTrie.SetValue("coral", 0xFF7F50); + hTrie.SetValue("cornflowerblue", 0x6495ED); + hTrie.SetValue("cornsilk", 0xFFF8DC); + hTrie.SetValue("corrupted", 0xA32C2E); // same as Corrupted item quality in Dota 2 + hTrie.SetValue("crimson", 0xDC143C); + hTrie.SetValue("cyan", 0x00FFFF); + hTrie.SetValue("darkblue", 0x00008B); + hTrie.SetValue("darkcyan", 0x008B8B); + hTrie.SetValue("darkgoldenrod", 0xB8860B); + hTrie.SetValue("darkgray", 0xA9A9A9); + hTrie.SetValue("darkgrey", 0xA9A9A9); + hTrie.SetValue("darkgreen", 0x006400); + hTrie.SetValue("darkkhaki", 0xBDB76B); + hTrie.SetValue("darkmagenta", 0x8B008B); + hTrie.SetValue("darkolivegreen", 0x556B2F); + hTrie.SetValue("darkorange", 0xFF8C00); + hTrie.SetValue("darkorchid", 0x9932CC); + hTrie.SetValue("darkred", 0x8B0000); + hTrie.SetValue("darksalmon", 0xE9967A); + hTrie.SetValue("darkseagreen", 0x8FBC8F); + hTrie.SetValue("darkslateblue", 0x483D8B); + hTrie.SetValue("darkslategray", 0x2F4F4F); + hTrie.SetValue("darkslategrey", 0x2F4F4F); + hTrie.SetValue("darkturquoise", 0x00CED1); + hTrie.SetValue("darkviolet", 0x9400D3); + hTrie.SetValue("deeppink", 0xFF1493); + hTrie.SetValue("deepskyblue", 0x00BFFF); + hTrie.SetValue("dimgray", 0x696969); + hTrie.SetValue("dimgrey", 0x696969); + hTrie.SetValue("dodgerblue", 0x1E90FF); + hTrie.SetValue("exalted", 0xCCCCCD); // same as Exalted item quality in Dota 2 + hTrie.SetValue("firebrick", 0xB22222); + hTrie.SetValue("floralwhite", 0xFFFAF0); + hTrie.SetValue("forestgreen", 0x228B22); + hTrie.SetValue("frozen", 0x4983B3); // same as Frozen item quality in Dota 2 + hTrie.SetValue("fuchsia", 0xFF00FF); + hTrie.SetValue("fullblue", 0x0000FF); + hTrie.SetValue("fullred", 0xFF0000); + hTrie.SetValue("gainsboro", 0xDCDCDC); + hTrie.SetValue("genuine", 0x4D7455); // same as Genuine item quality in TF2 + hTrie.SetValue("ghostwhite", 0xF8F8FF); + hTrie.SetValue("gold", 0xFFD700); + hTrie.SetValue("goldenrod", 0xDAA520); + hTrie.SetValue("gray", 0xCCCCCC); // same as spectator team color + hTrie.SetValue("grey", 0xCCCCCC); + hTrie.SetValue("green", 0x3EFF3E); + hTrie.SetValue("greenyellow", 0xADFF2F); + hTrie.SetValue("haunted", 0x38F3AB); // same as Haunted item quality in TF2 + hTrie.SetValue("honeydew", 0xF0FFF0); + hTrie.SetValue("hotpink", 0xFF69B4); + hTrie.SetValue("immortal", 0xE4AE33); // same as Immortal item rarity in Dota 2 + hTrie.SetValue("indianred", 0xCD5C5C); + hTrie.SetValue("indigo", 0x4B0082); + hTrie.SetValue("ivory", 0xFFFFF0); + hTrie.SetValue("khaki", 0xF0E68C); + hTrie.SetValue("lavender", 0xE6E6FA); + hTrie.SetValue("lavenderblush", 0xFFF0F5); + hTrie.SetValue("lawngreen", 0x7CFC00); + hTrie.SetValue("legendary", 0xD32CE6); // same as Legendary item rarity in Dota 2 + hTrie.SetValue("lemonchiffon", 0xFFFACD); + hTrie.SetValue("lightblue", 0xADD8E6); + hTrie.SetValue("lightcoral", 0xF08080); + hTrie.SetValue("lightcyan", 0xE0FFFF); + hTrie.SetValue("lightgoldenrodyellow", 0xFAFAD2); + hTrie.SetValue("lightgray", 0xD3D3D3); + hTrie.SetValue("lightgrey", 0xD3D3D3); + hTrie.SetValue("lightgreen", 0x99FF99); + hTrie.SetValue("lightpink", 0xFFB6C1); + hTrie.SetValue("lightsalmon", 0xFFA07A); + hTrie.SetValue("lightseagreen", 0x20B2AA); + hTrie.SetValue("lightskyblue", 0x87CEFA); + hTrie.SetValue("lightslategray", 0x778899); + hTrie.SetValue("lightslategrey", 0x778899); + hTrie.SetValue("lightsteelblue", 0xB0C4DE); + hTrie.SetValue("lightyellow", 0xFFFFE0); + hTrie.SetValue("lime", 0x00FF00); + hTrie.SetValue("limegreen", 0x32CD32); + hTrie.SetValue("linen", 0xFAF0E6); + hTrie.SetValue("magenta", 0xFF00FF); + hTrie.SetValue("maroon", 0x800000); + hTrie.SetValue("mediumaquamarine", 0x66CDAA); + hTrie.SetValue("mediumblue", 0x0000CD); + hTrie.SetValue("mediumorchid", 0xBA55D3); + hTrie.SetValue("mediumpurple", 0x9370D8); + hTrie.SetValue("mediumseagreen", 0x3CB371); + hTrie.SetValue("mediumslateblue", 0x7B68EE); + hTrie.SetValue("mediumspringgreen", 0x00FA9A); + hTrie.SetValue("mediumturquoise", 0x48D1CC); + hTrie.SetValue("mediumvioletred", 0xC71585); + hTrie.SetValue("midnightblue", 0x191970); + hTrie.SetValue("mintcream", 0xF5FFFA); + hTrie.SetValue("mistyrose", 0xFFE4E1); + hTrie.SetValue("moccasin", 0xFFE4B5); + hTrie.SetValue("mythical", 0x8847FF); // same as Mythical item rarity in Dota 2 + hTrie.SetValue("navajowhite", 0xFFDEAD); + hTrie.SetValue("navy", 0x000080); + hTrie.SetValue("normal", 0xB2B2B2); // same as Normal item quality in TF2 + hTrie.SetValue("oldlace", 0xFDF5E6); + hTrie.SetValue("olive", 0x9EC34F); + hTrie.SetValue("olivedrab", 0x6B8E23); + hTrie.SetValue("orange", 0xFFA500); + hTrie.SetValue("orangered", 0xFF4500); + hTrie.SetValue("orchid", 0xDA70D6); + hTrie.SetValue("palegoldenrod", 0xEEE8AA); + hTrie.SetValue("palegreen", 0x98FB98); + hTrie.SetValue("paleturquoise", 0xAFEEEE); + hTrie.SetValue("palevioletred", 0xD87093); + hTrie.SetValue("papayawhip", 0xFFEFD5); + hTrie.SetValue("peachpuff", 0xFFDAB9); + hTrie.SetValue("peru", 0xCD853F); + hTrie.SetValue("pink", 0xFFC0CB); + hTrie.SetValue("plum", 0xDDA0DD); + hTrie.SetValue("powderblue", 0xB0E0E6); + hTrie.SetValue("purple", 0x800080); + hTrie.SetValue("rare", 0x4B69FF); // same as Rare item rarity in Dota 2 + hTrie.SetValue("red", 0xFF4040); // same as RED/Terrorist team color + hTrie.SetValue("rosybrown", 0xBC8F8F); + hTrie.SetValue("royalblue", 0x4169E1); + hTrie.SetValue("saddlebrown", 0x8B4513); + hTrie.SetValue("salmon", 0xFA8072); + hTrie.SetValue("sandybrown", 0xF4A460); + hTrie.SetValue("seagreen", 0x2E8B57); + hTrie.SetValue("seashell", 0xFFF5EE); + hTrie.SetValue("selfmade", 0x70B04A); // same as Self-Made item quality in TF2 + hTrie.SetValue("sienna", 0xA0522D); + hTrie.SetValue("silver", 0xC0C0C0); + hTrie.SetValue("skyblue", 0x87CEEB); + hTrie.SetValue("slateblue", 0x6A5ACD); + hTrie.SetValue("slategray", 0x708090); + hTrie.SetValue("slategrey", 0x708090); + hTrie.SetValue("snow", 0xFFFAFA); + hTrie.SetValue("springgreen", 0x00FF7F); + hTrie.SetValue("steelblue", 0x4682B4); + hTrie.SetValue("strange", 0xCF6A32); // same as Strange item quality in TF2 + hTrie.SetValue("tan", 0xD2B48C); + hTrie.SetValue("teal", 0x008080); + hTrie.SetValue("thistle", 0xD8BFD8); + hTrie.SetValue("tomato", 0xFF6347); + hTrie.SetValue("turquoise", 0x40E0D0); + hTrie.SetValue("uncommon", 0xB0C3D9); // same as Uncommon item rarity in Dota 2 + hTrie.SetValue("unique", 0xFFD700); // same as Unique item quality in TF2 + hTrie.SetValue("unusual", 0x8650AC); // same as Unusual item quality in TF2 + hTrie.SetValue("valve", 0xA50F79); // same as Valve item quality in TF2 + hTrie.SetValue("vintage", 0x476291); // same as Vintage item quality in TF2 + hTrie.SetValue("violet", 0xEE82EE); + hTrie.SetValue("wheat", 0xF5DEB3); + hTrie.SetValue("white", 0xFFFFFF); + hTrie.SetValue("whitesmoke", 0xF5F5F5); + hTrie.SetValue("yellow", 0xFFFF00); + hTrie.SetValue("yellowgreen", 0x9ACD32); + + return hTrie; +} diff --git a/addons/sourcemod/translations/HNS-Anti-Frag.phrases.txt b/addons/sourcemod/translations/HNS-Anti-Frag.phrases.txt new file mode 100644 index 0000000..bd22310 --- /dev/null +++ b/addons/sourcemod/translations/HNS-Anti-Frag.phrases.txt @@ -0,0 +1,47 @@ +"Phrases" +{ + "CooldownTNotify" + { + "#format" "{1:.1f}" + "en" " {Green}Gold KingZ {grey}| You have {orchid}{1} Secs {grey}protection" + } + "CooldownCTNotify" + { + "#format" "{1:.1f},{2:N}" + "en" " {Green}Gold KingZ {grey}| Wait {orchid}{1} Secs {grey}cooldown stabbing {darkred}{2}" + } + +//========================================================================================== + + "CooldownCTNotifyTeamT" + { + "#format" "{1:.1f}" + "en" " {Green}Gold KingZ {grey}| Wait {orchid}{1} Secs {grey}cooldown stabbing {darkred}(T's)" + } + +//========================================================================================== + + "CooldownCTAnnouncedWithHP" + { + "#format" "{1:N},{2:N},{3:d}" + "en" " {Green}Gold KingZ {grey}| {darkblue}{1} {grey}Stabbed {darkred}{2} {lime}[HP: {3}]" + } + "CooldownCTAnnouncedWithHPDead" + { + "#format" "{1:N},{2:N}" + "en" " {Green}Gold KingZ {grey}| {darkblue}{1} {grey}Killed {darkred}{2} {lime}[HP: 0]" + } + +//========================================================================================== + + "CooldownCTAnnouncedWithoutHP" + { + "#format" "{1:N},{2:N}" + "en" " {Green}Gold KingZ {grey}| {darkblue}{1} {grey}Stabbed {darkred}{2}" + } + "CooldownCTAnnouncedWithoutHPDead" + { + "#format" "{1:N},{2:N}" + "en" " {Green}Gold KingZ {grey}| {darkblue}{1} {grey}Killed {darkred}{2}" + } +} \ No newline at end of file diff --git a/cfg/sourcemod/HNS-Anti-Frag.cfg b/cfg/sourcemod/HNS-Anti-Frag.cfg new file mode 100644 index 0000000..3b31cba --- /dev/null +++ b/cfg/sourcemod/HNS-Anti-Frag.cfg @@ -0,0 +1,56 @@ +//## Enable Anti-Frag Plugin +//## 1= Yes +//## 0= No +hns_f_enable_plugin "1" + +//========================================================================================== + +//## How Would You Like Cooldown Will Be For Attacker (CT) +//## 2= Give Attacker (CT) Cooldown From Stabbing To All T's +//## 1= Give Victim (T) Who Got Stabbed God Mode(Cooldown From Getting Stabbed) +//## 0= No (Disable Cooldown) +hns_f_ct_cooldown "1" + +//## (in sec) Cooldown Between Knife Stabs +hns_f_knife_cooldown "5.0" + +//## How Much Knife Damage To T's +//## Default: 50 HP +hns_f_knife_damage "50.0" + +//========================================================================================== + +//## Enable Transparent After Damage +//## 1= Yes +//## 0= No +hns_f_enable_transparent "1" + +//## How Much Transparent After Hit +//## 0= Invisible +//## 120= Transparent +//## 255=None +hns_f_transparent "120" + +//## Body Red Code Color Pick Here https://www.rapidtables.com/web/color/RGB_Color.html +hns_f_color_r "255" + +//## Body Green Code Color Pick Here https://www.rapidtables.com/web/color/RGB_Color.html +hns_f_color_g "0" + +//## Body Blue Code Color Pick Here https://www.rapidtables.com/web/color/RGB_Color.html +hns_f_color_b "0" + +//========================================================================================== + +//## Enable Notification Message Chat After Damage For +//## 3= Both Attacker (CT) And Victim (T) +//## 2= Victim (T) +//## 1= Attacker (CT) +//## 0= No Disable Notify Message +hns_f_notify "1" + +//## Do You Like The Notification Message To Be Announced To All Players About Who Got Stabbed+Killed +//## 2= Yes With Hp Left +//## 1= Yes +//## 0= No Disable Announcer +hns_f_notify_annoc "0" \ No newline at end of file