diff --git a/addons/sourcemod/configs/game_manager_maps.txt b/addons/sourcemod/configs/game_manager_maps.txt new file mode 100644 index 0000000..86107d1 --- /dev/null +++ b/addons/sourcemod/configs/game_manager_maps.txt @@ -0,0 +1,9 @@ +de_vertigo +de_mirage +de_dust2 +de_ancient +de_inferno +de_train +de_overpass +de_nuke +de_cache \ No newline at end of file diff --git a/addons/sourcemod/configs/maplists.cfg b/addons/sourcemod/configs/maplists.cfg new file mode 100644 index 0000000..c92a83e --- /dev/null +++ b/addons/sourcemod/configs/maplists.cfg @@ -0,0 +1,63 @@ +/** + * Use this file to configure map lists. + * + * Each section is a map list that plugins can use. For example, the Admin Menu + * requests an "admin menu" map list, and you can control which maps appear via + * this file. + * + * Each section must have a property that explains where to read the maps from. + * There are two properties: + * + * target - Redirect the request to another section. + * file - Read a file of map names, in mapcycle.txt format. + * + * There is one section by default, called "mapcyclefile" - it is mapped to the + * mapcycle.txt file, or whatever the contents of your mapcyclefile cvar is. + * + * If a plugin requests a map list file which doesn't exist, or is empty, SourceMod + * tries the "default" section, and then the "mapcyclefile" section. + */ +"MapLists" +{ + /** + * Default requests go right to the mapcyclefile. + */ + "default" + { + "target" "mapcyclefile" + } + + /* Admin menu, map menu */ + "sm_map menu" + { + "file" "addons/sourcemod/configs/adminmenu_maplist.ini" + } + + /* Admin menu, map voting menu */ + "sm_votemap menu" + { + "file" "addons/sourcemod/configs/adminmenu_maplist.ini" + } + + /* For the "randomcycle" plugin */ + "randomcycle" + { + "target" "default" + } + + /* For the "mapchooser" plugin */ + "mapchooser" + { + "target" "default" + } + + /* For the "nominations" plugin */ + "nominations" + { + "target" "default" + } + "gamemanager" + { + "file" "addons/sourcemod/configs/game_manager_maps.txt" + } +} diff --git a/addons/sourcemod/scripting/Game_Manager.sp b/addons/sourcemod/scripting/Game_Manager.sp new file mode 100644 index 0000000..933523f --- /dev/null +++ b/addons/sourcemod/scripting/Game_Manager.sp @@ -0,0 +1,1781 @@ +#pragma semicolon 1 +#pragma newdecls required + +#include +#include +#include +#include +#include +#include + +#define CFG_NAME "Game_Manager" +#define TEAM_NONE 0 +#define TEAM_SPEC 1 +#define TEAM_T 2 +#define TEAM_CT 3 + +ConVar g_enable; +ConVar g_msgsshorthanded; +ConVar g_radar; +ConVar g_moneyhud; +ConVar g_killfeed; +ConVar g_blockradioagent; +ConVar g_blockradionade; +ConVar g_blockwhell; +ConVar g_blockclantag; +ConVar g_cheats; +ConVar g_msgconnect; +ConVar g_msgdisconnect; +ConVar g_msgjointeam; +ConVar g_msgchangeteam; +ConVar g_msgcvar; +ConVar g_msgmoney; +ConVar g_msgsavedby; +ConVar g_msgteamattack; +ConVar g_msgchangename; +ConVar g_forceend; +ConVar g_blockchicken; +ConVar g_blockweapondrop; +ConVar g_showtime; +ConVar g_blockautomute; +ConVar g_blockfootsteps; +ConVar g_blockjumpland; +ConVar g_blockroundendsound; +ConVar g_blockradiostartround; +ConVar g_blockfalldamage; +ConVar g_knifesound; +ConVar Cvar_ListX; +ConVar Cvar_ListY; +ConVar Cvar_ListColor; +ConVar g_cEnableNoBlood; +ConVar g_cEnableNoSplatter; +ConVar g_ConVarEnable; +ConVar g_ConVarMethod; +ConVar g_ConVarDelay; +ConVar g_ConVarHibernate; + +int g_MapPos; +int g_MapListSerial; +int minutesBelowClientLimit; +int g_ownerOffset; +bool rotationMapChangeOccured; + +Handle g_balance; +Handle hPluginMe; +Handle g_Cvar_BotDelayEnable = INVALID_HANDLE; +Handle g_Cvar_BotQuota = INVALID_HANDLE; +Handle g_Cvar_BotDelay; +Handle bot_delay_timer = INVALID_HANDLE; +bool g_delayenable = false; +bool g_eenable = false; +int g_Tcount = 0; +int g_CTcount = 0; +int g_BotTcount = 0; +int g_BotCTcount = 0; +int g_botQuota = 0; +int g_botDelay = 1; +bool g_hookenabled = false; +Handle rotation_enable = INVALID_HANDLE; +Handle rotation_client_limit = INVALID_HANDLE; +Handle rotation_include_bots = INVALID_HANDLE; +Handle rotation_time_limit = INVALID_HANDLE; +Handle rotation_mode = INVALID_HANDLE; +Handle rotation_default_map = INVALID_HANDLE; +Handle rotation_config_to_exec = INVALID_HANDLE; +Handle g_MapList = INVALID_HANDLE; + +bool g_benable = false; +bool g_bradar = false; +bool g_bmoneyhud = false; +bool g_bkillfeed = false; +bool g_bblockradioagent = false; +bool g_bblockwhell = false; +bool g_bblockclantag = false; +bool g_bcheats = false; +bool g_bmsgconnect = false; +bool g_bmsgdisconnect = false; +bool g_bmsgjointeam = false; +bool g_bmsgchangeteam = false; +bool g_bmsgcvar = false; +bool g_bmsgmoney = false; +bool g_bmsgsavedby = false; +bool g_bmsgteamattack = false; +bool g_bmsgchangename = false; +bool g_bforceend = false; +bool g_bblockchicken = false; +bool g_bblockweapondrop = false; +bool g_bshowtime = false; +bool g_bblockautomute = false; +bool g_bblockfootsteps = false; +bool g_bblockjumpland = false; +bool g_bblockroundendsound = false; +bool g_bblockradiostartround = false; +bool g_bblockfalldamage = false; + +float g_ListX; +float g_ListY; +float g_fCvarDelay; + +bool g_phitted[MAXPLAYERS]; +bool g_bCvarEnabled; +bool g_bStartRandomMap; +bool g_bServerStarted; + +int g_iCvarMethod; +int g_iHybernateInitial; +int g_iListColor[4]; + +char g_sLogPath[PLATFORM_MAX_PATH]; + +Handle + Cheats = null; + +char RadioArray[][] = +{ + "coverme", + "takepoint", + "holdpos", + "regroup", + "followme", + "takingfire", + "go", + "fallback", + "sticktog", + "getinpos", + "stormfront", + "report", + "roger", + "enemyspot", + "needbackup", + "sectorclear", + "inposition", + "reportingin", + "getout", + "negative", + "enemydown", + "sorry", + "cheer", + "compliment", + "thanks", + "go_a", + "go_b", + "needrop", + "deathcry", + "deathcry" +}; + +char MoneyMessageArray[][] = +{ + "#Player_Cash_Award_Kill_Hostage", + "#Player_Cash_Award_Damage_Hostage", + "#Player_Cash_Award_Get_Killed", + "#Player_Cash_Award_Respawn", + "#Player_Cash_Award_Interact_Hostage", + "#Player_Cash_Award_Killed_Enemy", + "#Player_Cash_Award_Rescued_Hostage", + "#Player_Cash_Award_Bomb_Defused", + "#Player_Cash_Award_Bomb_Planted", + "#Player_Cash_Award_Killed_Enemy_Generic", + "#Player_Cash_Award_Killed_VIP", + "#Player_Cash_Award_Kill_Teammate", + "#Player_Cash_Award_ExplainSuicide_YouGotCash", + "#Player_Cash_Award_ExplainSuicide_TeammateGotCash", + "#Player_Cash_Award_ExplainSuicide_EnemyGotCash", + "#Player_Cash_Award_ExplainSuicide_Spectators", + "#Team_Cash_Award_Win_Hostages_Rescue", + "#Team_Cash_Award_Win_Defuse_Bomb", + "#Team_Cash_Award_Win_Time", + "#Team_Cash_Award_Elim_Bomb", + "#Team_Cash_Award_Elim_Hostage", + "#Team_Cash_Award_T_Win_Bomb", + "#Team_Cash_Award_Win_Hostage_Rescue", + "#Team_Cash_Award_Loser_Bonus", + "#Team_Cash_Award_Loser_Zero", + "#Team_Cash_Award_Rescued_Hostage", + "#Team_Cash_Award_Hostage_Interaction", + "#Team_Cash_Award_Hostage_Alive", + "#Team_Cash_Award_Planted_Bomb_But_Defused", + "#Team_Cash_Award_CT_VIP_Escaped", + "#Team_Cash_Award_T_VIP_Killed", + "#Team_Cash_Award_no_income", + "#Team_Cash_Award_Generic", + "#Team_Cash_Award_Custom", + "#Team_Cash_Award_no_income_suicide", +}; + +char SavedbyArray[][] = +{ + "#Chat_SavePlayer_Savior", + "#Chat_SavePlayer_Spectator", + "#Chat_SavePlayer_Saved", +}; + +char TeamWarningArray[][] = +{ + "#Game_teammate_attack", + "#SFUI_Notice_Killed_Teammate", + "#Cstrike_TitlesTXT_Game_teammate_attack", + "#Hint_try_not_to_injure_teammates", +}; + +public Plugin myinfo = +{ + name = "[CS:GO] Game Manager", + author = "Gold_KingZ", + description = "Game Manager ( Hide radar, money, messages, ping, and more )", + version = "1.0.7", + url = "https://steamcommunity.com/id/oQYh" +} + +public void OnPluginStart() +{ + LoadTranslations( "Game_Manager.phrases" ); + + CreateTimer(1.0, Timeleft, _, TIMER_REPEAT); + CreateTimer(1.0, Timer_Wep, 0, TIMER_REPEAT); + if (GetEngineVersion() != Engine_CSGO) + { + SetFailState("This plugin is for game use only. CS:GO"); + return; + } + + g_enable = CreateConVar("gm_enable_hide_and_block" , "1", ".::[Enable Hide And Block Feature]::. || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_radar = CreateConVar("gm_hide_radar" , "0", "Hide Radar (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_moneyhud = CreateConVar("gm_hide_moneyhud" , "0", "Hide Money Hud (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_killfeed = CreateConVar("gm_hide_killfeed" , "0", "Hide Kill Feed (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockradioagent = CreateConVar("gm_block_radio_voice_agents" , "0", "Block All Radio Voice Agents (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockradionade = CreateConVar("gm_block_radio_voice_grenades" , "0", "Block All Radio Voice Grenades Throw (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockwhell = CreateConVar("gm_block_wheel" , "0", "Block All Wheel + Ping (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockclantag = CreateConVar("gm_block_clantag" , "0", "Permanently Block Both Dynamic + Animated + Normal ClanTags (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_cheats = CreateConVar("gm_block_cheats" , "0", "Make sv_cheats 0 Automatically (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgconnect = CreateConVar("gm_block_connect_message" , "0", "Hide Connect Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgdisconnect = CreateConVar("gm_block_disconnect_message" , "0", "Hide Disconnect Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgjointeam = CreateConVar("gm_block_jointeam_message" , "0", "Hide First Time Connect Client Join Team Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgchangeteam = CreateConVar("gm_block_teamchange_message" , "0", "Hide Team Change Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgcvar = CreateConVar("gm_block_cvar_message" , "0", "Hide Server Cvar Change Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgmoney = CreateConVar("gm_block_hidemoney_message" , "0", "Hide All Money Team/Player Award Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgsavedby = CreateConVar("gm_block_savedby_message" , "0", "Hide Player Saved You By Player Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgteamattack = CreateConVar("gm_block_teammateattack_message" , "0", "Hide Team Mate Attack Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgchangename = CreateConVar("gm_block_changename_message" , "0", "Hide Change Name Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_msgsshorthanded = CreateConVar("gm_block_shorthanded_message" , "0", "Hide Short-Handed Incoming Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + + g_forceend = CreateConVar("gm_forceendmap" , "0", "Force End Map With Command mp_timelimit (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockchicken = CreateConVar("gm_block_chicken" , "0", "Permanently Remove Chickens (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockweapondrop = CreateConVar("gm_block_weapon_drop" , "0", "Delete/Clean Weapons Dropped (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_showtime = CreateConVar("gm_show_timeleft_hud" , "0", "Show Timeleft HUD (mp_timelimit) (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_balance = CreateConVar("gm_auto_balance_every_round", "0", "Auto Balance Every Round (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_Cvar_BotQuota = CreateConVar("gm_block_bots", "0", "Permanently Remove bots (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_cEnableNoBlood = CreateConVar("gm_hide_blood" , "0", "Hide Blood (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_cEnableNoSplatter = CreateConVar("gm_hide_splatter" , "0", "Hide Splatter Effect (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockautomute = CreateConVar("gm_block_auto_mute" , "0", "Remove Auto Communication Penalties (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockfootsteps = CreateConVar("gm_block_footsteps_sound" , "0", "Block Footsteps Sounds (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockjumpland = CreateConVar("gm_block_jumpland_sound" , "0", "Block Jump Land Sounds (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockroundendsound = CreateConVar("gm_block_roundend_sound" , "0", "Block Counter/Terrorist/Draw Win Sounds (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockradiostartround = CreateConVar("gm_block_radio_start_agents" , "0", "Block Round Start Radio Sounds (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_blockfalldamage = CreateConVar("gm_block_falldamage" , "0", "Disable Fall Damage (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + g_knifesound = CreateConVar("gm_block_zerodamge_knife", "0", "Block Knife Sound If Its Zero Damage (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + Cvar_ListX = CreateConVar("gm_hud_xaxis" , "0.00", "X-Axis Location From 0 To 1.0 Check /~https://github.com/oqyh/Game-Manager/blob/main/images/hud%20postions.png For Help"); + Cvar_ListY = CreateConVar("gm_hud_yaxis" , "0.35", "Y-Axis Location From 0 To 1.0 Check /~https://github.com/oqyh/Game-Manager/blob/main/images/hud%20postions.png For Help"); + Cvar_ListColor = CreateConVar("gm_hud_colors" , "255 0 189 0.8", "Hud color. [R G B A] Pick Colors https://rgbacolorpicker.com/"); + + ( g_ConVarEnable = CreateConVar("gm_restart_empty_enable", "0", ".::[Restart Server When Last Player Disconnect Feature]::. || 1= Yes || 0= No ")).AddChangeHook(OnCvarChanged); + ( g_ConVarMethod = CreateConVar("gm_restart_empty_method", "2", "When server is empty Which Method Do You Like (Need To Enable gm_restart_empty_enable) || 1= Restart || 2= Crash If Method 1 Is Not work")).AddChangeHook(OnCvarChanged); + ( g_ConVarDelay = CreateConVar("gm_restart_empty_delay", "900.0", "(in sec.) To Wait To Start gm_restart_empty_method (Need To Enable gm_restart_empty_enable)")).AddChangeHook(OnCvarChanged); + + rotation_enable = CreateConVar("gm_rotation_enable", "0", ".::[Map Rotation Feature]::. || 1= Yes || 0= No", _, true, 0.0, true, 1.0); + rotation_client_limit = CreateConVar("gm_rotation_client_limit", "1", "Number Of Clients That Must Be Connected To Disable Map Rotation Feature (Need To Enable gm_rotation_enable)", _, true, 0.0, false, 0.0); + rotation_include_bots = CreateConVar("gm_rotation_include_bots", "0", "Include Bots In Number Of Clients in gm_rotation_client_limit (Remember, Sourcetv Counts As A Bot) (Need To Enable gm_rotation_enable)", _, true, 0.0, true, 1.0); + rotation_time_limit = CreateConVar("gm_rotation_time_limit", "5", "(in min.) Pass While The Client Limit Has Not Been Reached For Rotation Feature To Occur (Need To Enable gm_rotation_enable)", _, true, 0.0, false, 0.0); + rotation_mode = CreateConVar("gm_rotation_mode", "1", "(Need To Enable gm_rotation_enable) \n 1= Use game_manager_maps.txt map list need to (Create New Line [gamemanager] + path In Sourcemod/configs/maplists.cfg) \n 2= Sm_nextmap Or Mapcycle (Requires Nextmap.smx) \n 3= Load Map In gm_rotation_default_map Cvar \n 0 or 4 and above = Reload Current Map", _, true, 0.0, true, 3.0); + rotation_default_map = CreateConVar("gm_rotation_default_map", "", "Map To Load If (gm_rotation_mode Is Set To 2) (Need To Enable gm_rotation_enable)"); + rotation_config_to_exec = CreateConVar("gm_rotation_config_to_exec", "", "Config To Exec When An Rotation Feature Occurs, If Desired. Executes After The Map Loads And Server.cfg And Sourcemod Plugin Configs Are Exec'd (Need To Enable gm_rotation_enable)"); + + + g_ListX = GetConVarFloat(Cvar_ListX); + g_ListY = GetConVarFloat(Cvar_ListY); + + char buffer[16]; + GetConVarString(Cvar_ListColor, buffer, sizeof(buffer)); + StrToRGBA(buffer); + + g_MapList = CreateArray(32); + + g_MapPos = -1; + g_MapListSerial = -1; + minutesBelowClientLimit = 0; + rotationMapChangeOccured = false; + + AutoExecConfig(true, CFG_NAME); + + + HookEvent("server_cvar", OnServerCvar , EventHookMode_Pre); + HookEvent("player_death", Event_PlayerDeath, EventHookMode_Pre); + HookEvent("player_connect", OnPlayerConnect, EventHookMode_Pre); + HookEvent("player_disconnect", OnPlayerDisconnect, EventHookMode_Pre); + HookEvent("player_team", OnPlayerTeam, EventHookMode_Pre); + HookEvent("round_end", Event_RoundEnd, EventHookMode_Pre); + HookEvent("round_prestart", Event_PreRoundStart); + + HookUserMessage(GetUserMessageId("RadioText"), OnRadioText, true); + HookUserMessage(GetUserMessageId("TextMsg"), OnHookTextMsg, true); + HookUserMessage(GetUserMessageId("TextMsg"), OnHookTextMsg2, true); + HookUserMessage(GetUserMessageId("TextMsg"), OnHookTextMsg3, true); + HookUserMessage(GetUserMessageId("SayText2"), OnHookTextMsg4, true); + + HookConVarChange(g_enable, OnSettingsChanged); + HookConVarChange(g_msgsshorthanded, OnSettingsChanged); + HookConVarChange(g_radar, OnSettingsChanged); + HookConVarChange(g_moneyhud, OnSettingsChanged); + HookConVarChange(g_killfeed, OnSettingsChanged); + HookConVarChange(g_blockradioagent, OnSettingsChanged); + HookConVarChange(g_blockradionade, OnSettingsChanged); + HookConVarChange(g_blockwhell, OnSettingsChanged); + HookConVarChange(g_blockclantag, OnSettingsChanged); + HookConVarChange(g_cheats, OnSettingsChanged); + HookConVarChange(g_msgconnect, OnSettingsChanged); + HookConVarChange(g_msgdisconnect, OnSettingsChanged); + HookConVarChange(g_msgjointeam, OnSettingsChanged); + HookConVarChange(g_msgchangeteam, OnSettingsChanged); + HookConVarChange(g_msgcvar, OnSettingsChanged); + HookConVarChange(g_msgmoney, OnSettingsChanged); + HookConVarChange(g_msgsavedby, OnSettingsChanged); + HookConVarChange(g_msgteamattack, OnSettingsChanged); + HookConVarChange(g_msgchangename, OnSettingsChanged); + HookConVarChange(g_forceend, OnSettingsChanged); + HookConVarChange(g_blockchicken, OnSettingsChanged); + HookConVarChange(g_blockweapondrop, OnSettingsChanged); + HookConVarChange(g_showtime, OnSettingsChanged); + HookConVarChange(g_blockautomute, OnSettingsChanged); + HookConVarChange(g_blockfootsteps, OnSettingsChanged); + HookConVarChange(g_blockjumpland, OnSettingsChanged); + HookConVarChange(g_blockroundendsound, OnSettingsChanged); + HookConVarChange(g_blockradiostartround, OnSettingsChanged); + HookConVarChange(g_blockfalldamage, OnSettingsChanged); + HookConVarChange(Cvar_ListX, OnConVarChange); + HookConVarChange(Cvar_ListY, OnConVarChange); + HookConVarChange(Cvar_ListColor, OnConVarChange); + AddTempEntHook("Blood Sprite", TE_OnWorldDecal); + AddTempEntHook("Entity Decal", TE_OnWorldDecal); + AddTempEntHook("EffectDispatch", TE_OnEffectDispatch); + AddTempEntHook("World Decal", TE_OnWorldDecal); + AddTempEntHook("Impact", TE_OnWorldDecal); + + AddNormalSoundHook(Call_Back_Radio); + AddNormalSoundHook(Call_Back_Sound); + HookEvent("player_hurt", PlayerHurt_Event, EventHookMode_Pre); + + g_eenable = GetConVarBool(g_enable); + HookConVarChange(g_enable, CvarChanged); + + + g_botQuota = GetConVarInt(g_Cvar_BotQuota); + HookConVarChange(g_Cvar_BotQuota, CvarChanged); + + if (!g_delayenable && g_hookenabled == false) { + HookEvent("player_team", Event_PlayerTeam); + g_hookenabled = true; + } + + AddCommandListener(Command_Ping, "chatwheel_ping"); + AddCommandListener(Command_Ping, "player_ping"); + AddCommandListener(Command_Ping, "playerradio"); + AddCommandListener(Command_Ping, "playerchatwheel"); + + Cheats = FindConVar("sv_cheats"); + + if (Cheats != null) + { + SetConVarBool(Cheats, false, true, false); + HookConVarChange(Cheats, CCheats); + } + + + for (int i = 0; i < sizeof(RadioArray); i++) + AddCommandListener(OnRadio, RadioArray[i]); + + + g_ConVarHibernate = FindConVar("sv_hibernate_when_empty"); + g_ownerOffset = FindSendPropInfo("CBaseCombatWeapon", "m_hOwnerEntity"); + BuildPath(Path_SM, g_sLogPath, sizeof(g_sLogPath), "logs/Game_Manager.log"); + + RemoveCrashLog(); + GetCvars(); + LoadCfg(); +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + hPluginMe = myself; + if( late ) + { + g_bServerStarted = true; + } + return APLRes_Success; +} + + +public int OnSettingsChanged(Handle convar, const char[] oldValue, const char[] newValue) +{ + if(convar == g_enable) + { + g_benable = g_enable.BoolValue; + } + + if (convar == g_radar ) + { + g_bradar = g_radar.BoolValue; + } + + if(convar == g_moneyhud) + { + g_bmoneyhud = g_moneyhud.BoolValue; + } + + if(convar == g_killfeed) + { + g_bkillfeed = g_killfeed.BoolValue; + } + + if(convar == g_blockradioagent) + { + g_bblockradioagent = g_blockradioagent.BoolValue; + } + + if(convar == g_blockwhell) + { + g_bblockwhell = g_blockwhell.BoolValue; + } + + if(convar == g_blockclantag) + { + g_bblockclantag = g_blockclantag.BoolValue; + } + + if(convar == g_cheats) + { + g_bcheats = g_cheats.BoolValue; + } + + if(convar == g_msgconnect) + { + g_bmsgconnect = g_msgconnect.BoolValue; + } + + if(convar == g_msgdisconnect) + { + g_bmsgdisconnect = g_msgdisconnect.BoolValue; + } + + if(convar == g_msgjointeam) + { + g_bmsgjointeam = g_msgjointeam.BoolValue; + } + + if(convar == g_msgchangeteam) + { + g_bmsgchangeteam = g_msgchangeteam.BoolValue; + } + + if(convar == g_msgcvar) + { + g_bmsgcvar = g_msgcvar.BoolValue; + } + + if(convar == g_msgmoney) + { + g_bmsgmoney = g_msgmoney.BoolValue; + } + + if(convar == g_msgsavedby) + { + g_bmsgsavedby = g_msgsavedby.BoolValue; + } + + if(convar == g_msgteamattack) + { + g_bmsgteamattack = g_msgteamattack.BoolValue; + } + + if(convar == g_msgchangename) + { + g_bmsgchangename = g_msgchangename.BoolValue; + } + + if(convar == g_forceend) + { + g_bforceend = g_forceend.BoolValue; + } + + if(convar == g_blockchicken) + { + g_bblockchicken = g_blockchicken.BoolValue; + } + + if(convar == g_blockweapondrop) + { + g_bblockweapondrop = g_blockweapondrop.BoolValue; + } + + if(convar == g_showtime) + { + g_bshowtime = g_showtime.BoolValue; + } + + if(convar == g_blockautomute) + { + g_bblockautomute = g_blockautomute.BoolValue; + } + + if(convar == g_blockfootsteps) + { + g_bblockfootsteps = g_blockfootsteps.BoolValue; + } + + if(convar == g_blockjumpland) + { + g_bblockjumpland = g_blockjumpland.BoolValue; + } + + if(convar == g_blockroundendsound) + { + g_bblockroundendsound = g_blockroundendsound.BoolValue; + } + + if(convar == g_blockradiostartround) + { + g_bblockradiostartround = g_blockradiostartround.BoolValue; + } + + if(convar == g_blockfalldamage) + { + g_bblockfalldamage = g_blockfalldamage.BoolValue; + } + + LoadCfg(); + + return 0; +} + + +public Action Event_RoundStart(Event event, const char[] name, bool quite) +{ + if (!g_benable || !g_bblockroundendsound) return Plugin_Continue; + + if (!quite) + { + SetEventBroadcast(event, true); + } + return Plugin_Changed; +} + + +public Action Event_RoundEnd(Event event, const char[] name, bool quite) +{ + if (!g_benable || !g_bblockroundendsound) return Plugin_Continue; + + if (!quite) + { + SetEventBroadcast(event, true); + } + return Plugin_Changed; +} + +public void OnConfigsExecuted() +{ + + g_benable = GetConVarBool(g_enable); + g_bradar = GetConVarBool(g_radar); + g_bmoneyhud = GetConVarBool(g_moneyhud); + g_bkillfeed = GetConVarBool(g_killfeed); + g_bblockradioagent = GetConVarBool(g_blockradioagent); + g_bblockwhell = GetConVarBool(g_blockwhell); + g_bblockclantag = GetConVarBool(g_blockclantag); + g_bcheats = GetConVarBool(g_cheats); + g_bmsgconnect = GetConVarBool(g_msgconnect); + g_bmsgdisconnect = GetConVarBool(g_msgdisconnect); + g_bmsgjointeam = GetConVarBool(g_msgjointeam); + g_bmsgchangeteam = GetConVarBool(g_msgchangeteam); + g_bmsgcvar = GetConVarBool(g_msgcvar); + g_bmsgmoney = GetConVarBool(g_msgmoney); + g_bmsgsavedby = GetConVarBool(g_msgsavedby); + g_bmsgteamattack = GetConVarBool(g_msgteamattack); + g_bmsgchangename = GetConVarBool(g_msgchangename); + g_bforceend = GetConVarBool(g_forceend); + g_bblockchicken = GetConVarBool(g_blockchicken); + g_bblockweapondrop = GetConVarBool(g_blockweapondrop); + g_bshowtime = GetConVarBool(g_showtime); + g_bblockautomute = GetConVarBool(g_blockautomute); + g_bblockfootsteps = GetConVarBool(g_blockfootsteps); + g_bblockjumpland = GetConVarBool(g_blockjumpland); + g_bblockroundendsound = GetConVarBool(g_blockroundendsound); + g_bblockradiostartround = GetConVarBool(g_blockradiostartround); + g_bblockfalldamage = GetConVarBool(g_blockfalldamage); + + char acmConfigToExecValue[32]; + GetConVarString(rotation_config_to_exec, acmConfigToExecValue, sizeof(acmConfigToExecValue)); + if (rotationMapChangeOccured && strcmp(acmConfigToExecValue, "") != 0) + { + PrintToServer("Game_Manager : Exec'ing %s.", acmConfigToExecValue); + ServerCommand("exec %s", acmConfigToExecValue); + } + + minutesBelowClientLimit = 0; + rotationMapChangeOccured = false; + + CreateTimer(60.0, CheckPlayerCount, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); + + + if( g_bStartRandomMap && !g_bServerStarted) + { + g_bServerStarted = true; + ChangeMap("Server is restarted"); + } + if( g_ConVarHibernate != null ) + { + g_iHybernateInitial = g_ConVarHibernate.IntValue; + g_ConVarHibernate.SetInt(0); + } + + LoadCfg(); +} + +void ChangeMap(char[] reason) +{ + char sMap[64]; + SetRandomSeed(GetTime()); + + ArrayList al = new ArrayList(ByteCountToCells(sizeof(sMap))); + + delete al; + LogToFileEx(g_sLogPath, "Changing map to: %s... Reason: %s", sMap, reason); + if( CommandExists("sm_map") ) + { + ServerCommand("sm_map %s", sMap); + } + else { + ForceChangeLevel(sMap, reason); + } +} + + +void LoadCfg() +{ + if( g_benable ) + { + if( g_bmoneyhud ) + { + SetConVarInt(FindConVar("mp_playercashawards"), 0); + SetConVarInt(FindConVar("mp_teamcashawards"), 0); + }else + + if( !g_bmoneyhud ) + { + SetConVarInt(FindConVar("mp_playercashawards"), 1); + SetConVarInt(FindConVar("mp_teamcashawards"), 1); + } + + if (g_msgsshorthanded.IntValue == 0) + { + ServerCommand("cash_team_bonus_shorthanded 1"); + }else + + if (g_msgsshorthanded.IntValue == 1) + { + ServerCommand("cash_team_bonus_shorthanded 0"); + } + + if (g_blockradionade.IntValue == 0) + { + ServerCommand("sv_ignoregrenaderadio 0"); + }else + + if (g_blockradionade.IntValue == 1) + { + ServerCommand("sv_ignoregrenaderadio 1"); + } + + if( g_bradar ) + { + ServerCommand("sv_disable_radar 1"); + }else + + if( !g_bradar ) + { + ServerCommand("sv_disable_radar 0"); + } + + if( g_bblockfalldamage ) + { + ServerCommand("sv_falldamage_scale 0"); + }else + + if( !g_bblockfalldamage ) + { + ServerCommand("sv_falldamage_scale 1"); + } + + if( g_bblockjumpland ) + { + ServerCommand("sv_min_jump_landing_sound 999999"); + }else + + if( !g_bblockjumpland ) + { + ServerCommand("sv_min_jump_landing_sound 260"); + } + + if( g_bblockfootsteps ) + { + ServerCommand("sm_cvar sv_footsteps 0"); + }else + + if( !g_bblockfootsteps ) + { + ServerCommand("sm_cvar sv_footsteps 1"); + } + + if( g_bblockautomute ) + { + ServerCommand("sm_cvar sv_mute_players_with_social_penalties 0"); + }else + + if( !g_bblockautomute ) + { + ServerCommand("sm_cvar sv_mute_players_with_social_penalties 1"); + } + } +} + +public void OnMapStart() +{ + if (g_delayenable && g_hookenabled == false) { + g_botDelay = GetConVarInt(g_Cvar_BotDelay); + bot_delay_timer = CreateTimer(g_botDelay * 1.0, Timer_BotDelay); + } + + CreateTimer(1.0, CheckRemainingTime, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); +} + +public void OnMapEnd() { + if (g_delayenable && g_hookenabled == true) { + UnhookEvent("player_team", Event_PlayerTeam); + g_hookenabled = false; + } + + if(bot_delay_timer != INVALID_HANDLE) { + KillTimer(bot_delay_timer); + bot_delay_timer = INVALID_HANDLE; + } +} + +public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) +{ + + if( g_benable ) + { + if( g_bkillfeed ) + { + event.BroadcastDisabled = true; + } + } else { + if( !g_bkillfeed ) + { + event.BroadcastDisabled = false; + } + } + + return Plugin_Continue; +} + +public Action Timer_Wep(Handle timer) +{ + int maxEntities; + maxEntities = GetMaxEntities(); + char classx[20]; + if (!g_benable || !g_bblockweapondrop) return Plugin_Continue; + + int j; + for (j = MaxClients + 1; j < maxEntities; j++) + { + if (IsValidEdict(j) && (GetEntDataEnt2(j, g_ownerOffset) == -1)) + { + GetEdictClassname(j, classx, sizeof(classx)); + if ((StrContains(classx, "weapon_") != -1) || (StrContains(classx, "item_") != -1)) + { + AcceptEntityInput(j, "Kill"); + } + } + } + return Plugin_Continue; +} + +public Action OnRadio(int client, const char[] command, int args) +{ + return (g_benable && g_bblockradioagent) ? + Plugin_Handled : + Plugin_Continue; +} + +public Action OnRadioText(UserMsg msg_id, Protobuf bf, const int[] players, int playersNum, bool reliable, bool init) +{ + return (g_benable && g_bblockradioagent) ? + Plugin_Handled : + Plugin_Continue; +} + +public Action Command_Ping(int iClient, char[] command, int args) +{ + return (g_benable && g_bblockwhell) ? + Plugin_Handled : + Plugin_Continue; +} + + +public Action OnClientCommandKeyValues(int client, KeyValues kv) +{ + if (!g_benable || !g_bblockclantag)return Plugin_Continue; + + char sSection[16]; + if (kv.GetSectionName(sSection, sizeof(sSection)) && StrEqual(sSection, "ClanTagChanged")) + return Plugin_Handled; + + return Plugin_Continue; +} + +public int CCheats(Handle cvar, char[] oldValue, char[] newValue) +{ + bool Status; + if ((g_benable && g_bcheats) && (Status = GetConVarBool(Cheats))) + CreateTimer(0.1, CCheats_Delay, !Status); + return 0; +} + +public Action CCheats_Delay(Handle hTimer, any NewStatus) +{ + SetConVarBool(Cheats, NewStatus, true, false); + return Plugin_Continue; +} + +public Action OnPlayerConnect(Handle hEvent, const char[] name, bool dontBroadcast) +{ + return (g_benable && g_bmsgconnect) ? + Plugin_Handled : + Plugin_Continue; +} + +public Action OnPlayerDisconnect(Handle hEvent, const char[] name, bool dontBroadcast) +{ + return (g_benable && g_bmsgdisconnect) ? + Plugin_Handled : + Plugin_Continue; +} + +public Action OnPlayerTeam(Handle hEvent, const char[] name, bool dontBroadcast) +{ + if (!GetEventBool(hEvent, "disconnect") && g_benable) + { + int iOldTeam = GetEventInt(hEvent, "oldteam"); + + if ((g_bmsgjointeam && iOldTeam == 0) + || (g_bmsgchangeteam && iOldTeam != 0)) + SetEventBool(hEvent, "silent", true); + } + + return Plugin_Continue; +} + +public Action OnServerCvar(Handle hEvent, const char[] name, bool dontBroadcast) +{ + return (g_benable && g_bmsgcvar) ? + Plugin_Handled : + Plugin_Continue; +} + +public Action OnHookTextMsg(UserMsg msg_id, Handle bf, int[] players, int playersNum, bool reliable, bool init) +{ + if (!g_benable || !g_bmsgmoney)return Plugin_Continue; + + char sBuffer[64]; + PbReadString(bf, "params", sBuffer, sizeof(sBuffer), 0); + + for (int i = 0; i < sizeof(MoneyMessageArray); i++) + { + if (!strcmp(sBuffer, MoneyMessageArray[i], false))return Plugin_Handled; + } + + return Plugin_Continue; +} + +public Action OnHookTextMsg2(UserMsg msg_id, Handle bf, int[] players, int playersNum, bool reliable, bool init) +{ + if (!g_benable || !g_bmsgsavedby)return Plugin_Continue; + + char sBuffer[64]; + PbReadString(bf, "params", sBuffer, sizeof(sBuffer), 0); + + for (int i = 0; i < sizeof(SavedbyArray); i++) + { + if (!strcmp(sBuffer, SavedbyArray[i], false))return Plugin_Handled; + } + + return Plugin_Continue; +} + +public Action OnHookTextMsg3(UserMsg msg_id, Handle bf, int[] players, int playersNum, bool reliable, bool init) +{ + if (!g_benable || !g_bmsgteamattack)return Plugin_Continue; + + char sBuffer[64]; + PbReadString(bf, "params", sBuffer, sizeof(sBuffer), 0); + + for (int i = 0; i < sizeof(TeamWarningArray); i++) + { + if (!strcmp(sBuffer, TeamWarningArray[i], false))return Plugin_Handled; + } + + return Plugin_Continue; +} + +public Action OnHookTextMsg4(UserMsg msg_id, Handle bf, int[] players, int playersNum, bool reliable, bool init) +{ + if (!g_benable || !g_bmsgchangename)return Plugin_Continue; + + char buffer[25]; + + if(GetUserMessageType() == UM_Protobuf) + { + PbReadString(bf, "msg_name", buffer, sizeof(buffer)); + + if(StrEqual(buffer, "#Cstrike_Name_Change")) + { + return Plugin_Handled; + } + } + return Plugin_Continue; +} + +public Action CheckRemainingTime(Handle timer) +{ + if (!g_benable || !g_bforceend)return Plugin_Continue; + Handle hTmp; + hTmp = FindConVar("mp_timelimit"); + int iTimeLimit = GetConVarInt(hTmp); + if (hTmp != INVALID_HANDLE) + CloseHandle(hTmp); + if (iTimeLimit > 0) + { + int timeleft; + GetMapTimeLeft(timeleft); + + switch(timeleft) + { + case 1800: CPrintToChatAll("%t","min30"); + case 1200: CPrintToChatAll("%t","min20"); + case 600: CPrintToChatAll("%t","min10"); + case 300: CPrintToChatAll("%t","min5"); + case 120: CPrintToChatAll("%t","min2"); + case 60: CPrintToChatAll("%t","60sec"); + case 30: CPrintToChatAll("%t","30sec"); + case 15: CPrintToChatAll("%t","15sec"); + case -1: CPrintToChatAll("%t","3sec"); + case -2: CPrintToChatAll("%t","2sec"); + case -3: CPrintToChatAll("%t","1sec"); + } + + if(timeleft < -3) + CS_TerminateRound(0.0, CSRoundEnd_Draw, true); + } + + return Plugin_Continue; +} + +public Action CS_OnTerminateRound(float &fDelay, CSRoundEndReason &iReason) +{ + if (!g_benable || !g_bforceend)return Plugin_Continue; + return Plugin_Continue; +} + +public void OnEntityCreated(int entity, const char[] classname) +{ + if (classname[0] == 'c') + { + if (StrEqual(classname, "chicken", true)) + { + SDKHook(entity, SDKHook_Spawn, SDK_OnChickenSpawn); + } + } + else if (classname[0] == 'i') + { + if (StrEqual(classname, "info_map_parameters", true)) + { + SDKHook(entity, SDKHook_Spawn, SDK_OnMapParametersSpawn); + } + } +} + +public Action SDK_OnChickenSpawn(int entity) +{ + if (!g_benable || !g_bblockchicken)return Plugin_Continue; + if (!IsValidEntity(entity)) + { + return Plugin_Continue; + } + + RequestFrame(Frame_RemoveEntity, EntIndexToEntRef(entity)); + return Plugin_Continue; +} + +public Action SDK_OnMapParametersSpawn(int entity) +{ + if (!g_benable || !g_bblockchicken)return Plugin_Continue; + if (!IsValidEntity(entity)) + { + return Plugin_Continue; + } + + SetEntProp(entity, Prop_Data, "m_iPetPopulation", 0); + return Plugin_Continue; +} +public void Frame_RemoveEntity(int reference) +{ + int entity = EntRefToEntIndex(reference); + if (entity == INVALID_ENT_REFERENCE) + { + return; + } + + AcceptEntityInput(entity, "Kill"); +} + +public void OnConVarChange(Handle convar, const char[] oldValue, const char[] newValue) +{ + if(convar == Cvar_ListX) + { + g_ListX = StringToFloat(newValue); + if( (g_ListX > 1.0 || g_ListX < 0) && g_ListX != -1.0) + { + PrintToServer("[Speclist] Error - Invalid X coordinate value: %f", g_ListX); + g_ListX = 0.17; + } + } + else if(convar == Cvar_ListY) + { + g_ListY = StringToFloat(newValue); + if( (g_ListY > 1.0 || g_ListY < 0) && g_ListY != -1.0) + { + PrintToServer("[Speclist] Error - Invalid Y coordinate value: %f", g_ListY); + g_ListY = 0.01; + } + } + else if(convar == Cvar_ListColor) + StrToRGBA(newValue); +} + +public Action Timeleft(Handle timer) +{ + if (!g_benable || !g_bshowtime)return Plugin_Continue; + char sTime[60]; + int iTimeleft; + + GetMapTimeLeft(iTimeleft); + if(iTimeleft > 0) + { + FormatTime(sTime, sizeof(sTime), "%M:%S", iTimeleft); + + for(int i = 1; i <= MaxClients; i++) + { + if(IsClientInGame(i) && !IsFakeClient(i)) + { + char message[60]; + Format(message, sizeof(message), "%t %s", "timerhud", sTime); + SetHudTextParams(g_ListX, g_ListY, 1.0, g_iListColor[0], g_iListColor[1], g_iListColor[2], g_iListColor[3], 0, 0.00, 0.00, 0.00); + ShowHudText(i, -1, message); + } + } + } + return Plugin_Continue; +} +void StrToRGBA(const char[] Color) +{ + char buffer[4][16]; + + if(ExplodeString(Color, " ", buffer, sizeof(buffer), sizeof(buffer[])) > 3) + { + for(int i = 0; i < 4; i++) + { + g_iListColor[i] = StringToInt(buffer[i], 10); + if(g_iListColor[i] > 255 || g_iListColor[i] < 0) + { + g_iListColor[i] = 255; + PrintToServer("[Speclist] Error - RGBA[%d]=%d is not in the range 0-255", i, g_iListColor[i]); + } + } + } + else + { + g_iListColor = {255, 255, 255, 150}; + PrintToServer("[Speclist] Error - Invalid color format: %s", Color); + } +} + +public Action Call_Back_Radio(int clients[MAXPLAYERS], int &numClients, char sample[PLATFORM_MAX_PATH], int &entity, int &channel, float &volume, int &level, int &pitch, int &flags, char soundEntry[PLATFORM_MAX_PATH], int &seed) +{ + if (IsValidEdict(entity) && IsValidEntity(entity)) + { + if (g_benable) + { + if (g_bblockradiostartround) + { + if (StrContains(sample, "request_move") != -1 || StrContains(sample, "round_start") != -1|| StrContains(sample, "radiobotstart") != -1 || StrContains(sample, "letsgo") != -1 || StrContains(sample, "locknload") != -1) + { + return Plugin_Handled; + } + } + } + } + return Plugin_Continue; +} + +public Action Event_PreRoundStart(Handle event, const char[] name, bool dontBroadcast) +{ + int T_Count = GetTeamClientCount(CS_TEAM_T); + int CT_Count = GetTeamClientCount(CS_TEAM_CT); + + if(!g_benable || !GetConVarBool(g_balance) || T_Count == CT_Count || T_Count + 1 == CT_Count || CT_Count + 1 == T_Count) + return Plugin_Continue; + + while(T_Count > CT_Count && T_Count != CT_Count + 1) + { + int client = GetRandomPlayer(CS_TEAM_T); + CS_SwitchTeam(client, CS_TEAM_CT); + T_Count--; + CT_Count++; + } + while(T_Count < CT_Count && CT_Count != T_Count + 1) + { + int client = GetRandomPlayer(CS_TEAM_CT); + CS_SwitchTeam(client, CS_TEAM_T); + CT_Count--; + T_Count++; + } + return Plugin_Continue; +} +stock int GetRandomPlayer(int team) +{ + int[] clients = new int[MaxClients]; + int clientCount; + for (int i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i) && GetClientTeam(i) == team) + { + clients[clientCount++] = i; + } + } + return (clientCount == 0) ? -1 : clients[GetRandomInt(0, clientCount - 1)]; +} + +public void CvarChanged(Handle cvar, const char[] oldValue, const char[] newValue){ + if (cvar == g_enable) { + g_eenable = GetConVarBool(g_enable); + CheckBalance(); + return; + } + if (cvar == g_Cvar_BotQuota) { + g_botQuota = GetConVarInt(g_Cvar_BotQuota); + CheckBalance(); + return; + } + if (cvar == g_Cvar_BotDelayEnable) { + g_delayenable = GetConVarBool(g_Cvar_BotDelayEnable); + CheckBalance(); + return; + } + if (cvar == g_Cvar_BotDelay) { + g_botDelay = GetConVarInt(g_Cvar_BotDelay); + CheckBalance(); + return; + } +} + +public Action Timer_BotDelay(Handle timer) { + RecalcTeamCount(); + CheckBalance(); + HookEvent("player_team", Event_PlayerTeam); + g_hookenabled = true; + + bot_delay_timer = INVALID_HANDLE; + return Plugin_Continue; +} + +void RecalcTeamCount() { + g_Tcount = 0; + g_CTcount = 0; + g_BotTcount = 0; + g_BotCTcount = 0; + for( int i = 1; i <= MaxClients; i++ ) { + if (IsClientInGame(i)) { + ChangeTeamCount(GetClientTeam(i), 1, IsFakeClient(i)); + } + } +} + +void ChangeTeamCount(int team, int diff, bool isBot) { + switch (team) { + case TEAM_T: { + if (isBot) { + g_BotTcount += diff; + } else { + g_Tcount += diff; + } + } + case TEAM_CT: { + if (isBot) { + g_BotCTcount += diff; + } else { + g_CTcount += diff; + } + } + } +} +public void Event_PlayerTeam(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(GetEventInt(event, "userid")); + int oldTeam = GetEventInt(event, "oldteam"); + int newTeam = GetEventInt(event, "team"); + bool disconnect = GetEventBool(event, "disconnect"); + + if (!disconnect) { + ChangeTeamCount(oldTeam, -1, IsFakeClient(client)); + ChangeTeamCount(newTeam, 1, IsFakeClient(client)); + } else { + RecalcTeamCount(); + } + + CheckBalance(); +} + +void CheckBalance() { + if (!g_eenable || (g_botQuota <= 0)) { + return; + } + + int bots = g_BotTcount + g_BotCTcount; + int humans = g_Tcount + g_CTcount; + + if (bots > 0 && humans == 0) { + ServerCommand("bot_kick all"); + } else if (humans >= g_botQuota && bots > 0) { + ServerCommand("bot_kick"); + } else if (humans < g_botQuota) { + int botQuota = g_botQuota - humans; + if (humans < 3) { + botQuota = botQuota - 2; + } + if (bots > botQuota) { + ServerCommand("bot_kick %s", (g_BotCTcount > g_BotTcount) ? "ct" : "t"); + } else if (bots < botQuota) { + ServerCommand("bot_add %s", (g_BotCTcount + g_CTcount <= g_BotTcount + g_Tcount) ? "ct" : "t"); + } + } +} + +public Action TE_OnEffectDispatch(const char[] te_name, const int[] Players, int numClients, float delay) +{ + if (!g_benable || !g_cEnableNoSplatter.BoolValue) return Plugin_Continue; + + int iEffectIndex = TE_ReadNum("m_iEffectName"); + int nHitBox = TE_ReadNum("m_nHitBox"); + char sEffectName[64]; + + GetEffectName(iEffectIndex, sEffectName, sizeof(sEffectName)); + + if (StrEqual(sEffectName, "csblood")|| StrEqual(sEffectName, "Impact")) + { + return Plugin_Handled; + } + + if (StrEqual(sEffectName, "ParticleEffect")) + { + char sParticleEffectName[64]; + GetParticleEffectName(nHitBox, sParticleEffectName, sizeof(sParticleEffectName)); + if(StrEqual(sParticleEffectName, "impact_helmet_headshot")) + { + return Plugin_Handled; + } + } + return Plugin_Continue; +} + +public Action TE_OnWorldDecal(const char[] te_name, const int[] Players, int numClients, float delay) +{ + if (!g_benable || !g_cEnableNoBlood.BoolValue) return Plugin_Continue; + + float vecOrigin[3]; + int nIndex = TE_ReadNum("m_nIndex"); + char sDecalName[64]; + + TE_ReadVector("m_vecOrigin", vecOrigin); + GetDecalName(nIndex, sDecalName, sizeof(sDecalName)); + + if (StrContains(sDecalName, "decals/blood") == 0 && StrContains(sDecalName, "_subrect") != -1) + { + return Plugin_Handled; + } + return Plugin_Continue; +} + +stock int GetParticleEffectName(int index, char[] sEffectName, int maxlen) +{ + int table = INVALID_STRING_TABLE; + + if (table == INVALID_STRING_TABLE) + { + table = FindStringTable("ParticleEffectNames"); + } + + return ReadStringTable(table, index, sEffectName, maxlen); +} + +stock int GetEffectName(int index, char[] sEffectName, int maxlen) +{ + int table = INVALID_STRING_TABLE; + + if (table == INVALID_STRING_TABLE) + { + table = FindStringTable("EffectDispatch"); + } + + return ReadStringTable(table, index, sEffectName, maxlen); +} + +stock int GetDecalName(int index, char[] sDecalName, int maxlen) +{ + int table = INVALID_STRING_TABLE; + + if (table == INVALID_STRING_TABLE) + { + table = FindStringTable("decalprecache"); + } + + return ReadStringTable(table, index, sDecalName, maxlen); +} + +public Action PlayerHurt_Event(Event event, const char[] name, bool dontBroadcast) +{ + int attacker = GetClientOfUserId(event.GetInt("attacker")); + + g_phitted[attacker] = true; + + return Plugin_Continue; +} + +public Action Call_Back_Sound(int clients[MAXPLAYERS], int &numClients, char sample[PLATFORM_MAX_PATH], int &entity, int &channel, float &volume, int &level, int &pitch, int &flags, char soundEntry[PLATFORM_MAX_PATH], int &seed) +{ + char classname[64]; + GetEdictClassname(entity, classname, sizeof(classname)); + + if (IsValidEdict(entity) && IsValidEntity(entity)) + { + if(StrContains(sample, "flesh") != -1 || StrContains(sample, "kevlar") != -1) + { + if (GetConVarBool(g_enable)) + { + if (GetConVarBool(g_knifesound)) + { + numClients = 0; + + return Plugin_Changed; + } + } + } + + if(StrContains(classname, "knife") != -1) + { + int client = GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity"); + + if(!IsValidClient(client, false)) + return Plugin_Continue; + + if(g_phitted[client]) + { + g_phitted[client] = false; + return Plugin_Continue; + } + + if (GetConVarBool(g_enable)) + { + if (GetConVarBool(g_knifesound)) + { + numClients = 0; + + g_phitted[client] = false; + } + } + return Plugin_Changed; + } + } + return Plugin_Continue; +} + +stock bool IsValidClient(int client, bool botcheck = true) +{ + return (1 <= client && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client) && (botcheck ? !IsFakeClient(client) : true)); +} + +public void OnCvarChanged(ConVar convar, const char[] oldValue, const char[] newValue) +{ + GetCvars(); +} + +void GetCvars() +{ + g_bCvarEnabled = g_ConVarEnable.BoolValue; + g_iCvarMethod = g_ConVarMethod.IntValue; + g_fCvarDelay = g_ConVarDelay.FloatValue; + + InitHook(); +} + +void InitHook() +{ + static bool bHooked; + + if( g_bCvarEnabled ) + { + if( !bHooked ) + { + HookEvent("player_disconnect", Event_PlayerDisconnect, EventHookMode_Pre); + bHooked = true; + } + } else { + if( bHooked ) + { + UnhookEvent("player_disconnect", Event_PlayerDisconnect, EventHookMode_Pre); + bHooked = false; + } + } +} + +public Action Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(event.GetInt("userid")); + + if( client == 0 || !IsFakeClient(client) ) + { + if( !RealPlayerExist(client) ) + { + + if( g_ConVarHibernate != null ) + { + g_ConVarHibernate.SetInt(0); + } + CreateTimer(g_fCvarDelay, Timer_CheckPlayers); + return Plugin_Continue; + + } + } + return Plugin_Continue; +} + + + +public Action Timer_CheckPlayers(Handle timer, int UserId) +{ + if( !RealPlayerExist() ) + { + StartRebootSequence(); + } + return Plugin_Continue; +} + +void StartRebootSequence() +{ + if( g_iCvarMethod != 2 ) + { + UnloadPluginsExcludeMe(); + KickAll(); + } + CreateTimer(0.1, Timer_RestartServer); +} + +public Action Timer_RestartServer(Handle timer) +{ + RestartServer(); + return Plugin_Continue; +} + +void RestartServer() +{ + switch( g_iCvarMethod ) + { + case 1: { + LogToFileEx(g_sLogPath, "Sending '_restart'... Reason: %s", RealPlayerExist() ? "Scheduled time" : "Empty Server"); + ServerCommand("_restart"); + } + case 2: { + LogToFileEx(g_sLogPath, "Sending 'crash'... Reason: %s", RealPlayerExist() ? "Scheduled time" : "Empty Server"); + SetCommandFlags("crash", GetCommandFlags("crash") &~ FCVAR_CHEAT); + ServerCommand("crash"); + } + } +} + +void KickAll() +{ + for( int i = 1; i <= MaxClients; i++ ) + { + if( IsClientInGame(i) ) + { + KickClient(i, "Server Restarts"); + } + } +} + +void UnloadPluginsExcludeMe() +{ + char name[64]; + Handle hPlugin; + Handle hIter = GetPluginIterator(); + + if( hIter ) + { + while( MorePlugins(hIter) ) + { + hPlugin = ReadPlugin(hIter); + + if( hPlugin != hPluginMe && hPlugin != INVALID_HANDLE ) + { + GetPluginFilename(hPlugin, name, sizeof(name)); + ServerCommand("sm plugins unload \"%s\"", name); + ServerExecute(); + } + } + CloseHandle(hIter); + } +} + + +public Action Timer_DoHybernate(Handle timer) +{ + if ( !RealPlayerExist() ) + { + g_ConVarHibernate.SetInt(g_iHybernateInitial); + } + return Plugin_Continue; +} + +public Action CheckPlayerCount(Handle timer) +{ + int acmClientLimitValue = GetConVarInt(rotation_client_limit); + + if (GetConVarInt(rotation_include_bots) == 0) + { + int players; + for (int i = 1; i <= MaxClients; i++) + { + if (IsClientConnected(i) && !IsFakeClient(i)) + { + players ++; + } + } + if (players < acmClientLimitValue) + { + minutesBelowClientLimit++; + } + else + { + minutesBelowClientLimit = 0; + } + } + else + { + if (GetClientCount() < acmClientLimitValue) + { + minutesBelowClientLimit++; + } + else + { + minutesBelowClientLimit = 0; + } + } + if(GetConVarBool(rotation_enable)) + { + if (minutesBelowClientLimit >= GetConVarInt(rotation_time_limit)) + { + SetMap(); + } + } + + return Plugin_Continue; +} + +void SetMap() +{ + + int acmModeValue = GetConVarInt(rotation_mode); + char nextmap[32]; + + switch(acmModeValue) + { + case 1: + { + if (ReadMapList(g_MapList, + g_MapListSerial, + "gamemanager", + MAPLIST_FLAG_CLEARARRAY|MAPLIST_FLAG_NO_DEFAULT) + == INVALID_HANDLE) + { + if (g_MapListSerial == -1) + { + LogError("FATAL: Cannot load map cycle."); + SetFailState("Mapcycle Not Found"); + } + } + + int mapCount = GetArraySize(g_MapList); + + if (g_MapPos == -1) + { + char current[64]; + GetCurrentMap(current, 64); + + for (int i = 0; i < mapCount; i++) + { + GetArrayString(g_MapList, i, nextmap, sizeof(nextmap)); + if (strcmp(current, nextmap, false) == 0) + { + g_MapPos = i; + break; + } + } + + if (g_MapPos == -1) + { + g_MapPos = 0; + } + } + + g_MapPos++; + if (g_MapPos >= mapCount) + { + g_MapPos = 0; + } + + GetArrayString(g_MapList, g_MapPos, nextmap, sizeof(nextmap)); + if (!IsMapValid(nextmap)) + { + PrintToServer("Game_Manager : invalid map name ('%s') found in mapcycle. Reloading current map...", nextmap); + GetCurrentMap(nextmap, sizeof(nextmap)); + } + + } + + case 2: + { + Handle h_sm_nextmap = FindConVar("sm_nextmap"); + + if (h_sm_nextmap == INVALID_HANDLE) + { + LogError("FATAL: Cannot find sm_nextmap cvar."); + SetFailState("sm_nextmap not found"); + } + + GetConVarString(h_sm_nextmap, nextmap, sizeof(nextmap)); + if (!IsMapValid(nextmap)) + { + PrintToServer("Game_Manager : sm_nextmap ('%s') does not contain valid map name. Reloading current map...", nextmap); + GetCurrentMap(nextmap, sizeof(nextmap)); + SetConVarString(h_sm_nextmap, nextmap); + } + CloseHandle(h_sm_nextmap); + } + + case 3: + { + GetConVarString(rotation_default_map, nextmap, sizeof(nextmap)); + + if (!IsMapValid(nextmap)) + { + PrintToServer("Game_Manager : Game_Manager_default_map ('%s') does not contain valid map name. Reloading current map...", nextmap); + GetCurrentMap(nextmap, sizeof(nextmap)); + } + + } + + default: + { + GetCurrentMap(nextmap, sizeof(nextmap)); + } + } + Handle nextmapPack; + CreateDataTimer(5.0, ChangeMapp, nextmapPack, TIMER_FLAG_NO_MAPCHANGE); + WritePackString(nextmapPack, nextmap); + PrintToChatAll("Game_Manager : Changing map to %s.", nextmap); + +} + +public Action ChangeMapp(Handle timer, Handle mapPack) +{ + char map[32]; + ResetPack(mapPack); + ReadPackString(mapPack, map, sizeof(map)); + rotationMapChangeOccured = true; + ServerCommand("changelevel %s", map); + return Plugin_Continue; +} + +bool RealPlayerExist(int iExclude = 0) +{ + for( int client = 1; client <= MaxClients; client++ ) + { + if( client != iExclude && IsClientConnected(client) ) + { + if( !IsFakeClient(client) ) + { + return true; + } + } + } + return false; +} + +void RemoveCrashLog() +{ + if( !FileExists(g_sLogPath) ) + { + return; + } + + char sFile[PLATFORM_MAX_PATH]; + int ft, ftReport = GetFileTime(g_sLogPath, FileTime_LastChange); + + if( DirExists("CRASH") ) + { + DirectoryListing hDir = OpenDirectory("CRASH"); + if( hDir != null ) + { + while( hDir.GetNext(sFile, sizeof(sFile)) ) + { + TrimString(sFile); + if( StrContains(sFile, "crash-") != -1 ) + { + Format(sFile, sizeof(sFile), "CRASH/%s", sFile); + ft = GetFileTime(sFile, FileTime_Created); + + if( 0 <= ft - ftReport < 10 ) + { + DeleteFile(sFile); + } + } + } + delete hDir; + } + } +} + +stock bool IsClientValid(int client) +{ + if(client > 0 && client <= MaxClients && IsClientInGame(client)) + return true; + return false; +} diff --git a/addons/sourcemod/scripting/include/multicolors.inc b/addons/sourcemod/scripting/include/multicolors.inc new file mode 100644 index 0000000..e6612a7 --- /dev/null +++ b/addons/sourcemod/scripting/include/multicolors.inc @@ -0,0 +1,460 @@ +#if defined _multicolors_included + #endinput +#endif +#define _multicolors_included + +#define MuCo_VERSION "2.1.2" + +#include +#include + +/* +* +* 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..fead95c --- /dev/null +++ b/addons/sourcemod/scripting/include/multicolors/colors.inc @@ -0,0 +1,897 @@ +/************************************************************************** + * * + * 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\n", tag, szBuffer); + display_in_chat = true; + } + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", 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 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\n", tag, szBuffer); + display_in_chat = true; + } + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", 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, 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 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", tag, szBuffer); + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + C_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, 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..2020b60 --- /dev/null +++ b/addons/sourcemod/scripting/include/multicolors/morecolors.inc @@ -0,0 +1,992 @@ +// 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 (!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 (!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); + } + + 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); + } + + 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\n", tag, szBuffer); + display_in_chat = true; + } + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 3); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", 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 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\n", tag, szBuffer); + display_in_chat = true; + } + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", 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, 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 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", tag, szBuffer); + } + else { + SetGlobalTransTarget(LANG_SERVER); + VFormat(szBuffer, sizeof(szBuffer), format, 4); + + MC_RemoveTags(szBuffer, sizeof(szBuffer)); + PrintToServer("%s%s\n", tag, 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/Game_Manager.phrases.txt b/addons/sourcemod/translations/Game_Manager.phrases.txt new file mode 100644 index 0000000..6fda54e --- /dev/null +++ b/addons/sourcemod/translations/Game_Manager.phrases.txt @@ -0,0 +1,87 @@ +"Phrases" +{ + "min30" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 30 minutes." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 30 минуты" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 30 minutos." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:30 分钟。" + } + "min20" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 20 minutes." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 20 минуты" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 20 minutos." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:20 分钟。" + } + "min10" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 10 minutes." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 10 минуты" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 10 minutos." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:10 分钟。" + } + "min5" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 5 minutes." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 5 минуты" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 5 minutos." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:5 分钟。" + } + "min2" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 2 minutes." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 2 минуты" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 2 minutos." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:2 分钟。" + } + "60sec" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 60 seconds." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 60 секунды" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 60 segundas." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:60 秒。" + } + "30sec" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 30 seconds." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 30 секунды" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 30 segundas." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:30 秒。" + } + "15sec" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 15 seconds." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 15 секунды" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 15 segundas." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:15 秒。" + } + "3sec" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 3 seconds." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 3 секунды" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 3 segundas." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:3 秒。" + } + "2sec" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 2 seconds." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 2 секунды" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 2 segundas." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:2 秒。" + } + "1sec" + { + "en" " {green}Gold KingZ {grey}| {lightred}Timeleft: 1 seconds." + "ru" " {green}Gold KingZ {grey}| {lightred}Осталось времени: 1 секунды" + "pt" " {green}Gold KingZ {grey}| {lightred}Tempo restante: 1 segundas." + "chi" " {green}Gold KingZ {grey}| {lightred}剩余时间:1 秒。" + } + "timerhud" + { + "en" "TimeLeft:" + "ru" "Время вышло:" + "pt" "Tempo restante:" + "chi" "剩余时间:" + } +} \ No newline at end of file diff --git a/cfg/sourcemod/Game_Manager.cfg b/cfg/sourcemod/Game_Manager.cfg new file mode 100644 index 0000000..331b4cf --- /dev/null +++ b/cfg/sourcemod/Game_Manager.cfg @@ -0,0 +1,163 @@ +//|||||||||||||||||||||||||||||||||| BLOCK/HIDE/MISC FEATURE ||||||||||||||||||||||||||||||||||||||||||||| +// .::[Enable Hide And Block Feature]::. || 1= Yes || 0= No +gm_enable_hide_and_block "1" +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + +//////////////////////>> .;[ MESSAGES ];. + +// Hide Connect Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_connect_message "0" + +// Hide Disconnect Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_disconnect_message "0" + +// Hide Change Name Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_changename_message "0" + +// Hide Server Cvar Change Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_cvar_message "0" + +// Hide All Money Team/Player Award Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_hidemoney_message "0" + +// Hide First Time Connect Client Join Team Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_jointeam_message "0" + +// Hide Player Saved You By Player Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_savedby_message "0" + +// Hide Short-Handed Incoming Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_shorthanded_message "0" + +// Hide Team Change Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_teamchange_message "0" + +// Hide Team Mate Attack Messages (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_teammateattack_message "0" + + +//////////////////////>> .;[ SOUNDS ];. + +// Block All Radio Voice Agents (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_radio_voice_agents "0" + +// Block Round Start Radio Sounds (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_radio_start_agents "0" + +// Block All Radio Voice Grenades Throw (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_radio_voice_grenades "0" + +// Block Footsteps Sounds (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_footsteps_sound "0" + +// Block Jump Land Sounds (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_jumpland_sound "0" + +// Block Counter/Terrorist/Draw Win Sounds (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_roundend_sound "0" + +// Block Knife Sound If Its Zero Damage (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_zerodamge_knife "0" + + +//////////////////////>> .;[ OTHER ];. + +// Delete/Clean Weapons Dropped (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_weapon_drop "0" + +// Permanently Remove bots (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_bots "0" + +// Permanently Remove Chickens (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_chicken "0" + +// Permanently Block Both Dynamic + Animated + Normal ClanTags (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_clantag "0" + +// Auto Balance Every Round (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_auto_balance_every_round "0" + +// Remove Auto Communication Penalties (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_auto_mute "0" + +// Make sv_cheats 0 Automatically (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_cheats "0" + +// Disable Fall Damage (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_falldamage "0" + +// Block All Wheel + Ping (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_block_wheel "0" + +// Hide Splatter Effect (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_hide_splatter "0" + +// Hide Blood (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_hide_blood "0" + +// Hide Kill Feed (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_hide_killfeed "0" + +// Hide Money Hud (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_hide_moneyhud "0" + +// Hide Radar (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_hide_radar "0" + + +// Force End Map With Command mp_timelimit (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_forceendmap "0" + +// Show Timeleft HUD (mp_timelimit) (Need To Enable gm_enable_hide_and_block) || 1= Yes || 0= No +gm_show_timeleft_hud "0" + +// Hud color. [R G B A] Pick Colors https://rgbacolorpicker.com/ +gm_hud_colors "255 0 189 0.8" + +// X-Axis Location From 0 To 1.0 Check /~https://github.com/oqyh/Game-Manager/blob/main/images/hud%20postions.png For Help +gm_hud_xaxis "0.00" + +// Y-Axis Location From 0 To 1.0 Check /~https://github.com/oqyh/Game-Manager/blob/main/images/hud%20postions.png For Help +gm_hud_yaxis "0.35" + + + +//|||||||||||||||||||| RESTART LAST PLAYER DISCONNECT FEATURE |||||||||||||||||||||||| +// .::[Restart Server When Last Player Disconnect Feature]::. || 1= Yes || 0= No +gm_restart_empty_enable "0" +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + +// When server is empty Which Method Do You Like (Need To Enable gm_restart_empty_enable) || 1= Restart || 2= Crash If Method 1 Is Not work +gm_restart_empty_method "2" + +// (in sec.) To Wait To Start gm_restart_empty_method (Need To Enable gm_restart_empty_enable) +gm_restart_empty_delay "900.0" + + + +//|||||||||||||||||||||||||||||||||||||||||| MAP ROTATION FEATURE ||||||||||||||||||||||||||||||||||||||||| +// .::[Map Rotation Feature]::. || 1= Yes || 0= No +gm_rotation_enable "0" +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| + +// (Need To Enable gm_rotation_enable) +// 1= Use game_manager_maps.txt map list need to (Create New Line [gamemanager] + path In Sourcemod/configs/maplists.cfg) +// 2= Sm_nextmap Or Mapcycle (Requires Nextmap.smx) +// 3= Load Map In gm_rotation_default_map Cvar +// 0 or 4 and above = Reload Current Map +gm_rotation_mode "1" + +// Number Of Clients That Must Be Connected To Disable Map Rotation Feature (Need To Enable gm_rotation_enable) +gm_rotation_client_limit "1" + +// Include Bots In Number Of Clients in gm_rotation_client_limit (Remember, Sourcetv Counts As A Bot) (Need To Enable gm_rotation_enable) +gm_rotation_include_bots "0" + +// (in min.) Pass While The Client Limit Has Not Been Reached For Rotation Feature To Occur (Need To Enable gm_rotation_enable) +gm_rotation_time_limit "5" + +// Map To Load If (gm_rotation_mode Is Set To 2) (Need To Enable gm_rotation_enable) +gm_rotation_default_map "" + +// Config To Exec When An Rotation Feature Occurs, If Desired. Executes After The Map Loads And Server.cfg And Sourcemod Plugin Configs Are Exec'd (Need To Enable gm_rotation_enable) +gm_rotation_config_to_exec "" \ No newline at end of file