mirror of
https://github.com/shavitush/bhoptimer.git
synced 2025-12-06 18:08:26 +00:00
2408 lines
67 KiB
SourcePawn
2408 lines
67 KiB
SourcePawn
/*
|
|
* shavit's Timer - Core
|
|
* 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 <sdkhooks>
|
|
#include <sdktools>
|
|
#include <geoip>
|
|
#include <clientprefs>
|
|
|
|
#undef REQUIRE_PLUGIN
|
|
#define USES_CHAT_COLORS
|
|
#include <shavit>
|
|
|
|
#pragma newdecls required
|
|
#pragma semicolon 1
|
|
|
|
// #define DEBUG
|
|
|
|
enum struct playertimer_t
|
|
{
|
|
bool bEnabled;
|
|
float fTimer;
|
|
bool bPaused;
|
|
int iJumps;
|
|
int iStyle;
|
|
bool bAuto;
|
|
int iLastButtons;
|
|
int iStrafes;
|
|
float fLastAngle;
|
|
int iTotalMeasures;
|
|
int iGoodGains;
|
|
bool bDoubleSteps;
|
|
float fStrafeWarning;
|
|
bool bPracticeMode;
|
|
int iSHSWCombination;
|
|
int iTrack;
|
|
int iMeasuredJumps;
|
|
int iPerfectJumps;
|
|
int iGroundTicks;
|
|
MoveType iMoveType;
|
|
}
|
|
|
|
// game type (CS:S/CS:GO/TF2)
|
|
EngineVersion gEV_Type = Engine_Unknown;
|
|
|
|
// database handle
|
|
Database gH_SQL = null;
|
|
bool gB_MySQL = false;
|
|
|
|
// forwards
|
|
Handle gH_Forwards_Start = null;
|
|
Handle gH_Forwards_Stop = null;
|
|
Handle gH_Forwards_FinishPre = null;
|
|
Handle gH_Forwards_Finish = null;
|
|
Handle gH_Forwards_OnRestart = null;
|
|
Handle gH_Forwards_OnEnd = null;
|
|
Handle gH_Forwards_OnPause = null;
|
|
Handle gH_Forwards_OnResume = null;
|
|
Handle gH_Forwards_OnStyleChanged = null;
|
|
Handle gH_Forwards_OnStyleConfigLoaded = null;
|
|
Handle gH_Forwards_OnDatabaseLoaded = null;
|
|
Handle gH_Forwards_OnChatConfigLoaded = null;
|
|
Handle gH_Forwards_OnUserCmdPre = null;
|
|
Handle gH_Forwards_OnTimerIncrement = null;
|
|
Handle gH_Forwards_OnTimerIncrementPost = null;
|
|
|
|
StringMap gSM_StyleCommands = null;
|
|
|
|
// player timer variables
|
|
playertimer_t gA_Timers[MAXPLAYERS+1];
|
|
|
|
// these are here until the compiler bug is fixed
|
|
float gF_PauseOrigin[MAXPLAYERS+1][3];
|
|
float gF_PauseAngles[MAXPLAYERS+1][3];
|
|
float gF_PauseVelocity[MAXPLAYERS+1][3];
|
|
|
|
// cookies
|
|
Handle gH_StyleCookie = null;
|
|
Handle gH_AutoBhopCookie = null;
|
|
|
|
// late load
|
|
bool gB_Late = false;
|
|
|
|
// modules
|
|
bool gB_Zones = false;
|
|
bool gB_WR = false;
|
|
bool gB_Replay = false;
|
|
bool gB_Rankings = false;
|
|
bool gB_HUD = false;
|
|
|
|
// cvars
|
|
ConVar gCV_Restart = null;
|
|
ConVar gCV_Pause = null;
|
|
ConVar gCV_AllowTimerWithoutZone = null;
|
|
ConVar gCV_BlockPreJump = null;
|
|
ConVar gCV_NoZAxisSpeed = null;
|
|
ConVar gCV_VelocityTeleport = null;
|
|
ConVar gCV_DefaultStyle = null;
|
|
|
|
// cached cvars
|
|
bool gB_Restart = true;
|
|
bool gB_Pause = true;
|
|
bool gB_AllowTimerWithoutZone = false;
|
|
bool gB_BlockPreJump = false;
|
|
bool gB_NoZAxisSpeed = true;
|
|
bool gB_VelocityTeleport = false;
|
|
int gI_DefaultStyle = 0;
|
|
bool gB_StyleCookies = true;
|
|
|
|
// table prefix
|
|
char gS_MySQLPrefix[32];
|
|
|
|
// server side
|
|
ConVar sv_airaccelerate = null;
|
|
ConVar sv_autobunnyhopping = null;
|
|
ConVar sv_enablebunnyhopping = null;
|
|
|
|
// timer settings
|
|
bool gB_Registered = false;
|
|
int gI_Styles = 0;
|
|
stylestrings_t gS_StyleStrings[STYLE_LIMIT];
|
|
stylesettings_t gA_StyleSettings[STYLE_LIMIT];
|
|
|
|
// chat settings
|
|
chatstrings_t gS_ChatStrings;
|
|
|
|
// misc cache
|
|
bool gB_StopChatSound = false;
|
|
bool gB_HookedJump = false;
|
|
char gS_LogPath[PLATFORM_MAX_PATH];
|
|
char gS_DeleteMap[MAXPLAYERS+1][160];
|
|
|
|
// flags
|
|
int gI_StyleFlag[STYLE_LIMIT];
|
|
char gS_StyleOverride[STYLE_LIMIT][32];
|
|
|
|
// kz support
|
|
bool gB_KZMap = false;
|
|
|
|
public Plugin myinfo =
|
|
{
|
|
name = "[shavit] Core",
|
|
author = "shavit",
|
|
description = "The core 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)
|
|
{
|
|
CreateNative("Shavit_FinishMap", Native_FinishMap);
|
|
CreateNative("Shavit_GetBhopStyle", Native_GetBhopStyle);
|
|
CreateNative("Shavit_GetChatStrings", Native_GetChatStrings);
|
|
CreateNative("Shavit_GetClientJumps", Native_GetClientJumps);
|
|
CreateNative("Shavit_GetClientTime", Native_GetClientTime);
|
|
CreateNative("Shavit_GetClientTrack", Native_GetClientTrack);
|
|
CreateNative("Shavit_GetDatabase", Native_GetDatabase);
|
|
CreateNative("Shavit_GetDB", Native_GetDB);
|
|
CreateNative("Shavit_GetGameType", Native_GetGameType);
|
|
CreateNative("Shavit_GetPerfectJumps", Native_GetPerfectJumps);
|
|
CreateNative("Shavit_GetStrafeCount", Native_GetStrafeCount);
|
|
CreateNative("Shavit_GetStyleCount", Native_GetStyleCount);
|
|
CreateNative("Shavit_GetStyleSettings", Native_GetStyleSettings);
|
|
CreateNative("Shavit_GetStyleStrings", Native_GetStyleStrings);
|
|
CreateNative("Shavit_GetSync", Native_GetSync);
|
|
CreateNative("Shavit_GetTimer", Native_GetTimer);
|
|
CreateNative("Shavit_GetTimerStatus", Native_GetTimerStatus);
|
|
CreateNative("Shavit_HasStyleAccess", Native_HasStyleAccess);
|
|
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);
|
|
CreateNative("Shavit_RestartTimer", Native_RestartTimer);
|
|
CreateNative("Shavit_ResumeTimer", Native_ResumeTimer);
|
|
CreateNative("Shavit_SaveSnapshot", Native_SaveSnapshot);
|
|
CreateNative("Shavit_SetPracticeMode", Native_SetPracticeMode);
|
|
CreateNative("Shavit_StartTimer", Native_StartTimer);
|
|
CreateNative("Shavit_StopChatSound", Native_StopChatSound);
|
|
CreateNative("Shavit_StopTimer", Native_StopTimer);
|
|
|
|
// registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins
|
|
RegPluginLibrary("shavit");
|
|
|
|
gB_Late = late;
|
|
|
|
return APLRes_Success;
|
|
}
|
|
|
|
public void OnPluginStart()
|
|
{
|
|
// forwards
|
|
gH_Forwards_Start = CreateGlobalForward("Shavit_OnStart", ET_Event, Param_Cell, Param_Cell);
|
|
gH_Forwards_Stop = CreateGlobalForward("Shavit_OnStop", ET_Event, Param_Cell, Param_Cell);
|
|
gH_Forwards_FinishPre = CreateGlobalForward("Shavit_OnFinishPre", ET_Event, Param_Cell, Param_Array);
|
|
gH_Forwards_Finish = CreateGlobalForward("Shavit_OnFinish", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
|
gH_Forwards_OnRestart = CreateGlobalForward("Shavit_OnRestart", ET_Event, Param_Cell, Param_Cell);
|
|
gH_Forwards_OnEnd = CreateGlobalForward("Shavit_OnEnd", ET_Event, Param_Cell, Param_Cell);
|
|
gH_Forwards_OnPause = CreateGlobalForward("Shavit_OnPause", ET_Event, Param_Cell, Param_Cell);
|
|
gH_Forwards_OnResume = CreateGlobalForward("Shavit_OnResume", ET_Event, Param_Cell, Param_Cell);
|
|
gH_Forwards_OnStyleChanged = CreateGlobalForward("Shavit_OnStyleChanged", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
|
gH_Forwards_OnStyleConfigLoaded = CreateGlobalForward("Shavit_OnStyleConfigLoaded", ET_Event, Param_Cell);
|
|
gH_Forwards_OnDatabaseLoaded = CreateGlobalForward("Shavit_OnDatabaseLoaded", ET_Event);
|
|
gH_Forwards_OnChatConfigLoaded = CreateGlobalForward("Shavit_OnChatConfigLoaded", ET_Event);
|
|
gH_Forwards_OnUserCmdPre = CreateGlobalForward("Shavit_OnUserCmdPre", ET_Event, Param_Cell, Param_CellByRef, Param_CellByRef, Param_Array, Param_Array, Param_Cell, Param_Cell, Param_Cell, Param_Array, Param_Array);
|
|
gH_Forwards_OnTimerIncrement = CreateGlobalForward("Shavit_OnTimeIncrement", ET_Event, Param_Cell, Param_Array, Param_CellByRef, Param_Array);
|
|
gH_Forwards_OnTimerIncrementPost = CreateGlobalForward("Shavit_OnTimeIncrementPost", ET_Event, Param_Cell, Param_Cell, Param_Array);
|
|
|
|
LoadTranslations("shavit-core.phrases");
|
|
|
|
// game types
|
|
gEV_Type = GetEngineVersion();
|
|
|
|
if(gEV_Type == Engine_CSGO)
|
|
{
|
|
sv_autobunnyhopping = FindConVar("sv_autobunnyhopping");
|
|
sv_autobunnyhopping.BoolValue = false;
|
|
}
|
|
|
|
else if(gEV_Type != Engine_CSS && gEV_Type != Engine_TF2)
|
|
{
|
|
SetFailState("This plugin was meant to be used in CS:S, CS:GO and TF2 *only*.");
|
|
}
|
|
|
|
// database connections
|
|
SQL_SetPrefix();
|
|
SQL_DBConnect();
|
|
|
|
// hooks
|
|
gB_HookedJump = HookEventEx("player_jump", Player_Jump);
|
|
HookEvent("player_death", Player_Death);
|
|
HookEvent("player_team", Player_Death);
|
|
HookEvent("player_spawn", Player_Death);
|
|
|
|
// commands START
|
|
// style
|
|
RegConsoleCmd("sm_style", Command_Style, "Choose your bhop style.");
|
|
RegConsoleCmd("sm_styles", Command_Style, "Choose your bhop style.");
|
|
RegConsoleCmd("sm_diff", Command_Style, "Choose your bhop style.");
|
|
RegConsoleCmd("sm_difficulty", Command_Style, "Choose your bhop style.");
|
|
gH_StyleCookie = RegClientCookie("shavit_style", "Style cookie", CookieAccess_Protected);
|
|
|
|
// timer start
|
|
RegConsoleCmd("sm_s", Command_StartTimer, "Start your timer.");
|
|
RegConsoleCmd("sm_start", Command_StartTimer, "Start your timer.");
|
|
RegConsoleCmd("sm_r", Command_StartTimer, "Start your timer.");
|
|
RegConsoleCmd("sm_restart", Command_StartTimer, "Start your timer.");
|
|
|
|
RegConsoleCmd("sm_b", Command_StartTimer, "Start your timer on the bonus track.");
|
|
RegConsoleCmd("sm_bonus", Command_StartTimer, "Start your timer on the bonus track.");
|
|
|
|
// teleport to end
|
|
RegConsoleCmd("sm_end", Command_TeleportEnd, "Teleport to endzone.");
|
|
|
|
RegConsoleCmd("sm_bend", Command_TeleportEnd, "Teleport to endzone of the bonus track.");
|
|
RegConsoleCmd("sm_bonusend", Command_TeleportEnd, "Teleport to endzone of the bonus track.");
|
|
|
|
// timer stop
|
|
RegConsoleCmd("sm_stop", Command_StopTimer, "Stop your timer.");
|
|
|
|
// timer pause / resume
|
|
RegConsoleCmd("sm_pause", Command_TogglePause, "Toggle pause.");
|
|
RegConsoleCmd("sm_unpause", Command_TogglePause, "Toggle pause.");
|
|
RegConsoleCmd("sm_resume", Command_TogglePause, "Toggle pause");
|
|
|
|
// autobhop toggle
|
|
RegConsoleCmd("sm_auto", Command_AutoBhop, "Toggle autobhop.");
|
|
RegConsoleCmd("sm_autobhop", Command_AutoBhop, "Toggle autobhop.");
|
|
gH_AutoBhopCookie = RegClientCookie("shavit_autobhop", "Autobhop cookie", CookieAccess_Protected);
|
|
|
|
// doublestep fixer
|
|
AddCommandListener(Command_DoubleStep, "+ds");
|
|
AddCommandListener(Command_DoubleStep, "-ds");
|
|
|
|
// style commands
|
|
gSM_StyleCommands = new StringMap();
|
|
|
|
#if defined DEBUG
|
|
RegConsoleCmd("sm_finishtest", Command_FinishTest);
|
|
#endif
|
|
|
|
// admin
|
|
RegAdminCmd("sm_deletemap", Command_DeleteMap, ADMFLAG_ROOT, "Deletes all map data. Usage: sm_deletemap <map>");
|
|
// 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_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_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_DefaultStyle = CreateConVar("shavit_core_defaultstyle", "0", "Default style ID.\nAdd the '!' prefix to disable style cookies - i.e. \"!3\" to *force* scroll to be the default style.", 0, true, 0.0);
|
|
|
|
gCV_Restart.AddChangeHook(OnConVarChanged);
|
|
gCV_Pause.AddChangeHook(OnConVarChanged);
|
|
gCV_AllowTimerWithoutZone.AddChangeHook(OnConVarChanged);
|
|
gCV_BlockPreJump.AddChangeHook(OnConVarChanged);
|
|
gCV_NoZAxisSpeed.AddChangeHook(OnConVarChanged);
|
|
gCV_VelocityTeleport.AddChangeHook(OnConVarChanged);
|
|
gCV_DefaultStyle.AddChangeHook(OnConVarChanged);
|
|
|
|
AutoExecConfig();
|
|
|
|
sv_airaccelerate = FindConVar("sv_airaccelerate");
|
|
sv_airaccelerate.Flags &= ~(FCVAR_NOTIFY | FCVAR_REPLICATED);
|
|
|
|
sv_enablebunnyhopping = FindConVar("sv_enablebunnyhopping");
|
|
|
|
if(sv_enablebunnyhopping != null)
|
|
{
|
|
sv_enablebunnyhopping.Flags &= ~(FCVAR_NOTIFY | FCVAR_REPLICATED);
|
|
}
|
|
|
|
// late
|
|
if(gB_Late)
|
|
{
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsValidClient(i))
|
|
{
|
|
OnClientPutInServer(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
gB_Zones = LibraryExists("shavit-zones");
|
|
gB_WR = LibraryExists("shavit-wr");
|
|
gB_Replay = LibraryExists("shavit-replay");
|
|
gB_Rankings = LibraryExists("shavit-rankings");
|
|
gB_HUD = LibraryExists("shavit-hud");
|
|
}
|
|
|
|
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
|
|
{
|
|
gB_Restart = gCV_Restart.BoolValue;
|
|
gB_Pause = gCV_Pause.BoolValue;
|
|
gB_AllowTimerWithoutZone = gCV_AllowTimerWithoutZone.BoolValue;
|
|
gB_BlockPreJump = gCV_BlockPreJump.BoolValue;
|
|
gB_NoZAxisSpeed = gCV_NoZAxisSpeed.BoolValue;
|
|
gB_VelocityTeleport = gCV_VelocityTeleport.BoolValue;
|
|
|
|
if(convar == gCV_DefaultStyle)
|
|
{
|
|
gB_StyleCookies = newValue[0] != '!';
|
|
gI_DefaultStyle = StringToInt(newValue[1]);
|
|
}
|
|
}
|
|
|
|
public void OnLibraryAdded(const char[] name)
|
|
{
|
|
if(StrEqual(name, "shavit-zones"))
|
|
{
|
|
gB_Zones = true;
|
|
}
|
|
|
|
else if(StrEqual(name, "shavit-wr"))
|
|
{
|
|
gB_WR = true;
|
|
}
|
|
|
|
else if(StrEqual(name, "shavit-replay"))
|
|
{
|
|
gB_Replay = true;
|
|
}
|
|
|
|
else if(StrEqual(name, "shavit-rankings"))
|
|
{
|
|
gB_Rankings = true;
|
|
}
|
|
|
|
else if(StrEqual(name, "shavit-hud"))
|
|
{
|
|
gB_HUD = true;
|
|
}
|
|
}
|
|
|
|
public void OnLibraryRemoved(const char[] name)
|
|
{
|
|
if(StrEqual(name, "shavit-zones"))
|
|
{
|
|
gB_Zones = false;
|
|
}
|
|
|
|
else if(StrEqual(name, "shavit-wr"))
|
|
{
|
|
gB_WR = false;
|
|
}
|
|
|
|
else if(StrEqual(name, "shavit-replay"))
|
|
{
|
|
gB_Replay = false;
|
|
}
|
|
|
|
else if(StrEqual(name, "shavit-rankings"))
|
|
{
|
|
gB_Rankings = false;
|
|
}
|
|
|
|
else if(StrEqual(name, "shavit-hud"))
|
|
{
|
|
gB_HUD = false;
|
|
}
|
|
}
|
|
|
|
public void OnMapStart()
|
|
{
|
|
// styles
|
|
if(!LoadStyles())
|
|
{
|
|
SetFailState("Could not load the styles configuration file. Make sure it exists (addons/sourcemod/configs/shavit-styles.cfg) and follows the proper syntax!");
|
|
}
|
|
|
|
// messages
|
|
if(!LoadMessages())
|
|
{
|
|
SetFailState("Could not load the chat messages configuration file. Make sure it exists (addons/sourcemod/configs/shavit-messages.cfg) and follows the proper syntax!");
|
|
}
|
|
}
|
|
|
|
public void OnMapEnd()
|
|
{
|
|
gB_KZMap = false;
|
|
}
|
|
|
|
public Action Command_StartTimer(int client, int args)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
char sCommand[16];
|
|
GetCmdArg(0, sCommand, 16);
|
|
|
|
if(!gB_Restart)
|
|
{
|
|
if(args != -1)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "CommandDisabled", client, gS_ChatStrings.sVariable, sCommand, gS_ChatStrings.sText);
|
|
}
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
int track = Track_Main;
|
|
|
|
if(StrContains(sCommand, "sm_b", false) == 0)
|
|
{
|
|
track = Track_Bonus;
|
|
}
|
|
|
|
if(gB_AllowTimerWithoutZone || (gB_Zones && (Shavit_ZoneExists(Zone_Start, track) || gB_KZMap)))
|
|
{
|
|
Call_StartForward(gH_Forwards_OnRestart);
|
|
Call_PushCell(client);
|
|
Call_PushCell(track);
|
|
Call_Finish();
|
|
|
|
if(gB_AllowTimerWithoutZone)
|
|
{
|
|
StartTimer(client, track);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "StartZoneUndefined", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
|
}
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Command_TeleportEnd(int client, int args)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
char sCommand[16];
|
|
GetCmdArg(0, sCommand, 16);
|
|
|
|
int track = Track_Main;
|
|
|
|
if(StrContains(sCommand, "sm_b", false) == 0)
|
|
{
|
|
track = Track_Bonus;
|
|
}
|
|
|
|
if(gB_Zones && (Shavit_ZoneExists(Zone_End, track) || gB_KZMap))
|
|
{
|
|
Shavit_StopTimer(client);
|
|
|
|
Call_StartForward(gH_Forwards_OnEnd);
|
|
Call_PushCell(client);
|
|
Call_PushCell(track);
|
|
Call_Finish();
|
|
}
|
|
|
|
else
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "EndZoneUndefined", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
|
}
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Command_StopTimer(int client, int args)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
Shavit_StopTimer(client);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Command_TogglePause(int client, int args)
|
|
{
|
|
if(!IsValidClient(client) || !gA_Timers[client].bEnabled)
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
if(Shavit_InsideZone(client, Zone_Start, gA_Timers[client].iTrack))
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "PauseStartZone", client, gS_ChatStrings.sText, gS_ChatStrings.sWarning, gS_ChatStrings.sText, gS_ChatStrings.sVariable, gS_ChatStrings.sText);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
if(!gB_Pause)
|
|
{
|
|
char sCommand[16];
|
|
GetCmdArg(0, sCommand, 16);
|
|
|
|
Shavit_PrintToChat(client, "%T", "CommandDisabled", client, gS_ChatStrings.sVariable, sCommand, gS_ChatStrings.sText);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
if(GetEntPropEnt(client, Prop_Send, "m_hGroundEntity") == -1 && GetEntityMoveType(client) != MOVETYPE_LADDER)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "PauseNotOnGround", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
if(gA_Timers[client].bPaused)
|
|
{
|
|
TeleportEntity(client, gF_PauseOrigin[client], gF_PauseAngles[client], gF_PauseVelocity[client]);
|
|
ResumeTimer(client);
|
|
|
|
Shavit_PrintToChat(client, "%T", "MessageUnpause", client, gS_ChatStrings.sText, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
|
}
|
|
|
|
else
|
|
{
|
|
GetClientAbsOrigin(client, gF_PauseOrigin[client]);
|
|
GetClientEyeAngles(client, gF_PauseAngles[client]);
|
|
GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", gF_PauseVelocity[client]);
|
|
|
|
PauseTimer(client);
|
|
|
|
Shavit_PrintToChat(client, "%T", "MessagePause", client, gS_ChatStrings.sText, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
|
}
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
#if defined DEBUG
|
|
public Action Command_FinishTest(int client, int args)
|
|
{
|
|
Shavit_FinishMap(client, gA_Timers[client].iTrack);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
#endif
|
|
|
|
public Action Command_DeleteMap(int client, int args)
|
|
{
|
|
if(args == 0)
|
|
{
|
|
ReplyToCommand(client, "Usage: sm_deletemap <map>\nOnce a map is chosen, \"sm_deletemap confirm\" to run the deletion.");
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
char sArgs[160];
|
|
GetCmdArgString(sArgs, 160);
|
|
|
|
if(StrEqual(sArgs, "confirm") && strlen(gS_DeleteMap[client]) > 0)
|
|
{
|
|
if(gB_WR)
|
|
{
|
|
Shavit_WR_DeleteMap(gS_DeleteMap[client]);
|
|
ReplyToCommand(client, "Deleted all records for %s.", gS_DeleteMap[client]);
|
|
}
|
|
|
|
if(gB_Zones)
|
|
{
|
|
Shavit_Zones_DeleteMap(gS_DeleteMap[client]);
|
|
ReplyToCommand(client, "Deleted all zones for %s.", gS_DeleteMap[client]);
|
|
}
|
|
|
|
if(gB_Replay)
|
|
{
|
|
Shavit_Replay_DeleteMap(gS_DeleteMap[client]);
|
|
ReplyToCommand(client, "Deleted all replay data for %s.", gS_DeleteMap[client]);
|
|
}
|
|
|
|
if(gB_Rankings)
|
|
{
|
|
Shavit_Rankings_DeleteMap(gS_DeleteMap[client]);
|
|
ReplyToCommand(client, "Deleted all rankings for %s.", gS_DeleteMap[client]);
|
|
}
|
|
|
|
ReplyToCommand(client, "Finished deleting data for %s.", gS_DeleteMap[client]);
|
|
strcopy(gS_DeleteMap[client], 160, "");
|
|
}
|
|
|
|
else
|
|
{
|
|
strcopy(gS_DeleteMap[client], 160, sArgs);
|
|
ReplyToCommand(client, "Map to delete is now %s.\nRun \"sm_deletemap confirm\" to delete all data regarding the map %s.", gS_DeleteMap[client], gS_DeleteMap[client]);
|
|
}
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Command_AutoBhop(int client, int args)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
gA_Timers[client].bAuto = !gA_Timers[client].bAuto;
|
|
|
|
if(gA_Timers[client].bAuto)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "AutobhopEnabled", client, gS_ChatStrings.sVariable2, gS_ChatStrings.sText);
|
|
}
|
|
|
|
else
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "AutobhopDisabled", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
|
}
|
|
|
|
char sAutoBhop[4];
|
|
IntToString(view_as<int>(gA_Timers[client].bAuto), sAutoBhop, 4);
|
|
SetClientCookie(client, gH_AutoBhopCookie, sAutoBhop);
|
|
|
|
UpdateStyleSettings(client);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Command_DoubleStep(int client, const char[] command, int args)
|
|
{
|
|
gA_Timers[client].bDoubleSteps = (command[0] == '+');
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Command_Style(int client, int args)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
Menu menu = new Menu(StyleMenu_Handler);
|
|
menu.SetTitle("%T", "StyleMenuTitle", client);
|
|
|
|
for(int i = 0; i < gI_Styles; i++)
|
|
{
|
|
char sInfo[8];
|
|
IntToString(i, sInfo, 8);
|
|
|
|
char sDisplay[64];
|
|
|
|
if(gA_StyleSettings[i].bUnranked)
|
|
{
|
|
FormatEx(sDisplay, 64, "%T %s", "StyleUnranked", client, gS_StyleStrings[i].sStyleName);
|
|
}
|
|
|
|
else
|
|
{
|
|
float time = 0.0;
|
|
|
|
if(gB_WR)
|
|
{
|
|
Shavit_GetWRTime(i, time, Track_Main);
|
|
}
|
|
|
|
if(time > 0.0)
|
|
{
|
|
char sTime[32];
|
|
FormatSeconds(time, sTime, 32, false);
|
|
|
|
FormatEx(sDisplay, 64, "%s - WR: %s", gS_StyleStrings[i].sStyleName, sTime);
|
|
}
|
|
|
|
else
|
|
{
|
|
strcopy(sDisplay, 64, gS_StyleStrings[i].sStyleName);
|
|
}
|
|
}
|
|
|
|
menu.AddItem(sInfo, sDisplay, (gA_Timers[client].iStyle == i || !Shavit_HasStyleAccess(client, i))? ITEMDRAW_DISABLED:ITEMDRAW_DEFAULT);
|
|
}
|
|
|
|
// should NEVER happen
|
|
if(menu.ItemCount == 0)
|
|
{
|
|
menu.AddItem("-1", "Nothing");
|
|
}
|
|
|
|
else if(menu.ItemCount <= ((gEV_Type == Engine_CSS)? 9:8))
|
|
{
|
|
menu.Pagination = MENU_NO_PAGINATION;
|
|
}
|
|
|
|
menu.ExitButton = true;
|
|
menu.Display(client, 20);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public int StyleMenu_Handler(Menu menu, MenuAction action, int param1, int param2)
|
|
{
|
|
if(action == MenuAction_Select)
|
|
{
|
|
char info[16];
|
|
menu.GetItem(param2, info, 16);
|
|
|
|
int style = StringToInt(info);
|
|
|
|
if(style == -1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ChangeClientStyle(param1, style, true);
|
|
}
|
|
|
|
else if(action == MenuAction_End)
|
|
{
|
|
delete menu;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CallOnStyleChanged(int client, int oldstyle, int newstyle, bool manual)
|
|
{
|
|
Call_StartForward(gH_Forwards_OnStyleChanged);
|
|
Call_PushCell(client);
|
|
Call_PushCell(oldstyle);
|
|
Call_PushCell(newstyle);
|
|
Call_PushCell(gA_Timers[client].iTrack);
|
|
Call_PushCell(manual);
|
|
Call_Finish();
|
|
|
|
gA_Timers[client].iStyle = newstyle;
|
|
|
|
UpdateStyleSettings(client);
|
|
}
|
|
|
|
void ChangeClientStyle(int client, int style, bool manual)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(!Shavit_HasStyleAccess(client, style))
|
|
{
|
|
if(manual)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "StyleNoAccess", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if(manual)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "StyleSelection", client, gS_ChatStrings.sStyle, gS_StyleStrings[style].sStyleName, gS_ChatStrings.sText);
|
|
}
|
|
|
|
if(gA_StyleSettings[style].bUnranked)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "UnrankedWarning", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
|
}
|
|
|
|
int aa_old = RoundToZero(gA_StyleSettings[gA_Timers[client].iStyle].fAiraccelerate);
|
|
int aa_new = RoundToZero(gA_StyleSettings[style].fAiraccelerate);
|
|
|
|
if(aa_old != aa_new)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "NewAiraccelerate", client, aa_old, gS_ChatStrings.sVariable, aa_new, gS_ChatStrings.sText);
|
|
}
|
|
|
|
CallOnStyleChanged(client, gA_Timers[client].iStyle, style, manual);
|
|
|
|
StopTimer(client);
|
|
|
|
if(gB_AllowTimerWithoutZone || (gB_Zones && (Shavit_ZoneExists(Zone_Start, gA_Timers[client].iTrack) || gB_KZMap)))
|
|
{
|
|
Call_StartForward(gH_Forwards_OnRestart);
|
|
Call_PushCell(client);
|
|
Call_PushCell(gA_Timers[client].iTrack);
|
|
Call_Finish();
|
|
}
|
|
|
|
char sStyle[4];
|
|
IntToString(style, sStyle, 4);
|
|
|
|
SetClientCookie(client, gH_StyleCookie, sStyle);
|
|
}
|
|
|
|
// used as an alternative for games where player_jump isn't a thing, such as TF2
|
|
public void Bunnyhop_OnLeaveGround(int client, bool jumped, bool ladder)
|
|
{
|
|
if(gB_HookedJump || !jumped || ladder)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DoJump(client);
|
|
}
|
|
|
|
public void Player_Jump(Event event, const char[] name, bool dontBroadcast)
|
|
{
|
|
DoJump(GetClientOfUserId(event.GetInt("userid")));
|
|
}
|
|
|
|
void DoJump(int client)
|
|
{
|
|
if(gA_Timers[client].bEnabled)
|
|
{
|
|
gA_Timers[client].iJumps++;
|
|
}
|
|
|
|
// TF2 doesn't use stamina
|
|
if(gEV_Type != Engine_TF2 && (gA_StyleSettings[gA_Timers[client].iStyle].bEasybhop) || Shavit_InsideZone(client, Zone_Easybhop, gA_Timers[client].iTrack))
|
|
{
|
|
SetEntPropFloat(client, Prop_Send, "m_flStamina", 0.0);
|
|
}
|
|
|
|
RequestFrame(VelocityChanges, GetClientSerial(client));
|
|
}
|
|
|
|
void VelocityChanges(int data)
|
|
{
|
|
int client = GetClientFromSerial(data);
|
|
|
|
if(client == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fSpeedMultiplier) != 1.0)
|
|
{
|
|
SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fSpeedMultiplier));
|
|
}
|
|
|
|
float fAbsVelocity[3];
|
|
GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fAbsVelocity);
|
|
|
|
float fSpeed = (SquareRoot(Pow(fAbsVelocity[0], 2.0) + Pow(fAbsVelocity[1], 2.0)));
|
|
|
|
if(fSpeed == 0.0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float fVelocityMultiplier = view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fVelocity);
|
|
float fVelocityBonus = view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fBonusVelocity);
|
|
float fMin = view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fMinVelocity);
|
|
|
|
if(fVelocityMultiplier != 0.0)
|
|
{
|
|
fAbsVelocity[0] *= fVelocityMultiplier;
|
|
fAbsVelocity[1] *= fVelocityMultiplier;
|
|
}
|
|
|
|
if(fVelocityBonus != 0.0)
|
|
{
|
|
float x = fSpeed / (fSpeed + fVelocityBonus);
|
|
fAbsVelocity[0] /= x;
|
|
fAbsVelocity[1] /= x;
|
|
}
|
|
|
|
if(fMin != 0.0 && fSpeed < fMin)
|
|
{
|
|
float x = (fSpeed / fMin);
|
|
fAbsVelocity[0] /= x;
|
|
fAbsVelocity[1] /= x;
|
|
}
|
|
|
|
if(!gB_VelocityTeleport)
|
|
{
|
|
SetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fAbsVelocity);
|
|
}
|
|
|
|
else
|
|
{
|
|
TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, fAbsVelocity);
|
|
}
|
|
}
|
|
|
|
public void Player_Death(Event event, const char[] name, bool dontBroadcast)
|
|
{
|
|
int client = GetClientOfUserId(event.GetInt("userid"));
|
|
|
|
ResumeTimer(client);
|
|
StopTimer(client);
|
|
}
|
|
|
|
public int Native_GetGameType(Handle handler, int numParams)
|
|
{
|
|
return view_as<int>(gEV_Type);
|
|
}
|
|
|
|
public int Native_GetDatabase(Handle handler, int numParams)
|
|
{
|
|
return view_as<int>(CloneHandle(gH_SQL, handler));
|
|
}
|
|
|
|
public int Native_GetDB(Handle handler, int numParams)
|
|
{
|
|
SetNativeCellRef(1, gH_SQL);
|
|
}
|
|
|
|
public int Native_GetTimer(Handle handler, int numParams)
|
|
{
|
|
// 1 - client
|
|
int client = GetNativeCell(1);
|
|
|
|
// 2 - time
|
|
SetNativeCellRef(2, gA_Timers[client].fTimer);
|
|
SetNativeCellRef(3, gA_Timers[client].iJumps);
|
|
SetNativeCellRef(4, gA_Timers[client].iStyle);
|
|
SetNativeCellRef(5, gA_Timers[client].bEnabled);
|
|
}
|
|
|
|
public int Native_GetClientTime(Handle handler, int numParams)
|
|
{
|
|
return view_as<int>(gA_Timers[GetNativeCell(1)].fTimer);
|
|
}
|
|
|
|
public int Native_GetClientTrack(Handle handler, int numParams)
|
|
{
|
|
return gA_Timers[GetNativeCell(1)].iTrack;
|
|
}
|
|
|
|
public int Native_GetClientJumps(Handle handler, int numParams)
|
|
{
|
|
return gA_Timers[GetNativeCell(1)].iJumps;
|
|
}
|
|
|
|
public int Native_GetBhopStyle(Handle handler, int numParams)
|
|
{
|
|
return gA_Timers[GetNativeCell(1)].iStyle;
|
|
}
|
|
|
|
public int Native_GetTimerStatus(Handle handler, int numParams)
|
|
{
|
|
return GetTimerStatus(GetNativeCell(1));
|
|
}
|
|
|
|
public int Native_HasStyleAccess(Handle handler, int numParams)
|
|
{
|
|
int style = GetNativeCell(2);
|
|
|
|
return CheckCommandAccess(GetNativeCell(1), (strlen(gS_StyleOverride[style]) > 0)? gS_StyleOverride[style]:"<none>", gI_StyleFlag[style]);
|
|
}
|
|
|
|
public int Native_IsKZMap(Handle handler, int numParams)
|
|
{
|
|
return view_as<bool>(gB_KZMap);
|
|
}
|
|
|
|
public int Native_StartTimer(Handle handler, int numParams)
|
|
{
|
|
StartTimer(GetNativeCell(1), GetNativeCell(2));
|
|
}
|
|
|
|
public int Native_StopTimer(Handle handler, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
|
|
StopTimer(client);
|
|
|
|
Call_StartForward(gH_Forwards_Stop);
|
|
Call_PushCell(client);
|
|
Call_PushCell(gA_Timers[client].iTrack);
|
|
Call_Finish();
|
|
}
|
|
|
|
public int Native_FinishMap(Handle handler, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
|
|
timer_snapshot_t snapshot;
|
|
snapshot.bTimerEnabled = gA_Timers[client].bEnabled;
|
|
snapshot.bClientPaused = gA_Timers[client].bPaused;
|
|
snapshot.iJumps = gA_Timers[client].iJumps;
|
|
snapshot.bsStyle = gA_Timers[client].iStyle;
|
|
snapshot.iStrafes = gA_Timers[client].iStrafes;
|
|
snapshot.iTotalMeasures = gA_Timers[client].iTotalMeasures;
|
|
snapshot.iGoodGains = gA_Timers[client].iGoodGains;
|
|
snapshot.fServerTime = GetEngineTime();
|
|
snapshot.fCurrentTime = gA_Timers[client].fTimer;
|
|
snapshot.iSHSWCombination = gA_Timers[client].iSHSWCombination;
|
|
snapshot.iTimerTrack = gA_Timers[client].iTrack;
|
|
snapshot.iMeasuredJumps = gA_Timers[client].iMeasuredJumps;
|
|
snapshot.iPerfectJumps = gA_Timers[client].iPerfectJumps;
|
|
|
|
Action result = Plugin_Continue;
|
|
Call_StartForward(gH_Forwards_FinishPre);
|
|
Call_PushCell(client);
|
|
Call_PushArrayEx(snapshot, sizeof(timer_snapshot_t), SM_PARAM_COPYBACK);
|
|
Call_Finish(result);
|
|
|
|
if(result != Plugin_Continue && result != Plugin_Changed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Call_StartForward(gH_Forwards_Finish);
|
|
Call_PushCell(client);
|
|
|
|
int style = 0;
|
|
int track = Track_Main;
|
|
float perfs = 100.0;
|
|
|
|
if(result == Plugin_Continue)
|
|
{
|
|
Call_PushCell(style = gA_Timers[client].iStyle);
|
|
Call_PushCell(gA_Timers[client].fTimer);
|
|
Call_PushCell(gA_Timers[client].iJumps);
|
|
Call_PushCell(gA_Timers[client].iStrafes);
|
|
Call_PushCell((gA_StyleSettings[gA_Timers[client].iStyle].bSync)? (gA_Timers[client].iGoodGains == 0)? 0.0:(gA_Timers[client].iGoodGains / float(gA_Timers[client].iTotalMeasures) * 100.0):-1.0);
|
|
Call_PushCell(track = gA_Timers[client].iTrack);
|
|
perfs = (gA_Timers[client].iMeasuredJumps == 0)? 100.0:(gA_Timers[client].iPerfectJumps / float(gA_Timers[client].iMeasuredJumps) * 100.0);
|
|
}
|
|
|
|
else
|
|
{
|
|
Call_PushCell(style = snapshot.bsStyle);
|
|
Call_PushCell(snapshot.fCurrentTime);
|
|
Call_PushCell(snapshot.iJumps);
|
|
Call_PushCell(snapshot.iStrafes);
|
|
Call_PushCell((gA_StyleSettings[snapshot.bsStyle].bSync)? (snapshot.iGoodGains == 0)? 0.0:(snapshot.iGoodGains / float(snapshot.iTotalMeasures) * 100.0):-1.0);
|
|
Call_PushCell(track = snapshot.iTimerTrack);
|
|
perfs = (snapshot.iMeasuredJumps == 0)? 100.0:(snapshot.iPerfectJumps / float(snapshot.iMeasuredJumps) * 100.0);
|
|
}
|
|
|
|
float oldtime = 0.0;
|
|
|
|
if(gB_WR)
|
|
{
|
|
Shavit_GetPlayerPB(client, style, oldtime, track);
|
|
}
|
|
|
|
Call_PushCell(oldtime);
|
|
Call_PushCell(perfs);
|
|
Call_Finish();
|
|
|
|
StopTimer(client);
|
|
}
|
|
|
|
public int Native_PauseTimer(Handle handler, int numParams)
|
|
{
|
|
PauseTimer(GetNativeCell(1));
|
|
}
|
|
|
|
public int Native_ResumeTimer(Handle handler, int numParams)
|
|
{
|
|
ResumeTimer(GetNativeCell(1));
|
|
}
|
|
|
|
public int Native_StopChatSound(Handle handler, int numParams)
|
|
{
|
|
gB_StopChatSound = true;
|
|
}
|
|
|
|
public int Native_PrintToChat(Handle handler, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
|
|
if(!IsClientInGame(client))
|
|
{
|
|
gB_StopChatSound = false;
|
|
|
|
return;
|
|
}
|
|
|
|
static int iWritten = 0; // useless?
|
|
|
|
char sBuffer[300];
|
|
FormatNativeString(0, 2, 3, 300, iWritten, sBuffer);
|
|
Format(sBuffer, 300, "%s %s%s", gS_ChatStrings.sPrefix, gS_ChatStrings.sText, sBuffer);
|
|
|
|
if(IsSource2013(gEV_Type))
|
|
{
|
|
Handle hSayText2 = StartMessageOne("SayText2", client);
|
|
|
|
if(hSayText2 != null)
|
|
{
|
|
BfWriteByte(hSayText2, 0);
|
|
BfWriteByte(hSayText2, !gB_StopChatSound);
|
|
BfWriteString(hSayText2, sBuffer);
|
|
}
|
|
|
|
EndMessage();
|
|
}
|
|
|
|
else
|
|
{
|
|
PrintToChat(client, " %s", sBuffer);
|
|
}
|
|
|
|
gB_StopChatSound = false;
|
|
}
|
|
|
|
public int Native_RestartTimer(Handle handler, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
int track = GetNativeCell(2);
|
|
|
|
Call_StartForward(gH_Forwards_OnRestart);
|
|
Call_PushCell(client);
|
|
Call_PushCell(track);
|
|
Call_Finish();
|
|
|
|
StartTimer(client, track);
|
|
}
|
|
|
|
public int Native_GetPerfectJumps(Handle handler, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
|
|
return view_as<int>((gA_Timers[client].iMeasuredJumps == 0)? 100.0:(gA_Timers[client].iPerfectJumps / float(gA_Timers[client].iMeasuredJumps) * 100.0));
|
|
}
|
|
|
|
public int Native_GetStrafeCount(Handle handler, int numParams)
|
|
{
|
|
return gA_Timers[GetNativeCell(1)].iStrafes;
|
|
}
|
|
|
|
public int Native_GetSync(Handle handler, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
|
|
return view_as<int>((gA_StyleSettings[gA_Timers[client].iStyle].bSync)? (gA_Timers[client].iGoodGains == 0)? 0.0:(gA_Timers[client].iGoodGains / float(gA_Timers[client].iTotalMeasures) * 100.0):-1.0);
|
|
}
|
|
|
|
public int Native_GetStyleCount(Handle handler, int numParams)
|
|
{
|
|
return (gI_Styles > 0)? gI_Styles:-1;
|
|
}
|
|
|
|
public int Native_GetStyleSettings(Handle handler, int numParams)
|
|
{
|
|
return SetNativeArray(2, gA_StyleSettings[GetNativeCell(1)], sizeof(stylesettings_t));
|
|
}
|
|
|
|
public int Native_GetStyleStrings(Handle handler, int numParams)
|
|
{
|
|
int style = GetNativeCell(1);
|
|
int type = GetNativeCell(2);
|
|
int size = GetNativeCell(4);
|
|
|
|
switch(type)
|
|
{
|
|
case sStyleName: return SetNativeString(3, gS_StyleStrings[style].sStyleName, size);
|
|
case sShortName: return SetNativeString(3, gS_StyleStrings[style].sShortName, size);
|
|
case sHTMLColor: return SetNativeString(3, gS_StyleStrings[style].sHTMLColor, size);
|
|
case sChangeCommand: return SetNativeString(3, gS_StyleStrings[style].sChangeCommand, size);
|
|
case sClanTag: return SetNativeString(3, gS_StyleStrings[style].sClanTag, size);
|
|
case sSpecialString: return SetNativeString(3, gS_StyleStrings[style].sSpecialString, size);
|
|
case sStylePermission: return SetNativeString(3, gS_StyleStrings[style].sStylePermission, size);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public int Native_GetChatStrings(Handle handler, int numParams)
|
|
{
|
|
int type = GetNativeCell(1);
|
|
int size = GetNativeCell(3);
|
|
|
|
switch(type)
|
|
{
|
|
case sMessagePrefix: return SetNativeString(2, gS_ChatStrings.sPrefix, size);
|
|
case sMessageText: return SetNativeString(2, gS_ChatStrings.sText, size);
|
|
case sMessageWarning: return SetNativeString(2, gS_ChatStrings.sWarning, size);
|
|
case sMessageVariable: return SetNativeString(2, gS_ChatStrings.sVariable, size);
|
|
case sMessageVariable2: return SetNativeString(2, gS_ChatStrings.sVariable2, size);
|
|
case sMessageStyle: return SetNativeString(2, gS_ChatStrings.sStyle, size);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public int Native_SetPracticeMode(Handle handler, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
bool practice = view_as<bool>(GetNativeCell(2));
|
|
bool alert = view_as<bool>(GetNativeCell(3));
|
|
|
|
if(alert && practice && !gA_Timers[client].bPracticeMode && (!gB_HUD || (Shavit_GetHUDSettings(client) & HUD_NOPRACALERT) == 0))
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "PracticeModeAlert", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
|
}
|
|
|
|
gA_Timers[client].bPracticeMode = practice;
|
|
}
|
|
|
|
public int Native_IsPracticeMode(Handle handler, int numParams)
|
|
{
|
|
return view_as<int>(gA_Timers[GetNativeCell(1)].bPracticeMode);
|
|
}
|
|
|
|
public int Native_SaveSnapshot(Handle handler, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
|
|
timer_snapshot_t snapshot;
|
|
snapshot.bTimerEnabled = gA_Timers[client].bEnabled;
|
|
snapshot.bClientPaused = gA_Timers[client].bPaused;
|
|
snapshot.iJumps = gA_Timers[client].iJumps;
|
|
snapshot.bsStyle = gA_Timers[client].iStyle;
|
|
snapshot.iStrafes = gA_Timers[client].iStrafes;
|
|
snapshot.iTotalMeasures = gA_Timers[client].iTotalMeasures;
|
|
snapshot.iGoodGains = gA_Timers[client].iGoodGains;
|
|
snapshot.fServerTime = GetEngineTime();
|
|
snapshot.fCurrentTime = gA_Timers[client].fTimer;
|
|
snapshot.iSHSWCombination = gA_Timers[client].iSHSWCombination;
|
|
snapshot.iTimerTrack = gA_Timers[client].iTrack;
|
|
snapshot.iMeasuredJumps = gA_Timers[client].iMeasuredJumps;
|
|
snapshot.iPerfectJumps = gA_Timers[client].iPerfectJumps;
|
|
|
|
return SetNativeArray(2, snapshot, sizeof(timer_snapshot_t));
|
|
}
|
|
|
|
public int Native_LoadSnapshot(Handle handler, int numParams)
|
|
{
|
|
int client = GetNativeCell(1);
|
|
|
|
timer_snapshot_t snapshot;
|
|
GetNativeArray(2, snapshot, sizeof(timer_snapshot_t));
|
|
|
|
gA_Timers[client].iTrack = snapshot.iTimerTrack;
|
|
|
|
if(gA_Timers[client].iStyle != snapshot.bsStyle && Shavit_HasStyleAccess(client, snapshot.bsStyle))
|
|
{
|
|
CallOnStyleChanged(client, gA_Timers[client].iStyle, snapshot.bsStyle, false);
|
|
}
|
|
|
|
gA_Timers[client].bEnabled = snapshot.bTimerEnabled;
|
|
gA_Timers[client].bPaused = snapshot.bClientPaused;
|
|
gA_Timers[client].iJumps = snapshot.iJumps;
|
|
gA_Timers[client].iStyle = snapshot.bsStyle;
|
|
gA_Timers[client].iStrafes = snapshot.iStrafes;
|
|
gA_Timers[client].iTotalMeasures = snapshot.iTotalMeasures;
|
|
gA_Timers[client].iGoodGains = snapshot.iGoodGains;
|
|
gA_Timers[client].fTimer = snapshot.fCurrentTime;
|
|
gA_Timers[client].iSHSWCombination = snapshot.iSHSWCombination;
|
|
gA_Timers[client].iMeasuredJumps = snapshot.iMeasuredJumps;
|
|
gA_Timers[client].iPerfectJumps = snapshot.iPerfectJumps;
|
|
}
|
|
|
|
public int Native_LogMessage(Handle plugin, int numParams)
|
|
{
|
|
char sPlugin[32];
|
|
|
|
if(!GetPluginInfo(plugin, PlInfo_Name, sPlugin, 32))
|
|
{
|
|
GetPluginFilename(plugin, sPlugin, 32);
|
|
}
|
|
|
|
static int iWritten = 0;
|
|
|
|
char sBuffer[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;
|
|
}
|
|
|
|
int GetTimerStatus(int client)
|
|
{
|
|
if(!gA_Timers[client].bEnabled)
|
|
{
|
|
return view_as<int>(Timer_Stopped);
|
|
}
|
|
|
|
else if(gA_Timers[client].bPaused)
|
|
{
|
|
return view_as<int>(Timer_Paused);
|
|
}
|
|
|
|
return view_as<int>(Timer_Running);
|
|
}
|
|
|
|
void StartTimer(int client, int track)
|
|
{
|
|
if(!IsValidClient(client, true) || GetClientTeam(client) < 2 || IsFakeClient(client))
|
|
{
|
|
return;
|
|
}
|
|
|
|
float fSpeed[3];
|
|
GetEntPropVector(client, Prop_Data, "m_vecVelocity", fSpeed);
|
|
|
|
if(!gB_NoZAxisSpeed || gA_StyleSettings[gA_Timers[client].iStyle].bPrespeed || (fSpeed[2] == 0.0 && SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0)) <= 290.0))
|
|
{
|
|
Action result = Plugin_Continue;
|
|
Call_StartForward(gH_Forwards_Start);
|
|
Call_PushCell(client);
|
|
Call_PushCell(track);
|
|
Call_Finish(result);
|
|
|
|
if(result == Plugin_Continue)
|
|
{
|
|
gA_Timers[client].bPaused = false;
|
|
gA_Timers[client].iStrafes = 0;
|
|
gA_Timers[client].iJumps = 0;
|
|
gA_Timers[client].iTotalMeasures = 0;
|
|
gA_Timers[client].iGoodGains = 0;
|
|
gA_Timers[client].iTrack = track;
|
|
gA_Timers[client].bEnabled = true;
|
|
gA_Timers[client].iSHSWCombination = -1;
|
|
gA_Timers[client].fTimer = 0.0;
|
|
gA_Timers[client].bPracticeMode = false;
|
|
gA_Timers[client].iMeasuredJumps = 0;
|
|
gA_Timers[client].iPerfectJumps = 0;
|
|
|
|
SetEntityGravity(client, view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fGravityMultiplier));
|
|
SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fSpeedMultiplier));
|
|
}
|
|
|
|
else if(result == Plugin_Handled || result == Plugin_Stop)
|
|
{
|
|
gA_Timers[client].bEnabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void StopTimer(int client)
|
|
{
|
|
if(!IsValidClient(client) || IsFakeClient(client))
|
|
{
|
|
return;
|
|
}
|
|
|
|
gA_Timers[client].bEnabled = false;
|
|
gA_Timers[client].iJumps = 0;
|
|
gA_Timers[client].fTimer = 0.0;
|
|
gA_Timers[client].bPaused = false;
|
|
gA_Timers[client].iStrafes = 0;
|
|
gA_Timers[client].iTotalMeasures = 0;
|
|
gA_Timers[client].iGoodGains = 0;
|
|
}
|
|
|
|
void PauseTimer(int client)
|
|
{
|
|
if(!IsValidClient(client) || IsFakeClient(client))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Call_StartForward(gH_Forwards_OnPause);
|
|
Call_PushCell(client);
|
|
Call_PushCell(gA_Timers[client].iTrack);
|
|
Call_Finish();
|
|
|
|
gA_Timers[client].bPaused = true;
|
|
}
|
|
|
|
void ResumeTimer(int client)
|
|
{
|
|
if(!IsValidClient(client) || IsFakeClient(client))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Call_StartForward(gH_Forwards_OnResume);
|
|
Call_PushCell(client);
|
|
Call_PushCell(gA_Timers[client].iTrack);
|
|
Call_Finish();
|
|
|
|
gA_Timers[client].bPaused = false;
|
|
}
|
|
|
|
public void OnClientDisconnect(int client)
|
|
{
|
|
StopTimer(client);
|
|
}
|
|
|
|
public void OnClientCookiesCached(int client)
|
|
{
|
|
if(IsFakeClient(client) || !IsClientInGame(client))
|
|
{
|
|
return;
|
|
}
|
|
|
|
char sCookie[4];
|
|
|
|
if(gH_AutoBhopCookie != null)
|
|
{
|
|
GetClientCookie(client, gH_AutoBhopCookie, sCookie, 4);
|
|
}
|
|
|
|
gA_Timers[client].bAuto = (strlen(sCookie) > 0)? view_as<bool>(StringToInt(sCookie)):true;
|
|
|
|
int style = gI_DefaultStyle;
|
|
|
|
if(gB_StyleCookies && gH_StyleCookie != null)
|
|
{
|
|
GetClientCookie(client, gH_StyleCookie, sCookie, 4);
|
|
int newstyle = StringToInt(sCookie);
|
|
|
|
if(0 <= newstyle < gI_Styles)
|
|
{
|
|
style = newstyle;
|
|
}
|
|
}
|
|
|
|
if(Shavit_HasStyleAccess(client, style))
|
|
{
|
|
CallOnStyleChanged(client, gA_Timers[client].iStyle, style, false);
|
|
}
|
|
}
|
|
|
|
public void OnClientPutInServer(int client)
|
|
{
|
|
StopTimer(client);
|
|
|
|
if(!IsClientConnected(client) || IsFakeClient(client))
|
|
{
|
|
return;
|
|
}
|
|
|
|
gA_Timers[client].bAuto = true;
|
|
gA_Timers[client].bDoubleSteps = false;
|
|
gA_Timers[client].fStrafeWarning = 0.0;
|
|
gA_Timers[client].bPracticeMode = false;
|
|
gA_Timers[client].iSHSWCombination = -1;
|
|
gA_Timers[client].iTrack = 0;
|
|
gA_Timers[client].iStyle = 0;
|
|
strcopy(gS_DeleteMap[client], 160, "");
|
|
|
|
if(AreClientCookiesCached(client))
|
|
{
|
|
OnClientCookiesCached(client);
|
|
}
|
|
|
|
// not adding style permission check here for obvious reasons
|
|
else
|
|
{
|
|
CallOnStyleChanged(client, 0, gI_DefaultStyle, false);
|
|
}
|
|
|
|
if(gH_SQL == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SDKHook(client, SDKHook_PreThinkPost, PreThinkPost);
|
|
|
|
char sAuthID3[32];
|
|
|
|
if(!GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
|
|
{
|
|
KickClient(client, "%T", "VerificationFailed", client);
|
|
|
|
return;
|
|
}
|
|
|
|
char sName[MAX_NAME_LENGTH_SQL];
|
|
GetClientName(client, sName, MAX_NAME_LENGTH_SQL);
|
|
ReplaceString(sName, MAX_NAME_LENGTH_SQL, "#", "?"); // to avoid this: https://user-images.githubusercontent.com/3672466/28637962-0d324952-724c-11e7-8b27-15ff021f0a59.png
|
|
|
|
int iLength = ((strlen(sName) * 2) + 1);
|
|
char[] sEscapedName = new char[iLength];
|
|
gH_SQL.Escape(sName, sEscapedName, iLength);
|
|
|
|
char sIP[64];
|
|
GetClientIP(client, sIP, 64);
|
|
|
|
char sCountry[128];
|
|
|
|
if(!GeoipCountry(sIP, sCountry, 128))
|
|
{
|
|
strcopy(sCountry, 128, "Local Area Network");
|
|
}
|
|
|
|
int iTime = GetTime();
|
|
|
|
char sQuery[512];
|
|
|
|
if(gB_MySQL)
|
|
{
|
|
FormatEx(sQuery, 512, "INSERT INTO %susers (auth, name, country, ip, lastlogin) VALUES ('%s', '%s', '%s', '%s', %d) ON DUPLICATE KEY UPDATE name = '%s', country = '%s', ip = '%s', lastlogin = %d;", gS_MySQLPrefix, sAuthID3, sEscapedName, sCountry, sIP, iTime, sEscapedName, sCountry, sIP, iTime);
|
|
}
|
|
|
|
else
|
|
{
|
|
FormatEx(sQuery, 512, "REPLACE INTO %susers (auth, name, country, ip, lastlogin) VALUES ('%s', '%s', '%s', '%s', %d);", gS_MySQLPrefix, sAuthID3, sEscapedName, sCountry, sIP, iTime);
|
|
}
|
|
|
|
gH_SQL.Query(SQL_InsertUser_Callback, sQuery, GetClientSerial(client));
|
|
}
|
|
|
|
public void SQL_InsertUser_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
int client = GetClientFromSerial(data);
|
|
|
|
if(client == 0)
|
|
{
|
|
LogError("Timer error! Failed to insert a disconnected player's data to the table. Reason: %s", error);
|
|
}
|
|
|
|
else
|
|
{
|
|
LogError("Timer error! Failed to insert \"%N\"'s data to the table. Reason: %s", client, error);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool LoadStyles()
|
|
{
|
|
char sPath[PLATFORM_MAX_PATH];
|
|
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-styles.cfg");
|
|
|
|
KeyValues kv = new KeyValues("shavit-styles");
|
|
|
|
if(!kv.ImportFromFile(sPath) || !kv.GotoFirstSubKey())
|
|
{
|
|
delete kv;
|
|
|
|
return false;
|
|
}
|
|
|
|
int i = 0;
|
|
|
|
do
|
|
{
|
|
kv.GetString("name", gS_StyleStrings[i].sStyleName, sizeof(stylestrings_t::sStyleName), "<MISSING STYLE NAME>");
|
|
kv.GetString("shortname", gS_StyleStrings[i].sShortName, sizeof(stylestrings_t::sShortName), "<MISSING SHORT STYLE NAME>");
|
|
kv.GetString("htmlcolor", gS_StyleStrings[i].sHTMLColor, sizeof(stylestrings_t::sHTMLColor), "<MISSING STYLE HTML COLOR>");
|
|
kv.GetString("command", gS_StyleStrings[i].sChangeCommand, sizeof(stylestrings_t::sChangeCommand), "");
|
|
kv.GetString("clantag", gS_StyleStrings[i].sClanTag, sizeof(stylestrings_t::sClanTag), "<MISSING STYLE CLAN TAG>");
|
|
kv.GetString("specialstring", gS_StyleStrings[i].sSpecialString, sizeof(stylestrings_t::sSpecialString), "");
|
|
kv.GetString("permission", gS_StyleStrings[i].sStylePermission, sizeof(stylestrings_t::sStylePermission), "");
|
|
|
|
gA_StyleSettings[i].bAutobhop = view_as<bool>(kv.GetNum("autobhop", 1));
|
|
gA_StyleSettings[i].bEasybhop = view_as<bool>(kv.GetNum("easybhop", 1));
|
|
gA_StyleSettings[i].bPrespeed = view_as<bool>(kv.GetNum("prespeed", 0));
|
|
gA_StyleSettings[i].fVelocityLimit = kv.GetFloat("velocity_limit", 0.0);
|
|
gA_StyleSettings[i].fAiraccelerate = kv.GetFloat("airaccelerate", 1000.0);
|
|
gA_StyleSettings[i].bEnableBunnyhopping = view_as<bool>(kv.GetNum("bunnyhopping", 1));
|
|
gA_StyleSettings[i].fRunspeed = kv.GetFloat("runspeed", 260.00);
|
|
gA_StyleSettings[i].fGravityMultiplier = kv.GetFloat("gravity", 1.0);
|
|
gA_StyleSettings[i].fSpeedMultiplier = kv.GetFloat("speed", 1.0);
|
|
gA_StyleSettings[i].fTimescale = view_as<bool>(kv.GetNum("halftime", 0))? 0.5:kv.GetFloat("timescale", 1.0); // backwards compat for old halftime settig
|
|
gA_StyleSettings[i].fVelocity = kv.GetFloat("velocity", 1.0);
|
|
gA_StyleSettings[i].fBonusVelocity = kv.GetFloat("bonus_velocity", 0.0);
|
|
gA_StyleSettings[i].fMinVelocity = kv.GetFloat("min_velocity", 0.0);
|
|
gA_StyleSettings[i].bBlockW = view_as<bool>(kv.GetNum("block_w", 0));
|
|
gA_StyleSettings[i].bBlockA = view_as<bool>(kv.GetNum("block_a", 0));
|
|
gA_StyleSettings[i].bBlockS = view_as<bool>(kv.GetNum("block_s", 0));
|
|
gA_StyleSettings[i].bBlockD = view_as<bool>(kv.GetNum("block_d", 0));
|
|
gA_StyleSettings[i].bBlockUse = view_as<bool>(kv.GetNum("block_use", 0));
|
|
gA_StyleSettings[i].iForceHSW = kv.GetNum("force_hsw", 0);
|
|
gA_StyleSettings[i].iBlockPLeft = kv.GetNum("block_pleft", 0);
|
|
gA_StyleSettings[i].iBlockPRight = kv.GetNum("block_pright", 0);
|
|
gA_StyleSettings[i].iBlockPStrafe = kv.GetNum("block_pstrafe", 0);
|
|
gA_StyleSettings[i].bUnranked = view_as<bool>(kv.GetNum("unranked", 0));
|
|
gA_StyleSettings[i].bNoReplay = view_as<bool>(kv.GetNum("noreplay", 0));
|
|
gA_StyleSettings[i].bSync = view_as<bool>(kv.GetNum("sync", 1));
|
|
gA_StyleSettings[i].bStrafeCountW = view_as<bool>(kv.GetNum("strafe_count_w", false));
|
|
gA_StyleSettings[i].bStrafeCountA = view_as<bool>(kv.GetNum("strafe_count_a", true));
|
|
gA_StyleSettings[i].bStrafeCountS = view_as<bool>(kv.GetNum("strafe_count_s", false));
|
|
gA_StyleSettings[i].bStrafeCountD = view_as<bool>(kv.GetNum("strafe_count_d", true));
|
|
gA_StyleSettings[i].fRankingMultiplier = kv.GetFloat("rankingmultiplier", 1.00);
|
|
gA_StyleSettings[i].iSpecial = kv.GetNum("special", 0);
|
|
|
|
if(!gB_Registered && strlen(gS_StyleStrings[i].sChangeCommand) > 0)
|
|
{
|
|
char sStyleCommands[32][32];
|
|
int iCommands = ExplodeString(gS_StyleStrings[i].sChangeCommand, ";", sStyleCommands, 32, 32, false);
|
|
|
|
char sDescription[128];
|
|
FormatEx(sDescription, 128, "Change style to %s.", gS_StyleStrings[i].sStyleName);
|
|
|
|
for(int x = 0; x < iCommands; x++)
|
|
{
|
|
TrimString(sStyleCommands[x]);
|
|
StripQuotes(sStyleCommands[x]);
|
|
|
|
char sCommand[32];
|
|
FormatEx(sCommand, 32, "sm_%s", sStyleCommands[x]);
|
|
|
|
gSM_StyleCommands.SetValue(sCommand, i);
|
|
|
|
RegConsoleCmd(sCommand, Command_StyleChange, sDescription);
|
|
}
|
|
}
|
|
|
|
if(StrContains(gS_StyleStrings[i].sStylePermission, ";") != -1)
|
|
{
|
|
char sText[2][32];
|
|
int iCount = ExplodeString(gS_StyleStrings[i].sStylePermission, ";", sText, 2, 32);
|
|
|
|
AdminFlag flag = Admin_Reservation;
|
|
|
|
if(FindFlagByChar(sText[0][0], flag))
|
|
{
|
|
gI_StyleFlag[i] = FlagToBit(flag);
|
|
}
|
|
|
|
strcopy(gS_StyleOverride[i], 32, (iCount >= 2)? sText[1]:"");
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
while(kv.GotoNextKey());
|
|
|
|
delete kv;
|
|
|
|
gI_Styles = i;
|
|
gB_Registered = true;
|
|
|
|
Call_StartForward(gH_Forwards_OnStyleConfigLoaded);
|
|
Call_PushCell(gI_Styles);
|
|
Call_Finish();
|
|
|
|
return true;
|
|
}
|
|
|
|
public Action Command_StyleChange(int client, int args)
|
|
{
|
|
char sCommand[128];
|
|
GetCmdArg(0, sCommand, 128);
|
|
|
|
int style = 0;
|
|
|
|
if(gSM_StyleCommands.GetValue(sCommand, style))
|
|
{
|
|
ChangeClientStyle(client, style, true);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
void ReplaceColors(char[] string, int size)
|
|
{
|
|
for(int x = 0; x < sizeof(gS_GlobalColorNames); x++)
|
|
{
|
|
ReplaceString(string, size, gS_GlobalColorNames[x], gS_GlobalColors[x]);
|
|
}
|
|
|
|
for(int x = 0; x < sizeof(gS_CSGOColorNames); x++)
|
|
{
|
|
ReplaceString(string, size, gS_CSGOColorNames[x], gS_CSGOColors[x]);
|
|
}
|
|
|
|
ReplaceString(string, size, "{RGB}", "\x07");
|
|
ReplaceString(string, size, "{RGBA}", "\x08");
|
|
}
|
|
|
|
bool LoadMessages()
|
|
{
|
|
char sPath[PLATFORM_MAX_PATH];
|
|
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-messages.cfg");
|
|
|
|
KeyValues kv = new KeyValues("shavit-messages");
|
|
|
|
if(!kv.ImportFromFile(sPath))
|
|
{
|
|
delete kv;
|
|
|
|
return false;
|
|
}
|
|
|
|
kv.JumpToKey((IsSource2013(gEV_Type))? "CS:S":"CS:GO");
|
|
|
|
kv.GetString("prefix", gS_ChatStrings.sPrefix, sizeof(chatstrings_t::sPrefix), "\x075e70d0[Timer]");
|
|
kv.GetString("text", gS_ChatStrings.sText, sizeof(chatstrings_t::sText), "\x07ffffff");
|
|
kv.GetString("warning", gS_ChatStrings.sWarning, sizeof(chatstrings_t::sWarning), "\x07af2a22");
|
|
kv.GetString("variable", gS_ChatStrings.sVariable, sizeof(chatstrings_t::sVariable), "\x077fd772");
|
|
kv.GetString("variable2", gS_ChatStrings.sVariable2, sizeof(chatstrings_t::sVariable2), "\x07276f5c");
|
|
kv.GetString("style", gS_ChatStrings.sStyle, sizeof(chatstrings_t::sStyle), "\x07db88c2");
|
|
|
|
delete kv;
|
|
|
|
ReplaceColors(gS_ChatStrings.sPrefix, sizeof(chatstrings_t::sPrefix));
|
|
ReplaceColors(gS_ChatStrings.sText, sizeof(chatstrings_t::sText));
|
|
ReplaceColors(gS_ChatStrings.sWarning, sizeof(chatstrings_t::sWarning));
|
|
ReplaceColors(gS_ChatStrings.sVariable, sizeof(chatstrings_t::sVariable));
|
|
ReplaceColors(gS_ChatStrings.sVariable2, sizeof(chatstrings_t::sVariable2));
|
|
ReplaceColors(gS_ChatStrings.sStyle, sizeof(chatstrings_t::sStyle));
|
|
|
|
Call_StartForward(gH_Forwards_OnChatConfigLoaded);
|
|
Call_Finish();
|
|
|
|
return true;
|
|
}
|
|
|
|
void SQL_SetPrefix()
|
|
{
|
|
char sFile[PLATFORM_MAX_PATH];
|
|
BuildPath(Path_SM, sFile, PLATFORM_MAX_PATH, "configs/shavit-prefix.txt");
|
|
|
|
File fFile = OpenFile(sFile, "r");
|
|
|
|
if(fFile == null)
|
|
{
|
|
SetFailState("Cannot open \"configs/shavit-prefix.txt\". Make sure this file exists and that the server has read permissions to it.");
|
|
}
|
|
|
|
char sLine[PLATFORM_MAX_PATH*2];
|
|
|
|
while(fFile.ReadLine(sLine, PLATFORM_MAX_PATH*2))
|
|
{
|
|
TrimString(sLine);
|
|
strcopy(gS_MySQLPrefix, 32, sLine);
|
|
|
|
break;
|
|
}
|
|
|
|
delete fFile;
|
|
}
|
|
|
|
void SQL_DBConnect()
|
|
{
|
|
if(gH_SQL != null)
|
|
{
|
|
delete gH_SQL;
|
|
}
|
|
|
|
char sError[255];
|
|
|
|
if(SQL_CheckConfig("shavit")) // can't be asynced as we have modules that require this database connection instantly
|
|
{
|
|
gH_SQL = SQL_Connect("shavit", true, sError, 255);
|
|
|
|
if(gH_SQL == null)
|
|
{
|
|
SetFailState("Timer startup failed. Reason: %s", sError);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
gH_SQL = SQLite_UseDatabase("shavit", sError, 255);
|
|
}
|
|
|
|
// support unicode names
|
|
if(!gH_SQL.SetCharset("utf8mb4"))
|
|
{
|
|
gH_SQL.SetCharset("utf8");
|
|
}
|
|
|
|
char sDriver[8];
|
|
gH_SQL.Driver.GetIdentifier(sDriver, 8);
|
|
gB_MySQL = StrEqual(sDriver, "mysql", false);
|
|
|
|
char sQuery[512];
|
|
|
|
if(gB_MySQL)
|
|
{
|
|
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%susers` (`auth` CHAR(32) NOT NULL, `name` VARCHAR(32) COLLATE 'utf8mb4_unicode_ci', `country` CHAR(32), `ip` CHAR(64), `lastlogin` INT NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), INDEX `points` (`points`)) ENGINE=INNODB;", gS_MySQLPrefix);
|
|
}
|
|
|
|
else
|
|
{
|
|
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%susers` (`auth` CHAR(32) NOT NULL PRIMARY KEY, `name` VARCHAR(32), `country` CHAR(32), `ip` CHAR(64), `lastlogin` INTEGER NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0);", gS_MySQLPrefix);
|
|
}
|
|
|
|
// CREATE TABLE IF NOT EXISTS
|
|
gH_SQL.Query(SQL_CreateTable_Callback, sQuery);
|
|
}
|
|
|
|
public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer error! Users' data table creation failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
char sQuery[192];
|
|
FormatEx(sQuery, 192, "SELECT lastlogin FROM %susers LIMIT 1;", gS_MySQLPrefix);
|
|
gH_SQL.Query(SQL_TableMigration1_Callback, sQuery, 0, DBPrio_High);
|
|
|
|
FormatEx(sQuery, 192, "SELECT points FROM %susers LIMIT 1;", gS_MySQLPrefix);
|
|
gH_SQL.Query(SQL_TableMigration2_Callback, sQuery, 0, DBPrio_High);
|
|
|
|
char sTables[][] =
|
|
{
|
|
"maptiers",
|
|
"mapzones",
|
|
"playertimes"
|
|
};
|
|
|
|
for(int i = 0; i < sizeof(sTables); i++)
|
|
{
|
|
DataPack dp = new DataPack();
|
|
dp.WriteString(sTables[i]);
|
|
|
|
FormatEx(sQuery, 192, "SELECT map FROM %s%s WHERE map LIKE 'workshop%%' GROUP BY map;", gS_MySQLPrefix, sTables[i]);
|
|
gH_SQL.Query(SQL_TableMigration3_Callback, sQuery, dp, DBPrio_Low);
|
|
}
|
|
|
|
Call_StartForward(gH_Forwards_OnDatabaseLoaded);
|
|
Call_Finish();
|
|
}
|
|
|
|
public void SQL_TableMigration1_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
char sQuery[128];
|
|
FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD %s;", gS_MySQLPrefix, (gB_MySQL)? "(`lastlogin` INT NOT NULL DEFAULT -1)":"COLUMN `lastlogin` INTEGER NOT NULL DEFAULT -1");
|
|
gH_SQL.Query(SQL_AlterTable1_Callback, sQuery);
|
|
}
|
|
}
|
|
|
|
public void SQL_AlterTable1_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer error! Table alteration 1 (core) failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void SQL_TableMigration2_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
char sQuery[128];
|
|
FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD %s;", gS_MySQLPrefix, (gB_MySQL)? "(`points` FLOAT NOT NULL DEFAULT 0)":"COLUMN `points` FLOAT NOT NULL DEFAULT 0");
|
|
gH_SQL.Query(SQL_AlterTable2_Callback, sQuery);
|
|
}
|
|
}
|
|
|
|
public void SQL_AlterTable2_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer error! Table alteration 2 (core) failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void SQL_TableMigration3_Callback(Database db, DBResultSet results, const char[] error, DataPack data)
|
|
{
|
|
char sTable[16];
|
|
|
|
data.Reset();
|
|
data.ReadString(sTable, 16);
|
|
delete data;
|
|
|
|
if(results == null || results.RowCount == 0)
|
|
{
|
|
// no error logging here because not everyone runs the rankings/wr modules
|
|
return;
|
|
}
|
|
|
|
while(results.FetchRow())
|
|
{
|
|
char sMap[160];
|
|
results.FetchString(0, sMap, 160);
|
|
|
|
char sDisplayMap[160];
|
|
GetMapDisplayName(sMap, sDisplayMap, 160);
|
|
|
|
char sQuery[256];
|
|
FormatEx(sQuery, 256, "UPDATE %s%s SET map = '%s' WHERE map = '%s';", gS_MySQLPrefix, sTable, sDisplayMap, sMap);
|
|
gH_SQL.Query(SQL_AlterTable3_Callback, sQuery, 0, DBPrio_High);
|
|
}
|
|
}
|
|
|
|
public void SQL_AlterTable3_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer error! Table alteration 3 (core) failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void PreThinkPost(int client)
|
|
{
|
|
if(IsPlayerAlive(client))
|
|
{
|
|
sv_airaccelerate.FloatValue = view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fAiraccelerate);
|
|
|
|
if(sv_enablebunnyhopping != null)
|
|
{
|
|
sv_enablebunnyhopping.BoolValue = view_as<bool>(gA_StyleSettings[gA_Timers[client].iStyle].bEnableBunnyhopping);
|
|
}
|
|
|
|
MoveType mtMoveType = GetEntityMoveType(client);
|
|
|
|
if(view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fGravityMultiplier) != 1.0 &&
|
|
(mtMoveType == MOVETYPE_WALK || mtMoveType == MOVETYPE_ISOMETRIC) &&
|
|
(gA_Timers[client].iMoveType == MOVETYPE_LADDER || GetEntityGravity(client) == 1.0))
|
|
{
|
|
SetEntityGravity(client, view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fGravityMultiplier));
|
|
}
|
|
|
|
gA_Timers[client].iMoveType = mtMoveType;
|
|
}
|
|
}
|
|
|
|
public void OnGameFrame()
|
|
{
|
|
float frametime = GetGameFrameTime();
|
|
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(gA_Timers[i].bPaused || !gA_Timers[i].bEnabled)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
float time = frametime * view_as<float>(gA_StyleSettings[gA_Timers[i].iStyle].fTimescale);
|
|
|
|
timer_snapshot_t snapshot;
|
|
snapshot.bTimerEnabled = gA_Timers[i].bEnabled;
|
|
snapshot.bClientPaused = gA_Timers[i].bPaused;
|
|
snapshot.iJumps = gA_Timers[i].iJumps;
|
|
snapshot.bsStyle = gA_Timers[i].iStyle;
|
|
snapshot.iStrafes = gA_Timers[i].iStrafes;
|
|
snapshot.iTotalMeasures = gA_Timers[i].iTotalMeasures;
|
|
snapshot.iGoodGains = gA_Timers[i].iGoodGains;
|
|
snapshot.fServerTime = GetEngineTime();
|
|
snapshot.fCurrentTime = gA_Timers[i].fTimer;
|
|
snapshot.iSHSWCombination = gA_Timers[i].iSHSWCombination;
|
|
snapshot.iTimerTrack = gA_Timers[i].iTrack;
|
|
|
|
Call_StartForward(gH_Forwards_OnTimerIncrement);
|
|
Call_PushCell(i);
|
|
Call_PushArray(snapshot, sizeof(timer_snapshot_t));
|
|
Call_PushCellRef(time);
|
|
Call_PushArray(gA_StyleSettings[gA_Timers[i].iStyle], sizeof(stylesettings_t));
|
|
Call_Finish();
|
|
|
|
gA_Timers[i].fTimer += time;
|
|
|
|
Call_StartForward(gH_Forwards_OnTimerIncrementPost);
|
|
Call_PushCell(i);
|
|
Call_PushCell(time);
|
|
Call_PushArray(gA_StyleSettings[gA_Timers[i].iStyle], sizeof(stylesettings_t));
|
|
Call_Finish();
|
|
}
|
|
}
|
|
|
|
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2])
|
|
{
|
|
if(!IsPlayerAlive(client) || IsFakeClient(client))
|
|
{
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
int flags = GetEntityFlags(client);
|
|
|
|
if(gA_Timers[client].bPaused)
|
|
{
|
|
buttons = 0;
|
|
vel = view_as<float>({0.0, 0.0, 0.0});
|
|
|
|
SetEntityFlags(client, (flags | FL_ATCONTROLS));
|
|
|
|
return Plugin_Changed;
|
|
}
|
|
|
|
SetEntityFlags(client, (flags & ~FL_ATCONTROLS));
|
|
|
|
Action result = Plugin_Continue;
|
|
Call_StartForward(gH_Forwards_OnUserCmdPre);
|
|
Call_PushCell(client);
|
|
Call_PushCellRef(buttons);
|
|
Call_PushCellRef(impulse);
|
|
Call_PushArrayEx(vel, 3, SM_PARAM_COPYBACK);
|
|
Call_PushArrayEx(angles, 3, SM_PARAM_COPYBACK);
|
|
Call_PushCell(GetTimerStatus(client));
|
|
Call_PushCell(gA_Timers[client].iTrack);
|
|
Call_PushCell(gA_Timers[client].iStyle);
|
|
Call_PushArray(gA_StyleSettings[gA_Timers[client].iStyle], sizeof(stylesettings_t));
|
|
Call_PushArrayEx(mouse, 2, SM_PARAM_COPYBACK);
|
|
Call_Finish(result);
|
|
|
|
if(result != Plugin_Continue && result != Plugin_Changed)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
int iGroundEntity = GetEntPropEnt(client, Prop_Send, "m_hGroundEntity");
|
|
bool bInStart = Shavit_InsideZone(client, Zone_Start, gA_Timers[client].iTrack);
|
|
|
|
if(gA_Timers[client].bEnabled && !gA_Timers[client].bPaused)
|
|
{
|
|
// +left/right block
|
|
if(!gB_Zones || (!bInStart && ((gA_StyleSettings[gA_Timers[client].iStyle].iBlockPLeft > 0 &&
|
|
(buttons & IN_LEFT) > 0) || (gA_StyleSettings[gA_Timers[client].iStyle].iBlockPRight > 0 && (buttons & IN_RIGHT) > 0))))
|
|
{
|
|
vel[0] = 0.0;
|
|
vel[1] = 0.0;
|
|
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].iBlockPRight >= 2)
|
|
{
|
|
char sCheatDetected[64];
|
|
FormatEx(sCheatDetected, 64, "%T", "LeftRightCheat", client);
|
|
StopTimer_Cheat(client, sCheatDetected);
|
|
}
|
|
}
|
|
|
|
// +strafe block
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].iBlockPStrafe > 0 &&
|
|
((vel[0] > 0.0 && (buttons & IN_FORWARD) == 0) || (vel[0] < 0.0 && (buttons & IN_BACK) == 0) ||
|
|
(vel[1] > 0.0 && (buttons & IN_MOVERIGHT) == 0) || (vel[1] < 0.0 && (buttons & IN_MOVELEFT) == 0)))
|
|
{
|
|
if(gA_Timers[client].fStrafeWarning < gA_Timers[client].fTimer)
|
|
{
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].iBlockPStrafe >= 2)
|
|
{
|
|
char sCheatDetected[64];
|
|
FormatEx(sCheatDetected, 64, "%T", "Inconsistencies", client);
|
|
StopTimer_Cheat(client, sCheatDetected);
|
|
}
|
|
|
|
vel[0] = 0.0;
|
|
vel[1] = 0.0;
|
|
|
|
return Plugin_Changed;
|
|
}
|
|
|
|
gA_Timers[client].fStrafeWarning = gA_Timers[client].fTimer + 0.3;
|
|
}
|
|
}
|
|
|
|
#if defined DEBUG
|
|
static int cycle = 0;
|
|
|
|
if(++cycle % 50 == 0)
|
|
{
|
|
Shavit_StopChatSound();
|
|
Shavit_PrintToChat(client, "vel[0]: %.01f | vel[1]: %.01f", vel[0], vel[1]);
|
|
}
|
|
#endif
|
|
|
|
MoveType mtMoveType = GetEntityMoveType(client);
|
|
|
|
// key blocking
|
|
if(mtMoveType != MOVETYPE_NOCLIP && mtMoveType != MOVETYPE_LADDER && !Shavit_InsideZone(client, Zone_Freestyle, -1))
|
|
{
|
|
// block E
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bBlockUse && (buttons & IN_USE) > 0)
|
|
{
|
|
buttons &= ~IN_USE;
|
|
}
|
|
|
|
if(iGroundEntity == -1)
|
|
{
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bBlockW && ((buttons & IN_FORWARD) > 0 || vel[0] > 0.0))
|
|
{
|
|
vel[0] = 0.0;
|
|
buttons &= ~IN_FORWARD;
|
|
}
|
|
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bBlockA && ((buttons & IN_MOVELEFT) > 0 || vel[1] < 0.0))
|
|
{
|
|
vel[1] = 0.0;
|
|
buttons &= ~IN_MOVELEFT;
|
|
}
|
|
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bBlockS && ((buttons & IN_BACK) > 0 || vel[0] < 0.0))
|
|
{
|
|
vel[0] = 0.0;
|
|
buttons &= ~IN_BACK;
|
|
}
|
|
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bBlockD && ((buttons & IN_MOVERIGHT) > 0 || vel[1] > 0.0))
|
|
{
|
|
vel[1] = 0.0;
|
|
buttons &= ~IN_MOVERIGHT;
|
|
}
|
|
|
|
// HSW
|
|
// Theory about blocking non-HSW strafes while playing HSW:
|
|
// Block S and W without A or D.
|
|
// Block A and D without S or W.
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].iForceHSW > 0)
|
|
{
|
|
bool bSHSW = (gA_StyleSettings[gA_Timers[client].iStyle].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] >= 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)
|
|
{
|
|
if((bForward && bMoveLeft) || (bBack && bMoveRight))
|
|
{
|
|
iCombination = 0;
|
|
}
|
|
|
|
else if((bForward && bMoveRight || bBack && bMoveLeft))
|
|
{
|
|
iCombination = 1;
|
|
}
|
|
|
|
// int gI_SHSW_FirstCombination[MAXPLAYERS+1]; // 0 - W/A S/D | 1 - W/D S/A
|
|
if(gA_Timers[client].iSHSWCombination == -1 && iCombination != -1)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", (iCombination == 0)? "SHSWCombination0":"SHSWCombination1", client, gS_ChatStrings.sVariable, gS_ChatStrings.sText);
|
|
gA_Timers[client].iSHSWCombination = iCombination;
|
|
}
|
|
|
|
bool bStop = false;
|
|
|
|
// W/A S/D
|
|
if((gA_Timers[client].iSHSWCombination == 0 && iCombination != 0) ||
|
|
// W/D S/A
|
|
(gA_Timers[client].iSHSWCombination == 1 && iCombination != 1) ||
|
|
// no valid combination & no valid input
|
|
(gA_Timers[client].iSHSWCombination == -1 && iCombination == -1))
|
|
{
|
|
bStop = true;
|
|
}
|
|
|
|
if(bStop)
|
|
{
|
|
vel[0] = 0.0;
|
|
vel[1] = 0.0;
|
|
|
|
buttons &= ~IN_FORWARD;
|
|
buttons &= ~IN_MOVELEFT;
|
|
buttons &= ~IN_MOVERIGHT;
|
|
buttons &= ~IN_BACK;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
if((bForward || bBack) && !(bMoveLeft || bMoveRight))
|
|
{
|
|
vel[0] = 0.0;
|
|
|
|
buttons &= ~IN_FORWARD;
|
|
buttons &= ~IN_BACK;
|
|
}
|
|
|
|
if((bMoveLeft || bMoveRight) && !(bForward || bBack))
|
|
{
|
|
vel[1] = 0.0;
|
|
|
|
buttons &= ~IN_MOVELEFT;
|
|
buttons &= ~IN_MOVERIGHT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bStrafeCountW && !gA_StyleSettings[gA_Timers[client].iStyle].bBlockW &&
|
|
(gA_Timers[client].iLastButtons & IN_FORWARD) == 0 && (buttons & IN_FORWARD) > 0)
|
|
{
|
|
gA_Timers[client].iStrafes++;
|
|
}
|
|
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bStrafeCountA && !gA_StyleSettings[gA_Timers[client].iStyle].bBlockA && (gA_Timers[client].iLastButtons & IN_MOVELEFT) == 0 &&
|
|
(buttons & IN_MOVELEFT) > 0 && (gA_StyleSettings[gA_Timers[client].iStyle].iForceHSW > 0 || ((buttons & IN_FORWARD) == 0 && (buttons & IN_BACK) == 0)))
|
|
{
|
|
gA_Timers[client].iStrafes++;
|
|
}
|
|
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bStrafeCountS && !gA_StyleSettings[gA_Timers[client].iStyle].bBlockS &&
|
|
(gA_Timers[client].iLastButtons & IN_BACK) == 0 && (buttons & IN_BACK) > 0)
|
|
{
|
|
gA_Timers[client].iStrafes++;
|
|
}
|
|
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bStrafeCountD && !gA_StyleSettings[gA_Timers[client].iStyle].bBlockD && (gA_Timers[client].iLastButtons & IN_MOVERIGHT) == 0 &&
|
|
(buttons & IN_MOVERIGHT) > 0 && (gA_StyleSettings[gA_Timers[client].iStyle].iForceHSW > 0 || ((buttons & IN_FORWARD) == 0 && (buttons & IN_BACK) == 0)))
|
|
{
|
|
gA_Timers[client].iStrafes++;
|
|
}
|
|
|
|
bool bInWater = (GetEntProp(client, Prop_Send, "m_nWaterLevel") >= 2);
|
|
|
|
// enable duck-jumping/bhop in tf2
|
|
if(gEV_Type == Engine_TF2 && gA_StyleSettings[gA_Timers[client].iStyle].bEnableBunnyhopping && (buttons & IN_JUMP) > 0 && iGroundEntity != -1)
|
|
{
|
|
float fSpeed[3];
|
|
GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fSpeed);
|
|
|
|
fSpeed[2] = 271.0;
|
|
SetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fSpeed);
|
|
}
|
|
|
|
int iPButtons = buttons;
|
|
|
|
if(gA_StyleSettings[gA_Timers[client].iStyle].bAutobhop && gA_Timers[client].bAuto && (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));
|
|
iPButtons &= ~IN_JUMP;
|
|
}
|
|
|
|
else if(gA_Timers[client].bDoubleSteps && (buttons & IN_JUMP) == 0)
|
|
{
|
|
iPButtons = buttons |= IN_JUMP;
|
|
}
|
|
|
|
// perf jump measuring
|
|
if(!bInWater && mtMoveType == MOVETYPE_WALK && iGroundEntity != -1)
|
|
{
|
|
gA_Timers[client].iGroundTicks++;
|
|
|
|
if((((gA_Timers[client].iLastButtons & IN_JUMP) == 0 && (iPButtons & IN_JUMP) > 0) || iPButtons != buttons) &&
|
|
1 <= gA_Timers[client].iGroundTicks <= 8)
|
|
{
|
|
gA_Timers[client].iMeasuredJumps++;
|
|
|
|
if(gA_Timers[client].iGroundTicks == 1)
|
|
{
|
|
gA_Timers[client].iPerfectJumps++;
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
gA_Timers[client].iGroundTicks = 0;
|
|
}
|
|
|
|
if(bInStart && gB_BlockPreJump && !gA_StyleSettings[gA_Timers[client].iStyle].bPrespeed && (vel[2] > 0 || (buttons & IN_JUMP) > 0))
|
|
{
|
|
vel[2] = 0.0;
|
|
buttons &= ~IN_JUMP;
|
|
}
|
|
|
|
// velocity limit
|
|
if(iGroundEntity != -1 && view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fVelocityLimit > 0.0) &&
|
|
(!gB_Zones || !Shavit_InsideZone(client, Zone_NoVelLimit, -1)))
|
|
{
|
|
float fSpeed[3];
|
|
GetEntPropVector(client, Prop_Data, "m_vecVelocity", fSpeed);
|
|
|
|
float fSpeed_New = (SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0)));
|
|
|
|
if(fSpeed_New > 0.0)
|
|
{
|
|
float fScale = view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fVelocityLimit) / fSpeed_New;
|
|
|
|
if(fScale < 1.0)
|
|
{
|
|
ScaleVector(fSpeed, fScale);
|
|
TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, fSpeed); // maybe change this to SetEntPropVector some time?
|
|
}
|
|
}
|
|
}
|
|
|
|
float fAngle = (angles[1] - gA_Timers[client].fLastAngle);
|
|
|
|
while(fAngle > 180.0)
|
|
{
|
|
fAngle -= 360.0;
|
|
}
|
|
|
|
while(fAngle < -180.0)
|
|
{
|
|
fAngle += 360.0;
|
|
}
|
|
|
|
if(iGroundEntity == -1 && (GetEntityFlags(client) & FL_INWATER) == 0 && fAngle != 0.0)
|
|
{
|
|
float fAbsVelocity[3];
|
|
GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fAbsVelocity);
|
|
|
|
if(SquareRoot(Pow(fAbsVelocity[0], 2.0) + Pow(fAbsVelocity[1], 2.0)) > 0.0)
|
|
{
|
|
float fTempAngle = angles[1];
|
|
|
|
float fAngles[3];
|
|
GetVectorAngles(fAbsVelocity, fAngles);
|
|
|
|
if(fTempAngle < 0.0)
|
|
{
|
|
fTempAngle += 360.0;
|
|
}
|
|
|
|
float fDirectionAngle = (fTempAngle - fAngles[1]);
|
|
|
|
if(fDirectionAngle < 0.0)
|
|
{
|
|
fDirectionAngle = -fDirectionAngle;
|
|
}
|
|
|
|
if(fDirectionAngle < 22.5 || fDirectionAngle > 337.5)
|
|
{
|
|
gA_Timers[client].iTotalMeasures++;
|
|
|
|
if((fAngle > 0.0 && vel[1] <= -100.0) || (fAngle < 0.0 && vel[1] >= 100.0))
|
|
{
|
|
gA_Timers[client].iGoodGains++;
|
|
}
|
|
}
|
|
|
|
else if((fDirectionAngle > 67.5 && fDirectionAngle < 112.5) || (fDirectionAngle > 247.5 && fDirectionAngle < 292.5))
|
|
{
|
|
gA_Timers[client].iTotalMeasures++;
|
|
|
|
if(vel[0] <= -100.0 || vel[0] >= 100.0)
|
|
{
|
|
gA_Timers[client].iGoodGains++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gA_Timers[client].iLastButtons = iPButtons;
|
|
gA_Timers[client].fLastAngle = angles[1];
|
|
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
void StopTimer_Cheat(int client, const char[] message)
|
|
{
|
|
Shavit_StopTimer(client);
|
|
Shavit_PrintToChat(client, "%T", "CheatTimerStop", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText, message);
|
|
}
|
|
|
|
void UpdateStyleSettings(int client)
|
|
{
|
|
if(sv_autobunnyhopping != null)
|
|
{
|
|
sv_autobunnyhopping.ReplicateToClient(client, (gA_StyleSettings[gA_Timers[client].iStyle].bAutobhop && gA_Timers[client].bAuto)? "1":"0");
|
|
}
|
|
|
|
if(sv_enablebunnyhopping != null)
|
|
{
|
|
sv_enablebunnyhopping.ReplicateToClient(client, (gA_StyleSettings[gA_Timers[client].iStyle].bEnableBunnyhopping)? "1":"0");
|
|
}
|
|
|
|
char sAiraccelerate[8];
|
|
FloatToString(gA_StyleSettings[gA_Timers[client].iStyle].fAiraccelerate, sAiraccelerate, 8);
|
|
sv_airaccelerate.ReplicateToClient(client, sAiraccelerate);
|
|
|
|
SetEntityGravity(client, view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fGravityMultiplier));
|
|
}
|