bhoptimer/addons/sourcemod/scripting/shavit-hud.sp
2019-01-13 12:23:04 +00:00

1552 lines
38 KiB
SourcePawn
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* shavit's Timer - HUD
* by: shavit
*
* This file is part of shavit's Timer.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <clientprefs>
#undef REQUIRE_PLUGIN
#include <shavit>
#include <bhopstats>
#pragma newdecls required
#pragma semicolon 1
// HUD2 - these settings will *disable* elements for the main hud
#define HUD2_TIME (1 << 0)
#define HUD2_SPEED (1 << 1)
#define HUD2_JUMPS (1 << 2)
#define HUD2_STRAFE (1 << 3)
#define HUD2_SYNC (1 << 4)
#define HUD2_STYLE (1 << 5)
#define HUD2_RANK (1 << 6)
#define HUD2_TRACK (1 << 7)
#define HUD_DEFAULT (HUD_MASTER|HUD_CENTER|HUD_ZONEHUD|HUD_OBSERVE|HUD_TOPLEFT|HUD_SYNC|HUD_TIMELEFT|HUD_2DVEL|HUD_SPECTATORS)
#define HUD_DEFAULT2 0
enum ZoneHUD
{
ZoneHUD_None,
ZoneHUD_Start,
ZoneHUD_End
};
enum struct huddata_t
{
int iTarget;
float fTime;
int iSpeed;
int iStyle;
int iTrack;
int iJumps;
int iStrafes;
int iRank;
float fSync;
float fPB;
float fWR;
bool bReplay;
bool bPractice;
TimerStatus iTimerStatus;
ZoneHUD iZoneHUD;
};
enum struct color_t
{
int r;
int g;
int b;
};
// game type (CS:S/CS:GO/TF2)
EngineVersion gEV_Type = Engine_Unknown;
// modules
bool gB_Replay = false;
bool gB_Zones = false;
bool gB_Sounds = false;
bool gB_BhopStats = false;
// cache
int gI_Cycle = 0;
color_t gI_Gradient;
int gI_GradientDirection = -1;
int gI_Styles = 0;
Handle gH_HUDCookie = null;
Handle gH_HUDCookieMain = null;
int gI_HUDSettings[MAXPLAYERS+1];
int gI_HUD2Settings[MAXPLAYERS+1];
int gI_NameLength = MAX_NAME_LENGTH;
int gI_LastScrollCount[MAXPLAYERS+1];
int gI_ScrollCount[MAXPLAYERS+1];
int gI_Buttons[MAXPLAYERS+1];
float gF_ConnectTime[MAXPLAYERS+1];
bool gB_FirstPrint[MAXPLAYERS+1];
int gI_PreviousSpeed[MAXPLAYERS+1];
bool gB_Late = false;
// hud handle
Handle gH_HUD = null;
// plugin cvars
ConVar gCV_GradientStepSize = null;
ConVar gCV_TicksPerUpdate = null;
ConVar gCV_SpectatorList = null;
// timer settings
stylestrings_t gS_StyleStrings[STYLE_LIMIT];
stylesettings_t gA_StyleSettings[STYLE_LIMIT];
public Plugin myinfo =
{
name = "[shavit] HUD",
author = "shavit",
description = "HUD for shavit's bhop timer.",
version = SHAVIT_VERSION,
url = "https://github.com/shavitush/bhoptimer"
}
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
// natives
CreateNative("Shavit_ForceHUDUpdate", Native_ForceHUDUpdate);
CreateNative("Shavit_GetHUDSettings", Native_GetHUDSettings);
// registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins
RegPluginLibrary("shavit-hud");
gB_Late = late;
return APLRes_Success;
}
public void OnPluginStart()
{
LoadTranslations("shavit-common.phrases");
LoadTranslations("shavit-hud.phrases");
// game-specific
gEV_Type = GetEngineVersion();
if(IsSource2013(gEV_Type))
{
gI_NameLength = MAX_NAME_LENGTH;
}
else
{
gI_NameLength = 14; // 14 because long names will make it look spammy in CS:GO due to the font
}
if(gEV_Type == Engine_TF2)
{
HookEvent("player_changeclass", Player_ChangeClass);
HookEvent("player_team", Player_ChangeClass);
HookEvent("teamplay_round_start", Teamplay_Round_Start);
}
// prevent errors in case the replay bot isn't loaded
gB_Replay = LibraryExists("shavit-replay");
gB_Zones = LibraryExists("shavit-zones");
gB_Sounds = LibraryExists("shavit-sounds");
gB_BhopStats = LibraryExists("bhopstats");
// HUD handle
gH_HUD = CreateHudSynchronizer();
// plugin convars
gCV_GradientStepSize = CreateConVar("shavit_hud_gradientstepsize", "15", "How fast should the start/end HUD gradient be?\nThe number is the amount of color change per 0.1 seconds.\nThe higher the number the faster the gradient.", 0, true, 1.0, true, 255.0);
gCV_TicksPerUpdate = CreateConVar("shavit_hud_ticksperupdate", "5", "How often (in ticks) should the HUD update?\nPlay around with this value until you find the best for your server.\nThe maximum value is your tickrate.", 0, true, 1.0, true, (1.0 / GetTickInterval()));
gCV_SpectatorList = CreateConVar("shavit_hud_speclist", "1", "Who to show in the specators list?\n0 - everyone\n1 - all admins (admin_speclisthide override to bypass)\n2 - players you can target", 0, true, 0.0, true, 2.0);
AutoExecConfig();
// commands
RegConsoleCmd("sm_hud", Command_HUD, "Opens the HUD settings menu");
RegConsoleCmd("sm_options", Command_HUD, "Opens the HUD settings menu (alias for sm_hud");
// cookies
gH_HUDCookie = RegClientCookie("shavit_hud_setting", "HUD settings", CookieAccess_Protected);
gH_HUDCookieMain = RegClientCookie("shavit_hud_settingmain", "HUD settings for main ", CookieAccess_Protected);
if(gB_Late)
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClient(i))
{
OnClientPutInServer(i);
if(AreClientCookiesCached(i))
{
OnClientCookiesCached(i);
}
}
}
}
}
public void OnMapStart()
{
if(gB_Late)
{
Shavit_OnStyleConfigLoaded(-1);
}
}
public void OnLibraryAdded(const char[] name)
{
if(StrEqual(name, "shavit-replay"))
{
gB_Replay = true;
}
else if(StrEqual(name, "shavit-zones"))
{
gB_Zones = true;
}
else if(StrEqual(name, "shavit-sounds"))
{
gB_Sounds = true;
}
else if(StrEqual(name, "bhopstats"))
{
gB_BhopStats = true;
}
}
public void OnLibraryRemoved(const char[] name)
{
if(StrEqual(name, "shavit-replay"))
{
gB_Replay = false;
}
else if(StrEqual(name, "shavit-zones"))
{
gB_Zones = false;
}
else if(StrEqual(name, "shavit-sounds"))
{
gB_Sounds = false;
}
else if(StrEqual(name, "bhopstats"))
{
gB_BhopStats = false;
}
}
public void OnConfigsExecuted()
{
ConVar sv_hudhint_sound = FindConVar("sv_hudhint_sound");
if(sv_hudhint_sound != null)
{
sv_hudhint_sound.SetBool(false);
}
}
public void Shavit_OnStyleConfigLoaded(int styles)
{
if(styles == -1)
{
styles = Shavit_GetStyleCount();
}
gI_Styles = styles;
for(int i = 0; i < styles; i++)
{
Shavit_GetStyleSettings(i, gA_StyleSettings[i]);
Shavit_GetStyleStrings(i, sStyleName, gS_StyleStrings[i].sStyleName, sizeof(stylestrings_t::sStyleName));
Shavit_GetStyleStrings(i, sHTMLColor, gS_StyleStrings[i].sHTMLColor, sizeof(stylestrings_t::sHTMLColor));
}
}
public Action Shavit_OnUserCmdPre(int client, int &buttons, int &impulse, float vel[3], float angles[3], TimerStatus status, int track, int style, stylesettings_t stylsettings)
{
gI_Buttons[client] = buttons;
for(int i = 1; i <= MaxClients; i++)
{
if(i == client || (IsValidClient(i) && GetHUDTarget(i) == client))
{
TriggerHUDUpdate(i, true);
}
}
return Plugin_Continue;
}
public void OnClientPutInServer(int client)
{
gI_LastScrollCount[client] = 0;
gI_ScrollCount[client] = 0;
gB_FirstPrint[client] = false;
if(IsFakeClient(client))
{
SDKHook(client, SDKHook_PostThinkPost, PostThinkPost);
}
}
public void PostThinkPost(int client)
{
int buttons = GetClientButtons(client);
if(gI_Buttons[client] != buttons)
{
gI_Buttons[client] = buttons;
for(int i = 1; i <= MaxClients; i++)
{
if(i != client && (IsValidClient(i) && GetHUDTarget(i) == client))
{
TriggerHUDUpdate(i, true);
}
}
}
}
public void OnClientCookiesCached(int client)
{
char sHUDSettings[8];
GetClientCookie(client, gH_HUDCookie, sHUDSettings, 8);
if(strlen(sHUDSettings) == 0)
{
IntToString(HUD_DEFAULT, sHUDSettings, 8);
SetClientCookie(client, gH_HUDCookie, sHUDSettings);
gI_HUDSettings[client] = HUD_DEFAULT;
}
else
{
gI_HUDSettings[client] = StringToInt(sHUDSettings);
}
char sHUDSettingsMain[8];
GetClientCookie(client, gH_HUDCookieMain, sHUDSettingsMain, 8);
if(strlen(sHUDSettingsMain) == 0)
{
IntToString(HUD_DEFAULT2, sHUDSettingsMain, 8);
SetClientCookie(client, gH_HUDCookieMain, sHUDSettingsMain);
gI_HUD2Settings[client] = HUD_DEFAULT2;
}
else
{
gI_HUD2Settings[client] = StringToInt(sHUDSettingsMain);
}
}
public void Player_ChangeClass(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if((gI_HUDSettings[client] & HUD_MASTER) > 0 && (gI_HUDSettings[client] & HUD_CENTER) > 0)
{
CreateTimer(0.5, Timer_FillerHintText, GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
}
}
public void Teamplay_Round_Start(Event event, const char[] name, bool dontBroadcast)
{
CreateTimer(0.5, Timer_FillerHintTextAll, 0, TIMER_FLAG_NO_MAPCHANGE);
}
public Action Timer_FillerHintTextAll(Handle timer, any data)
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientConnected(i) && IsClientInGame(i))
{
FillerHintText(i);
}
}
return Plugin_Stop;
}
public Action Timer_FillerHintText(Handle timer, any data)
{
int client = GetClientFromSerial(data);
if(client != 0)
{
FillerHintText(client);
}
return Plugin_Stop;
}
void FillerHintText(int client)
{
PrintHintText(client, "...");
gF_ConnectTime[client] = GetEngineTime();
gB_FirstPrint[client] = true;
}
public Action Command_HUD(int client, int args)
{
return ShowHUDMenu(client, 0);
}
Action ShowHUDMenu(int client, int item)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
Menu menu = new Menu(MenuHandler_HUD, MENU_ACTIONS_DEFAULT|MenuAction_DisplayItem);
menu.SetTitle("%T", "HUDMenuTitle", client);
char sInfo[16];
char sHudItem[64];
FormatEx(sInfo, 16, "!%d", HUD_MASTER);
FormatEx(sHudItem, 64, "%T", "HudMaster", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "!%d", HUD_CENTER);
FormatEx(sHudItem, 64, "%T", "HudCenter", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "!%d", HUD_ZONEHUD);
FormatEx(sHudItem, 64, "%T", "HudZoneHud", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "!%d", HUD_OBSERVE);
FormatEx(sHudItem, 64, "%T", "HudObserve", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "!%d", HUD_SPECTATORS);
FormatEx(sHudItem, 64, "%T", "HudSpectators", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "!%d", HUD_KEYOVERLAY);
FormatEx(sHudItem, 64, "%T", "HudKeyOverlay", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "!%d", HUD_HIDEWEAPON);
FormatEx(sHudItem, 64, "%T", "HudHideWeapon", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "!%d", HUD_TOPLEFT);
FormatEx(sHudItem, 64, "%T", "HudTopLeft", client);
menu.AddItem(sInfo, sHudItem);
if(IsSource2013(gEV_Type))
{
FormatEx(sInfo, 16, "!%d", HUD_SYNC);
FormatEx(sHudItem, 64, "%T", "HudSync", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "!%d", HUD_TIMELEFT);
FormatEx(sHudItem, 64, "%T", "HudTimeLeft", client);
menu.AddItem(sInfo, sHudItem);
}
FormatEx(sInfo, 16, "!%d", HUD_2DVEL);
FormatEx(sHudItem, 64, "%T", "Hud2dVel", client);
menu.AddItem(sInfo, sHudItem);
if(gB_Sounds)
{
FormatEx(sInfo, 16, "!%d", HUD_NOSOUNDS);
FormatEx(sHudItem, 64, "%T", "HudNoRecordSounds", client);
menu.AddItem(sInfo, sHudItem);
}
FormatEx(sInfo, 16, "!%d", HUD_NOPRACALERT);
FormatEx(sHudItem, 64, "%T", "HudPracticeModeAlert", client);
menu.AddItem(sInfo, sHudItem);
// HUD2 - disables selected elements
FormatEx(sInfo, 16, "@%d", HUD2_TIME);
FormatEx(sHudItem, 64, "%T", "HudTimeText", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "@%d", HUD2_SPEED);
FormatEx(sHudItem, 64, "%T", "HudSpeedText", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "@%d", HUD2_JUMPS);
FormatEx(sHudItem, 64, "%T", "HudJumpsText", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "@%d", HUD2_STRAFE);
FormatEx(sHudItem, 64, "%T", "HudStrafeText", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "@%d", HUD2_SYNC);
FormatEx(sHudItem, 64, "%T", "HudSync", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "@%d", HUD2_STYLE);
FormatEx(sHudItem, 64, "%T", "HudStyleText", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "@%d", HUD2_RANK);
FormatEx(sHudItem, 64, "%T", "HudRankText", client);
menu.AddItem(sInfo, sHudItem);
FormatEx(sInfo, 16, "@%d", HUD2_TRACK);
FormatEx(sHudItem, 64, "%T", "HudTrackText", client);
menu.AddItem(sInfo, sHudItem);
menu.ExitButton = true;
menu.DisplayAt(client, item, 60);
return Plugin_Handled;
}
public int MenuHandler_HUD(Menu menu, MenuAction action, int param1, int param2)
{
if(action == MenuAction_Select)
{
char sCookie[16];
menu.GetItem(param2, sCookie, 16);
int type = (sCookie[0] == '!')? 1:2;
ReplaceString(sCookie, 16, "!", "");
ReplaceString(sCookie, 16, "@", "");
int iSelection = StringToInt(sCookie);
if(type == 1)
{
gI_HUDSettings[param1] ^= iSelection;
IntToString(gI_HUDSettings[param1], sCookie, 16);
SetClientCookie(param1, gH_HUDCookie, sCookie);
}
else
{
gI_HUD2Settings[param1] ^= iSelection;
IntToString(gI_HUD2Settings[param1], sCookie, 16);
SetClientCookie(param1, gH_HUDCookieMain, sCookie);
}
if(gEV_Type == Engine_TF2 && iSelection == HUD_CENTER && (gI_HUDSettings[param1] & HUD_MASTER) > 0)
{
FillerHintText(param1);
}
ShowHUDMenu(param1, GetMenuSelectionPosition());
}
else if(action == MenuAction_DisplayItem)
{
char sInfo[16];
char sDisplay[64];
int style = 0;
menu.GetItem(param2, sInfo, 16, style, sDisplay, 64);
int type = (sInfo[0] == '!')? 1:2;
ReplaceString(sInfo, 16, "!", "");
ReplaceString(sInfo, 16, "@", "");
if(type == 1)
{
Format(sDisplay, 64, "[%c] %s", ((gI_HUDSettings[param1] & StringToInt(sInfo)) > 0)? '+':' ', sDisplay);
}
else
{
Format(sDisplay, 64, "[%c] %s", ((gI_HUD2Settings[param1] & StringToInt(sInfo)) > 0)? '-':' ', sDisplay);
}
return RedrawMenuItem(sDisplay);
}
else if(action == MenuAction_End)
{
delete menu;
}
return 0;
}
public void OnGameFrame()
{
if((GetGameTickCount() % gCV_TicksPerUpdate.IntValue) == 0)
{
Cron();
}
}
void Cron()
{
if(++gI_Cycle >= 65535)
{
gI_Cycle = 0;
}
switch(gI_GradientDirection)
{
case 0:
{
gI_Gradient.b += gCV_GradientStepSize.IntValue;
if(gI_Gradient.b >= 255)
{
gI_Gradient.b = 255;
gI_GradientDirection = 1;
}
}
case 1:
{
gI_Gradient.r -= gCV_GradientStepSize.IntValue;
if(gI_Gradient.r <= 0)
{
gI_Gradient.r = 0;
gI_GradientDirection = 2;
}
}
case 2:
{
gI_Gradient.g += gCV_GradientStepSize.IntValue;
if(gI_Gradient.g >= 255)
{
gI_Gradient.g = 255;
gI_GradientDirection = 3;
}
}
case 3:
{
gI_Gradient.b -= gCV_GradientStepSize.IntValue;
if(gI_Gradient.b <= 0)
{
gI_Gradient.b = 0;
gI_GradientDirection = 4;
}
}
case 4:
{
gI_Gradient.r += gCV_GradientStepSize.IntValue;
if(gI_Gradient.r >= 255)
{
gI_Gradient.r = 255;
gI_GradientDirection = 5;
}
}
case 5:
{
gI_Gradient.g -= gCV_GradientStepSize.IntValue;
if(gI_Gradient.g <= 0)
{
gI_Gradient.g = 0;
gI_GradientDirection = 0;
}
}
default:
{
gI_Gradient.r = 255;
gI_GradientDirection = 0;
}
}
for(int i = 1; i <= MaxClients; i++)
{
if(!IsValidClient(i) || IsFakeClient(i) || (gI_HUDSettings[i] & HUD_MASTER) == 0)
{
continue;
}
if((gI_Cycle % 50) == 0)
{
float fSpeed[3];
GetEntPropVector(GetHUDTarget(i), Prop_Data, "m_vecVelocity", fSpeed);
gI_PreviousSpeed[i] = RoundToNearest(((gI_HUDSettings[i] & HUD_2DVEL) == 0)? GetVectorLength(fSpeed):(SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0))));
}
TriggerHUDUpdate(i);
}
}
void TriggerHUDUpdate(int client, bool keysonly = false) // keysonly because CS:S lags when you send too many usermessages
{
if(!keysonly)
{
UpdateMainHUD(client);
SetEntProp(client, Prop_Data, "m_bDrawViewmodel", ((gI_HUDSettings[client] & HUD_HIDEWEAPON) > 0)? 0:1);
UpdateTopLeftHUD(client, true);
}
if(IsSource2013(gEV_Type))
{
if(!keysonly)
{
UpdateKeyHint(client);
}
UpdateCenterKeys(client);
}
else if(((gI_HUDSettings[client] & HUD_KEYOVERLAY) > 0 || (gI_HUDSettings[client] & HUD_SPECTATORS) > 0) && (!gB_Zones || !Shavit_IsClientCreatingZone(client)) && (GetClientMenu(client, null) == MenuSource_None || GetClientMenu(client, null) == MenuSource_RawPanel))
{
bool bShouldDraw = false;
Panel pHUD = new Panel();
UpdateKeyOverlay(client, pHUD, bShouldDraw);
pHUD.DrawItem("", ITEMDRAW_RAWLINE);
UpdateSpectatorList(client, pHUD, bShouldDraw);
if(bShouldDraw)
{
pHUD.Send(client, PanelHandler_Nothing, 1);
}
delete pHUD;
}
}
void AddHUDLine(char[] buffer, int maxlen, const char[] line)
{
if(strlen(buffer) > 0)
{
Format(buffer, maxlen, "%s\n%s", buffer, line);
}
else
{
StrCat(buffer, maxlen, line);
}
}
void GetRGB(int color, color_t arr)
{
arr.r = ((color >> 16) & 0xFF);
arr.g = ((color >> 8) & 0xFF);
arr.b = (color & 0xFF);
}
int GetHex(color_t color)
{
return (((color.r & 0xFF) << 16) + ((color.g & 0xFF) << 8) + (color.b & 0xFF));
}
int GetGradient(int start, int end, int steps)
{
color_t aColorStart;
GetRGB(start, aColorStart);
color_t aColorEnd;
GetRGB(end, aColorEnd);
color_t aColorGradient;
aColorGradient.r = (aColorStart.r + RoundToZero((aColorEnd.r - aColorStart.r) * steps / 100.0));
aColorGradient.g = (aColorStart.g + RoundToZero((aColorEnd.g - aColorStart.g) * steps / 100.0));
aColorGradient.b = (aColorStart.b + RoundToZero((aColorEnd.b - aColorStart.b) * steps / 100.0));
return GetHex(aColorGradient);
}
void AddHUDToBuffer_Source2013(int client, huddata_t data, char[] buffer, int maxlen)
{
char sLine[128];
if(data.bReplay)
{
if(data.iStyle != -1 && data.fTime > 0.0 && data.fTime <= data.fWR && Shavit_IsReplayDataLoaded(data.iStyle, data.iTrack))
{
char sTrack[32];
if(data.iTrack != Track_Main && (gI_HUD2Settings[client] & HUD2_TRACK) == 0)
{
GetTrackName(client, data.iTrack, sTrack, 32);
Format(sTrack, 32, "(%s) ", sTrack);
}
if((gI_HUD2Settings[client] & HUD2_STYLE) == 0)
{
FormatEx(sLine, 128, "%s %s%T", gS_StyleStrings[data.iStyle].sStyleName, sTrack, "ReplayText", client);
AddHUDLine(buffer, maxlen, sLine);
}
char sPlayerName[MAX_NAME_LENGTH];
Shavit_GetReplayName(data.iStyle, data.iTrack, sPlayerName, MAX_NAME_LENGTH);
AddHUDLine(buffer, maxlen, sPlayerName);
if((gI_HUD2Settings[client] & HUD2_TIME) == 0)
{
char sTime[32];
FormatSeconds(data.fTime, sTime, 32, false);
char sWR[32];
FormatSeconds(data.fWR, sWR, 32, false);
FormatEx(sLine, 128, "%s / %s\n(%.1f)", sTime, sWR, ((data.fTime / data.fWR) * 100));
AddHUDLine(buffer, maxlen, sLine);
}
if((gI_HUD2Settings[client] & HUD2_SPEED) == 0)
{
FormatEx(sLine, 128, "%d u/s", data.iSpeed);
AddHUDLine(buffer, maxlen, sLine);
}
}
else
{
FormatEx(sLine, 128, "%T", (gEV_Type == Engine_TF2)? "NoReplayDataTF2":"NoReplayData", client);
AddHUDLine(buffer, maxlen, sLine);
}
return;
}
if((gI_HUDSettings[client] & HUD_ZONEHUD) > 0 && data.iZoneHUD != ZoneHUD_None)
{
FormatEx(sLine, 128, "%T ", (data.iZoneHUD == ZoneHUD_Start)? "HudInStartZone":"HudInEndZone", client, data.iSpeed);
AddHUDLine(buffer, maxlen, sLine);
return;
}
if(data.iTimerStatus != Timer_Stopped)
{
if((gI_HUD2Settings[client] & HUD2_STYLE) == 0)
{
AddHUDLine(buffer, maxlen, gS_StyleStrings[data.iStyle].sStyleName);
}
if(data.bPractice || data.iTimerStatus == Timer_Paused)
{
FormatEx(sLine, 128, "%T", (data.iTimerStatus == Timer_Paused)? "HudPaused":"HudPracticeMode", client);
AddHUDLine(buffer, maxlen, sLine);
}
if((gI_HUD2Settings[client] & HUD2_TIME) == 0)
{
char sTime[32];
FormatSeconds(data.fTime, sTime, 32, false);
if((gI_HUD2Settings[client] & HUD2_RANK) == 0)
{
FormatEx(sLine, 128, "%T: %s (%d)", "HudTimeText", client, sTime, data.iRank);
}
else
{
FormatEx(sLine, 128, "%T: %s", "HudTimeText", client, sTime);
}
AddHUDLine(buffer, maxlen, sLine);
}
if((gI_HUD2Settings[client] & HUD2_JUMPS) == 0)
{
FormatEx(sLine, 128, "%T: %d", "HudJumpsText", client, data.iJumps);
AddHUDLine(buffer, maxlen, sLine);
}
if((gI_HUD2Settings[client] & HUD2_STRAFE) == 0)
{
FormatEx(sLine, 128, "%T: %d", "HudStrafeText", client, data.iStrafes);
AddHUDLine(buffer, maxlen, sLine);
}
}
if((gI_HUD2Settings[client] & HUD2_SPEED) == 0)
{
// timer: Speed: %d
// no timer: straight up number
if(data.iTimerStatus != Timer_Stopped)
{
FormatEx(sLine, 128, "%T: %d", "HudSpeedText", client, data.iSpeed);
}
else
{
IntToString(data.iSpeed, sLine, 128);
}
AddHUDLine(buffer, maxlen, sLine);
}
if(data.iTimerStatus != Timer_Stopped && data.iTrack != Track_Main && (gI_HUD2Settings[client] & HUD2_TRACK) == 0)
{
char sTrack[32];
GetTrackName(client, data.iTrack, sTrack, 32);
Format(sTrack, 32, "%s", sTrack);
AddHUDLine(buffer, maxlen, sTrack);
}
}
void AddHUDToBuffer_CSGO(int client, huddata_t data, char[] buffer, int maxlen)
{
char sLine[128];
if(data.bReplay)
{
StrCat(buffer, maxlen, "<span class='fontSize-l'>");
if(data.iStyle != -1 && data.fTime > 0.0 && data.fTime <= data.fWR && Shavit_IsReplayDataLoaded(data.iStyle, data.iTrack))
{
char sPlayerName[MAX_NAME_LENGTH];
Shavit_GetReplayName(data.iStyle, data.iTrack, sPlayerName, MAX_NAME_LENGTH);
char sTrack[32];
if(data.iTrack != Track_Main && (gI_HUD2Settings[client] & HUD2_TRACK) == 0)
{
GetTrackName(client, data.iTrack, sTrack, 32);
Format(sTrack, 32, "(%s) ", sTrack);
}
FormatEx(sLine, 128, "<u><span color='#%s'>%s %s%T</span></u> <span color='#DB88C2'>%s</span>", gS_StyleStrings[data.iStyle].sHTMLColor, gS_StyleStrings[data.iStyle].sStyleName, sTrack, "ReplayText", client, sPlayerName);
AddHUDLine(buffer, maxlen, sLine);
if((gI_HUD2Settings[client] & HUD2_TIME) == 0)
{
char sTime[32];
FormatSeconds(data.fTime, sTime, 32, false);
char sWR[32];
FormatSeconds(data.fWR, sWR, 32, false);
FormatEx(sLine, 128, "%s / %s (%.1f%%)", sTime, sWR, ((data.fTime / data.fWR) * 100));
AddHUDLine(buffer, maxlen, sLine);
}
if((gI_HUD2Settings[client] & HUD2_SPEED) == 0)
{
FormatEx(sLine, 128, "%d u/s", data.iSpeed);
AddHUDLine(buffer, maxlen, sLine);
}
}
else
{
FormatEx(sLine, 128, "%T", "NoReplayData", client);
AddHUDLine(buffer, maxlen, sLine);
}
StrCat(buffer, maxlen, "</span>");
return;
}
if((gI_HUDSettings[client] & HUD_ZONEHUD) > 0 && data.iZoneHUD != ZoneHUD_None)
{
char sZoneHUD[64];
FormatEx(sZoneHUD, 64, "<span class='fontSize-xxl' color='#%06X'>", ((gI_Gradient.r << 16) + (gI_Gradient.g << 8) + (gI_Gradient.b)));
StrCat(buffer, maxlen, sZoneHUD);
FormatEx(sZoneHUD, 64, "%T</span>", (data.iZoneHUD == ZoneHUD_Start)? "HudInStartZoneCSGO":"HudInEndZoneCSGO", client, data.iSpeed);
StrCat(buffer, maxlen, sZoneHUD);
return;
}
StrCat(buffer, maxlen, "<span class='fontSize-l'>");
if(data.iTimerStatus != Timer_Stopped)
{
if(data.bPractice || data.iTimerStatus == Timer_Paused)
{
FormatEx(sLine, 128, "%T", (data.iTimerStatus == Timer_Paused)? "HudPaused":"HudPracticeMode", client);
AddHUDLine(buffer, maxlen, sLine);
}
if(data.iTimerStatus != Timer_Stopped && data.iTrack != Track_Main && (gI_HUD2Settings[client] & HUD2_TRACK) == 0)
{
char sTrack[32];
GetTrackName(client, data.iTrack, sTrack, 32);
Format(sTrack, 32, "%s", sTrack);
AddHUDLine(buffer, maxlen, sTrack);
}
if((gI_HUD2Settings[client] & HUD2_TIME) == 0)
{
int iColor = 0xFF0000; // red, worse than both pb and wr
if(data.iTimerStatus == Timer_Paused) iColor = 0xA9C5E8; // blue sky
else if(data.fTime < data.fWR || data.fWR == 0.0) iColor = GetGradient(0x00FF00, 0x96172C, RoundToZero((data.fTime / data.fWR) * 100));
else if(data.fPB != 0.0 && data.fTime < data.fPB) iColor = 0xFFA500; // orange
char sTime[32];
FormatSeconds(data.fTime, sTime, 32, false);
if((gI_HUD2Settings[client] & HUD2_RANK) == 0)
{
FormatEx(sLine, 128, "<span color='#%06X'>%s</span> (#%d)", iColor, sTime, data.iRank);
}
else
{
FormatEx(sLine, 128, "<span color='#%06X'>%s</span>", iColor, sTime);
}
AddHUDLine(buffer, maxlen, sLine);
}
}
if((gI_HUD2Settings[client] & HUD2_SPEED) == 0)
{
int iColor = 0xA0FFFF;
if((data.iSpeed - gI_PreviousSpeed[client]) < 0)
{
iColor = 0xFFC966;
}
FormatEx(sLine, 128, "<span color='#%06X'>%d u/s</span>", iColor, data.iSpeed);
AddHUDLine(buffer, maxlen, sLine);
}
if(data.iTimerStatus != Timer_Stopped)
{
if((gI_HUD2Settings[client] & HUD2_JUMPS) == 0)
{
FormatEx(sLine, 128, "%d %T", data.iJumps, "HudJumpsText", client);
AddHUDLine(buffer, maxlen, sLine);
}
if((gI_HUD2Settings[client] & HUD2_STRAFE) == 0)
{
if((gI_HUD2Settings[client] & HUD2_SYNC) == 0)
{
FormatEx(sLine, 128, "%d %T (%.1f%%)", data.iStrafes, "HudStrafeText", client, data.fSync);
}
else
{
FormatEx(sLine, 128, "%d %T", data.iStrafes, "HudStrafeText", client);
}
AddHUDLine(buffer, maxlen, sLine);
}
}
if((gI_HUD2Settings[client] & HUD2_STYLE) == 0)
{
FormatEx(sLine, 128, "<span color='#%s'>%s</span>", gS_StyleStrings[data.iStyle].sHTMLColor, gS_StyleStrings[data.iStyle].sStyleName);
AddHUDLine(buffer, maxlen, sLine);
}
StrCat(buffer, maxlen, "</span>");
}
void UpdateMainHUD(int client)
{
int target = GetHUDTarget(client);
if((gI_HUDSettings[client] & HUD_CENTER) == 0 ||
((gI_HUDSettings[client] & HUD_OBSERVE) == 0 && client != target) ||
(gEV_Type == Engine_TF2 && (!gB_FirstPrint[target] || GetEngineTime() - gF_ConnectTime[target] < 1.5))) // TF2 has weird handling for hint text
{
return;
}
float fSpeed[3];
GetEntPropVector(target, Prop_Data, "m_vecVelocity", fSpeed);
bool bReplay = (gB_Replay && IsFakeClient(target));
ZoneHUD iZoneHUD = ZoneHUD_None;
int iReplayStyle = 0;
int iReplayTrack = 0;
float fReplayTime = 0.0;
float fReplayLength = 0.0;
if(!bReplay)
{
if(Shavit_InsideZone(target, Zone_Start, -1))
{
iZoneHUD = ZoneHUD_Start;
}
else if(Shavit_InsideZone(target, Zone_End, -1))
{
iZoneHUD = ZoneHUD_End;
}
}
else
{
iReplayStyle = Shavit_GetReplayBotStyle(target);
iReplayTrack = Shavit_GetReplayBotTrack(target);
if(iReplayStyle != -1)
{
fReplayTime = (Shavit_GetReplayTime(iReplayStyle, iReplayTrack) * gA_StyleSettings[iReplayStyle].fTimescale);
fReplayLength = Shavit_GetReplayLength(iReplayStyle, iReplayTrack);
}
}
huddata_t huddata;
huddata.iTarget = target;
huddata.iSpeed = RoundToNearest(((gI_HUDSettings[client] & HUD_2DVEL) == 0)? GetVectorLength(fSpeed):(SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0))));
huddata.iZoneHUD = iZoneHUD;
huddata.iStyle = (bReplay)? iReplayStyle:Shavit_GetBhopStyle(target);
huddata.iTrack = (bReplay)? iReplayTrack:Shavit_GetClientTrack(target);
huddata.fTime = (bReplay)? fReplayTime:Shavit_GetClientTime(target);
huddata.iJumps = (bReplay)? 0:Shavit_GetClientJumps(target);
huddata.iStrafes = (bReplay)? 0:Shavit_GetStrafeCount(target);
huddata.iRank = (bReplay)? 0:Shavit_GetRankForTime(huddata.iStyle, huddata.fTime, huddata.iTrack);
huddata.fSync = (bReplay)? 0.0:Shavit_GetSync(target);
huddata.fPB = (bReplay)? 0.0:Shavit_GetClientPB(target, huddata.iStyle, huddata.iTrack);
huddata.fWR = (bReplay)? fReplayLength:Shavit_GetWorldRecord(huddata.iStyle, huddata.iTrack);
huddata.iTimerStatus = (bReplay)? Timer_Running:Shavit_GetTimerStatus(target);
huddata.bReplay = bReplay;
huddata.bPractice = (bReplay)? false:Shavit_IsPracticeMode(target);
char sBuffer[512];
int iLen = 0;
if(IsSource2013(gEV_Type))
{
AddHUDToBuffer_Source2013(client, huddata, sBuffer, 512);
iLen = strlen(sBuffer);
}
else
{
StrCat(sBuffer, 512, "<pre>");
AddHUDToBuffer_CSGO(client, huddata, sBuffer, 512);
iLen = (strlen(sBuffer) - 5); // excluding <pre>
StrCat(sBuffer, 512, "</pre>");
}
if(iLen > 0)
{
PrintHintText(client, "%s", sBuffer);
}
}
void UpdateKeyOverlay(int client, Panel panel, bool &draw)
{
if((gI_HUDSettings[client] & HUD_KEYOVERLAY) == 0)
{
return;
}
int target = GetHUDTarget(client);
if(((gI_HUDSettings[client] & HUD_OBSERVE) == 0 && client != target) || !IsValidClient(target) || IsClientObserver(target))
{
return;
}
// to make it shorter
int buttons = gI_Buttons[target];
int style = (IsFakeClient(target))? Shavit_GetReplayBotStyle(target):Shavit_GetBhopStyle(target);
if(!(0 <= style < gI_Styles))
{
style = 0;
}
char sPanelLine[128];
if(gB_BhopStats && !gA_StyleSettings[style].bAutobhop)
{
FormatEx(sPanelLine, 64, " %d%s%d\n", gI_ScrollCount[target], (gI_ScrollCount[target] > 9)? " ":" ", gI_LastScrollCount[target]);
}
Format(sPanelLine, 128, "%s%s %s\n   %s\n%s  %s  %s", sPanelLine,
(buttons & IN_JUMP) > 0? "":"", (buttons & IN_DUCK) > 0? "":"",
(buttons & IN_FORWARD) > 0? "":"", (buttons & IN_MOVELEFT) > 0? "":"",
(buttons & IN_BACK) > 0? "":"", (buttons & IN_MOVERIGHT) > 0? "":"");
panel.DrawItem(sPanelLine, ITEMDRAW_RAWLINE);
draw = true;
}
public void Bunnyhop_OnTouchGround(int client)
{
gI_LastScrollCount[client] = BunnyhopStats.GetScrollCount(client);
}
public void Bunnyhop_OnJumpPressed(int client)
{
gI_ScrollCount[client] = BunnyhopStats.GetScrollCount(client);
}
void UpdateCenterKeys(int client)
{
if((gI_HUDSettings[client] & HUD_KEYOVERLAY) == 0)
{
return;
}
int target = GetHUDTarget(client);
if(((gI_HUDSettings[client] & HUD_OBSERVE) == 0 && client != target) || !IsValidClient(target) || IsClientObserver(target))
{
return;
}
int buttons = gI_Buttons[target];
char sCenterText[64];
FormatEx(sCenterText, 64, " %s  %s\n   %s\n%s  %s  %s",
(buttons & IN_JUMP) > 0? "":"", (buttons & IN_DUCK) > 0? "":"",
(buttons & IN_FORWARD) > 0? "":"", (buttons & IN_MOVELEFT) > 0? "":"",
(buttons & IN_BACK) > 0? "":"", (buttons & IN_MOVERIGHT) > 0? "":"");
int style = (IsFakeClient(target))? Shavit_GetReplayBotStyle(target):Shavit_GetBhopStyle(target);
if(!(0 <= style < gI_Styles))
{
style = 0;
}
if(gB_BhopStats && !gA_StyleSettings[style].bAutobhop)
{
Format(sCenterText, 64, "%s\n  %d %d", sCenterText, gI_ScrollCount[target], gI_LastScrollCount[target]);
}
PrintCenterText(client, "%s", sCenterText);
}
void UpdateSpectatorList(int client, Panel panel, bool &draw)
{
if((gI_HUDSettings[client] & HUD_SPECTATORS) == 0)
{
return;
}
int target = GetHUDTarget(client);
if(((gI_HUDSettings[client] & HUD_OBSERVE) == 0 && client != target) || !IsValidClient(target))
{
return;
}
int[] iSpectatorClients = new int[MaxClients];
int iSpectators = 0;
bool bIsAdmin = CheckCommandAccess(client, "admin_speclisthide", ADMFLAG_KICK);
for(int i = 1; i <= MaxClients; i++)
{
if(i == client || !IsValidClient(i) || IsFakeClient(i) || !IsClientObserver(i) || GetClientTeam(i) < 1 || GetHUDTarget(i) != target)
{
continue;
}
if((gCV_SpectatorList.IntValue == 1 && !bIsAdmin && CheckCommandAccess(i, "admin_speclisthide", ADMFLAG_KICK)) ||
(gCV_SpectatorList.IntValue == 2 && !CanUserTarget(client, i)))
{
continue;
}
iSpectatorClients[iSpectators++] = i;
}
if(iSpectators > 0)
{
char sSpectators[32];
char sSpectatorsPersonal[64];
char sSpectatorWatching[64];
FormatEx(sSpectatorsPersonal, 32, "%T", "SpectatorPersonal", client);
FormatEx(sSpectatorWatching, 32, "%T", "SpectatorWatching", client);
FormatEx(sSpectators, 32, "%s (%d):", (client == target)? sSpectatorsPersonal:sSpectatorWatching, iSpectators);
panel.DrawItem(sSpectators, ITEMDRAW_RAWLINE);
for(int i = 0; i < iSpectators; i++)
{
if(i == 7)
{
panel.DrawItem("...", ITEMDRAW_RAWLINE);
break;
}
char[] sName = new char[gI_NameLength];
GetClientName(iSpectatorClients[i], sName, gI_NameLength);
ReplaceString(sName, gI_NameLength, "#", "?");
panel.DrawItem(sName, ITEMDRAW_RAWLINE);
}
draw = true;
}
}
void UpdateTopLeftHUD(int client, bool wait)
{
if((!wait || gI_Cycle % 25 == 0) && (gI_HUDSettings[client] & HUD_TOPLEFT) > 0)
{
int target = GetHUDTarget(client);
int track = 0;
int style = 0;
if(!IsFakeClient(target))
{
style = Shavit_GetBhopStyle(target);
track = Shavit_GetClientTrack(target);
}
else
{
style = Shavit_GetReplayBotStyle(target);
track = Shavit_GetReplayBotTrack(target);
}
if(!(0 <= style < gI_Styles) || !(0 <= track <= TRACKS_SIZE))
{
return;
}
float fWRTime = Shavit_GetWorldRecord(style, track);
if(fWRTime != 0.0)
{
char sWRTime[16];
FormatSeconds(fWRTime, sWRTime, 16);
char sWRName[MAX_NAME_LENGTH];
Shavit_GetWRName(style, sWRName, MAX_NAME_LENGTH, track);
float fPBTime = Shavit_GetClientPB(target, style, track);
char sPBTime[16];
FormatSeconds(fPBTime, sPBTime, MAX_NAME_LENGTH);
char sTopLeft[128];
if(fPBTime != 0.0)
{
FormatEx(sTopLeft, 128, "WR: %s (%s)\n%T: %s (#%d)", sWRTime, sWRName, "HudBestText", client, sPBTime, Shavit_GetRankForTime(style, fPBTime, track));
}
else
{
FormatEx(sTopLeft, 128, "WR: %s (%s)", sWRTime, sWRName);
}
SetHudTextParams(0.01, 0.01, 2.5, 255, 255, 255, 255, 0, 0.0, 0.0, 0.0);
ShowSyncHudText(client, gH_HUD, "%s", sTopLeft);
}
}
}
void UpdateKeyHint(int client)
{
if((gI_Cycle % 10) == 0 && ((gI_HUDSettings[client] & HUD_SYNC) > 0 || (gI_HUDSettings[client] & HUD_TIMELEFT) > 0))
{
char sMessage[256];
int iTimeLeft = -1;
if((gI_HUDSettings[client] & HUD_TIMELEFT) > 0 && GetMapTimeLeft(iTimeLeft) && iTimeLeft > 0)
{
FormatEx(sMessage, 256, (iTimeLeft > 60)? "%T: %d minutes":"%T: <1 minute", "HudTimeLeft", client, (iTimeLeft / 60), "HudTimeLeft", client);
}
int target = GetHUDTarget(client);
if(IsValidClient(target) && (target == client || (gI_HUDSettings[client] & HUD_OBSERVE) > 0))
{
int style = Shavit_GetBhopStyle(target);
if((gI_HUDSettings[client] & HUD_SYNC) > 0 && Shavit_GetTimerStatus(target) == Timer_Running && gA_StyleSettings[style].bSync && !IsFakeClient(target) && (!gB_Zones || !Shavit_InsideZone(target, Zone_Start, -1)))
{
Format(sMessage, 256, "%s%s%T: %.01f", sMessage, (strlen(sMessage) > 0)? "\n\n":"", "HudSync", client, Shavit_GetSync(target));
if(!gA_StyleSettings[style].bAutobhop)
{
Format(sMessage, 256, "%s\n%T: %.1f", sMessage, "HudPerfs", client, Shavit_GetPerfectJumps(target));
}
}
if((gI_HUDSettings[client] & HUD_SPECTATORS) > 0)
{
int[] iSpectatorClients = new int[MaxClients];
int iSpectators = 0;
bool bIsAdmin = CheckCommandAccess(client, "admin_speclisthide", ADMFLAG_KICK);
for(int i = 1; i <= MaxClients; i++)
{
if(i == client || !IsValidClient(i) || IsFakeClient(i) || !IsClientObserver(i) || GetClientTeam(i) < 1 || GetHUDTarget(i) != target)
{
continue;
}
if((gCV_SpectatorList.IntValue == 1 && !bIsAdmin && CheckCommandAccess(i, "admin_speclisthide", ADMFLAG_KICK)) ||
(gCV_SpectatorList.IntValue == 2 && !CanUserTarget(client, i)))
{
continue;
}
iSpectatorClients[iSpectators++] = i;
}
if(iSpectators > 0)
{
Format(sMessage, 256, "%s%s%spectators (%d):", sMessage, (strlen(sMessage) > 0)? "\n\n":"", (client == target)? "S":"Other S", iSpectators);
for(int i = 0; i < iSpectators; i++)
{
if(i == 7)
{
Format(sMessage, 256, "%s\n...", sMessage);
break;
}
char[] sName = new char[gI_NameLength];
GetClientName(iSpectatorClients[i], sName, gI_NameLength);
ReplaceString(sName, gI_NameLength, "#", "?");
Format(sMessage, 256, "%s\n%s", sMessage, sName);
}
}
}
}
if(strlen(sMessage) > 0)
{
Handle hKeyHintText = StartMessageOne("KeyHintText", client);
BfWriteByte(hKeyHintText, 1);
BfWriteString(hKeyHintText, sMessage);
EndMessage();
}
}
}
int GetHUDTarget(int client)
{
int target = client;
if(IsClientObserver(client))
{
int iObserverMode = GetEntProp(client, Prop_Send, "m_iObserverMode");
if(iObserverMode >= 3 && iObserverMode <= 5)
{
int iTarget = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget");
if(IsValidClient(iTarget, true))
{
target = iTarget;
}
}
}
return target;
}
public int PanelHandler_Nothing(Menu m, MenuAction action, int param1, int param2)
{
// i don't need anything here
return 0;
}
public void Shavit_OnStyleChanged(int client, int oldstyle, int newstyle, int track, bool manual)
{
if(IsClientInGame(client))
{
UpdateTopLeftHUD(client, false);
}
}
public int Native_ForceHUDUpdate(Handle handler, int numParams)
{
int[] clients = new int[MaxClients];
int count = 0;
int client = GetNativeCell(1);
if(client < 0 || client > MaxClients || !IsClientInGame(client))
{
ThrowNativeError(200, "Invalid client index %d", client);
return -1;
}
clients[count++] = client;
if(view_as<bool>(GetNativeCell(2)))
{
for(int i = 1; i <= MaxClients; i++)
{
if(i == client || !IsValidClient(i) || GetHUDTarget(i) != client)
{
continue;
}
clients[count++] = client;
}
}
for(int i = 0; i < count; i++)
{
TriggerHUDUpdate(clients[i]);
}
return count;
}
public int Native_GetHUDSettings(Handle handler, int numParams)
{
int client = GetNativeCell(1);
if(client < 0 || client > MaxClients)
{
ThrowNativeError(200, "Invalid client index %d", client);
return -1;
}
return gI_HUDSettings[client];
}
void GetTrackName(int client, int track, char[] output, int size)
{
if(track < 0 || track >= TRACKS_SIZE)
{
FormatEx(output, size, "%T", "Track_Unknown", client);
return;
}
static char sTrack[16];
FormatEx(sTrack, 16, "Track_%d", track);
FormatEx(output, size, "%T", sTrack, client);
}