diff --git a/FEATURES.md b/FEATURES.md index 5211d52a..026bd14b 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -23,7 +23,8 @@ It also contains support for built-in map timers (KZ) and the [Fly](https://gith The chat plugin manipulates chat messages sent by players. It includes custom chat names, tags, colors and all can be defined by the players/admins. Admins need the chat flag, or the "shavit_chat" override (good for a donator perk). -There's a user-friendly command named !cchelp so the users can easily understand what's going on. +There's a user-friendly command named !cchelp so the users can easily understand what's going on. +In addition, it integrates with rankings and allows you to have titles for players according to their ranking, relative ranking or points in the server using !chatranks. #### shavit-hud The HUD plugin is `bhoptimer`'s OSD frontend. diff --git a/addons/sourcemod/configs/shavit-chat.cfg b/addons/sourcemod/configs/shavit-chat.cfg new file mode 100644 index 00000000..c5dd1fe7 --- /dev/null +++ b/addons/sourcemod/configs/shavit-chat.cfg @@ -0,0 +1,82 @@ +// Available settings: +// "ranks" - inclusive rank range. (i.e. 1, 2, 10-19 or 0.0%-0.5%). Use a percent sign to use a percentile of total players. Add "p" as a prefix to use points instead of ranks, don't specify a range for points if you only want a minimum to unlock the title. +// "name" - custom name appearance. Default: "{name}" +// "message" - a prefix to the message itself. Default: "" +// "display" - display text in the !chatranks menu. "" for a new line. Filling this is required. +// "free" - is this title available for everyone to use? Default: "0" +// +// Global variables: +// {default} - default color +// {team} - team color +// {green} - green color +// {name} - player name +// {clan} - clan tag +// {rand} - random color. +// {message} - message text +// {rank} - player rank (whole number) +// {rank1} - player rank in percentage (1 decimal point) +// {rank2} - player rank in percentage (2 decimal points) +// {rank3} - player rank in percentage (3 decimal points) +// +// Refer to shavit-messages.cfg for color settings. +// +"Chat" +{ + "0" // unranked + { + "ranks" "0" + "name" "{team}[Unranked] {name}" + "display" "[Unranked]Title used by unranked players." + } + + "1" + { + "ranks" "p10000" + "free" "0" + "name" "{rand}10k! {team}{name}" + "display" "10k ChallengerYou are insane. You are a hero. You are a challenger.A title awarded to the magnificent players who achieve 10,000 points." + } + + "2" + { + "ranks" "1" + "name" "{rand}ONE TRUE GOD {team}{name}" + "message" "{rand}" + "display" "[ONE TRUE GOD]A title awarded only to the very best players." + } + + "3" + { + "ranks" "2" + "name" "{green}LEGENDARY {name}" + "display" "[LEGENDARY]A title obtained by legendary players." + } + + "4" + { + "ranks" "3" + "name" "{green}HERO {team}{name}" + "display" "[HERO]You're a hero, and you deserve this title." + } + + "5" + { + "ranks" "4-10" + "name" "{rand}scrub{rand}! {name}" + "display" "scrub!You're a noob." + } + + "6" + { + "ranks" "11-100%" + "name" ":( {name}" + "display" "sad faceYou're terrible. Get good!" + } + + "7" + { + "free" "1" + "name" "{rand}:) {name}" + "display" ":)Free chat title." + } +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/include/chat-processor.inc b/addons/sourcemod/scripting/include/chat-processor.inc index cd722bd6..00b13e39 100644 --- a/addons/sourcemod/scripting/include/chat-processor.inc +++ b/addons/sourcemod/scripting/include/chat-processor.inc @@ -61,7 +61,7 @@ forward Action CP_OnChatMessage(int& author, ArrayList recipients, char[] flagst forward void CP_OnChatMessagePost(int author, ArrayList recipients, const char[] flagstring, const char[] formatstring, const char[] name, const char[] message, bool processcolors, bool removecolors); #if !defined REQUIRE_PLUGIN -public __pl_chat_processor_SetNTVOptional() +public void __pl_chat_processor_SetNTVOptional() { MarkNativeAsOptional("ChatProcessor_GetFlagFormatString"); } diff --git a/addons/sourcemod/scripting/include/shavit.inc b/addons/sourcemod/scripting/include/shavit.inc index 4a257b1c..9d019bf6 100644 --- a/addons/sourcemod/scripting/include/shavit.inc +++ b/addons/sourcemod/scripting/include/shavit.inc @@ -23,7 +23,7 @@ #endif #define _shavit_included -#define SHAVIT_VERSION "1.5b" +#define SHAVIT_VERSION "2.0.0" #define STYLE_LIMIT 256 #define MAX_ZONES 64 @@ -1102,12 +1102,22 @@ native StringMap Shavit_GetMapTiers(); * This native will auto-assign colors and a chat prefix. * * @param client Client index. - * @param format Formattiing rules. + * @param format Formatting rules. * @param any Variable number of format parameters. * @return PrintToChat() */ native int Shavit_PrintToChat(int client, const char[] format, any ...); +/** + * Logs an entry to bhoptimer's log file. + * (addons/sourcemod/logs/shavit.log) + * + * @param format Formatting rules. + * @param any Variable number of format parameters. + * @noreturn + */ +native void Shavit_LogMessage(const char[] format, any ...); + // same as Shavit_PrintToChat() but loops through the whole server // code stolen from the base halflife.inc file stock void Shavit_PrintToChatAll(const char[] format, any ...) diff --git a/addons/sourcemod/scripting/shavit-chat.sp b/addons/sourcemod/scripting/shavit-chat.sp index 5affd318..124101be 100644 --- a/addons/sourcemod/scripting/shavit-chat.sp +++ b/addons/sourcemod/scripting/shavit-chat.sp @@ -22,25 +22,65 @@ #include #include +#include #undef REQUIRE_PLUGIN #define USES_CHAT_COLORS #include #include +#undef REQUIRE_EXTENSIONS +#include + +enum ChatRanksCache +{ + iCRRangeType, // 0 - flat, 1 - percent, 2 - point range + Float:fCRFrom, + Float:fCRTo, + bool:bCRFree, + String:sCRName[MAXLENGTH_NAME], + String:sCRMessage[MAXLENGTH_MESSAGE], + String:sCRDisplay[192], + CRCACHE_SIZE +} + +enum +{ + Rank_Flat, + Rank_Percentage, + Rank_Points +} + #pragma newdecls required #pragma semicolon 1 +#pragma dynamic 131072 // database Database gH_SQL = null; char gS_MySQLPrefix[32]; // modules +bool gB_Rankings = false; bool gB_RTLer = false; +// cvars +ConVar gCV_RankingsIntegration = null; +ConVar gCV_CustomChat = null; + +// cached cvars +bool gB_RankingsIntegration = true; +int gI_CustomChat = 1; + // cache EngineVersion gEV_Type = Engine_Unknown; +Handle gH_ChatCookie = null; + +// -2: auto-assign - user will fallback to this if they're on an index that they don't have access to. +// -1: custom ccname/ccmsg +int gI_ChatSelection[MAXPLAYERS+1]; +ArrayList gA_ChatRanks = null; + bool gB_AllowCustom[MAXPLAYERS+1]; bool gB_NameEnabled[MAXPLAYERS+1]; @@ -53,7 +93,7 @@ public Plugin myinfo = { name = "[shavit] Chat", author = "shavit", - description = "Custom chat privileges (custom name and message colors).", + description = "Custom chat privileges (custom name/message colors), and rankings integration.", version = SHAVIT_VERSION, url = "https://github.com/shavitush/bhoptimer" } @@ -79,20 +119,123 @@ public void OnPluginStart() RegConsoleCmd("sm_ccname", Command_CCName, "Toggles/sets a custom chat name. Usage: sm_ccname or sm_ccname \"off\" to disable."); RegConsoleCmd("sm_ccmsg", Command_CCMessage, "Toggles/sets a custom chat message color. Usage: sm_ccmsg or sm_ccmsg \"off\" to disable."); RegConsoleCmd("sm_ccmessage", Command_CCMessage, "Toggles/sets a custom chat message color. Usage: sm_ccmessage or sm_ccmessage \"off\" to disable."); + RegConsoleCmd("sm_chatrank", Command_ChatRanks, "View a menu with the chat ranks available to you."); + RegConsoleCmd("sm_chatranks", Command_ChatRanks, "View a menu with the chat ranks available to you."); RegAdminCmd("sm_cclist", Command_CCList, ADMFLAG_CHAT, "Print the custom chat setting of all online players."); + RegAdminCmd("sm_reloadchatranks", Command_ReloadChatRanks, ADMFLAG_ROOT, "Reloads the chatranks config file."); + + gCV_RankingsIntegration = CreateConVar("shavit_chat_rankings", "1", "Integrate with rankings?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); + gCV_CustomChat = CreateConVar("shavit_chat_customchat", "1", "Allow custom chat names or message colors?\n0 - Disabled\n1 - Enabled (requires chat flag/'shavit_chat' override)\n2 - Allow use by everyone", 0, true, 0.0, true, 2.0); + + gCV_RankingsIntegration.AddChangeHook(OnConVarChanged); + gCV_CustomChat.AddChangeHook(OnConVarChanged); + + AutoExecConfig(); + + gH_ChatCookie = RegClientCookie("shavit_chat_selection", "Chat settings", CookieAccess_Protected); + gA_ChatRanks = new ArrayList(view_as(CRCACHE_SIZE)); for(int i = 1; i <= MaxClients; i++) { if(IsClientInGame(i) && !IsFakeClient(i)) { OnClientPostAdminCheck(i); + + if(AreClientCookiesCached(i)) + { + OnClientCookiesCached(i); + } } } SQL_SetPrefix(); } +public void OnMapStart() +{ + if(!LoadChatConfig()) + { + SetFailState("Could not load the chat configuration file. Make sure it exists (addons/sourcemod/configs/shavit-chat.cfg) and follows the proper syntax!"); + } +} + +bool LoadChatConfig() +{ + char[] sPath = new char[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-chat.cfg"); + + KeyValues kv = new KeyValues("shavit-chat"); + + if(!kv.ImportFromFile(sPath) || !kv.GotoFirstSubKey()) + { + delete kv; + + return false; + } + + gA_ChatRanks.Clear(); + + do + { + any[] aChatTitle = new any[CRCACHE_SIZE]; + char[] sRanks = new char[32]; + kv.GetString("ranks", sRanks, MAXLENGTH_NAME, "0"); + + if(sRanks[0] == 'p') + { + aChatTitle[iCRRangeType] = Rank_Points; + } + + else + { + aChatTitle[iCRRangeType] = (StrContains(sRanks, "%%") == -1)? Rank_Flat:Rank_Percentage; + } + + ReplaceString(sRanks, 32, "p", ""); + ReplaceString(sRanks, 32, "%%", ""); + + if(StrContains(sRanks, "-") != -1) + { + char[][] sExplodedString = new char[2][16]; + ExplodeString(sRanks, "-", sExplodedString, 2, 64); + aChatTitle[fCRFrom] = StringToFloat(sExplodedString[0]); + aChatTitle[fCRTo] = StringToFloat(sExplodedString[1]); + } + + else + { + float fRank = StringToFloat(sRanks); + + aChatTitle[fCRFrom] = fRank; + aChatTitle[fCRTo] = (aChatTitle[iCRRangeType] != Rank_Points)? fRank:2147483648.0; + } + + aChatTitle[bCRFree] = view_as(kv.GetNum("free", false)); + + kv.GetString("name", aChatTitle[sCRName], MAXLENGTH_NAME, "{name}"); + kv.GetString("message", aChatTitle[sCRMessage], MAXLENGTH_MESSAGE, ""); + kv.GetString("display", aChatTitle[sCRDisplay], 192, ""); + + if(strlen(aChatTitle[sCRDisplay]) > 0) + { + gA_ChatRanks.PushArray(aChatTitle); + } + } + + while(kv.GotoNextKey()); + + delete kv; + + return true; +} + +public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue) +{ + gB_RankingsIntegration = gCV_RankingsIntegration.BoolValue; + gI_CustomChat = gCV_CustomChat.IntValue; +} + public void Shavit_OnDatabaseLoaded() { gH_SQL = Shavit_GetDatabase(); @@ -154,6 +297,11 @@ public void OnLibraryAdded(const char[] name) { gB_RTLer = true; } + + else if(StrEqual(name, "shavit-rankings")) + { + gB_Rankings = true; + } } public void OnLibraryRemoved(const char[] name) @@ -162,6 +310,28 @@ public void OnLibraryRemoved(const char[] name) { gB_RTLer = false; } + + else if(StrEqual(name, "shavit-rankings")) + { + gB_Rankings = false; + } +} + +public void OnClientCookiesCached(int client) +{ + char[] sChatSettings = new char[8]; + GetClientCookie(client, gH_ChatCookie, sChatSettings, 8); + + if(strlen(sChatSettings) == 0) + { + SetClientCookie(client, gH_ChatCookie, "-2"); + gI_ChatSelection[client] = -2; + } + + else + { + gI_ChatSelection[client] = StringToInt(sChatSettings); + } } public void OnClientDisconnect(int client) @@ -182,7 +352,7 @@ public void OnClientPutInServer(int client) public void OnClientPostAdminCheck(int client) { - gB_AllowCustom[client] = CheckCommandAccess(client, "shavit_chat", ADMFLAG_CHAT); + gB_AllowCustom[client] = gI_CustomChat > 0 && (CheckCommandAccess(client, "shavit_chat", ADMFLAG_CHAT) || gI_CustomChat == 2); if(gH_SQL != null) { @@ -201,14 +371,16 @@ public Action Command_CCHelp(int client, int args) Shavit_PrintToChat(client, "%T", "CheckConsole", client); - PrintToConsole(client, "%T\n", "CCHelp_Intro", client); - PrintToConsole(client, "%T", "CCHelp_Generic", client); - PrintToConsole(client, "%T", "CCHelp_GenericVariables", client); + PrintToConsole(client, "%T\n\n%T\n\n%T\n", + "CCHelp_Intro", client, + "CCHelp_Generic", client, + "CCHelp_GenericVariables", client); if(IsSource2013(gEV_Type)) { - PrintToConsole(client, "%T", "CCHelp_CSS_1", client); - PrintToConsole(client, "%T", "CCHelp_CSS_2", client); + PrintToConsole(client, "%T\n\n%T", + "CCHelp_CSS_1", client, + "CCHelp_CSS_2", client); } else @@ -237,8 +409,6 @@ public Action Command_CCName(int client, int args) char[] sArgs = new char[128]; GetCmdArgString(sArgs, 128); - TrimString(sArgs); - FormatColors(sArgs, 128, true, true); if(args == 0 || strlen(sArgs) == 0) { @@ -287,8 +457,6 @@ public Action Command_CCMessage(int client, int args) char[] sArgs = new char[32]; GetCmdArgString(sArgs, 32); - TrimString(sArgs); - FormatColors(sArgs, 32, true, true); if(args == 0 || strlen(sArgs) == 0) { @@ -319,6 +487,175 @@ public Action Command_CCMessage(int client, int args) return Plugin_Handled; } +public Action Command_ChatRanks(int client, int args) +{ + if(client == 0) + { + return Plugin_Handled; + } + + return ShowChatRanksMenu(client, 0); +} + +Action ShowChatRanksMenu(int client, int item) +{ + Menu menu = new Menu(MenuHandler_ChatRanks); + menu.SetTitle("%T\n ", "SelectChatRank", client); + + char[] sDisplay = new char[128]; + FormatEx(sDisplay, 128, "%T\n ", "AutoAssign", client); + menu.AddItem("-2", sDisplay, (gI_ChatSelection[client] == -2)? ITEMDRAW_DISABLED:ITEMDRAW_DEFAULT); + + if(gB_AllowCustom[client]) + { + FormatEx(sDisplay, 128, "%T\n ", "CustomChat", client); + menu.AddItem("-1", sDisplay, (gI_ChatSelection[client] == -1)? ITEMDRAW_DISABLED:ITEMDRAW_DEFAULT); + } + + int iLength = gA_ChatRanks.Length; + + for(int i = 0; i < iLength; i++) + { + if(!HasRankAccess(client, i)) + { + continue; + } + + char[] sInfo = new char[8]; + IntToString(i, sInfo, 8); + + any[] aCache = new any[CRCACHE_SIZE]; + gA_ChatRanks.GetArray(i, aCache, view_as(CRCACHE_SIZE)); + + strcopy(sDisplay, 192, aCache[sCRDisplay]); + ReplaceString(sDisplay, 192, "", "\n"); + StrCat(sDisplay, 192, "\n "); // to add spacing between each entry + + menu.AddItem(sInfo, sDisplay, (gI_ChatSelection[client] == i)? ITEMDRAW_DISABLED:ITEMDRAW_DEFAULT); + } + + menu.ExitButton = true; + menu.DisplayAt(client, item, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +public int MenuHandler_ChatRanks(Menu menu, MenuAction action, int param1, int param2) +{ + if(action == MenuAction_Select) + { + char[] sInfo = new char[8]; + menu.GetItem(param2, sInfo, 8); + + int iChoice = StringToInt(sInfo); + + gI_ChatSelection[param1] = iChoice; + SetClientCookie(param1, gH_ChatCookie, sInfo); + + Shavit_PrintToChat(param1, "%T", "ChatUpdated", param1); + ShowChatRanksMenu(param1, GetMenuSelectionPosition()); + } + + else if(action == MenuAction_End) + { + delete menu; + } +} + +bool HasRankAccess(int client, int rank) +{ + if(rank == -2 || + (rank == -1 && gB_AllowCustom[client])) + { + return true; + } + + else if(!(0 <= rank <= (gA_ChatRanks.Length - 1))) + { + return false; + } + + static any aCache[view_as(bCRFree)+1]; + gA_ChatRanks.GetArray(rank, aCache[0], sizeof(aCache)); // a hack to only retrieve up to what we want + + if(aCache[bCRFree]) + { + return true; + } + + if(!gB_Rankings || !gB_RankingsIntegration) + { + return false; + } + + float fRank = (aCache[iCRRangeType] != Rank_Points)? float(Shavit_GetRank(client)):Shavit_GetPoints(client); + + if(aCache[iCRRangeType] == Rank_Flat || aCache[iCRRangeType] == Rank_Points) + { + if(aCache[fCRFrom] <= fRank <= aCache[fCRTo]) + { + return true; + } + } + + else + { + int iRanked = Shavit_GetRankedPlayers(); + + // just in case.. + if(iRanked == 0) + { + iRanked = 1; + } + + float fPercentile = (fRank / iRanked) * 100.0; + + if(aCache[fCRFrom] <= fPercentile <= aCache[fCRTo]) + { + PrintToServer("%.1f <= %.2f <= %.2f", aCache[fCRFrom], fPercentile, aCache[fCRTo]); + + return true; + } + } + + return false; +} + +void GetPlayerChatSettings(int client, char[] name, char[] message) +{ + int iRank = gI_ChatSelection[client]; + + if(!HasRankAccess(client, iRank)) + { + iRank = -2; + } + + int iLength = gA_ChatRanks.Length; + + // if we auto-assign, start looking for an available rank starting from index 0 + if(iRank == -2) + { + for(int i = 0; i < iLength; i++) + { + if(HasRankAccess(client, i)) + { + iRank = i; + + break; + } + } + } + + if(0 <= iRank <= (iLength - 1)) + { + any[] aCache = new any[CRCACHE_SIZE]; + gA_ChatRanks.GetArray(iRank, aCache, view_as(CRCACHE_SIZE)); + + strcopy(name, MAXLENGTH_NAME, aCache[sCRName]); + strcopy(message, MAXLENGTH_NAME, aCache[sCRMessage]); + } +} + public Action Command_CCList(int client, int args) { ReplyToCommand(client, "%T", "CheckConsole", client); @@ -327,36 +664,67 @@ public Action Command_CCList(int client, int args) { if(gB_AllowCustom[i]) { - PrintToConsole(client, "%N (%d/%d) (name: \"%s\"; message: \"%s\")", i, i, GetClientUserId(i), gS_CustomName[i], gS_CustomMessage[i]); + PrintToConsole(client, "%N (%d/#%d) (name: \"%s\"; message: \"%s\")", i, i, GetClientUserId(i), gS_CustomName[i], gS_CustomMessage[i]); } } return Plugin_Handled; } +public Action Command_ReloadChatRanks(int client, int args) +{ + if(LoadChatConfig()) + { + ReplyToCommand(client, "Reloaded chatranks config."); + } + + return Plugin_Handled; +} + public Action CP_OnChatMessage(int &author, ArrayList recipients, char[] flagstring, char[] name, char[] message, bool &processcolors, bool &removecolors) { - if(author == 0 || !gB_AllowCustom[author]) + if(author == 0) { return Plugin_Continue; } - if(gB_NameEnabled[author] && strlen(gS_CustomName[author]) > 0) + char[] sName = new char[MAXLENGTH_NAME]; + char[] sMessage = new char[MAXLENGTH_MESSAGE]; + + if(gB_AllowCustom[author] && gI_ChatSelection[author] == -1) { - char[] sName = new char[MAX_NAME_LENGTH]; - GetClientName(author, sName, MAX_NAME_LENGTH); - ReplaceString(gS_CustomName[author], MAXLENGTH_NAME, "{name}", sName); - - strcopy(name, MAXLENGTH_NAME, gS_CustomName[author]); - FormatRandom(name, MAXLENGTH_NAME); - - if(gEV_Type == Engine_CSGO) + if(gB_NameEnabled[author]) { - Format(name, MAXLENGTH_NAME, " %s", name); + strcopy(sName, MAXLENGTH_NAME, gS_CustomName[author]); + } + + if(gB_MessageEnabled[author]) + { + strcopy(sMessage, MAXLENGTH_MESSAGE, gS_CustomMessage[author]); } } - if(gB_MessageEnabled[author] && strlen(gS_CustomMessage[author]) > 0) + else + { + GetPlayerChatSettings(author, sName, sMessage); + } + + if(strlen(sName) > 0) + { + if(gEV_Type == Engine_CSGO) + { + FormatEx(name, MAXLENGTH_NAME, " %s", sName); + } + + else + { + strcopy(name, MAXLENGTH_NAME, sName); + } + + FormatChat(author, name, MAXLENGTH_NAME); + } + + if(strlen(sMessage) > 0) { char[] sTemp = new char[MAXLENGTH_MESSAGE]; @@ -364,34 +732,21 @@ public Action CP_OnChatMessage(int &author, ArrayList recipients, char[] flagstr if(gB_RTLer && RTLify(sTemp, MAXLENGTH_MESSAGE, message) > 0) { TrimString(message); - Format(message, MAXLENGTH_MESSAGE, "%s%s", message, gS_CustomMessage[author]); + Format(message, MAXLENGTH_MESSAGE, "%s%s", message, sMessage); } else { - Format(message, MAXLENGTH_MESSAGE, "%s%s", gS_CustomMessage[author], message); + Format(message, MAXLENGTH_MESSAGE, "%s%s", sMessage, message); } - FormatRandom(message, MAXLENGTH_MESSAGE); + FormatChat(author, message, MAXLENGTH_NAME); } #if defined DEBUG PrintToServer("%N %s", author, flagstring); #endif - bool allchat = (StrContains(flagstring, "_All") != -1); - int team = GetClientTeam(author); - - recipients.Clear(); - - for(int i = 1; i <= MaxClients; i++) - { - if(i == author || (IsClientInGame(i) && (allchat || GetClientTeam(i) == team))) - { - recipients.Push(i); - } - } - removecolors = true; processcolors = false; @@ -407,9 +762,12 @@ void FormatColors(char[] buffer, int size, bool colors, bool escape) ReplaceString(buffer, size, gS_GlobalColorNames[i], gS_GlobalColors[i]); } - for(int i = 0; i < sizeof(gS_CSGOColorNames); i++) + if(gEV_Type == Engine_CSGO) { - ReplaceString(buffer, size, gS_CSGOColorNames[i], gS_CSGOColors[i]); + for(int i = 0; i < sizeof(gS_CSGOColorNames); i++) + { + ReplaceString(buffer, size, gS_CSGOColorNames[i], gS_CSGOColors[i]); + } } ReplaceString(buffer, size, "^", "\x07"); @@ -424,8 +782,10 @@ void FormatColors(char[] buffer, int size, bool colors, bool escape) } } -void FormatRandom(char[] buffer, int size) +void FormatChat(int client, char[] buffer, int size) { + FormatColors(buffer, size, true, true); + char[] temp = new char[8]; do @@ -446,6 +806,42 @@ void FormatRandom(char[] buffer, int size) } while(ReplaceStringEx(buffer, size, "{rand}", temp) > 0); + + if(gEV_Type != Engine_TF2) + { + char[] sTag = new char[32]; + CS_GetClientClanTag(client, sTag, 32); + ReplaceString(buffer, size, "{clan}", sTag); + } + + if(gB_Rankings) + { + int iRank = Shavit_GetRank(client); + char[] sRank = new char[16]; + IntToString(iRank, sRank, 16); + ReplaceString(buffer, size, "{rank}", sRank); + + int iRanked = Shavit_GetRankedPlayers(); + + if(iRanked == 0) + { + iRanked = 1; + } + + float fPercentile = (float(iRank) / iRanked) * 100.0; + FormatEx(sRank, 16, "%.01f", fPercentile); + ReplaceString(buffer, size, "{rank1}", sRank); + + FormatEx(sRank, 16, "%.02f", fPercentile); + ReplaceString(buffer, size, "{rank2}", sRank); + + FormatEx(sRank, 16, "%.03f", fPercentile); + ReplaceString(buffer, size, "{rank3}", sRank); + } + + char[] sName = new char[MAX_NAME_LENGTH]; + GetClientName(client, sName, MAX_NAME_LENGTH); + ReplaceString(buffer, size, "{name}", sName); } int RealRandomInt(int min, int max) diff --git a/addons/sourcemod/scripting/shavit-core.sp b/addons/sourcemod/scripting/shavit-core.sp index f8f592fe..4abbbc88 100644 --- a/addons/sourcemod/scripting/shavit-core.sp +++ b/addons/sourcemod/scripting/shavit-core.sp @@ -94,22 +94,16 @@ bool gB_Zones = false; bool gB_WR = false; // cvars -ConVar gCV_Autobhop = null; -ConVar gCV_LeftRight = null; ConVar gCV_Restart = null; ConVar gCV_Pause = null; -ConVar gCV_NoStaminaReset = null; ConVar gCV_AllowTimerWithoutZone = null; ConVar gCV_BlockPreJump = null; ConVar gCV_NoZAxisSpeed = null; ConVar gCV_VelocityTeleport = null; // cached cvars -bool gB_Autobhop = true; -bool gB_LeftRight = true; bool gB_Restart = true; bool gB_Pause = true; -bool gB_NoStaminaReset = true; bool gB_AllowTimerWithoutZone = false; bool gB_BlockPreJump = false; bool gB_NoZAxisSpeed = true; @@ -135,6 +129,7 @@ char gS_ChatStrings[CHATSETTINGS_SIZE][128]; // misc cache bool gB_StopChatSound = false; bool gB_HookedJump = false; +char gS_LogPath[PLATFORM_MAX_PATH]; // kz support bool gB_KZMap = false; @@ -169,6 +164,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max CreateNative("Shavit_IsKZMap", Native_IsKZMap); CreateNative("Shavit_IsPracticeMode", Native_IsPracticeMode); CreateNative("Shavit_LoadSnapshot", Native_LoadSnapshot); + CreateNative("Shavit_LogMessage", Native_LogMessage); CreateNative("Shavit_MarkKZMap", Native_MarkKZMap); CreateNative("Shavit_PauseTimer", Native_PauseTimer); CreateNative("Shavit_PrintToChat", Native_PrintToChat); @@ -282,29 +278,26 @@ public void OnPluginStart() // style commands gSM_StyleCommands = new StringMap(); - // commands END #if defined DEBUG RegConsoleCmd("sm_finishtest", Command_FinishTest); #endif + // commands END + + // logs + BuildPath(Path_SM, gS_LogPath, PLATFORM_MAX_PATH, "logs/shavit.log"); CreateConVar("shavit_version", SHAVIT_VERSION, "Plugin version.", (FCVAR_NOTIFY | FCVAR_DONTRECORD)); - gCV_Autobhop = CreateConVar("shavit_core_autobhop", "1", "Enable autobhop?\nWill be forced to not work if STYLE_AUTOBHOP is not defined for a style!", FCVAR_NOTIFY, true, 0.0, true, 1.0); - gCV_LeftRight = CreateConVar("shavit_core_blockleftright", "1", "Block +left/right?", 0, true, 0.0, true, 1.0); gCV_Restart = CreateConVar("shavit_core_restart", "1", "Allow commands that restart the timer?", 0, true, 0.0, true, 1.0); gCV_Pause = CreateConVar("shavit_core_pause", "1", "Allow pausing?", 0, true, 0.0, true, 1.0); - gCV_NoStaminaReset = CreateConVar("shavit_core_nostaminareset", "1", "Disables the built-in stamina reset.\nAlso known as 'easybhop'.\nWill be forced to not work if STYLE_EASYBHOP is not defined for a style!", 0, true, 0.0, true, 1.0); gCV_AllowTimerWithoutZone = CreateConVar("shavit_core_timernozone", "0", "Allow the timer to start if there's no start zone?", 0, true, 0.0, true, 1.0); gCV_BlockPreJump = CreateConVar("shavit_core_blockprejump", "0", "Prevents jumping in the start zone.", 0, true, 0.0, true, 1.0); gCV_NoZAxisSpeed = CreateConVar("shavit_core_nozaxisspeed", "1", "Don't start timer if vertical speed exists (btimes style).", 0, true, 0.0, true, 1.0); gCV_VelocityTeleport = CreateConVar("shavit_core_velocityteleport", "0", "Teleport the client when changing its velocity? (for special styles)", 0, true, 0.0, true, 1.0); - gCV_Autobhop.AddChangeHook(OnConVarChanged); - gCV_LeftRight.AddChangeHook(OnConVarChanged); gCV_Restart.AddChangeHook(OnConVarChanged); gCV_Pause.AddChangeHook(OnConVarChanged); - gCV_NoStaminaReset.AddChangeHook(OnConVarChanged); gCV_AllowTimerWithoutZone.AddChangeHook(OnConVarChanged); gCV_BlockPreJump.AddChangeHook(OnConVarChanged); gCV_NoZAxisSpeed.AddChangeHook(OnConVarChanged); @@ -342,11 +335,8 @@ public void OnPluginStart() public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue) { - gB_Autobhop = gCV_Autobhop.BoolValue; - gB_LeftRight = gCV_LeftRight.BoolValue; gB_Restart = gCV_Restart.BoolValue; gB_Pause = gCV_Pause.BoolValue; - gB_NoStaminaReset = gCV_NoStaminaReset.BoolValue; gB_AllowTimerWithoutZone = gCV_AllowTimerWithoutZone.BoolValue; gB_BlockPreJump = gCV_BlockPreJump.BoolValue; gB_NoZAxisSpeed = gCV_NoZAxisSpeed.BoolValue; @@ -801,7 +791,7 @@ void DoJump(int client) } // TF2 doesn't use stamina - if(gEV_Type != Engine_TF2 && (gB_NoStaminaReset && gA_StyleSettings[gBS_Style[client]][bEasybhop]) || Shavit_InsideZone(client, Zone_Easybhop, gI_Track[client])) + if(gEV_Type != Engine_TF2 && (gA_StyleSettings[gBS_Style[client]][bEasybhop]) || Shavit_InsideZone(client, Zone_Easybhop, gI_Track[client])) { SetEntPropFloat(client, Prop_Send, "m_flStamina", 0.0); } @@ -1040,11 +1030,11 @@ public int Native_StopChatSound(Handle handler, int numParams) public int Native_PrintToChat(Handle handler, int numParams) { int client = GetNativeCell(1); - static int written = 0; // useless? + static int iWritten = 0; // useless? - char[] buffer = new char[300]; - FormatNativeString(0, 2, 3, 300, written, buffer); - Format(buffer, 300, "%s %s%s", gS_ChatStrings[sMessagePrefix], gS_ChatStrings[sMessageText], buffer); + char[] sBuffer = new char[300]; + FormatNativeString(0, 2, 3, 300, iWritten, sBuffer); + Format(sBuffer, 300, "%s %s%s", gS_ChatStrings[sMessagePrefix], gS_ChatStrings[sMessageText], sBuffer); if(IsSource2013(gEV_Type)) { @@ -1054,7 +1044,7 @@ public int Native_PrintToChat(Handle handler, int numParams) { BfWriteByte(hSayText2, 0); BfWriteByte(hSayText2, !gB_StopChatSound); - BfWriteString(hSayText2, buffer); + BfWriteString(hSayText2, sBuffer); } EndMessage(); @@ -1062,7 +1052,7 @@ public int Native_PrintToChat(Handle handler, int numParams) else { - PrintToChat(client, " %s", buffer); + PrintToChat(client, " %s", sBuffer); } gB_StopChatSound = false; @@ -1177,6 +1167,23 @@ public int Native_LoadSnapshot(Handle handler, int numParams) gI_SHSW_FirstCombination[client] = view_as(snapshot[iSHSWCombination]); } +public int Native_LogMessage(Handle plugin, int numParams) +{ + char[] sPlugin = new char[32]; + + if(!GetPluginInfo(plugin, PlInfo_Name, sPlugin, 32)) + { + GetPluginFilename(plugin, sPlugin, 32); + } + + static int iWritten = 0; + + char[] sBuffer = new char[300]; + FormatNativeString(0, 1, 2, 300, iWritten, sBuffer); + + LogToFileEx(gS_LogPath, "[%s] %s", sPlugin, sBuffer); +} + public int Native_MarkKZMap(Handle handler, int numParams) { gB_KZMap = true; @@ -1217,6 +1224,7 @@ void StartTimer(int client, int track) if(result == Plugin_Continue) { + gB_ClientPaused[client] = false; gI_Strafes[client] = 0; gI_Jumps[client] = 0; gI_TotalMeasures[client] = 0; @@ -1862,7 +1870,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 char[] sCheatDetected = new char[64]; // +left/right block - if(gB_LeftRight && (!gB_Zones || !bInStart && ((gA_StyleSettings[gBS_Style[client]][bBlockPLeft] && + if(!gB_Zones || (!bInStart && ((gA_StyleSettings[gBS_Style[client]][bBlockPLeft] && (buttons & IN_LEFT) > 0) || (gA_StyleSettings[gBS_Style[client]][bBlockPRight] && (buttons & IN_RIGHT) > 0)))) { FormatEx(sCheatDetected, 64, "%T", "LeftRightCheat", client); @@ -1949,10 +1957,10 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 bool bSHSW = (gA_StyleSettings[gBS_Style[client]][iForceHSW] == 2) && !bInStart; // don't decide on the first valid input until out of start zone! int iCombination = -1; - bool bForward = ((buttons & IN_FORWARD) > 0 && vel[0] >= 200.0); - bool bMoveLeft = ((buttons & IN_MOVELEFT) > 0 && vel[1] <= -200.0); - bool bBack = ((buttons & IN_BACK) > 0 && vel[0] <= -200.0); - bool bMoveRight = ((buttons & IN_MOVERIGHT) > 0 && vel[1] >= 200.0); + bool bForward = ((buttons & IN_FORWARD) > 0 && vel[0] >= 100.0); + bool bMoveLeft = ((buttons & IN_MOVELEFT) > 0 && vel[1] <= -100.0); + bool bBack = ((buttons & IN_BACK) > 0 && vel[0] <= -100.0); + bool bMoveRight = ((buttons & IN_MOVERIGHT) > 0 && vel[1] >= 100.0); if(bSHSW) { @@ -2055,7 +2063,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 SetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fSpeed); } - if(gA_StyleSettings[gBS_Style[client]][bAutobhop] && gB_Autobhop && gB_Auto[client] && (buttons & IN_JUMP) > 0 && mtMoveType == MOVETYPE_WALK && !bInWater) + if(gA_StyleSettings[gBS_Style[client]][bAutobhop] && gB_Auto[client] && (buttons & IN_JUMP) > 0 && mtMoveType == MOVETYPE_WALK && !bInWater) { int iOldButtons = GetEntProp(client, Prop_Data, "m_nOldButtons"); SetEntProp(client, Prop_Data, "m_nOldButtons", iOldButtons & ~IN_JUMP); @@ -2133,7 +2141,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 { gI_TotalMeasures[client]++; - if((fAngle > 0.0 && vel[1] < 0.0) || (fAngle < 0.0 && vel[1] > 0.0)) + if((fAngle > 0.0 && vel[1] <= -100.0) || (fAngle < 0.0 && vel[1] >= 100.0)) { gI_GoodGains[client]++; } @@ -2143,7 +2151,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 { gI_TotalMeasures[client]++; - if(vel[0] != 0.0) + if(vel[0] <= -100.0 || vel[0] >= 100.0) { gI_GoodGains[client]++; } @@ -2167,7 +2175,7 @@ void UpdateAutoBhop(int client) { if(sv_autobunnyhopping != null) { - sv_autobunnyhopping.ReplicateToClient(client, (gA_StyleSettings[gBS_Style[client]][bAutobhop] && gB_Autobhop && gB_Auto[client])? "1":"0"); + sv_autobunnyhopping.ReplicateToClient(client, (gA_StyleSettings[gBS_Style[client]][bAutobhop] && gB_Auto[client])? "1":"0"); } } diff --git a/addons/sourcemod/scripting/shavit-misc.sp b/addons/sourcemod/scripting/shavit-misc.sp index bc30b79f..0078b342 100644 --- a/addons/sourcemod/scripting/shavit-misc.sp +++ b/addons/sourcemod/scripting/shavit-misc.sp @@ -71,7 +71,6 @@ char gS_RadioCommands[][] = {"coverme", "takepoint", "holdpos", "regroup", "foll // cache ConVar sv_disable_immunity_alpha = null; -ConVar sv_footsteps = null; ConVar hostname = null; ConVar hostport = null; @@ -204,9 +203,6 @@ public void OnPluginStart() sv_disable_immunity_alpha = FindConVar("sv_disable_immunity_alpha"); - sv_footsteps = FindConVar("sv_footsteps"); - sv_footsteps.Flags &= ~(FCVAR_NOTIFY | FCVAR_REPLICATED); - // spectator list RegConsoleCmd("sm_specs", Command_Specs, "Show a list of spectators."); RegConsoleCmd("sm_spectators", Command_Specs, "Show a list of spectators."); @@ -285,7 +281,7 @@ public void OnPluginStart() // cvars and stuff gCV_GodMode = CreateConVar("shavit_misc_godmode", "3", "Enable godmode for players?\n0 - Disabled\n1 - Only prevent fall/world damage.\n2 - Only prevent damage from other players.\n3 - Full godmode.", 0, true, 0.0, true, 3.0); - gCV_PreSpeed = CreateConVar("shavit_misc_prespeed", "1", "Stop prespeeding in the start zone?\n0 - Disabled, fully allow prespeeding.\n1 - Limit relatively to shavit_misc_prestrafelimit.\n2 - Block bunnyhopping in startzone.\n3 - Limit to shavit_misc_prestrafelimit and block bunnyhopping.", 0, true, 0.0, true, 3.0); + gCV_PreSpeed = CreateConVar("shavit_misc_prespeed", "1", "Stop prespeeding in the start zone?\n0 - Disabled, fully allow prespeeding.\n1 - Limit relatively to prestrafelimit.\n2 - Block bunnyhopping in startzone.\n3 - Limit to prestrafelimit and block bunnyhopping.\n4 - Limit to prestrafelimit but allow prespeeding.", 0, true, 0.0, true, 4.0); gCV_HideTeamChanges = CreateConVar("shavit_misc_hideteamchanges", "1", "Hide team changes in chat?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); gCV_RespawnOnTeam = CreateConVar("shavit_misc_respawnonteam", "1", "Respawn whenever a player joins a team?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); gCV_RespawnOnRestart = CreateConVar("shavit_misc_respawnonrestart", "1", "Respawn a dead player if they use the timer restart command?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); @@ -416,8 +412,6 @@ public void OnClientCookiesCached(int client) gB_Hide[client] = view_as(StringToInt(sSetting)); } - UpdateFootsteps(client); - GetClientCookie(client, gH_CheckpointsCookie, sSetting, 8); if(strlen(sSetting) == 0) @@ -534,7 +528,7 @@ public void OnMapStart() { for(int iTeam = 1; iTeam <= 2; iTeam++) { - int iSpawnPoint = CreateEntityByName((iTeam == 1)? "info_player_terrorist":"info_player_counterterrorist"); + int iSpawnPoint = CreateEntityByName((gEV_Type == Engine_TF2)? "info_player_teamspawn":((iTeam == 1)? "info_player_terrorist":"info_player_counterterrorist")); if(DispatchSpawn(iSpawnPoint)) { @@ -941,18 +935,23 @@ public Action Shavit_OnUserCmdPre(int client, int &buttons, int &impulse, float return Plugin_Continue; } - if(gI_PreSpeed == 1 || gI_PreSpeed == 3) + if(gI_PreSpeed == 1 || gI_PreSpeed >= 3) { + float fLimit = gF_PrestrafeLimit; + float fSpeed[3]; GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fSpeed); - float fLimit = view_as(gA_StyleSettings[gBS_Style[client]][fRunspeed]) + gF_PrestrafeLimit; - - // if trying to jump, add a very low limit to stop prespeeding in an elegant way - // otherwise, make sure nothing weird is happening (such as sliding at ridiculous speeds, at zone enter) - if(fSpeed[2] > 0.0) + if(gI_PreSpeed < 4) { - fLimit /= 3.0; + fLimit = view_as(gA_StyleSettings[gBS_Style[client]][fRunspeed]) + gF_PrestrafeLimit; + + // if trying to jump, add a very low limit to stop prespeeding in an elegant way + // otherwise, make sure nothing weird is happening (such as sliding at ridiculous speeds, at zone enter) + if(fSpeed[2] > 0.0) + { + fLimit /= 3.0; + } } float fSpeedXY = (SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0))); @@ -993,8 +992,6 @@ public void OnClientPutInServer(int client) gBS_Style[client] = Shavit_GetBhopStyle(client); gB_Hide[client] = false; gI_CheckpointsSettings[client] = CP_DEFAULT; - - UpdateFootsteps(client); } if(gH_GetPlayerMaxSpeed != null) @@ -1154,7 +1151,6 @@ public Action Command_Hide(int client, int args) } gB_Hide[client] = !gB_Hide[client]; - UpdateFootsteps(client); char[] sCookie = new char[4]; IntToString(view_as(gB_Hide[client]), sCookie, 4); @@ -1456,12 +1452,9 @@ public Action Command_Save(int client, int args) } } - else + else if((bSaved = SaveCheckpoint(client, (CP_MAX - 1)))) { - if((bSaved = SaveCheckpoint(client, (CP_MAX - 1)))) - { - gI_CheckpointsCache[client][iCurrentCheckpoint] = CP_MAX; - } + gI_CheckpointsCache[client][iCurrentCheckpoint] = CP_MAX; } if(bSaved) @@ -1671,14 +1664,14 @@ bool SaveCheckpoint(int client, int index) int iObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode"); int iObserverTarget = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); - if(IsClientObserver(client) && !IsFakeClient(iObserverTarget) && IsValidClient(iObserverTarget) && iObserverMode >= 3 && iObserverMode <= 5) + if(IsClientObserver(client) && IsValidClient(iObserverTarget) && iObserverMode >= 3 && iObserverMode <= 5) { target = iObserverTarget; } else if(!IsPlayerAlive(client)) { - Shavit_PrintToChat(client, "%T", "CommandAliveSpectate", client, gS_ChatStrings[sMessageVariable], gS_ChatStrings[sMessageText]); + Shavit_PrintToChat(client, "%T", "CommandAliveSpectate", client, gS_ChatStrings[sMessageVariable], gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], gS_ChatStrings[sMessageText]); return false; } @@ -1705,9 +1698,32 @@ bool SaveCheckpoint(int client, int index) cpcache[iCPFlags] = GetEntityFlags(target); any snapshot[TIMERSNAPSHOT_SIZE]; - Shavit_SaveSnapshot(target, snapshot); - CopyArray(snapshot, cpcache[aCPSnapshot], TIMERSNAPSHOT_SIZE); + if(IsFakeClient(target)) + { + // unfortunately replay bots don't have a snapshot, so we can generate a fake one + int style = Shavit_GetReplayBotStyle(target); + int track = Shavit_GetReplayBotTrack(target); + + snapshot[bTimerEnabled] = true; + snapshot[fCurrentTime] = Shavit_GetReplayTime(style, track); + snapshot[bClientPaused] = false; + snapshot[bsStyle] = style; + snapshot[iJumps] = 0; + snapshot[iStrafes] = 0; + snapshot[iTotalMeasures] = 0; + snapshot[iGoodGains] = 0; + snapshot[fServerTime] = GetEngineTime(); + snapshot[iSHSWCombination] = -1; + snapshot[iTimerTrack] = track; + } + + else + { + Shavit_SaveSnapshot(target, snapshot); + } + + CopyArray(snapshot, cpcache[aCPSnapshot], TIMERSNAPSHOT_SIZE); SetCheckpoint(client, index, cpcache); return true; @@ -1954,7 +1970,7 @@ public Action Shavit_OnStart(int client) return Plugin_Stop; } - if(gB_ResetTargetname) + if(gB_ResetTargetname || Shavit_IsPracticeMode(client)) // practice mode can be abused to break map triggers { DispatchKeyValue(client, "targetname", ""); } @@ -2506,16 +2522,6 @@ bool SetCheckpoint(int client, int index, CheckpointsCache cpcache[PCPCACHE_SIZE return gSM_Checkpoints.SetArray(sKey, cpcache[0], view_as(PCPCACHE_SIZE)); } -void UpdateFootsteps(int client) -{ - if(sv_footsteps != null) - { - char[] sFootsteps = new char[4]; - IntToString((gB_Hide[client])? 0:sv_footsteps.IntValue, sFootsteps, 4); - sv_footsteps.ReplicateToClient(client, sFootsteps); - } -} - void CopyArray(const any[] from, any[] to, int size) { for(int i = 0; i < size; i++) diff --git a/addons/sourcemod/scripting/shavit-rankings.sp b/addons/sourcemod/scripting/shavit-rankings.sp index d7fed7d3..c89b52f5 100644 --- a/addons/sourcemod/scripting/shavit-rankings.sp +++ b/addons/sourcemod/scripting/shavit-rankings.sp @@ -135,7 +135,7 @@ public void OnPluginStart() RegConsoleCmd("sm_top", Command_Top, "Show the top 100 players."); // The rewrite of rankings will not have the ability to show over 100 entries. Dynamic fetching can be exploited and overload the database. RegAdminCmd("sm_settier", Command_SetTier, ADMFLAG_RCON, "Change the map's tier. Usage: sm_settier "); - RegAdminCmd("sm_setmaptier", Command_SetTier, ADMFLAG_RCON, "Prints the map's tier to chat. Usage: sm_setmaptier (sm_settier alias)"); + RegAdminCmd("sm_setmaptier", Command_SetTier, ADMFLAG_RCON, "Change the map's tier. Usage: sm_setmaptier (sm_settier alias)"); RegAdminCmd("sm_recalcmap", Command_RecalcMap, ADMFLAG_RCON, "Recalculate the current map's records' points."); diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 9defc382..ab653a21 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -86,7 +86,7 @@ int gI_DefaultTeamSlots = 0; // server specific float gF_Tickrate = 0.0; -char gS_Map[192]; +char gS_Map[160]; int gI_ExpectedBots = 0; ConVar bot_quota = null; any gA_CentralCache[CENTRALBOTCACHE_SIZE]; @@ -527,28 +527,6 @@ public Action Cron(Handle Timer) return Plugin_Continue; } -public void OnEntityCreated(int entity, const char[] classname) -{ - // trigger_once | trigger_multiple.. etc - // func_door | func_door_rotating - if(StrContains(classname, "trigger_") != -1 || StrContains(classname, "_door") != -1) - { - SDKHook(entity, SDKHook_StartTouch, HookTriggers); - SDKHook(entity, SDKHook_EndTouch, HookTriggers); - SDKHook(entity, SDKHook_Touch, HookTriggers); - } -} - -public Action HookTriggers(int entity, int other) -{ - if(other >= 1 && other <= MaxClients && IsFakeClient(other)) - { - return Plugin_Handled; - } - - return Plugin_Continue; -} - bool LoadStyling() { char[] sPath = new char[PLATFORM_MAX_PATH]; @@ -606,8 +584,8 @@ public void OnMapStart() gB_ForciblyStopped = false; - GetCurrentMap(gS_Map, 192); - GetMapDisplayName(gS_Map, gS_Map, 192); + GetCurrentMap(gS_Map, 160); + GetMapDisplayName(gS_Map, gS_Map, 160); if(!gB_Enabled) { @@ -1117,7 +1095,7 @@ void UpdateReplayInfo(int client, int style, float time, int track) return; } - SetEntProp(client, Prop_Data, "m_CollisionGroup", 1); + SetEntProp(client, Prop_Data, "m_CollisionGroup", 2); SetEntityMoveType(client, MOVETYPE_NOCLIP); bool central = (gA_CentralCache[iCentralClient] == client); @@ -1494,9 +1472,9 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 MoveType movetype = gA_Frames[style][track].Get(gI_ReplayTick[style], 7); - if(movetype == MOVETYPE_WALK || movetype == MOVETYPE_LADDER) + if(movetype == MOVETYPE_LADDER) { - mt = movetype; + mt = MOVETYPE_LADDER; } } @@ -1556,7 +1534,13 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 public Action Timer_EndReplay(Handle Timer, any data) { - gB_ForciblyStopped = false; + if(gB_CentralBot && gB_ForciblyStopped) + { + gB_ForciblyStopped = false; + + return Plugin_Stop; + } + gI_ReplayTick[data] = 0; if(gI_ReplayBotClient[data] != gA_CentralCache[iCentralClient]) @@ -1684,9 +1668,17 @@ public Action Hook_SayText2(UserMsg msg_id, any msg, const int[] players, int pl return Plugin_Continue; } + // caching usermessage type rather than call it every time + static UserMessageType um = view_as(-1); + + if(um == view_as(-1)) + { + um = GetUserMessageType(); + } + char[] sMessage = new char[24]; - if(GetUserMessageType() == UM_Protobuf) + if(um == UM_Protobuf) { Protobuf pbmsg = msg; pbmsg.ReadString("msg_name", sMessage, 24); diff --git a/addons/sourcemod/scripting/shavit-wr.sp b/addons/sourcemod/scripting/shavit-wr.sp index dcfb7d81..6dda74f0 100644 --- a/addons/sourcemod/scripting/shavit-wr.sp +++ b/addons/sourcemod/scripting/shavit-wr.sp @@ -774,8 +774,14 @@ public int MenuHandler_DeleteAll(Menu menu, MenuAction action, int param1, int p return 0; } + char[] sTrack = new char[32]; + GetTrackName(LANG_SERVER, gI_LastTrack[param1], sTrack, 32); + + Shavit_LogMessage("%L - deleted all %s track records from map `%s`.", param1, sTrack, gS_Map); + char[] sQuery = new char[256]; FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE map = '%s' AND track = %d;", gS_MySQLPrefix, gS_Map, gI_LastTrack[param1]); + gH_SQL.Query(DeleteAll_Callback, sQuery, GetClientSerial(param1), DBPrio_High); } @@ -903,6 +909,8 @@ public int MenuHandler_DeleteStyleRecords_Confirm(Menu menu, MenuAction action, return 0; } + Shavit_LogMessage("%L - deleted all %s style records from map `%s`.", param1, gS_StyleStrings[style][sStyleName], gS_Map); + char[] sQuery = new char[256]; FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE map = '%s' AND style = %d;", gS_MySQLPrefix, gS_Map, style); @@ -1135,8 +1143,12 @@ public int DeleteConfirm_Handler(Menu menu, MenuAction action, int param1, int p } } + // TODO: display record details here (map name, player name/authid, time, rank on map) without dropping threaded queries + Shavit_LogMessage("%L - deleted record id %d.", param1, iRecordID); + char[] sQuery = new char[256]; FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE id = %d;", gS_MySQLPrefix, iRecordID); + gH_SQL.Query(DeleteConfirm_Callback, sQuery, GetClientSerial(param1), DBPrio_High); } diff --git a/addons/sourcemod/scripting/shavit-zones.sp b/addons/sourcemod/scripting/shavit-zones.sp index 99743d09..a0fad806 100644 --- a/addons/sourcemod/scripting/shavit-zones.sp +++ b/addons/sourcemod/scripting/shavit-zones.sp @@ -956,6 +956,8 @@ public Action Command_DelSpawn(int client, int args) return Plugin_Handled; } + Shavit_LogMessage("%L - deleted custom spawn from map `%s`.", client, gS_Map); + char[] sQuery = new char[256]; FormatEx(sQuery, 256, "DELETE FROM %smapzones WHERE type = '%d' AND map = '%s';", gS_MySQLPrefix, Zone_CustomSpawn, gS_Map); @@ -1227,6 +1229,8 @@ public int DeleteZone_MenuHandler(Menu menu, MenuAction action, int param1, int default: { + Shavit_LogMessage("%L - deleted %s (id %d) from map `%s`.", param1, gS_ZoneNames[gA_ZoneCache[id][iZoneType]], gA_ZoneCache[id][iDatabaseID], gS_Map); + char[] sQuery = new char[256]; FormatEx(sQuery, 256, "DELETE FROM %smapzones WHERE %s = %d;", gS_MySQLPrefix, (gB_MySQL)? "id":"rowid", gA_ZoneCache[id][iDatabaseID]); @@ -1321,6 +1325,8 @@ public int DeleteAllZones_MenuHandler(Menu menu, MenuAction action, int param1, return; } + Shavit_LogMessage("%L - deleted all zones from map `%s`.", param1, gS_Map); + char[] sQuery = new char[256]; FormatEx(sQuery, 256, "DELETE FROM %smapzones WHERE map = '%s';", gS_MySQLPrefix, gS_Map); @@ -1901,11 +1907,15 @@ void InsertZone(int client) if(type == Zone_CustomSpawn) { + Shavit_LogMessage("%L - added custom spawn {%.2f, %.2f, %.2f} to map `%s`.", client, gV_Point1[client][0], gV_Point1[client][1], gV_Point1[client][2], gS_Map); + FormatEx(sQuery, 512, "INSERT INTO %smapzones (map, type, destination_x, destination_y, destination_z) VALUES ('%s', '%d', '%.03f', '%.03f', '%.03f');", gS_MySQLPrefix, gS_Map, type, gV_Point1[client][0], gV_Point1[client][1], gV_Point1[client][2]); } else if(insert) // insert { + Shavit_LogMessage("%L - added %s to map `%s`.", client, gS_ZoneNames[type], gS_Map); + if(type != Zone_Teleport) { FormatEx(sQuery, 512, "INSERT INTO %smapzones (map, type, corner1_x, corner1_y, corner1_z, corner2_x, corner2_y, corner2_z, track) VALUES ('%s', '%d', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%.03f', '%d');", gS_MySQLPrefix, gS_Map, type, gV_Point1[client][0], gV_Point1[client][1], gV_Point1[client][2], gV_Point2[client][0], gV_Point2[client][1], gV_Point2[client][2], gI_ZoneTrack[client]); @@ -1919,6 +1929,8 @@ void InsertZone(int client) else // update { + Shavit_LogMessage("%L - updated %s in map `%s`.", client, gS_ZoneNames[type], gS_Map); + if(gI_ZoneDatabaseID[client] == -1) { for(int i = 0; i < gI_MapZones; i++) @@ -2409,7 +2421,7 @@ public void Shavit_OnEnd(int client, int track) bool EmptyVector(float vec[3]) { - return (vec[0] == 0.0 && vec[1] == 0.0 && vec[2] == 0.0); + return (IsNullVector(vec) || (vec[0] == 0.0 && vec[1] == 0.0 && vec[2] == 0.0)); } // returns -1 if there's no zone diff --git a/addons/sourcemod/translations/shavit-chat.phrases.txt b/addons/sourcemod/translations/shavit-chat.phrases.txt index 4be43d2a..04feca76 100644 --- a/addons/sourcemod/translations/shavit-chat.phrases.txt +++ b/addons/sourcemod/translations/shavit-chat.phrases.txt @@ -32,7 +32,7 @@ } "CCHelp_GenericVariables" { - "en" "- {name} - your in-game name.\n- {rand} - a random color.\n- {team} - your team color.\n- {green} - green color." + "en" "- {name} - your in-game name.\n- {clan} - your clan tag.\n- {rand} - a random color.\n- {team} - your team color.\n- {green} - green color." } "CCHelp_CSS_1" { @@ -46,4 +46,17 @@ { "en" "- The following colors are also available: {blue}, {bluegrey}, {darkblue}, {darkred}, {gold}, {grey}, {grey2}, {lightgreen}, {lightred}, {lime}, {orchid}, {yellow} and {palered}." } + // ---------- Menu ---------- // + "SelectChatRank" + { + "en" "Select chat rank:\n" + } + "AutoAssign" + { + "en" "Auto-assign\nAutomatically assign using your rank." + } + "CustomChat" + { + "en" "Custom\nUse custom chat settings. See !cchelp for more information." + } } \ No newline at end of file