Merge pull request #603 from shavitush/chat

Chat ranks!
This commit is contained in:
shavit 2018-03-18 11:37:12 +02:00 committed by GitHub
commit f9b67450db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 682 additions and 150 deletions

View File

@ -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.

View File

@ -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. "<n>" 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]<n>Title used by unranked players."
}
"1"
{
"ranks" "p10000"
"free" "0"
"name" "{rand}10k! {team}{name}"
"display" "10k Challenger<n>You are insane. You are a hero. You are a challenger.<n>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]<n>A title awarded only to the very best players."
}
"3"
{
"ranks" "2"
"name" "{green}LEGENDARY {name}"
"display" "[LEGENDARY]<n>A title obtained by legendary players."
}
"4"
{
"ranks" "3"
"name" "{green}HERO {team}{name}"
"display" "[HERO]<n>You're a hero, and you deserve this title."
}
"5"
{
"ranks" "4-10"
"name" "{rand}scrub{rand}! {name}"
"display" "scrub!<n>You're a noob."
}
"6"
{
"ranks" "11-100%"
"name" ":( {name}"
"display" "sad face<n>You're terrible. Get good!"
}
"7"
{
"free" "1"
"name" "{rand}:) {name}"
"display" ":)<n>Free chat title."
}
}

View File

@ -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");
}

View File

@ -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 ...)

View File

@ -22,25 +22,65 @@
#include <sourcemod>
#include <chat-processor>
#include <clientprefs>
#undef REQUIRE_PLUGIN
#define USES_CHAT_COLORS
#include <shavit>
#include <rtler>
#undef REQUIRE_EXTENSIONS
#include <cstrike>
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 <text> or sm_ccname \"off\" to disable.");
RegConsoleCmd("sm_ccmsg", Command_CCMessage, "Toggles/sets a custom chat message color. Usage: sm_ccmsg <color> or sm_ccmsg \"off\" to disable.");
RegConsoleCmd("sm_ccmessage", Command_CCMessage, "Toggles/sets a custom chat message color. Usage: sm_ccmessage <color> 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<int>(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<bool>(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<int>(CRCACHE_SIZE));
strcopy(sDisplay, 192, aCache[sCRDisplay]);
ReplaceString(sDisplay, 192, "<n>", "\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<int>(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<int>(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)

View File

@ -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<int>(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");
}
}

View File

@ -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<bool>(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<float>(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<float>(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<int>(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<int>(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++)

View File

@ -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 <tier>");
RegAdminCmd("sm_setmaptier", Command_SetTier, ADMFLAG_RCON, "Prints the map's tier to chat. Usage: sm_setmaptier <tier> (sm_settier alias)");
RegAdminCmd("sm_setmaptier", Command_SetTier, ADMFLAG_RCON, "Change the map's tier. Usage: sm_setmaptier <tier> (sm_settier alias)");
RegAdminCmd("sm_recalcmap", Command_RecalcMap, ADMFLAG_RCON, "Recalculate the current map's records' points.");

View File

@ -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<UserMessageType>(-1);
if(um == view_as<UserMessageType>(-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);

View File

@ -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);
}

View File

@ -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

View File

@ -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."
}
}