mirror of
https://github.com/shavitush/bhoptimer.git
synced 2025-12-08 02:48:26 +00:00
commit
3e558558b0
@ -36,7 +36,7 @@ Some features are: Per-player settings (!hud), truevel and gradient-like display
|
||||
#### shavit-misc
|
||||
This plugin handles miscellaneous things used in bunnyhop servers.
|
||||
|
||||
Such as: Team handling (respawning/spectating too), spectators list (!specs), smart player hiding that works for spectating too, teleportation to other players, weapon commands (!knife/!usp/!glock) and ammo management, segmented checkpoints, noclipping (can be set to work for VIPs/admins only), drop-all, godmode, prespeed blocking, prespeed limitation, chat tidying, radar hiding, weapon drop cleaning, player collision removal, auto-respawning, spawn points generator, radio removal, scoreboard manipulation, model opacity changes, fixed runspeed, automatic and configurable chat advertisements, player ragdoll removal and WR messages.
|
||||
Such as: Segmented runs, team handling (respawning/spectating too), spectators list (!specs), smart player hiding that works for spectating too, teleportation to other players, weapon commands (!knife/!usp/!glock) and ammo management, segmented checkpoints, noclipping (can be set to work for VIPs/admins only), drop-all, godmode, prespeed blocking, prespeed limitation, chat tidying, radar hiding, weapon drop cleaning, player collision removal, auto-respawning, spawn points generator, radio removal, scoreboard manipulation, model opacity changes, fixed runspeed, automatic and configurable chat advertisements, player ragdoll removal and WR messages.
|
||||
|
||||
#### shavit-rankings
|
||||
Enables !rank, !top and introduces map tiers (!settier).
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
This is (nearly) an all-in-one server plugin for Counter-Strike: Source, Counter-Strike: Global Offensive and Team Fortress 2 that adds a timer system and many other utilities, so you can install it and have a proper bunnyhop server running.
|
||||
|
||||
Including a records system, map zones (start/end marks etc), bonuses, HUD with useful information, chat processor, miscellaneous such as weapon commands/spawn point generator, bots that replay the best records of the map, sounds, statistics, a fair & competitive rankings system and more!
|
||||
Including a records system, map zones (start/end marks etc), bonuses, HUD with useful information, chat processor, miscellaneous such as weapon commands/spawn point generator, bots that replay the best records of the map, sounds, statistics, segmented running, a fair & competitive rankings system and more!
|
||||
|
||||
[Mapzones' setup demonstration](https://youtu.be/OXFMGm40F6c)
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
|
||||
// Special flags
|
||||
"special" "0" // For third-party modules. The core plugins will not need this setting.
|
||||
"specialstring" "" // For third-party modules. The core plugins will not need this setting.
|
||||
"specialstring" "" // For modularity. Separated with semicolon. Built-in flags: "segments".
|
||||
"permission" "" // Permission required. Syntax: "flag;override". For example "p;style_tas" to require the 'p' flag or the "style_tas" override.
|
||||
}
|
||||
|
||||
@ -187,6 +187,18 @@
|
||||
}
|
||||
|
||||
"7"
|
||||
{
|
||||
"name" "Segmented"
|
||||
"shortname" "SEG"
|
||||
"htmlcolor" "FFFFFF"
|
||||
"command" "sr; seg; segment; segmented"
|
||||
"clantag" "SEG"
|
||||
|
||||
"rankingmultiplier" "0.0"
|
||||
"specialstring" "segments"
|
||||
}
|
||||
|
||||
"8"
|
||||
{
|
||||
"name" "Low Gravity"
|
||||
"shortname" "LG"
|
||||
@ -199,7 +211,7 @@
|
||||
"unranked" "1"
|
||||
}
|
||||
|
||||
"8"
|
||||
"9"
|
||||
{
|
||||
"name" "Slow Motion"
|
||||
"shortname" "SLOW"
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#endif
|
||||
#define _shavit_included
|
||||
|
||||
#define SHAVIT_VERSION "2.0.3"
|
||||
#define SHAVIT_VERSION "2.1.0"
|
||||
#define STYLE_LIMIT 256
|
||||
#define MAX_ZONES 64
|
||||
|
||||
@ -145,6 +145,8 @@ enum
|
||||
fServerTime,
|
||||
iSHSWCombination,
|
||||
iTimerTrack,
|
||||
iMeasuredJumps,
|
||||
iPerfectJumps,
|
||||
TIMERSNAPSHOT_SIZE
|
||||
};
|
||||
|
||||
@ -386,9 +388,10 @@ forward Action Shavit_OnFinishPre(int client, any snapshot[TIMERSNAPSHOT_SIZE]);
|
||||
* @param sync Sync percentage (0.0 to 100.0) or -1.0 when not measured.
|
||||
* @param track Timer track.
|
||||
* @param oldtime The player's best time on the map before this finish.
|
||||
* @param perfs Perfect jump percentage (0.0 to 100.0) or 100.0 when not measured.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnFinish(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime);
|
||||
forward void Shavit_OnFinish(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs);
|
||||
|
||||
/**
|
||||
* Like Shavit_OnFinish, but after the insertion query was called.
|
||||
@ -403,9 +406,11 @@ forward void Shavit_OnFinish(int client, int style, float time, int jumps, int s
|
||||
* @param rank Rank on map.
|
||||
* @param overwrite 1 - brand new record. 2 - update.
|
||||
* @param track Timer track.
|
||||
* @param oldtime The player's best time on the map before this finish.
|
||||
* @param perfs Perfect jump percentage (0.0 to 100.0) or 100.0 when not measured.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnFinish_Post(int client, int style, float time, int jumps, int strafes, float sync, int rank, int overwrite, int track);
|
||||
forward void Shavit_OnFinish_Post(int client, int style, float time, int jumps, int strafes, float sync, int rank, int overwrite, int track, float oldtime, float perfs);
|
||||
|
||||
/**
|
||||
* Called when there's a new WR on the map.
|
||||
@ -418,9 +423,11 @@ forward void Shavit_OnFinish_Post(int client, int style, float time, int jumps,
|
||||
* @param sync Sync percentage (0.0 to 100.0) or -1.0 when not measured.
|
||||
* @param track Timer track.
|
||||
* @param oldwr Time of the old WR. 0.0 if there's none.
|
||||
* @param oldtime The player's best time on the map before this finish.
|
||||
* @param perfs Perfect jump percentage (0.0 to 100.0) or 100.0 when not measured.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnWorldRecord(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldwr);
|
||||
forward void Shavit_OnWorldRecord(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldwr, float oldtime, float perfs);
|
||||
|
||||
/**
|
||||
* Called when an admin deletes a WR.
|
||||
@ -520,9 +527,11 @@ forward void Shavit_OnLeaveZone(int client, int type, int track, int id, int ent
|
||||
* @param strafes Amount of strafes.
|
||||
* @param sync Sync percentage (0.0 to 100.0) or -1.0 when not measured.
|
||||
* @param track Timer track.
|
||||
* @param oldtime The player's best time on the map before this finish.
|
||||
* @param perfs Perfect jump percentage (0.0 to 100.0) or 100.0 when not measured.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnWorstRecord(int client, int style, float time, int jumps, int strafes, float sync, int track);
|
||||
forward void Shavit_OnWorstRecord(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs);
|
||||
|
||||
/**
|
||||
* Gets called when a map's tier is assigned.
|
||||
@ -661,6 +670,15 @@ native TimerStatus Shavit_GetTimerStatus(int client);
|
||||
*/
|
||||
native int Shavit_GetStrafeCount(int client);
|
||||
|
||||
/**
|
||||
* Retrieve the perfect jumps percentage for the player.
|
||||
* Will return 100.0 if no jumps were measured.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return Perfect jump percentage.
|
||||
*/
|
||||
native float Shavit_GetPerfectJumps(int client);
|
||||
|
||||
/**
|
||||
* Retrieve strafe sync since timer start.
|
||||
* Will return 0.0 if timer isn't running or -1.0 when not measured.
|
||||
@ -871,6 +889,17 @@ native float Shavit_GetReplayTime(int style, int track);
|
||||
*/
|
||||
native void Shavit_GetReplayName(int style, int track, char[] buffer, int length);
|
||||
|
||||
/**
|
||||
* Hijack the replay data so that this view angle will be used for the next tick.
|
||||
* Use case is to make segmented runs look smoother.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param pitch Vertical view angle.
|
||||
* @param yaw Horizontal view angle.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_HijackAngles(int client, float pitch, float yaw);
|
||||
|
||||
/**
|
||||
* Checks if there's loaded replay data for a bhop style or not.
|
||||
*
|
||||
@ -1172,6 +1201,7 @@ public void __pl_shavit_SetNTVOptional()
|
||||
MarkNativeAsOptional("Shavit_GetHUDSettings");
|
||||
MarkNativeAsOptional("Shavit_GetMapTier");
|
||||
MarkNativeAsOptional("Shavit_GetMapTiers");
|
||||
MarkNativeAsOptional("Shavit_GetPerfectJumps");
|
||||
MarkNativeAsOptional("Shavit_GetPlayerPB");
|
||||
MarkNativeAsOptional("Shavit_GetPoints");
|
||||
MarkNativeAsOptional("Shavit_GetRank");
|
||||
@ -1202,6 +1232,7 @@ public void __pl_shavit_SetNTVOptional()
|
||||
MarkNativeAsOptional("Shavit_GetWRRecordID");
|
||||
MarkNativeAsOptional("Shavit_GetWRTime");
|
||||
MarkNativeAsOptional("Shavit_HasStyleAccess");
|
||||
MarkNativeAsOptional("Shavit_HijackAngles");
|
||||
MarkNativeAsOptional("Shavit_InsideZone");
|
||||
MarkNativeAsOptional("Shavit_IsClientCreatingZone");
|
||||
MarkNativeAsOptional("Shavit_IsKZMap");
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
#include <clientprefs>
|
||||
|
||||
#undef REQUIRE_PLUGIN
|
||||
#include <adminmenu>
|
||||
#include <bhopstats>
|
||||
|
||||
#define USES_CHAT_COLORS
|
||||
@ -79,6 +78,8 @@ float gF_StrafeWarning[MAXPLAYERS+1];
|
||||
bool gB_PracticeMode[MAXPLAYERS+1];
|
||||
int gI_SHSW_FirstCombination[MAXPLAYERS+1];
|
||||
int gI_Track[MAXPLAYERS+1];
|
||||
int gI_MeasuredJumps[MAXPLAYERS+1];
|
||||
int gI_PerfectJumps[MAXPLAYERS+1];
|
||||
|
||||
StringMap gSM_StyleCommands = null;
|
||||
|
||||
@ -133,6 +134,7 @@ char gS_ChatStrings[CHATSETTINGS_SIZE][128];
|
||||
bool gB_StopChatSound = false;
|
||||
bool gB_HookedJump = false;
|
||||
char gS_LogPath[PLATFORM_MAX_PATH];
|
||||
int gI_GroundTicks[MAXPLAYERS+1];
|
||||
|
||||
// flags
|
||||
int gI_StyleFlag[STYLE_LIMIT];
|
||||
@ -161,6 +163,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
|
||||
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);
|
||||
@ -198,7 +201,7 @@ public void OnPluginStart()
|
||||
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);
|
||||
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);
|
||||
@ -328,8 +331,6 @@ public void OnPluginStart()
|
||||
// late
|
||||
if(gB_Late)
|
||||
{
|
||||
OnAdminMenuReady(null);
|
||||
|
||||
for(int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if(IsValidClient(i))
|
||||
@ -385,29 +386,6 @@ public void OnLibraryRemoved(const char[] name)
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAdminMenuReady(Handle topmenu)
|
||||
{
|
||||
Handle hTopMenu = INVALID_HANDLE;
|
||||
|
||||
if(LibraryExists("adminmenu") && ((hTopMenu = GetAdminTopMenu()) != INVALID_HANDLE))
|
||||
{
|
||||
AddToTopMenu(hTopMenu, "Timer Commands", TopMenuObject_Category, CategoryHandler, INVALID_TOPMENUOBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
public void CategoryHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
|
||||
{
|
||||
if(action == TopMenuAction_DisplayTitle)
|
||||
{
|
||||
strcopy(buffer, maxlength, "Timer Commands:");
|
||||
}
|
||||
|
||||
else if(action == TopMenuAction_DisplayOption)
|
||||
{
|
||||
strcopy(buffer, maxlength, "Timer Commands");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMapStart()
|
||||
{
|
||||
// styles
|
||||
@ -981,6 +959,8 @@ public int Native_FinishMap(Handle handler, int numParams)
|
||||
snapshot[fCurrentTime] = gF_PlayerTimer[client];
|
||||
snapshot[iSHSWCombination] = gI_SHSW_FirstCombination[client];
|
||||
snapshot[iTimerTrack] = gI_Track[client];
|
||||
snapshot[iMeasuredJumps] = gI_MeasuredJumps[client];
|
||||
snapshot[iPerfectJumps] = gI_PerfectJumps[client];
|
||||
|
||||
Action result = Plugin_Continue;
|
||||
Call_StartForward(gH_Forwards_FinishPre);
|
||||
@ -998,6 +978,7 @@ public int Native_FinishMap(Handle handler, int numParams)
|
||||
|
||||
int style = 0;
|
||||
int track = Track_Main;
|
||||
float perfs = 100.0;
|
||||
|
||||
if(result == Plugin_Continue)
|
||||
{
|
||||
@ -1007,6 +988,7 @@ public int Native_FinishMap(Handle handler, int numParams)
|
||||
Call_PushCell(gI_Strafes[client]);
|
||||
Call_PushCell((gA_StyleSettings[gI_Style[client]][bSync])? (gI_GoodGains[client] == 0)? 0.0:(gI_GoodGains[client] / float(gI_TotalMeasures[client]) * 100.0):-1.0);
|
||||
Call_PushCell(track = gI_Track[client]);
|
||||
perfs = (gI_MeasuredJumps[client] == 0)? 100.0:(gI_PerfectJumps[client] / float(gI_MeasuredJumps[client]) * 100.0);
|
||||
}
|
||||
|
||||
else
|
||||
@ -1017,6 +999,7 @@ public int Native_FinishMap(Handle handler, int numParams)
|
||||
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;
|
||||
@ -1027,6 +1010,7 @@ public int Native_FinishMap(Handle handler, int numParams)
|
||||
}
|
||||
|
||||
Call_PushCell(oldtime);
|
||||
Call_PushCell(perfs);
|
||||
Call_Finish();
|
||||
|
||||
StopTimer(client);
|
||||
@ -1091,6 +1075,13 @@ public int Native_RestartTimer(Handle handler, int numParams)
|
||||
StartTimer(client, track);
|
||||
}
|
||||
|
||||
public int Native_GetPerfectJumps(Handle handler, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
|
||||
return view_as<int>((gI_MeasuredJumps[client] == 0)? 100.0:(gI_PerfectJumps[client] / float(gI_MeasuredJumps[client]) * 100.0));
|
||||
}
|
||||
|
||||
public int Native_GetStrafeCount(Handle handler, int numParams)
|
||||
{
|
||||
return gI_Strafes[GetNativeCell(1)];
|
||||
@ -1158,6 +1149,8 @@ public int Native_SaveSnapshot(Handle handler, int numParams)
|
||||
snapshot[fCurrentTime] = gF_PlayerTimer[client];
|
||||
snapshot[iSHSWCombination] = gI_SHSW_FirstCombination[client];
|
||||
snapshot[iTimerTrack] = gI_Track[client];
|
||||
snapshot[iMeasuredJumps] = gI_MeasuredJumps[client];
|
||||
snapshot[iPerfectJumps] = gI_PerfectJumps[client];
|
||||
|
||||
return SetNativeArray(2, snapshot, TIMERSNAPSHOT_SIZE);
|
||||
}
|
||||
@ -1185,6 +1178,8 @@ public int Native_LoadSnapshot(Handle handler, int numParams)
|
||||
gI_GoodGains[client] = view_as<int>(snapshot[iGoodGains]);
|
||||
gF_PlayerTimer[client] = snapshot[fCurrentTime];
|
||||
gI_SHSW_FirstCombination[client] = view_as<int>(snapshot[iSHSWCombination]);
|
||||
gI_MeasuredJumps[client] = view_as<int>(snapshot[iMeasuredJumps]);
|
||||
gI_PerfectJumps[client] = view_as<int>(snapshot[iPerfectJumps]);
|
||||
}
|
||||
|
||||
public int Native_LogMessage(Handle plugin, int numParams)
|
||||
@ -1255,6 +1250,8 @@ void StartTimer(int client, int track)
|
||||
gI_SHSW_FirstCombination[client] = -1;
|
||||
gF_PlayerTimer[client] = 0.0;
|
||||
gB_PracticeMode[client] = false;
|
||||
gI_MeasuredJumps[client] = 0;
|
||||
gI_PerfectJumps[client] = 0;
|
||||
|
||||
SetEntityGravity(client, view_as<float>(gA_StyleSettings[gI_Style[client]][fGravityMultiplier]));
|
||||
SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", view_as<float>(gA_StyleSettings[gI_Style[client]][fSpeedMultiplier]));
|
||||
@ -2112,15 +2109,40 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
||||
SetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fSpeed);
|
||||
}
|
||||
|
||||
int iPButtons = buttons;
|
||||
|
||||
if(gA_StyleSettings[gI_Style[client]][bAutobhop] && gB_Auto[client] && (buttons & IN_JUMP) > 0 && mtMoveType == MOVETYPE_WALK && !bInWater)
|
||||
{
|
||||
int iOldButtons = GetEntProp(client, Prop_Data, "m_nOldButtons");
|
||||
SetEntProp(client, Prop_Data, "m_nOldButtons", iOldButtons & ~IN_JUMP);
|
||||
SetEntProp(client, Prop_Data, "m_nOldButtons", (iOldButtons & ~IN_JUMP));
|
||||
iPButtons &= ~IN_JUMP;
|
||||
}
|
||||
|
||||
else if(gB_DoubleSteps[client] && (buttons & IN_JUMP) == 0)
|
||||
{
|
||||
buttons |= IN_JUMP;
|
||||
iPButtons = buttons |= IN_JUMP;
|
||||
}
|
||||
|
||||
// perf jump measuring
|
||||
if(!bInWater && mtMoveType == MOVETYPE_WALK && iGroundEntity != -1)
|
||||
{
|
||||
gI_GroundTicks[client]++;
|
||||
|
||||
if((((gI_ButtonCache[client] & IN_JUMP) == 0 && (iPButtons & IN_JUMP) > 0) || iPButtons != buttons) &&
|
||||
1 <= gI_GroundTicks[client] <= 8)
|
||||
{
|
||||
gI_MeasuredJumps[client]++;
|
||||
|
||||
if(gI_GroundTicks[client] == 1)
|
||||
{
|
||||
gI_PerfectJumps[client]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
gI_GroundTicks[client] = 0;
|
||||
}
|
||||
|
||||
if(bInStart && gB_BlockPreJump && !gA_StyleSettings[gI_Style[client]][bPrespeed] && (vel[2] > 0 || (buttons & IN_JUMP) > 0))
|
||||
@ -2208,7 +2230,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
||||
}
|
||||
}
|
||||
|
||||
gI_ButtonCache[client] = buttons;
|
||||
gI_ButtonCache[client] = iPButtons;
|
||||
gF_AngleCache[client] = angles[1];
|
||||
|
||||
return Plugin_Continue;
|
||||
|
||||
@ -761,7 +761,7 @@ void UpdateHUD(int client)
|
||||
{
|
||||
if(gA_StyleSettings[style][bSync])
|
||||
{
|
||||
Format(sHintText, 512, "%s%s\t%T: %d (%.02f%%)", sHintText, (iSpeed < 1000)? "\t":"", "HudStrafeText", client, strafes, Shavit_GetSync(target));
|
||||
Format(sHintText, 512, "%s%s\t%T: %d (%.01f%%)", sHintText, (iSpeed < 1000)? "\t":"", "HudStrafeText", client, strafes, Shavit_GetSync(target));
|
||||
}
|
||||
|
||||
else
|
||||
@ -1075,9 +1075,16 @@ void UpdateKeyHint(int client)
|
||||
|
||||
if(IsValidClient(target) && (target == client || (gI_HUDSettings[client] & HUD_OBSERVE) > 0))
|
||||
{
|
||||
if((gI_HUDSettings[client] & HUD_SYNC) > 0 && Shavit_GetTimerStatus(target) == Timer_Running && gA_StyleSettings[Shavit_GetBhopStyle(target)][bSync] && !IsFakeClient(target) && (!gB_Zones || !Shavit_InsideZone(target, Zone_Start, -1)))
|
||||
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: %.02f", sMessage, (strlen(sMessage) > 0)? "\n\n":"", "HudSync", client, Shavit_GetSync(target));
|
||||
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)
|
||||
|
||||
@ -50,19 +50,23 @@ enum CheckpointsCache
|
||||
iCPFlags,
|
||||
any:aCPSnapshot[TIMERSNAPSHOT_SIZE],
|
||||
String:sCPTargetname[32],
|
||||
ArrayList:aCPFrames,
|
||||
bool:bCPSegmented,
|
||||
bool:bCPSpectated,
|
||||
PCPCACHE_SIZE
|
||||
}
|
||||
|
||||
#pragma newdecls required
|
||||
#pragma semicolon 1
|
||||
#pragma dynamic 131072
|
||||
#pragma dynamic 524288
|
||||
|
||||
#define CP_ANGLES (1 << 0)
|
||||
#define CP_VELOCITY (1 << 1)
|
||||
|
||||
#define CP_DEFAULT (CP_ANGLES|CP_VELOCITY)
|
||||
|
||||
#define CP_MAX 1000 // segmented runs shouldn't even reach 1k jumps on any map anyways
|
||||
#define CP_MAX 1000 // shouldn't even reach 1k jumps on any map when routing anyways
|
||||
#define CP_MAX_SEGMENTED 10
|
||||
|
||||
// game specific
|
||||
EngineVersion gEV_Type = Engine_Unknown;
|
||||
@ -74,6 +78,7 @@ char gS_RadioCommands[][] = {"coverme", "takepoint", "holdpos", "regroup", "foll
|
||||
|
||||
// cache
|
||||
ConVar sv_disable_immunity_alpha = null;
|
||||
ConVar mp_humanteam = null;
|
||||
ConVar hostname = null;
|
||||
ConVar hostport = null;
|
||||
|
||||
@ -84,7 +89,7 @@ int gI_LastShot[MAXPLAYERS+1];
|
||||
ArrayList gA_Advertisements = null;
|
||||
int gI_AdvertisementsCycle = 0;
|
||||
char gS_CurrentMap[192];
|
||||
int gBS_Style[MAXPLAYERS+1];
|
||||
int gI_Style[MAXPLAYERS+1];
|
||||
|
||||
enum
|
||||
{
|
||||
@ -167,6 +172,7 @@ bool gB_DropAll = true;
|
||||
bool gB_ResetTargetname = false;
|
||||
bool gB_RestoreStates = false;
|
||||
bool gB_JointeamHook = true;
|
||||
int gI_HumanTeam = 0;
|
||||
|
||||
// dhooks
|
||||
Handle gH_GetPlayerMaxSpeed = null;
|
||||
@ -277,6 +283,12 @@ public void OnPluginStart()
|
||||
gA_Advertisements = new ArrayList(300);
|
||||
hostname = FindConVar("hostname");
|
||||
hostport = FindConVar("hostport");
|
||||
mp_humanteam = FindConVar("mp_humanteam");
|
||||
|
||||
if(mp_humanteam == null)
|
||||
{
|
||||
mp_humanteam = FindConVar("mp_humans_must_join_team");
|
||||
}
|
||||
|
||||
// cvars and stuff
|
||||
gCV_GodMode = CreateConVar("shavit_misc_godmode", "3", "Enable godmode for players?\n0 - Disabled\n1 - Only prevent fall/world damage.\n2 - Only prevent damage from other players.\n3 - Full godmode.", 0, true, 0.0, true, 3.0);
|
||||
@ -336,6 +348,7 @@ public void OnPluginStart()
|
||||
gCV_ResetTargetname.AddChangeHook(OnConVarChanged);
|
||||
gCV_RestoreStates.AddChangeHook(OnConVarChanged);
|
||||
gCV_JointeamHook.AddChangeHook(OnConVarChanged);
|
||||
mp_humanteam.AddChangeHook(OnConVarChanged);
|
||||
|
||||
AutoExecConfig();
|
||||
|
||||
@ -425,7 +438,7 @@ public void OnClientCookiesCached(int client)
|
||||
gI_CheckpointsSettings[client] = StringToInt(sSetting);
|
||||
}
|
||||
|
||||
gBS_Style[client] = Shavit_GetBhopStyle(client);
|
||||
gI_Style[client] = Shavit_GetBhopStyle(client);
|
||||
}
|
||||
|
||||
public void Shavit_OnStyleConfigLoaded(int styles)
|
||||
@ -440,6 +453,7 @@ public void Shavit_OnStyleConfigLoaded(int styles)
|
||||
Shavit_GetStyleSettings(i, gA_StyleSettings[i]);
|
||||
Shavit_GetStyleStrings(i, sStyleName, gS_StyleStrings[i][sStyleName], 128);
|
||||
Shavit_GetStyleStrings(i, sClanTag, gS_StyleStrings[i][sClanTag], 128);
|
||||
Shavit_GetStyleStrings(i, sSpecialString, gS_StyleStrings[i][sSpecialString], 128);
|
||||
}
|
||||
}
|
||||
|
||||
@ -458,7 +472,14 @@ public void Shavit_OnChatConfigLoaded()
|
||||
|
||||
public void Shavit_OnStyleChanged(int client, int oldstyle, int newstyle, int track, bool manual)
|
||||
{
|
||||
gBS_Style[client] = newstyle;
|
||||
gI_Style[client] = newstyle;
|
||||
|
||||
if(StrContains(gS_StyleStrings[oldstyle][sSpecialString], "segments") == -1 &&
|
||||
StrContains(gS_StyleStrings[newstyle][sSpecialString], "segments") != -1)
|
||||
{
|
||||
OpenCheckpointsMenu(client, 0);
|
||||
Shavit_PrintToChat(client, "%T", "MiscSegmentedCommand", client, gS_ChatStrings[sMessageVariable], gS_ChatStrings[sMessageText]);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
|
||||
@ -491,6 +512,24 @@ public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] n
|
||||
gB_ResetTargetname = gCV_ResetTargetname.BoolValue;
|
||||
gB_RestoreStates = gCV_RestoreStates.BoolValue;
|
||||
gB_JointeamHook = gCV_JointeamHook.BoolValue;
|
||||
|
||||
if(convar == mp_humanteam)
|
||||
{
|
||||
if(StrEqual(newValue, "t", false) || StrEqual(newValue, "red", false))
|
||||
{
|
||||
gI_HumanTeam = 2;
|
||||
}
|
||||
|
||||
else if(StrEqual(newValue, "ct", false) || StrEqual(newValue, "blue", false))
|
||||
{
|
||||
gI_HumanTeam = 3;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
gI_HumanTeam = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnConfigsExecuted()
|
||||
@ -503,6 +542,11 @@ public void OnConfigsExecuted()
|
||||
|
||||
public void OnMapStart()
|
||||
{
|
||||
for(int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
ResetCheckpoints(i);
|
||||
}
|
||||
|
||||
gSM_Checkpoints.Clear();
|
||||
|
||||
GetCurrentMap(gS_CurrentMap, 192);
|
||||
@ -547,6 +591,14 @@ public void OnMapStart()
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMapEnd()
|
||||
{
|
||||
for(int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
ResetCheckpoints(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadAdvertisementsConfig()
|
||||
{
|
||||
gA_Advertisements.Clear();
|
||||
@ -637,6 +689,11 @@ public Action Command_Jointeam(int client, const char[] command, int args)
|
||||
|
||||
int iTeam = StringToInt(arg1);
|
||||
|
||||
if(gI_HumanTeam == 0 && !(0 <= iTeam <= 1))
|
||||
{
|
||||
iTeam = gI_HumanTeam;
|
||||
}
|
||||
|
||||
bool bRespawn = false;
|
||||
|
||||
switch(iTeam)
|
||||
@ -727,7 +784,7 @@ public MRESReturn DHook_GetPlayerMaxSpeed(int pThis, Handle hReturn)
|
||||
return MRES_Ignored;
|
||||
}
|
||||
|
||||
DHookSetReturn(hReturn, view_as<float>(gA_StyleSettings[gBS_Style[pThis]][fRunspeed]));
|
||||
DHookSetReturn(hReturn, view_as<float>(gA_StyleSettings[gI_Style[pThis]][fRunspeed]));
|
||||
|
||||
return MRES_Override;
|
||||
}
|
||||
@ -888,8 +945,8 @@ void UpdateClanTag(int client)
|
||||
|
||||
char[] sCustomTag = new char[32];
|
||||
strcopy(sCustomTag, 32, gS_ClanTag);
|
||||
ReplaceString(sCustomTag, 32, "{style}", gS_StyleStrings[gBS_Style[client]][sStyleName]);
|
||||
ReplaceString(sCustomTag, 32, "{styletag}", gS_StyleStrings[gBS_Style[client]][sClanTag]);
|
||||
ReplaceString(sCustomTag, 32, "{style}", gS_StyleStrings[gI_Style[client]][sStyleName]);
|
||||
ReplaceString(sCustomTag, 32, "{styletag}", gS_StyleStrings[gI_Style[client]][sClanTag]);
|
||||
ReplaceString(sCustomTag, 32, "{time}", sTime);
|
||||
ReplaceString(sCustomTag, 32, "{tr}", sTrack);
|
||||
|
||||
@ -919,7 +976,7 @@ public Action Shavit_OnUserCmdPre(int client, int &buttons, int &impulse, float
|
||||
int iGroundEntity = GetEntPropEnt(client, Prop_Send, "m_hGroundEntity");
|
||||
|
||||
// prespeed
|
||||
if(!bNoclip && !gA_StyleSettings[gBS_Style[client]][bPrespeed] && Shavit_InsideZone(client, Zone_Start, track))
|
||||
if(!bNoclip && !gA_StyleSettings[gI_Style[client]][bPrespeed] && Shavit_InsideZone(client, Zone_Start, track))
|
||||
{
|
||||
if((gI_PreSpeed == 2 || gI_PreSpeed == 3) && gI_GroundEntity[client] == -1 && iGroundEntity != -1 && (buttons & IN_JUMP) > 0)
|
||||
{
|
||||
@ -940,7 +997,7 @@ public Action Shavit_OnUserCmdPre(int client, int &buttons, int &impulse, float
|
||||
|
||||
if(gI_PreSpeed < 4)
|
||||
{
|
||||
fLimit = view_as<float>(gA_StyleSettings[gBS_Style[client]][fRunspeed]) + gF_PrestrafeLimit;
|
||||
fLimit = view_as<float>(gA_StyleSettings[gI_Style[client]][fRunspeed]) + gF_PrestrafeLimit;
|
||||
|
||||
// if trying to jump, add a very low limit to stop prespeeding in an elegant way
|
||||
// otherwise, make sure nothing weird is happening (such as sliding at ridiculous speeds, at zone enter)
|
||||
@ -985,7 +1042,7 @@ public void OnClientPutInServer(int client)
|
||||
|
||||
if(!AreClientCookiesCached(client))
|
||||
{
|
||||
gBS_Style[client] = Shavit_GetBhopStyle(client);
|
||||
gI_Style[client] = Shavit_GetBhopStyle(client);
|
||||
gB_Hide[client] = false;
|
||||
gI_CheckpointsSettings[client] = CP_DEFAULT;
|
||||
}
|
||||
@ -1004,9 +1061,30 @@ public void OnClientPutInServer(int client)
|
||||
|
||||
public void OnClientDisconnect(int client)
|
||||
{
|
||||
if(gB_NoWeaponDrops)
|
||||
{
|
||||
int entity = -1;
|
||||
|
||||
while((entity = FindEntityByClassname(entity, "weapon_*")) != -1)
|
||||
{
|
||||
if(GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity") == client)
|
||||
{
|
||||
RequestFrame(RemoveWeapon, EntIndexToEntRef(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResetCheckpoints(client);
|
||||
}
|
||||
|
||||
void RemoveWeapon(any data)
|
||||
{
|
||||
if(IsValidEntity(data))
|
||||
{
|
||||
AcceptEntityInput(data, "Kill");
|
||||
}
|
||||
}
|
||||
|
||||
void ResetCheckpoints(int client)
|
||||
{
|
||||
int serial = GetClientSerial(client);
|
||||
@ -1015,6 +1093,14 @@ void ResetCheckpoints(int client)
|
||||
for(int i = 0; i < gI_CheckpointsCache[client][iCheckpoints]; i++)
|
||||
{
|
||||
FormatEx(key, 32, "%d_%d", serial, i);
|
||||
|
||||
CheckpointsCache cpcache[PCPCACHE_SIZE];
|
||||
|
||||
if(gSM_Checkpoints.GetArray(key, cpcache[0], view_as<int>(PCPCACHE_SIZE)))
|
||||
{
|
||||
delete cpcache[aCPFrames]; // free up replay frames if there are any
|
||||
}
|
||||
|
||||
gSM_Checkpoints.Remove(key);
|
||||
}
|
||||
|
||||
@ -1099,7 +1185,7 @@ public void OnPreThink(int client)
|
||||
if(IsPlayerAlive(client))
|
||||
{
|
||||
// not the best method, but only one i found for tf2
|
||||
SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", view_as<float>(gA_StyleSettings[gBS_Style[client]][fRunspeed]));
|
||||
SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", view_as<float>(gA_StyleSettings[gI_Style[client]][fRunspeed]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1409,13 +1495,17 @@ public Action Command_Save(int client, int args)
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
if(!gB_Checkpoints)
|
||||
bool bSegmented = CanSegment(client);
|
||||
|
||||
if(!gB_Checkpoints && !bSegmented)
|
||||
{
|
||||
Shavit_PrintToChat(client, "%T", "FeatureDisabled", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
int iMaxCPs = GetMaxCPs(client);
|
||||
|
||||
if(args > 0)
|
||||
{
|
||||
int index = 0;
|
||||
@ -1425,7 +1515,7 @@ public Action Command_Save(int client, int args)
|
||||
|
||||
int parsed = StringToInt(arg);
|
||||
|
||||
if(parsed > 0 && parsed <= CP_MAX)
|
||||
if(parsed > 0 && parsed <= iMaxCPs)
|
||||
{
|
||||
index = (parsed - 1);
|
||||
}
|
||||
@ -1440,7 +1530,7 @@ public Action Command_Save(int client, int args)
|
||||
{
|
||||
bool bSaved = false;
|
||||
|
||||
if(gI_CheckpointsCache[client][iCheckpoints] < CP_MAX)
|
||||
if(gI_CheckpointsCache[client][iCheckpoints] < iMaxCPs)
|
||||
{
|
||||
if((bSaved = SaveCheckpoint(client, gI_CheckpointsCache[client][iCheckpoints])))
|
||||
{
|
||||
@ -1448,9 +1538,9 @@ public Action Command_Save(int client, int args)
|
||||
}
|
||||
}
|
||||
|
||||
else if((bSaved = SaveCheckpoint(client, (CP_MAX - 1))))
|
||||
else if((bSaved = SaveCheckpoint(client, (iMaxCPs - 1), true)))
|
||||
{
|
||||
gI_CheckpointsCache[client][iCurrentCheckpoint] = CP_MAX;
|
||||
gI_CheckpointsCache[client][iCurrentCheckpoint] = iMaxCPs;
|
||||
}
|
||||
|
||||
if(bSaved)
|
||||
@ -1501,7 +1591,9 @@ public Action Command_Tele(int client, int args)
|
||||
|
||||
public Action OpenCheckpointsMenu(int client, int item)
|
||||
{
|
||||
if(!gB_Checkpoints)
|
||||
bool bSegmented = CanSegment(client);
|
||||
|
||||
if(!gB_Checkpoints && !bSegmented)
|
||||
{
|
||||
Shavit_PrintToChat(client, "%T", "FeatureDisabled", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
|
||||
|
||||
@ -1509,7 +1601,16 @@ public Action OpenCheckpointsMenu(int client, int item)
|
||||
}
|
||||
|
||||
Menu menu = new Menu(MenuHandler_Checkpoints, MENU_ACTIONS_DEFAULT|MenuAction_DisplayItem);
|
||||
|
||||
if(!bSegmented)
|
||||
{
|
||||
menu.SetTitle("%T\n%T\n ", "MiscCheckpointMenu", client, "MiscCheckpointWarning", client);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
menu.SetTitle("%T\n ", "MiscCheckpointMenuSegmented", client);
|
||||
}
|
||||
|
||||
char[] sDisplay = new char[64];
|
||||
FormatEx(sDisplay, 64, "%T", "MiscCheckpointSave", client, (gI_CheckpointsCache[client][iCheckpoints] + 1));
|
||||
@ -1536,6 +1637,8 @@ public Action OpenCheckpointsMenu(int client, int item)
|
||||
FormatEx(sDisplay, 64, "%T", "MiscCheckpointReset", client);
|
||||
menu.AddItem("reset", sDisplay);
|
||||
|
||||
if(!bSegmented)
|
||||
{
|
||||
char[] sInfo = new char[16];
|
||||
IntToString(CP_ANGLES, sInfo, 16);
|
||||
FormatEx(sDisplay, 64, "%T", "MiscCheckpointUseAngles", client);
|
||||
@ -1544,6 +1647,7 @@ public Action OpenCheckpointsMenu(int client, int item)
|
||||
IntToString(CP_VELOCITY, sInfo, 16);
|
||||
FormatEx(sDisplay, 64, "%T", "MiscCheckpointUseVelocity", client);
|
||||
menu.AddItem(sInfo, sDisplay);
|
||||
}
|
||||
|
||||
menu.Pagination = MENU_NO_PAGINATION;
|
||||
menu.ExitButton = true;
|
||||
@ -1556,14 +1660,18 @@ public int MenuHandler_Checkpoints(Menu menu, MenuAction action, int param1, int
|
||||
{
|
||||
if(action == MenuAction_Select)
|
||||
{
|
||||
int current = gI_CheckpointsCache[param1][iCurrentCheckpoint];
|
||||
bool bSegmenting = CanSegment(param1);
|
||||
int iMaxCPs = GetMaxCPs(param1);
|
||||
int iCurrent = gI_CheckpointsCache[param1][iCurrentCheckpoint];
|
||||
|
||||
switch(param2)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if(!bSegmenting)
|
||||
{
|
||||
// fight an exploit
|
||||
if(gI_CheckpointsCache[param1][iCheckpoints] >= CP_MAX)
|
||||
if(gI_CheckpointsCache[param1][iCheckpoints] >= iMaxCPs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -1572,14 +1680,22 @@ public int MenuHandler_Checkpoints(Menu menu, MenuAction action, int param1, int
|
||||
gI_CheckpointsCache[param1][iCurrentCheckpoint] = ++gI_CheckpointsCache[param1][iCheckpoints];
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
bool bOverflow = gI_CheckpointsCache[param1][iCheckpoints] >= iMaxCPs;
|
||||
SaveCheckpoint(param1, gI_CheckpointsCache[param1][iCheckpoints], bOverflow);
|
||||
gI_CheckpointsCache[param1][iCurrentCheckpoint] = (bOverflow)? iMaxCPs:++gI_CheckpointsCache[param1][iCheckpoints];
|
||||
}
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
TeleportToCheckpoint(param1, current - 1, true);
|
||||
TeleportToCheckpoint(param1, iCurrent - 1, true);
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
if(current > 1)
|
||||
if(iCurrent > 1)
|
||||
{
|
||||
gI_CheckpointsCache[param1][iCurrentCheckpoint]--;
|
||||
}
|
||||
@ -1589,7 +1705,7 @@ public int MenuHandler_Checkpoints(Menu menu, MenuAction action, int param1, int
|
||||
{
|
||||
CheckpointsCache cpcache[PCPCACHE_SIZE];
|
||||
|
||||
if(current < CP_MAX && GetCheckpoint(param1, current, cpcache))
|
||||
if(iCurrent < iMaxCPs && GetCheckpoint(param1, iCurrent, cpcache))
|
||||
{
|
||||
gI_CheckpointsCache[param1][iCurrentCheckpoint]++;
|
||||
}
|
||||
@ -1636,7 +1752,7 @@ public int MenuHandler_Checkpoints(Menu menu, MenuAction action, int param1, int
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SaveCheckpoint(int client, int index)
|
||||
bool SaveCheckpoint(int client, int index, bool overflow = false)
|
||||
{
|
||||
int target = client;
|
||||
|
||||
@ -1655,6 +1771,18 @@ bool SaveCheckpoint(int client, int index)
|
||||
return false;
|
||||
}
|
||||
|
||||
char[] sKey = new char[32];
|
||||
int iSerial = GetClientSerial(client);
|
||||
FormatEx(sKey, 32, "%d_%d", iSerial, index);
|
||||
|
||||
CheckpointsCache cpcacheprev[PCPCACHE_SIZE];
|
||||
|
||||
if(gSM_Checkpoints.GetArray(sKey, cpcacheprev[0], view_as<int>(PCPCACHE_SIZE)))
|
||||
{
|
||||
delete cpcacheprev[aCPFrames];
|
||||
gSM_Checkpoints.SetArray(sKey, cpcacheprev[0], view_as<int>(PCPCACHE_SIZE));
|
||||
}
|
||||
|
||||
CheckpointsCache cpcache[PCPCACHE_SIZE];
|
||||
float temp[3];
|
||||
|
||||
@ -1726,6 +1854,55 @@ bool SaveCheckpoint(int client, int index)
|
||||
}
|
||||
|
||||
CopyArray(snapshot, cpcache[aCPSnapshot], TIMERSNAPSHOT_SIZE);
|
||||
|
||||
if(CanSegment(target))
|
||||
{
|
||||
if(gB_Replay)
|
||||
{
|
||||
cpcache[aCPFrames] = Shavit_GetReplayData(target);
|
||||
}
|
||||
|
||||
cpcache[bCPSegmented] = true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
cpcache[aCPFrames] = null;
|
||||
cpcache[bCPSegmented] = false;
|
||||
}
|
||||
|
||||
cpcache[bCPSpectated] = (client != target);
|
||||
|
||||
if(overflow)
|
||||
{
|
||||
int iMaxCPs = GetMaxCPs(client);
|
||||
|
||||
for(int i = 0; i < iMaxCPs; i++)
|
||||
{
|
||||
CheckpointsCache cpcacheold[PCPCACHE_SIZE];
|
||||
FormatEx(sKey, 32, "%d_%d", iSerial, i);
|
||||
|
||||
if(!gSM_Checkpoints.GetArray(sKey, cpcacheold[0], view_as<int>(PCPCACHE_SIZE)))
|
||||
{
|
||||
continue; // ???
|
||||
}
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
delete cpcacheold[aCPFrames];
|
||||
gSM_Checkpoints.Remove(sKey);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
gSM_Checkpoints.Remove(sKey);
|
||||
FormatEx(sKey, 32, "%d_%d", iSerial, (i - 1)); // set cp index to one less
|
||||
gSM_Checkpoints.SetArray(sKey, cpcacheold[0], view_as<int>(PCPCACHE_SIZE));
|
||||
}
|
||||
|
||||
index = (iMaxCPs - 1);
|
||||
}
|
||||
|
||||
SetCheckpoint(client, index, cpcache);
|
||||
|
||||
return true;
|
||||
@ -1733,7 +1910,7 @@ bool SaveCheckpoint(int client, int index)
|
||||
|
||||
void TeleportToCheckpoint(int client, int index, bool suppressMessage)
|
||||
{
|
||||
if(index < 0 || index >= CP_MAX)
|
||||
if(index < 0 || index >= CP_MAX || (!gB_Checkpoints && !CanSegment(client)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1769,7 +1946,10 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
|
||||
Shavit_StopTimer(client);
|
||||
}
|
||||
|
||||
if(!cpcache[bCPSegmented] || cpcache[bCPSpectated])
|
||||
{
|
||||
Shavit_SetPracticeMode(client, true, !bInStart);
|
||||
}
|
||||
|
||||
any snapshot[TIMERSNAPSHOT_SIZE];
|
||||
CopyArray(cpcache[aCPSnapshot], snapshot, TIMERSNAPSHOT_SIZE);
|
||||
@ -1782,8 +1962,8 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
|
||||
CopyArray(cpcache[fCPVelocity], vel, 3);
|
||||
|
||||
TeleportEntity(client, pos,
|
||||
((gI_CheckpointsSettings[client] & CP_ANGLES) > 0)? ang:NULL_VECTOR,
|
||||
((gI_CheckpointsSettings[client] & CP_VELOCITY) > 0)? vel:NULL_VECTOR);
|
||||
((gI_CheckpointsSettings[client] & CP_ANGLES) > 0 || cpcache[bCPSegmented])? ang:NULL_VECTOR,
|
||||
((gI_CheckpointsSettings[client] & CP_VELOCITY) > 0 || cpcache[bCPSegmented])? vel:NULL_VECTOR);
|
||||
|
||||
MoveType mt = cpcache[mtCPMoveType];
|
||||
|
||||
@ -1816,6 +1996,24 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
|
||||
SetEntPropFloat(client, Prop_Send, "m_flDuckSpeed", cpcache[fCPDuckSpeed]);
|
||||
}
|
||||
|
||||
if(cpcache[bCPSegmented] && gB_Replay)
|
||||
{
|
||||
if(cpcache[aCPFrames] == null)
|
||||
{
|
||||
LogError("SetReplayData for %L failed, recorded frames are null.", client);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Shavit_SetReplayData(client, cpcache[aCPFrames]);
|
||||
|
||||
if((gI_CheckpointsSettings[client] & CP_ANGLES) > 0)
|
||||
{
|
||||
Shavit_HijackAngles(client, ang[0], ang[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!suppressMessage)
|
||||
{
|
||||
Shavit_PrintToChat(client, "%T", "MiscCheckpointsTeleported", client, (index + 1), gS_ChatStrings[sMessageVariable], gS_ChatStrings[sMessageText]);
|
||||
@ -1977,7 +2175,7 @@ public Action Command_Specs(int client, int args)
|
||||
|
||||
public Action Shavit_OnStart(int client)
|
||||
{
|
||||
if(!gA_StyleSettings[gBS_Style[client]][bPrespeed] && GetEntityMoveType(client) == MOVETYPE_NOCLIP)
|
||||
if(!gA_StyleSettings[gI_Style[client]][bPrespeed] && GetEntityMoveType(client) == MOVETYPE_NOCLIP)
|
||||
{
|
||||
return Plugin_Stop;
|
||||
}
|
||||
@ -2499,6 +2697,7 @@ void LoadState(int client)
|
||||
if(gB_Replay && gA_SaveFrames[client] != null)
|
||||
{
|
||||
Shavit_SetReplayData(client, gA_SaveFrames[client]);
|
||||
Shavit_HijackAngles(client, gF_SaveStateData[client][1][0], gF_SaveStateData[client][1][1]);
|
||||
}
|
||||
|
||||
delete gA_SaveFrames[client];
|
||||
@ -2550,3 +2749,13 @@ void CopyArray(const any[] from, any[] to, int size)
|
||||
to[i] = from[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool CanSegment(int client)
|
||||
{
|
||||
return StrContains(gS_StyleStrings[gI_Style[client]][sSpecialString], "segments") != -1;
|
||||
}
|
||||
|
||||
int GetMaxCPs(int client)
|
||||
{
|
||||
return CanSegment(client)? CP_MAX_SEGMENTED:CP_MAX;
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#undef REQUIRE_PLUGIN
|
||||
#include <shavit>
|
||||
#include <adminmenu>
|
||||
|
||||
#undef REQUIRE_EXTENSIONS
|
||||
#include <cstrike>
|
||||
@ -60,6 +61,12 @@ enum
|
||||
REPLAYSTRINGS_SIZE
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
iBotShooting_Attack1 = (1 << 0),
|
||||
iBotShooting_Attack2 = (1 << 1)
|
||||
}
|
||||
|
||||
// game type
|
||||
EngineVersion gEV_Type = Engine_Unknown;
|
||||
|
||||
@ -82,7 +89,6 @@ bool gB_Record[MAXPLAYERS+1];
|
||||
int gI_Track[MAXPLAYERS+1];
|
||||
|
||||
bool gB_Late = false;
|
||||
int gI_DefaultTeamSlots = 0;
|
||||
|
||||
// server specific
|
||||
float gF_Tickrate = 0.0;
|
||||
@ -94,6 +100,8 @@ any gA_CentralCache[CENTRALBOTCACHE_SIZE];
|
||||
// how do i call this
|
||||
bool gB_HideNameChange = false;
|
||||
bool gB_DontCallTimer = false;
|
||||
bool gB_HijackFrame[MAXPLAYERS+1];
|
||||
float gF_HijackedAngles[MAXPLAYERS+1][2];
|
||||
|
||||
// plugin cvars
|
||||
ConVar gCV_Enabled = null;
|
||||
@ -101,6 +109,7 @@ ConVar gCV_ReplayDelay = null;
|
||||
ConVar gCV_TimeLimit = null;
|
||||
ConVar gCV_DefaultTeam = null;
|
||||
ConVar gCV_CentralBot = null;
|
||||
ConVar gCV_BotShooting = null;
|
||||
|
||||
// cached cvars
|
||||
bool gB_Enabled = true;
|
||||
@ -108,6 +117,7 @@ float gF_ReplayDelay = 5.0;
|
||||
float gF_TimeLimit = 5400.0;
|
||||
int gI_DefaultTeam = 3;
|
||||
bool gB_CentralBot = true;
|
||||
int gI_BotShooting = 3;
|
||||
|
||||
// timer settings
|
||||
int gI_Styles = 0;
|
||||
@ -120,6 +130,10 @@ char gS_ChatStrings[CHATSETTINGS_SIZE][128];
|
||||
// replay settings
|
||||
char gS_ReplayStrings[REPLAYSTRINGS_SIZE][MAX_NAME_LENGTH];
|
||||
|
||||
// admin menu
|
||||
TopMenu gH_AdminMenu = null;
|
||||
TopMenuObject gH_TimerCommands = INVALID_TOPMENUOBJECT;
|
||||
|
||||
// database related things
|
||||
Database gH_SQL = null;
|
||||
char gS_MySQLPrefix[32];
|
||||
@ -146,6 +160,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
|
||||
CreateNative("Shavit_GetReplayLength", Native_GetReplayLength);
|
||||
CreateNative("Shavit_GetReplayName", Native_GetReplayName);
|
||||
CreateNative("Shavit_GetReplayTime", Native_GetReplayTime);
|
||||
CreateNative("Shavit_HijackAngles", Native_HijackAngles);
|
||||
CreateNative("Shavit_IsReplayDataLoaded", Native_IsReplayDataLoaded);
|
||||
CreateNative("Shavit_ReloadReplay", Native_ReloadReplay);
|
||||
CreateNative("Shavit_ReloadReplays", Native_ReloadReplays);
|
||||
@ -196,22 +211,29 @@ public void OnPluginStart()
|
||||
gCV_TimeLimit = CreateConVar("shavit_replay_timelimit", "5400.0", "Maximum amount of time (in seconds) to allow saving to disk.\nDefault is 5400.0 (1:30 hours)\n0 - Disabled");
|
||||
gCV_DefaultTeam = CreateConVar("shavit_replay_defaultteam", "3", "Default team to make the bots join, if possible.\n2 - Terrorists/RED\n3 - Counter Terrorists/BLU", 0, true, 2.0, true, 3.0);
|
||||
gCV_CentralBot = CreateConVar("shavit_replay_centralbot", "1", "Have one central bot instead of one bot per replay.\nTriggered with !replay.\nRestart the map for changes to take effect.\nThe disabled setting is not supported - use at your own risk.\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0);
|
||||
gCV_BotShooting = CreateConVar("shavit_replay_botshooting", "3", "Attacking buttons to allow for bots.\n0 - none\1 - +attack\n2 - +attack2\n3 - both", 0, true, 0.0, true, 3.0);
|
||||
|
||||
gCV_Enabled.AddChangeHook(OnConVarChanged);
|
||||
gCV_ReplayDelay.AddChangeHook(OnConVarChanged);
|
||||
gCV_TimeLimit.AddChangeHook(OnConVarChanged);
|
||||
gCV_DefaultTeam.AddChangeHook(OnConVarChanged);
|
||||
gCV_CentralBot.AddChangeHook(OnConVarChanged);
|
||||
gCV_BotShooting.AddChangeHook(OnConVarChanged);
|
||||
|
||||
AutoExecConfig();
|
||||
|
||||
// admin menu
|
||||
if(LibraryExists("adminmenu") && ((gH_AdminMenu = GetAdminTopMenu()) != null))
|
||||
{
|
||||
OnAdminMenuReady(gH_AdminMenu);
|
||||
}
|
||||
|
||||
// hooks
|
||||
HookEvent("player_spawn", Player_Event, EventHookMode_Pre);
|
||||
HookEvent("player_death", Player_Event, EventHookMode_Pre);
|
||||
HookEvent("player_connect", BotEvents, EventHookMode_Pre);
|
||||
HookEvent("player_disconnect", BotEvents, EventHookMode_Pre);
|
||||
HookEventEx("player_connect_client", BotEvents, EventHookMode_Pre);
|
||||
HookEvent("round_start", Round_Start);
|
||||
|
||||
// name change suppression
|
||||
HookUserMessage(GetUserMessageId("SayText2"), Hook_SayText2, true);
|
||||
@ -231,6 +253,7 @@ public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] n
|
||||
gF_TimeLimit = gCV_TimeLimit.FloatValue;
|
||||
gI_DefaultTeam = gCV_DefaultTeam.IntValue;
|
||||
gB_CentralBot = gCV_CentralBot.BoolValue;
|
||||
gI_BotShooting = gCV_BotShooting.IntValue;
|
||||
|
||||
if(convar == gCV_CentralBot)
|
||||
{
|
||||
@ -238,6 +261,60 @@ public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] n
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAdminMenuCreated(Handle topmenu)
|
||||
{
|
||||
if(gH_AdminMenu == null || (topmenu == gH_AdminMenu && gH_TimerCommands != INVALID_TOPMENUOBJECT))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gH_TimerCommands = gH_AdminMenu.AddCategory("Timer Commands", CategoryHandler, "shavit_admin", ADMFLAG_RCON);
|
||||
}
|
||||
|
||||
public void CategoryHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
|
||||
{
|
||||
if(action == TopMenuAction_DisplayTitle)
|
||||
{
|
||||
FormatEx(buffer, maxlength, "%T:", "TimerCommands", param);
|
||||
}
|
||||
|
||||
else if(action == TopMenuAction_DisplayOption)
|
||||
{
|
||||
FormatEx(buffer, maxlength, "%T", "TimerCommands", param);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAdminMenuReady(Handle topmenu)
|
||||
{
|
||||
if((gH_AdminMenu = GetAdminTopMenu()) != null)
|
||||
{
|
||||
if(gH_TimerCommands == INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
gH_TimerCommands = gH_AdminMenu.FindCategory("Timer Commands");
|
||||
|
||||
if(gH_TimerCommands == INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
OnAdminMenuCreated(topmenu);
|
||||
}
|
||||
}
|
||||
|
||||
gH_AdminMenu.AddItem("sm_deletereplay", AdminMenu_DeleteReplay, gH_TimerCommands, "sm_deletereplay", ADMFLAG_RCON);
|
||||
}
|
||||
}
|
||||
|
||||
public void AdminMenu_DeleteReplay(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
|
||||
{
|
||||
if(action == TopMenuAction_DisplayOption)
|
||||
{
|
||||
FormatEx(buffer, maxlength, "%t", "DeleteReplayAdminMenu");
|
||||
}
|
||||
|
||||
else if(action == TopMenuAction_SelectOption)
|
||||
{
|
||||
Command_DeleteReplay(param, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public int Native_GetReplayBotFirstFrame(Handle handler, int numParams)
|
||||
{
|
||||
SetNativeCellRef(2, gF_StartTick[GetNativeCell(1)]);
|
||||
@ -360,10 +437,16 @@ public int Native_SetReplayData(Handle handler, int numParams)
|
||||
int client = GetNativeCell(1);
|
||||
|
||||
ArrayList frames = view_as<ArrayList>(CloneHandle(GetNativeCell(2), handler));
|
||||
delete gA_PlayerFrames[client];
|
||||
gA_PlayerFrames[client] = frames.Clone();
|
||||
delete frames;
|
||||
|
||||
gI_PlayerFrames[client] = gA_PlayerFrames[client].Length;
|
||||
|
||||
if(gI_PlayerFrames[client] > 0)
|
||||
{
|
||||
gB_Record[client] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public int Native_GetReplayData(Handle handler, int numParams)
|
||||
@ -422,6 +505,15 @@ public int Native_GetReplayTime(Handle handler, int numParams)
|
||||
return view_as<int>(float(gI_ReplayTick[style]) / gF_Tickrate);
|
||||
}
|
||||
|
||||
public int Native_HijackAngles(Handle handler, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
|
||||
gB_HijackFrame[client] = true;
|
||||
gF_HijackedAngles[client][0] = view_as<float>(GetNativeCell(2));
|
||||
gF_HijackedAngles[client][1] = view_as<float>(GetNativeCell(3));
|
||||
}
|
||||
|
||||
public int Native_GetReplayBotStyle(Handle handler, int numParams)
|
||||
{
|
||||
return (gB_CentralBot && gA_CentralCache[iCentralReplayStatus] == Replay_Idle)? -1:GetReplayStyle(GetNativeCell(1));
|
||||
@ -1185,7 +1277,7 @@ void UpdateReplayInfo(int client, int style, float time, int track)
|
||||
}
|
||||
}
|
||||
|
||||
if(gI_DefaultTeamSlots >= gI_Styles && GetClientTeam(client) != gI_DefaultTeam)
|
||||
if(GetClientTeam(client) != gI_DefaultTeam)
|
||||
{
|
||||
if(gEV_Type == Engine_TF2)
|
||||
{
|
||||
@ -1461,6 +1553,16 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
||||
|
||||
buttons = gA_Frames[style][track].Get(gI_ReplayTick[style], 5);
|
||||
|
||||
if((gI_BotShooting & iBotShooting_Attack1) == 0)
|
||||
{
|
||||
buttons &= ~IN_ATTACK;
|
||||
}
|
||||
|
||||
if((gI_BotShooting & iBotShooting_Attack2) == 0)
|
||||
{
|
||||
buttons &= ~IN_ATTACK2;
|
||||
}
|
||||
|
||||
MoveType mt = MOVETYPE_NOCLIP;
|
||||
|
||||
if(gA_FrameCache[style][track][3] >= 0x02)
|
||||
@ -1524,8 +1626,19 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
||||
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], vecCurrentPosition[1], 1);
|
||||
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], vecCurrentPosition[2], 2);
|
||||
|
||||
if(!gB_HijackFrame[client])
|
||||
{
|
||||
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], angles[0], 3);
|
||||
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], angles[1], 4);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], gF_HijackedAngles[client][0], 3);
|
||||
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], gF_HijackedAngles[client][1], 4);
|
||||
|
||||
gB_HijackFrame[client] = false;
|
||||
}
|
||||
|
||||
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], buttons, 5);
|
||||
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], GetEntityFlags(client), 6);
|
||||
@ -1642,30 +1755,6 @@ public void BotEvents(Event event, const char[] name, bool dontBroadcast)
|
||||
}
|
||||
}
|
||||
|
||||
public void Round_Start(Event event, const char[] name, bool dontBroadcast)
|
||||
{
|
||||
gI_DefaultTeamSlots = 0;
|
||||
|
||||
char[] sEntity = new char[32];
|
||||
|
||||
if(gEV_Type == Engine_TF2)
|
||||
{
|
||||
strcopy(sEntity, 32, "info_player_teamspawn");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
strcopy(sEntity, 32, (gI_DefaultTeam == 2)? "info_player_terrorist":"info_player_counterterrorist");
|
||||
}
|
||||
|
||||
int iEntity = -1;
|
||||
|
||||
while((iEntity = FindEntityByClassname(iEntity, sEntity)) != INVALID_ENT_REFERENCE)
|
||||
{
|
||||
gI_DefaultTeamSlots++;
|
||||
}
|
||||
}
|
||||
|
||||
public Action Hook_SayText2(UserMsg msg_id, any msg, const int[] players, int playersNum, bool reliable, bool init)
|
||||
{
|
||||
if(!gB_HideNameChange || !gB_Enabled)
|
||||
|
||||
@ -62,7 +62,8 @@ ArrayList gA_Leaderboard[STYLE_LIMIT][TRACKS_SIZE];
|
||||
float gF_PlayerRecord[MAXPLAYERS+1][STYLE_LIMIT][TRACKS_SIZE];
|
||||
|
||||
// admin menu
|
||||
Handle gH_AdminMenu = null;
|
||||
TopMenu gH_AdminMenu = null;
|
||||
TopMenuObject gH_TimerCommands = INVALID_TOPMENUOBJECT;
|
||||
|
||||
// table prefix
|
||||
char gS_MySQLPrefix[32];
|
||||
@ -130,10 +131,10 @@ public void OnPluginStart()
|
||||
#endif
|
||||
|
||||
// forwards
|
||||
gH_OnWorldRecord = CreateGlobalForward("Shavit_OnWorldRecord", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
||||
gH_OnFinish_Post = CreateGlobalForward("Shavit_OnFinish_Post", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
||||
gH_OnWorldRecord = CreateGlobalForward("Shavit_OnWorldRecord", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
||||
gH_OnFinish_Post = CreateGlobalForward("Shavit_OnFinish_Post", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
||||
gH_OnWRDeleted = CreateGlobalForward("Shavit_OnWRDeleted", ET_Event, Param_Cell, Param_Cell, Param_Cell);
|
||||
gH_OnWorstRecord = CreateGlobalForward("Shavit_OnWorstRecord", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
||||
gH_OnWorstRecord = CreateGlobalForward("Shavit_OnWorstRecord", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
||||
|
||||
// player commands
|
||||
RegConsoleCmd("sm_wr", Command_WorldRecord, "View the leaderboard of a map. Usage: sm_wr [map]");
|
||||
@ -164,7 +165,10 @@ public void OnPluginStart()
|
||||
AutoExecConfig();
|
||||
|
||||
// admin menu
|
||||
OnAdminMenuReady(null);
|
||||
if(LibraryExists("adminmenu") && ((gH_AdminMenu = GetAdminTopMenu()) != null))
|
||||
{
|
||||
OnAdminMenuReady(gH_AdminMenu);
|
||||
}
|
||||
|
||||
// modules
|
||||
gB_Rankings = LibraryExists("shavit-rankings");
|
||||
@ -182,19 +186,47 @@ public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] n
|
||||
gI_RecentLimit = gCV_RecentLimit.IntValue;
|
||||
}
|
||||
|
||||
public void OnAdminMenuCreated(Handle topmenu)
|
||||
{
|
||||
if(gH_AdminMenu == null || (topmenu == gH_AdminMenu && gH_TimerCommands != INVALID_TOPMENUOBJECT))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gH_TimerCommands = gH_AdminMenu.AddCategory("Timer Commands", CategoryHandler, "shavit_admin", ADMFLAG_RCON);
|
||||
}
|
||||
|
||||
public void CategoryHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
|
||||
{
|
||||
if(action == TopMenuAction_DisplayTitle)
|
||||
{
|
||||
FormatEx(buffer, maxlength, "%T:", "TimerCommands", param);
|
||||
}
|
||||
|
||||
else if(action == TopMenuAction_DisplayOption)
|
||||
{
|
||||
FormatEx(buffer, maxlength, "%T", "TimerCommands", param);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAdminMenuReady(Handle topmenu)
|
||||
{
|
||||
if(LibraryExists("adminmenu") && ((gH_AdminMenu = GetAdminTopMenu()) != null))
|
||||
if((gH_AdminMenu = GetAdminTopMenu()) != null)
|
||||
{
|
||||
TopMenuObject tmoTimer = FindTopMenuCategory(gH_AdminMenu, "Timer Commands");
|
||||
if(gH_TimerCommands == INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
gH_TimerCommands = gH_AdminMenu.FindCategory("Timer Commands");
|
||||
|
||||
if(tmoTimer != INVALID_TOPMENUOBJECT)
|
||||
if(gH_TimerCommands == INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
AddToTopMenu(gH_AdminMenu, "sm_deleteall", TopMenuObject_Item, AdminMenu_DeleteAll, tmoTimer, "sm_deleteall", ADMFLAG_RCON);
|
||||
AddToTopMenu(gH_AdminMenu, "sm_delete", TopMenuObject_Item, AdminMenu_Delete, tmoTimer, "sm_delete", ADMFLAG_RCON);
|
||||
AddToTopMenu(gH_AdminMenu, "sm_deletestylerecords", TopMenuObject_Item, AdminMenu_DeleteStyleRecords, tmoTimer, "sm_deletestylerecords", ADMFLAG_RCON);
|
||||
OnAdminMenuCreated(topmenu);
|
||||
}
|
||||
}
|
||||
|
||||
gH_AdminMenu.AddItem("sm_deleteall", AdminMenu_DeleteAll, gH_TimerCommands, "sm_deleteall", ADMFLAG_RCON);
|
||||
gH_AdminMenu.AddItem("sm_delete", AdminMenu_Delete, gH_TimerCommands, "sm_delete", ADMFLAG_RCON);
|
||||
gH_AdminMenu.AddItem("sm_deletestylerecords", AdminMenu_DeleteStyleRecords, gH_TimerCommands, "sm_deletestylerecords", ADMFLAG_RCON);
|
||||
}
|
||||
}
|
||||
|
||||
public void AdminMenu_Delete(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
|
||||
@ -263,7 +295,7 @@ public void OnLibraryRemoved(const char[] name)
|
||||
|
||||
else if(StrEqual(name, "adminmenu"))
|
||||
{
|
||||
gH_AdminMenu = null;
|
||||
delete gH_AdminMenu;
|
||||
}
|
||||
}
|
||||
|
||||
@ -668,7 +700,7 @@ void DeleteSubmenu(int client)
|
||||
char[] sDisplay = new char[64];
|
||||
FormatEx(sDisplay, 64, "%s (%T: %d)", gS_StyleStrings[i][sStyleName], "WRRecord", client, gI_RecordAmount[i][gI_LastTrack[client]]);
|
||||
|
||||
menu.AddItem(sInfo, gS_StyleStrings[i][sStyleName]);
|
||||
menu.AddItem(sInfo, sDisplay, (gI_RecordAmount[i][gI_LastTrack[client]] > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
||||
}
|
||||
|
||||
menu.ExitButton = true;
|
||||
@ -1639,7 +1671,7 @@ public int RRMenu_Handler(Menu m, MenuAction action, int param1, int param2)
|
||||
void OpenSubMenu(int client, int id)
|
||||
{
|
||||
char[] sQuery = new char[512];
|
||||
FormatEx(sQuery, 512, "SELECT u.name, p.time, p.jumps, p.style, u.auth, p.date, p.map, p.strafes, p.sync, p.points, p.track FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE p.id = %d LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, id);
|
||||
FormatEx(sQuery, 512, "SELECT u.name, p.time, p.jumps, p.style, u.auth, p.date, p.map, p.strafes, p.sync, p.perfs, p.points, p.track FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE p.id = %d LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, id);
|
||||
|
||||
DataPack datapack = new DataPack();
|
||||
datapack.WriteCell(GetClientSerial(client));
|
||||
@ -1690,19 +1722,30 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
|
||||
menu.AddItem("-1", sDisplay);
|
||||
|
||||
// 2 - jumps
|
||||
int style = results.FetchInt(3);
|
||||
int jumps = results.FetchInt(2);
|
||||
|
||||
if(gA_StyleSettings[style][bAutobhop])
|
||||
{
|
||||
FormatEx(sDisplay, 128, "%T: %d", "WRJumps", client, jumps);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
float perfs = results.FetchFloat(9);
|
||||
FormatEx(sDisplay, 128, "%T: %d (%.2f%%)", "WRJumps", client, jumps, perfs);
|
||||
}
|
||||
|
||||
menu.AddItem("-1", sDisplay);
|
||||
|
||||
// 3 - style
|
||||
int style = results.FetchInt(3);
|
||||
FormatEx(sDisplay, 128, "%T: %s", "WRStyle", client, gS_StyleStrings[style][sStyleName]);
|
||||
menu.AddItem("-1", sDisplay);
|
||||
|
||||
// 6 - map
|
||||
results.FetchString(6, sMap, 192);
|
||||
|
||||
float fPoints = results.FetchFloat(9);
|
||||
float fPoints = results.FetchFloat(10);
|
||||
|
||||
if(gB_Rankings && fPoints > 0.0)
|
||||
{
|
||||
@ -1752,7 +1795,7 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
|
||||
menu.AddItem(sInfo, sMenuItem);
|
||||
}
|
||||
|
||||
GetTrackName(client, results.FetchInt(10), sTrack, 32);
|
||||
GetTrackName(client, results.FetchInt(11), sTrack, 32);
|
||||
}
|
||||
|
||||
else
|
||||
@ -1889,12 +1932,12 @@ void SQL_DBConnect()
|
||||
|
||||
if(gB_MySQL)
|
||||
{
|
||||
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `auth` CHAR(32), `map` CHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` CHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`)) ENGINE=INNODB;", gS_MySQLPrefix);
|
||||
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `auth` CHAR(32), `map` CHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` CHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`)) ENGINE=INNODB;", gS_MySQLPrefix);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `auth` CHAR(32), `map` CHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` CHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0);", gS_MySQLPrefix);
|
||||
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `auth` CHAR(32), `map` CHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` CHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0);", gS_MySQLPrefix);
|
||||
}
|
||||
|
||||
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
|
||||
@ -1934,6 +1977,9 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
|
||||
|
||||
FormatEx(sQuery, 64, "SELECT track FROM %splayertimes LIMIT 1;", gS_MySQLPrefix);
|
||||
gH_SQL.Query(SQL_TableMigration4_Callback, sQuery);
|
||||
|
||||
FormatEx(sQuery, 64, "SELECT perfs FROM %splayertimes LIMIT 1;", gS_MySQLPrefix);
|
||||
gH_SQL.Query(SQL_TableMigration5_Callback, sQuery);
|
||||
}
|
||||
|
||||
public void SQL_TableMigration1_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||
@ -1964,8 +2010,6 @@ public void SQL_AlterTable1_Callback(Database db, DBResultSet results, const cha
|
||||
if(results == null)
|
||||
{
|
||||
LogError("Timer (WR module) error! Times' table migration (1) failed. Reason: %s", error);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1974,8 +2018,6 @@ public void SQL_AlterTable2_Callback(Database db, DBResultSet results, const cha
|
||||
if(results == null)
|
||||
{
|
||||
LogError("Timer (WR module) error! Times' table migration (2) failed. Reason: %s", error);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1994,8 +2036,6 @@ public void SQL_AlterTable3_Callback(Database db, DBResultSet results, const cha
|
||||
if(results == null)
|
||||
{
|
||||
LogError("Timer (WR module) error! Times' table migration (3) failed. Reason: %s", error);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2006,11 +2046,7 @@ public void SQL_TableMigration4_Callback(Database db, DBResultSet results, const
|
||||
char[] sQuery = new char[256];
|
||||
FormatEx(sQuery, 256, "ALTER TABLE `%splayertimes` ADD %s;", gS_MySQLPrefix, (gB_MySQL)? "(`track` INT NOT NULL DEFAULT 0)":"COLUMN `track` INT NOT NULL DEFAULT 0");
|
||||
gH_SQL.Query(SQL_AlterTable4_Callback, sQuery);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
OnMapStart();
|
||||
}
|
||||
|
||||
public void SQL_AlterTable4_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||
@ -2018,6 +2054,26 @@ public void SQL_AlterTable4_Callback(Database db, DBResultSet results, const cha
|
||||
if(results == null)
|
||||
{
|
||||
LogError("Timer (WR module) error! Times' table migration (4) failed. Reason: %s", error);
|
||||
}
|
||||
}
|
||||
|
||||
public void SQL_TableMigration5_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||
{
|
||||
if(results == null)
|
||||
{
|
||||
char[] sQuery = new char[256];
|
||||
|
||||
if(gB_MySQL)
|
||||
{
|
||||
FormatEx(sQuery, 256, "ALTER TABLE `%splayertimes` ADD (`perfs` FLOAT DEFAULT 0);", gS_MySQLPrefix);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
FormatEx(sQuery, 256, "ALTER TABLE `%splayertimes` ADD COLUMN `perfs` FLOAT DEFAULT 0;", gS_MySQLPrefix);
|
||||
}
|
||||
|
||||
gH_SQL.Query(SQL_AlterTable5_Callback, sQuery);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -2025,7 +2081,19 @@ public void SQL_AlterTable4_Callback(Database db, DBResultSet results, const cha
|
||||
OnMapStart();
|
||||
}
|
||||
|
||||
public void Shavit_OnFinish(int client, int style, float time, int jumps, int strafes, float sync, int track)
|
||||
public void SQL_AlterTable5_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||
{
|
||||
if(results == null)
|
||||
{
|
||||
LogError("Timer (WR module) error! Times' table migration (5) failed. Reason: %s", error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
OnMapStart();
|
||||
}
|
||||
|
||||
public void Shavit_OnFinish(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs)
|
||||
{
|
||||
char[] sTime = new char[32];
|
||||
FormatSeconds(time, sTime, 32);
|
||||
@ -2067,6 +2135,8 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
|
||||
Call_PushCell(sync);
|
||||
Call_PushCell(track);
|
||||
Call_PushCell(oldwr);
|
||||
Call_PushCell(oldtime);
|
||||
Call_PushCell(perfs);
|
||||
Call_Finish();
|
||||
|
||||
#if defined DEBUG
|
||||
@ -2086,6 +2156,8 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
|
||||
Call_PushCell(strafes);
|
||||
Call_PushCell(sync);
|
||||
Call_PushCell(track);
|
||||
Call_PushCell(oldtime);
|
||||
Call_PushCell(perfs);
|
||||
Call_Finish();
|
||||
}
|
||||
|
||||
@ -2118,14 +2190,14 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
|
||||
return;
|
||||
}
|
||||
|
||||
FormatEx(sQuery, 512, "INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync, points, track) VALUES ('%s', '%s', %.03f, %d, %d, %d, %d, %.2f, 0.0, %d);", gS_MySQLPrefix, sAuthID, gS_Map, time, jumps, GetTime(), style, strafes, sync, track);
|
||||
FormatEx(sQuery, 512, "INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync, points, track, perfs) VALUES ('%s', '%s', %.03f, %d, %d, %d, %d, %.2f, 0.0, %d, %.2f);", gS_MySQLPrefix, sAuthID, gS_Map, time, jumps, GetTime(), style, strafes, sync, track, perfs);
|
||||
}
|
||||
|
||||
else // update
|
||||
{
|
||||
Shavit_PrintToChatAll("%s[%s]%s %T", gS_ChatStrings[sMessageVariable], sTrack, gS_ChatStrings[sMessageText], "NotFirstCompletion", LANG_SERVER, gS_ChatStrings[sMessageVariable2], client, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageStyle], gS_StyleStrings[style][sStyleName], gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable2], sTime, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], iRank, gS_ChatStrings[sMessageText], jumps, strafes, sSync, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageWarning], sDifference);
|
||||
|
||||
FormatEx(sQuery, 512, "UPDATE %splayertimes SET time = %.03f, jumps = %d, date = %d, strafes = %d, sync = %.02f, points = 0.0 WHERE map = '%s' AND auth = '%s' AND style = %d AND track = %d;", gS_MySQLPrefix, time, jumps, GetTime(), strafes, sync, gS_Map, sAuthID, style, track);
|
||||
FormatEx(sQuery, 512, "UPDATE %splayertimes SET time = %.03f, jumps = %d, date = %d, strafes = %d, sync = %.02f, points = 0.0, perfs = %.2f WHERE map = '%s' AND auth = '%s' AND style = %d AND track = %d;", gS_MySQLPrefix, time, jumps, GetTime(), strafes, sync, perfs, gS_Map, sAuthID, style, track);
|
||||
}
|
||||
|
||||
gH_SQL.Query(SQL_OnFinish_Callback, sQuery, GetClientSerial(client), DBPrio_High);
|
||||
@ -2140,6 +2212,8 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
|
||||
Call_PushCell(iRank);
|
||||
Call_PushCell(overwrite);
|
||||
Call_PushCell(track);
|
||||
Call_PushCell(oldtime);
|
||||
Call_PushCell(perfs);
|
||||
Call_Finish();
|
||||
|
||||
gF_PlayerRecord[client][style][track] = time;
|
||||
|
||||
@ -108,7 +108,8 @@ int gI_BeamSprite = -1;
|
||||
int gI_HaloSprite = -1;
|
||||
|
||||
// admin menu
|
||||
Handle gH_AdminMenu = INVALID_HANDLE;
|
||||
TopMenu gH_AdminMenu = null;
|
||||
TopMenuObject gH_TimerCommands = INVALID_TOPMENUOBJECT;
|
||||
|
||||
// misc cache
|
||||
bool gB_Late = false;
|
||||
@ -177,11 +178,6 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
|
||||
|
||||
public void OnAllPluginsLoaded()
|
||||
{
|
||||
if(gB_Late)
|
||||
{
|
||||
OnAdminMenuReady(null);
|
||||
}
|
||||
|
||||
if(gH_SQL == null)
|
||||
{
|
||||
Shavit_OnDatabaseLoaded();
|
||||
@ -252,6 +248,12 @@ public void OnPluginStart()
|
||||
|
||||
AutoExecConfig();
|
||||
|
||||
// admin menu
|
||||
if(LibraryExists("adminmenu") && ((gH_AdminMenu = GetAdminTopMenu()) != null))
|
||||
{
|
||||
OnAdminMenuReady(gH_AdminMenu);
|
||||
}
|
||||
|
||||
// misc cvars
|
||||
sv_gravity = FindConVar("sv_gravity");
|
||||
|
||||
@ -322,20 +324,14 @@ public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] n
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAdminMenuReady(Handle topmenu)
|
||||
public void OnAdminMenuCreated(Handle topmenu)
|
||||
{
|
||||
if(LibraryExists("adminmenu") && ((gH_AdminMenu = GetAdminTopMenu()) != null))
|
||||
if(gH_AdminMenu == null || (topmenu == gH_AdminMenu && gH_TimerCommands != INVALID_TOPMENUOBJECT))
|
||||
{
|
||||
TopMenuObject tmoTimer = FindTopMenuCategory(gH_AdminMenu, "Timer Commands");
|
||||
return;
|
||||
}
|
||||
|
||||
if(tmoTimer != INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
AddToTopMenu(gH_AdminMenu, "sm_zones", TopMenuObject_Item, AdminMenu_Zones, tmoTimer, "sm_zones", ADMFLAG_RCON);
|
||||
AddToTopMenu(gH_AdminMenu, "sm_deletezone", TopMenuObject_Item, AdminMenu_DeleteZone, tmoTimer, "sm_deletezone", ADMFLAG_RCON);
|
||||
AddToTopMenu(gH_AdminMenu, "sm_deleteallzones", TopMenuObject_Item, AdminMenu_DeleteAllZones, tmoTimer, "sm_deleteallzones", ADMFLAG_RCON);
|
||||
AddToTopMenu(gH_AdminMenu, "sm_zoneedit", TopMenuObject_Item, AdminMenu_ZoneEdit, tmoTimer, "sm_zoneedit", ADMFLAG_RCON);
|
||||
}
|
||||
}
|
||||
gH_TimerCommands = gH_AdminMenu.AddCategory("Timer Commands", CategoryHandler, "shavit_admin", ADMFLAG_RCON);
|
||||
}
|
||||
|
||||
public void CategoryHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
|
||||
@ -351,6 +347,27 @@ public void CategoryHandler(Handle topmenu, TopMenuAction action, TopMenuObject
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAdminMenuReady(Handle topmenu)
|
||||
{
|
||||
if((gH_AdminMenu = GetAdminTopMenu()) != null)
|
||||
{
|
||||
if(gH_TimerCommands == INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
gH_TimerCommands = gH_AdminMenu.FindCategory("Timer Commands");
|
||||
|
||||
if(gH_TimerCommands == INVALID_TOPMENUOBJECT)
|
||||
{
|
||||
OnAdminMenuCreated(topmenu);
|
||||
}
|
||||
}
|
||||
|
||||
gH_AdminMenu.AddItem("sm_zones", AdminMenu_Zones, gH_TimerCommands, "sm_zones", ADMFLAG_RCON);
|
||||
gH_AdminMenu.AddItem("sm_deletezone", AdminMenu_DeleteZone, gH_TimerCommands, "sm_deletezone", ADMFLAG_RCON);
|
||||
gH_AdminMenu.AddItem("sm_deleteallzones", AdminMenu_DeleteAllZones, gH_TimerCommands, "sm_deleteallzones", ADMFLAG_RCON);
|
||||
gH_AdminMenu.AddItem("sm_zoneedit", AdminMenu_ZoneEdit, gH_TimerCommands, "sm_zoneedit", ADMFLAG_RCON);
|
||||
}
|
||||
}
|
||||
|
||||
public void AdminMenu_Zones(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
|
||||
{
|
||||
if(action == TopMenuAction_DisplayOption)
|
||||
|
||||
@ -31,6 +31,10 @@
|
||||
"#format" "{1:s}"
|
||||
"en" "Usage: {1}"
|
||||
}
|
||||
"TimerCommands"
|
||||
{
|
||||
"en" "Timer Commands"
|
||||
}
|
||||
// ---------- Timelimit ---------- //
|
||||
"Minutes"
|
||||
{
|
||||
|
||||
@ -56,6 +56,10 @@
|
||||
{
|
||||
"en" "Sync"
|
||||
}
|
||||
"HudPerfs"
|
||||
{
|
||||
"en" "Perfect jumps"
|
||||
}
|
||||
"HudPracticeMode"
|
||||
{
|
||||
"en" "[PRACTICE]"
|
||||
|
||||
@ -83,6 +83,11 @@
|
||||
"#format" "{1:d},{2:s},{3:s}"
|
||||
"en" "Checkpoint {1} is {2}empty{3}."
|
||||
}
|
||||
"MiscSegmentedCommand"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Use {1}!cp{2} to re-open the segmented checkpoints menu."
|
||||
}
|
||||
// ---------- Menus ---------- //
|
||||
"TeleportMenuTitle"
|
||||
{
|
||||
@ -97,6 +102,10 @@
|
||||
{
|
||||
"en" "Checkpoints"
|
||||
}
|
||||
"MiscCheckpointMenuSegmented"
|
||||
{
|
||||
"en" "Segmented Checkpoints"
|
||||
}
|
||||
"MiscCheckpointWarning"
|
||||
{
|
||||
"en" "WARNING: Teleporting will stop your timer!"
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
"Phrases"
|
||||
{
|
||||
// ---------- Menus ---------- //
|
||||
"DeleteReplayAdminMenu"
|
||||
{
|
||||
"en" "Delete replay"
|
||||
}
|
||||
"DeleteReplayMenuTitle"
|
||||
{
|
||||
"en" "Delete a replay:"
|
||||
|
||||
@ -13,10 +13,6 @@
|
||||
{
|
||||
"en" "Delete map zone"
|
||||
}
|
||||
"TimerCommands"
|
||||
{
|
||||
"en" "Timer Commands"
|
||||
}
|
||||
// ---------- Commands ---------- //
|
||||
"ModifierCommandNoArgs"
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user