mirror of
https://github.com/shavitush/bhoptimer.git
synced 2025-12-07 10:28:26 +00:00
commit
a0d205247a
@ -60,6 +60,7 @@
|
|||||||
"special" "0" // For third-party modules. The core plugins will not need this setting.
|
"special" "0" // For third-party modules. The core plugins will not need this setting.
|
||||||
"specialstring" "" // For modularity. Separated with semicolon. Built-in flags: "segments".
|
"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.
|
"permission" "" // Permission required. Syntax: "flag;override". For example "p;style_tas" to require the 'p' flag or the "style_tas" override.
|
||||||
|
"ordering" "0" // Ordering in menus where styles appear. If this value is not present, style ID will be used instead.
|
||||||
}
|
}
|
||||||
|
|
||||||
"1"
|
"1"
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#define _shavit_included
|
#define _shavit_included
|
||||||
|
|
||||||
#define SHAVIT_VERSION "2.4.0"
|
#define SHAVIT_VERSION "2.4.1"
|
||||||
#define STYLE_LIMIT 256
|
#define STYLE_LIMIT 256
|
||||||
#define MAX_ZONES 64
|
#define MAX_ZONES 64
|
||||||
#define MAX_NAME_LENGTH_SQL 32
|
#define MAX_NAME_LENGTH_SQL 32
|
||||||
@ -156,6 +156,7 @@ enum struct stylesettings_t
|
|||||||
bool bStrafeCountD;
|
bool bStrafeCountD;
|
||||||
float fRankingMultiplier;
|
float fRankingMultiplier;
|
||||||
int iSpecial;
|
int iSpecial;
|
||||||
|
int iOrdering;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum struct chatstrings_t
|
enum struct chatstrings_t
|
||||||
@ -546,6 +547,18 @@ forward void Shavit_OnWorstRecord(int client, int style, float time, int jumps,
|
|||||||
*/
|
*/
|
||||||
forward void Shavit_OnTierAssigned(const char[] map, int tier);
|
forward void Shavit_OnTierAssigned(const char[] map, int tier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets called when the server acknowledges the client's ranking status.
|
||||||
|
* It is called after OnClientPostAdminCheck and at forced rank recalculations.
|
||||||
|
*
|
||||||
|
* @param client Client index.
|
||||||
|
* @param rank Client's rank. (0 if unranked or unassigned)
|
||||||
|
* @param points Client's points. (0.0 if unranked or unassigned)
|
||||||
|
* @param first True if the forward is called after the initial connection, false if it is caused by recalculation.
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
forward void Shavit_OnRankAssigned(int client, int rank, float points, bool first);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when replay playback starts.
|
* Called when replay playback starts.
|
||||||
*
|
*
|
||||||
@ -652,6 +665,18 @@ native void Shavit_Replay_DeleteMap(const char[] map);
|
|||||||
*/
|
*/
|
||||||
native void Shavit_Rankings_DeleteMap(const char[] map);
|
native void Shavit_Rankings_DeleteMap(const char[] map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes a player's bhop style.
|
||||||
|
*
|
||||||
|
* @param client Client index.
|
||||||
|
* @param style Style.
|
||||||
|
* @param force Ignore style permissions.
|
||||||
|
* @param manual Is it a manual style change? (Was it caused by user interaction?)
|
||||||
|
* @param noforward Bypasses the call to `Shavit_OnStyleChanged`.
|
||||||
|
* @return False if failed due to lack of access, true otherwise.
|
||||||
|
*/
|
||||||
|
native bool Shavit_ChangeClientStyle(int client, int style, bool force = false, bool manual = false, bool noforward = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finishes the map for a player, with their current timer stats.
|
* Finishes the map for a player, with their current timer stats.
|
||||||
* Will not teleport the player to anywhere, it's handled inside the mapzones plugin.
|
* Will not teleport the player to anywhere, it's handled inside the mapzones plugin.
|
||||||
@ -762,6 +787,13 @@ native void Shavit_GetWRTime(int style, float &time, int track);
|
|||||||
*/
|
*/
|
||||||
native float Shavit_GetWorldRecord(int style, int track);
|
native float Shavit_GetWorldRecord(int style, int track);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads WR leaderboards cache for the current map.
|
||||||
|
*
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
native void Shavit_ReloadLeaderboards();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the WR's record ID for the current map on a variable.
|
* Saves the WR's record ID for the current map on a variable.
|
||||||
* Unused in base plugins, as of pre-1.4b.
|
* Unused in base plugins, as of pre-1.4b.
|
||||||
@ -878,6 +910,17 @@ native void Shavit_PauseTimer(int client);
|
|||||||
*/
|
*/
|
||||||
native void Shavit_ResumeTimer(int client);
|
native void Shavit_ResumeTimer(int client);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the specified replay file.
|
||||||
|
* Replay data will be unloaded if necessary.
|
||||||
|
*
|
||||||
|
* @param map Map display name.
|
||||||
|
* @param style Bhop style.
|
||||||
|
* @param track Timer track.
|
||||||
|
* @return true if replay existed, false otherwise.
|
||||||
|
*/
|
||||||
|
native bool Shavit_DeleteReplay(const char[] map, int style, int track);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the engine time of the replay bot's first frame.
|
* Retrieves the engine time of the replay bot's first frame.
|
||||||
*
|
*
|
||||||
@ -1063,6 +1106,15 @@ native int Shavit_GetStyleStrings(int style, int stringtype, char[] StyleStrings
|
|||||||
*/
|
*/
|
||||||
native int Shavit_GetStyleCount();
|
native int Shavit_GetStyleCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an array with style IDs in their configured menu ordering as specified in the styles config.
|
||||||
|
*
|
||||||
|
* @param arr Reference to array to fill with style IDs.
|
||||||
|
* @param size Array size.
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
native void Shavit_GetOrderedStyles(int[] arr, int size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves chat related strings on string references.
|
* Saves chat related strings on string references.
|
||||||
*
|
*
|
||||||
@ -1212,6 +1264,14 @@ native StringMap Shavit_GetMapTiers();
|
|||||||
*/
|
*/
|
||||||
native bool Shavit_HasStyleAccess(int client, int style);
|
native bool Shavit_HasStyleAccess(int client, int style);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether a client's timer is paused or not.
|
||||||
|
*
|
||||||
|
* @param client Client index.
|
||||||
|
* @return Boolean value.
|
||||||
|
*/
|
||||||
|
native bool Shavit_IsPaused(int client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this native when printing anything in chat if it's related to the timer.
|
* Use this native when printing anything in chat if it's related to the timer.
|
||||||
* This native will auto-assign colors and a chat prefix.
|
* This native will auto-assign colors and a chat prefix.
|
||||||
@ -1265,6 +1325,8 @@ public SharedPlugin __pl_shavit =
|
|||||||
#if !defined REQUIRE_PLUGIN
|
#if !defined REQUIRE_PLUGIN
|
||||||
public void __pl_shavit_SetNTVOptional()
|
public void __pl_shavit_SetNTVOptional()
|
||||||
{
|
{
|
||||||
|
MarkNativeAsOptional("Shavit_ChangeClientStyle");
|
||||||
|
MarkNativeAsOptional("Shavit_DeleteReplay");
|
||||||
MarkNativeAsOptional("Shavit_FinishMap");
|
MarkNativeAsOptional("Shavit_FinishMap");
|
||||||
MarkNativeAsOptional("Shavit_ForceHUDUpdate");
|
MarkNativeAsOptional("Shavit_ForceHUDUpdate");
|
||||||
MarkNativeAsOptional("Shavit_FormatChat");
|
MarkNativeAsOptional("Shavit_FormatChat");
|
||||||
@ -1279,6 +1341,7 @@ public void __pl_shavit_SetNTVOptional()
|
|||||||
MarkNativeAsOptional("Shavit_GetHUDSettings");
|
MarkNativeAsOptional("Shavit_GetHUDSettings");
|
||||||
MarkNativeAsOptional("Shavit_GetMapTier");
|
MarkNativeAsOptional("Shavit_GetMapTier");
|
||||||
MarkNativeAsOptional("Shavit_GetMapTiers");
|
MarkNativeAsOptional("Shavit_GetMapTiers");
|
||||||
|
MarkNativeAsOptional("Shavit_GetOrderedStyles");
|
||||||
MarkNativeAsOptional("Shavit_GetPerfectJumps");
|
MarkNativeAsOptional("Shavit_GetPerfectJumps");
|
||||||
MarkNativeAsOptional("Shavit_GetPlayerPB");
|
MarkNativeAsOptional("Shavit_GetPlayerPB");
|
||||||
MarkNativeAsOptional("Shavit_GetPoints");
|
MarkNativeAsOptional("Shavit_GetPoints");
|
||||||
@ -1315,6 +1378,7 @@ public void __pl_shavit_SetNTVOptional()
|
|||||||
MarkNativeAsOptional("Shavit_InsideZone");
|
MarkNativeAsOptional("Shavit_InsideZone");
|
||||||
MarkNativeAsOptional("Shavit_IsClientCreatingZone");
|
MarkNativeAsOptional("Shavit_IsClientCreatingZone");
|
||||||
MarkNativeAsOptional("Shavit_IsKZMap");
|
MarkNativeAsOptional("Shavit_IsKZMap");
|
||||||
|
MarkNativeAsOptional("Shavit_IsPaused");
|
||||||
MarkNativeAsOptional("Shavit_IsPracticeMode");
|
MarkNativeAsOptional("Shavit_IsPracticeMode");
|
||||||
MarkNativeAsOptional("Shavit_IsReplayDataLoaded");
|
MarkNativeAsOptional("Shavit_IsReplayDataLoaded");
|
||||||
MarkNativeAsOptional("Shavit_LoadSnapshot");
|
MarkNativeAsOptional("Shavit_LoadSnapshot");
|
||||||
@ -1323,6 +1387,7 @@ public void __pl_shavit_SetNTVOptional()
|
|||||||
MarkNativeAsOptional("Shavit_PauseTimer");
|
MarkNativeAsOptional("Shavit_PauseTimer");
|
||||||
MarkNativeAsOptional("Shavit_PrintToChat");
|
MarkNativeAsOptional("Shavit_PrintToChat");
|
||||||
MarkNativeAsOptional("Shavit_Rankings_DeleteMap");
|
MarkNativeAsOptional("Shavit_Rankings_DeleteMap");
|
||||||
|
MarkNativeAsOptional("Shavit_ReloadLeaderboards");
|
||||||
MarkNativeAsOptional("Shavit_ReloadReplay");
|
MarkNativeAsOptional("Shavit_ReloadReplay");
|
||||||
MarkNativeAsOptional("Shavit_ReloadReplays");
|
MarkNativeAsOptional("Shavit_ReloadReplays");
|
||||||
MarkNativeAsOptional("Shavit_Replay_DeleteMap");
|
MarkNativeAsOptional("Shavit_Replay_DeleteMap");
|
||||||
|
|||||||
@ -131,6 +131,7 @@ ConVar sv_enablebunnyhopping = null;
|
|||||||
// timer settings
|
// timer settings
|
||||||
bool gB_Registered = false;
|
bool gB_Registered = false;
|
||||||
int gI_Styles = 0;
|
int gI_Styles = 0;
|
||||||
|
int gI_OrderedStyles[STYLE_LIMIT];
|
||||||
stylestrings_t gS_StyleStrings[STYLE_LIMIT];
|
stylestrings_t gS_StyleStrings[STYLE_LIMIT];
|
||||||
stylesettings_t gA_StyleSettings[STYLE_LIMIT];
|
stylesettings_t gA_StyleSettings[STYLE_LIMIT];
|
||||||
|
|
||||||
@ -142,6 +143,8 @@ bool gB_StopChatSound = false;
|
|||||||
bool gB_HookedJump = false;
|
bool gB_HookedJump = false;
|
||||||
char gS_LogPath[PLATFORM_MAX_PATH];
|
char gS_LogPath[PLATFORM_MAX_PATH];
|
||||||
char gS_DeleteMap[MAXPLAYERS+1][160];
|
char gS_DeleteMap[MAXPLAYERS+1][160];
|
||||||
|
char gS_WipePlayerID[MAXPLAYERS+1][32];
|
||||||
|
char gS_Verification[MAXPLAYERS+1][16];
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
int gI_StyleFlag[STYLE_LIMIT];
|
int gI_StyleFlag[STYLE_LIMIT];
|
||||||
@ -161,6 +164,7 @@ public Plugin myinfo =
|
|||||||
|
|
||||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
||||||
{
|
{
|
||||||
|
CreateNative("Shavit_ChangeClientStyle", Native_ChangeClientStyle);
|
||||||
CreateNative("Shavit_FinishMap", Native_FinishMap);
|
CreateNative("Shavit_FinishMap", Native_FinishMap);
|
||||||
CreateNative("Shavit_GetBhopStyle", Native_GetBhopStyle);
|
CreateNative("Shavit_GetBhopStyle", Native_GetBhopStyle);
|
||||||
CreateNative("Shavit_GetChatStrings", Native_GetChatStrings);
|
CreateNative("Shavit_GetChatStrings", Native_GetChatStrings);
|
||||||
@ -170,6 +174,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
|
|||||||
CreateNative("Shavit_GetDatabase", Native_GetDatabase);
|
CreateNative("Shavit_GetDatabase", Native_GetDatabase);
|
||||||
CreateNative("Shavit_GetDB", Native_GetDB);
|
CreateNative("Shavit_GetDB", Native_GetDB);
|
||||||
CreateNative("Shavit_GetGameType", Native_GetGameType);
|
CreateNative("Shavit_GetGameType", Native_GetGameType);
|
||||||
|
CreateNative("Shavit_GetOrderedStyles", Native_GetOrderedStyles);
|
||||||
CreateNative("Shavit_GetPerfectJumps", Native_GetPerfectJumps);
|
CreateNative("Shavit_GetPerfectJumps", Native_GetPerfectJumps);
|
||||||
CreateNative("Shavit_GetStrafeCount", Native_GetStrafeCount);
|
CreateNative("Shavit_GetStrafeCount", Native_GetStrafeCount);
|
||||||
CreateNative("Shavit_GetStyleCount", Native_GetStyleCount);
|
CreateNative("Shavit_GetStyleCount", Native_GetStyleCount);
|
||||||
@ -180,6 +185,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
|
|||||||
CreateNative("Shavit_GetTimerStatus", Native_GetTimerStatus);
|
CreateNative("Shavit_GetTimerStatus", Native_GetTimerStatus);
|
||||||
CreateNative("Shavit_HasStyleAccess", Native_HasStyleAccess);
|
CreateNative("Shavit_HasStyleAccess", Native_HasStyleAccess);
|
||||||
CreateNative("Shavit_IsKZMap", Native_IsKZMap);
|
CreateNative("Shavit_IsKZMap", Native_IsKZMap);
|
||||||
|
CreateNative("Shavit_IsPaused", Native_IsPaused);
|
||||||
CreateNative("Shavit_IsPracticeMode", Native_IsPracticeMode);
|
CreateNative("Shavit_IsPracticeMode", Native_IsPracticeMode);
|
||||||
CreateNative("Shavit_LoadSnapshot", Native_LoadSnapshot);
|
CreateNative("Shavit_LoadSnapshot", Native_LoadSnapshot);
|
||||||
CreateNative("Shavit_LogMessage", Native_LogMessage);
|
CreateNative("Shavit_LogMessage", Native_LogMessage);
|
||||||
@ -222,6 +228,7 @@ public void OnPluginStart()
|
|||||||
gH_Forwards_OnTimerIncrementPost = CreateGlobalForward("Shavit_OnTimeIncrementPost", ET_Event, Param_Cell, Param_Cell, Param_Array);
|
gH_Forwards_OnTimerIncrementPost = CreateGlobalForward("Shavit_OnTimeIncrementPost", ET_Event, Param_Cell, Param_Cell, Param_Array);
|
||||||
|
|
||||||
LoadTranslations("shavit-core.phrases");
|
LoadTranslations("shavit-core.phrases");
|
||||||
|
LoadTranslations("shavit-common.phrases");
|
||||||
|
|
||||||
// game types
|
// game types
|
||||||
gEV_Type = GetEngineVersion();
|
gEV_Type = GetEngineVersion();
|
||||||
@ -297,6 +304,7 @@ public void OnPluginStart()
|
|||||||
|
|
||||||
// admin
|
// admin
|
||||||
RegAdminCmd("sm_deletemap", Command_DeleteMap, ADMFLAG_ROOT, "Deletes all map data. Usage: sm_deletemap <map>");
|
RegAdminCmd("sm_deletemap", Command_DeleteMap, ADMFLAG_ROOT, "Deletes all map data. Usage: sm_deletemap <map>");
|
||||||
|
RegAdminCmd("sm_wipeplayer", Command_WipePlayer, ADMFLAG_BAN, "Wipes all bhoptimer data for specified player. Usage: sm_wipeplayer <steamid3>");
|
||||||
// commands END
|
// commands END
|
||||||
|
|
||||||
// logs
|
// logs
|
||||||
@ -470,7 +478,10 @@ public Action Command_StartTimer(int client, int args)
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Shavit_PrintToChat(client, "%T", "StartZoneUndefined", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText);
|
char sTrack[32];
|
||||||
|
GetTrackName(client, track, sTrack, 32);
|
||||||
|
|
||||||
|
Shavit_PrintToChat(client, "%T", "StartZoneUndefined", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText, gS_ChatStrings.sVariable2, sTrack, gS_ChatStrings.sText);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
@ -636,6 +647,214 @@ public Action Command_DeleteMap(int client, int args)
|
|||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Action Command_WipePlayer(int client, int args)
|
||||||
|
{
|
||||||
|
if(args == 0)
|
||||||
|
{
|
||||||
|
ReplyToCommand(client, "Usage: sm_wipeplayer <steamid3>\nAfter entering a SteamID, you will be prompted with a verification captcha.");
|
||||||
|
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
char sArgString[32];
|
||||||
|
GetCmdArgString(sArgString, 32);
|
||||||
|
|
||||||
|
if(strlen(gS_Verification[client]) == 0 || !StrEqual(sArgString, gS_Verification[client]))
|
||||||
|
{
|
||||||
|
char sAlphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#";
|
||||||
|
|
||||||
|
for(int i = 0; i < GetRandomInt(5, 7); i++)
|
||||||
|
{
|
||||||
|
gS_Verification[client][i] = sAlphabet[GetRandomInt(0, sizeof(sAlphabet))];
|
||||||
|
}
|
||||||
|
|
||||||
|
strcopy(gS_WipePlayerID[client], 32, sArgString);
|
||||||
|
|
||||||
|
Shavit_PrintToChat(client, "Preparing to delete all user data for SteamID %s%s%s. To confirm, enter %s!wipeplayer %s",
|
||||||
|
gS_ChatStrings.sVariable, sArgString, gS_ChatStrings.sText, gS_ChatStrings.sVariable2, gS_Verification[client]);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int iLength = ((strlen(gS_WipePlayerID[client]) * 2) + 1);
|
||||||
|
char[] sEscapedAuthID = new char[iLength];
|
||||||
|
gH_SQL.Escape(gS_WipePlayerID[client], sEscapedAuthID, iLength);
|
||||||
|
|
||||||
|
Shavit_PrintToChat(client, "Deleting data for SteamID %s%s%s...",
|
||||||
|
gS_ChatStrings.sVariable, sEscapedAuthID, gS_ChatStrings.sText);
|
||||||
|
|
||||||
|
DeleteUserData(client, sEscapedAuthID);
|
||||||
|
|
||||||
|
strcopy(gS_Verification[client], 32, "");
|
||||||
|
strcopy(gS_WipePlayerID[client], 32, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteUserData(int client, const char[] sAuthID3)
|
||||||
|
{
|
||||||
|
if(gB_Replay)
|
||||||
|
{
|
||||||
|
char sQueryGetWorldRecords[256];
|
||||||
|
FormatEx(sQueryGetWorldRecords, 256,
|
||||||
|
"SELECT map, id, style, track FROM %splayertimes WHERE auth = '%s' GROUP BY map, style, track;",
|
||||||
|
gS_MySQLPrefix, sAuthID3);
|
||||||
|
|
||||||
|
DataPack pack = new DataPack();
|
||||||
|
pack.WriteCell(client);
|
||||||
|
pack.WriteString(sAuthID3);
|
||||||
|
|
||||||
|
gH_SQL.Query(SQL_DeleteUserData_GetRecords_Callback, sQueryGetWorldRecords, pack, DBPrio_High);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char sQueryDeleteUserTimes[256];
|
||||||
|
FormatEx(sQueryDeleteUserTimes, 256,
|
||||||
|
"DELETE FROM %splayertimes WHERE auth = '%s';",
|
||||||
|
gS_MySQLPrefix, sAuthID3);
|
||||||
|
|
||||||
|
DataPack steamPack = new DataPack();
|
||||||
|
steamPack.WriteString(sAuthID3);
|
||||||
|
steamPack.WriteCell(client);
|
||||||
|
|
||||||
|
gH_SQL.Query(SQL_DeleteUserTimes_Callback, sQueryDeleteUserTimes, steamPack, DBPrio_High);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SQL_DeleteUserData_GetRecords_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||||
|
{
|
||||||
|
DataPack pack = view_as<DataPack>(data);
|
||||||
|
pack.Reset();
|
||||||
|
int client = pack.ReadCell();
|
||||||
|
|
||||||
|
char sAuthID3[32];
|
||||||
|
pack.ReadString(sAuthID3, 32);
|
||||||
|
delete pack;
|
||||||
|
|
||||||
|
if(results == null)
|
||||||
|
{
|
||||||
|
LogError("Timer error! Failed to wipe user data (wipe | get player records). Reason: %s", error);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transaction trans = new Transaction();
|
||||||
|
|
||||||
|
while(results.FetchRow())
|
||||||
|
{
|
||||||
|
char map[160];
|
||||||
|
results.FetchString(0, map, 160);
|
||||||
|
|
||||||
|
int id = results.FetchInt(1);
|
||||||
|
int style = results.FetchInt(2);
|
||||||
|
int track = results.FetchInt(3);
|
||||||
|
|
||||||
|
char sQueryGetWorldRecordID[256];
|
||||||
|
FormatEx(sQueryGetWorldRecordID, 256,
|
||||||
|
"SELECT id FROM %splayertimes WHERE map = '%s' AND style = %d AND track = %d ORDER BY time LIMIT 1;",
|
||||||
|
gS_MySQLPrefix, map, style, track);
|
||||||
|
|
||||||
|
DataPack transPack = new DataPack();
|
||||||
|
transPack.WriteString(map);
|
||||||
|
transPack.WriteCell(id);
|
||||||
|
transPack.WriteCell(style);
|
||||||
|
transPack.WriteCell(track);
|
||||||
|
|
||||||
|
trans.AddQuery(sQueryGetWorldRecordID, transPack);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataPack steamPack = new DataPack();
|
||||||
|
steamPack.WriteString(sAuthID3);
|
||||||
|
steamPack.WriteCell(client);
|
||||||
|
|
||||||
|
gH_SQL.Execute(trans, Trans_OnRecordCompare, INVALID_FUNCTION, steamPack, DBPrio_High);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Trans_OnRecordCompare(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData)
|
||||||
|
{
|
||||||
|
DataPack pack = view_as<DataPack>(data);
|
||||||
|
pack.Reset();
|
||||||
|
char sAuthID3[32];
|
||||||
|
pack.ReadString(sAuthID3, 32);
|
||||||
|
|
||||||
|
for(int i = 0; i < numQueries; i++)
|
||||||
|
{
|
||||||
|
DataPack hQueryPack = view_as<DataPack>(queryData[i]);
|
||||||
|
hQueryPack.Reset();
|
||||||
|
char sMap[32];
|
||||||
|
hQueryPack.ReadString(sMap, 32);
|
||||||
|
|
||||||
|
int iRecordID = hQueryPack.ReadCell();
|
||||||
|
int iStyle = hQueryPack.ReadCell();
|
||||||
|
int iTrack = hQueryPack.ReadCell();
|
||||||
|
delete hQueryPack;
|
||||||
|
|
||||||
|
if(results[i] != null && results[i].FetchRow())
|
||||||
|
{
|
||||||
|
int iWR = results[i].FetchInt(0);
|
||||||
|
|
||||||
|
if(iWR == iRecordID)
|
||||||
|
{
|
||||||
|
Shavit_DeleteReplay(sMap, iStyle, iTrack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char sQueryDeleteUserTimes[256];
|
||||||
|
FormatEx(sQueryDeleteUserTimes, 256,
|
||||||
|
"DELETE FROM %splayertimes WHERE auth = '%s';",
|
||||||
|
gS_MySQLPrefix, sAuthID3);
|
||||||
|
|
||||||
|
gH_SQL.Query(SQL_DeleteUserTimes_Callback, sQueryDeleteUserTimes, pack, DBPrio_High);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SQL_DeleteUserTimes_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||||
|
{
|
||||||
|
DataPack pack = view_as<DataPack>(data);
|
||||||
|
pack.Reset();
|
||||||
|
char sAuthID3[32];
|
||||||
|
pack.ReadString(sAuthID3, 32);
|
||||||
|
|
||||||
|
if(results == null)
|
||||||
|
{
|
||||||
|
LogError("Timer error! Failed to wipe user data (wipe | delete user times). Reason: %s", error);
|
||||||
|
|
||||||
|
delete pack;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char sQueryDeleteUsers[256];
|
||||||
|
FormatEx(sQueryDeleteUsers, 256, "DELETE FROM %susers WHERE auth = '%s';",
|
||||||
|
gS_MySQLPrefix, sAuthID3);
|
||||||
|
|
||||||
|
gH_SQL.Query(SQL_DeleteUserData_Callback, sQueryDeleteUsers, pack, DBPrio_High);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SQL_DeleteUserData_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||||
|
{
|
||||||
|
DataPack pack = view_as<DataPack>(data);
|
||||||
|
pack.Reset();
|
||||||
|
char sAuthID3[32];
|
||||||
|
pack.ReadString(sAuthID3, 32);
|
||||||
|
int client = pack.ReadCell();
|
||||||
|
delete pack;
|
||||||
|
|
||||||
|
if(results == null)
|
||||||
|
{
|
||||||
|
LogError("Timer error! Failed to wipe user data (wipe | delete user data, id %s). Reason: %s", error, sAuthID3);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shavit_ReloadLeaderboards();
|
||||||
|
|
||||||
|
Shavit_PrintToChat(client, "Finished wiping timer data for user %s%s%s.",
|
||||||
|
gS_ChatStrings.sVariable, sAuthID3, gS_ChatStrings.sText);
|
||||||
|
}
|
||||||
|
|
||||||
public Action Command_AutoBhop(int client, int args)
|
public Action Command_AutoBhop(int client, int args)
|
||||||
{
|
{
|
||||||
if(!IsValidClient(client))
|
if(!IsValidClient(client))
|
||||||
@ -683,14 +902,16 @@ public Action Command_Style(int client, int args)
|
|||||||
|
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
for(int i = 0; i < gI_Styles; i++)
|
||||||
{
|
{
|
||||||
|
int iStyle = gI_OrderedStyles[i];
|
||||||
|
|
||||||
char sInfo[8];
|
char sInfo[8];
|
||||||
IntToString(i, sInfo, 8);
|
IntToString(iStyle, sInfo, 8);
|
||||||
|
|
||||||
char sDisplay[64];
|
char sDisplay[64];
|
||||||
|
|
||||||
if(gA_StyleSettings[i].bUnranked)
|
if(gA_StyleSettings[iStyle].bUnranked)
|
||||||
{
|
{
|
||||||
FormatEx(sDisplay, 64, "%T %s", "StyleUnranked", client, gS_StyleStrings[i].sStyleName);
|
FormatEx(sDisplay, 64, "%T %s", "StyleUnranked", client, gS_StyleStrings[iStyle].sStyleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -699,7 +920,7 @@ public Action Command_Style(int client, int args)
|
|||||||
|
|
||||||
if(gB_WR)
|
if(gB_WR)
|
||||||
{
|
{
|
||||||
time = Shavit_GetWorldRecord(i, Track_Main);
|
time = Shavit_GetWorldRecord(iStyle, Track_Main);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(time > 0.0)
|
if(time > 0.0)
|
||||||
@ -707,16 +928,16 @@ public Action Command_Style(int client, int args)
|
|||||||
char sTime[32];
|
char sTime[32];
|
||||||
FormatSeconds(time, sTime, 32, false);
|
FormatSeconds(time, sTime, 32, false);
|
||||||
|
|
||||||
FormatEx(sDisplay, 64, "%s - WR: %s", gS_StyleStrings[i].sStyleName, sTime);
|
FormatEx(sDisplay, 64, "%s - WR: %s", gS_StyleStrings[iStyle].sStyleName, sTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcopy(sDisplay, 64, gS_StyleStrings[i].sStyleName);
|
strcopy(sDisplay, 64, gS_StyleStrings[iStyle].sStyleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.AddItem(sInfo, sDisplay, (gA_Timers[client].iStyle == i || !Shavit_HasStyleAccess(client, i))? ITEMDRAW_DISABLED:ITEMDRAW_DEFAULT);
|
menu.AddItem(sInfo, sDisplay, (gA_Timers[client].iStyle == iStyle || !Shavit_HasStyleAccess(client, iStyle))? ITEMDRAW_DISABLED:ITEMDRAW_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// should NEVER happen
|
// should NEVER happen
|
||||||
@ -933,6 +1154,11 @@ public int Native_GetGameType(Handle handler, int numParams)
|
|||||||
return view_as<int>(gEV_Type);
|
return view_as<int>(gEV_Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Native_GetOrderedStyles(Handle handler, int numParams)
|
||||||
|
{
|
||||||
|
return SetNativeArray(1, gI_OrderedStyles, GetNativeCell(2));
|
||||||
|
}
|
||||||
|
|
||||||
public int Native_GetDatabase(Handle handler, int numParams)
|
public int Native_GetDatabase(Handle handler, int numParams)
|
||||||
{
|
{
|
||||||
return view_as<int>(CloneHandle(gH_SQL, handler));
|
return view_as<int>(CloneHandle(gH_SQL, handler));
|
||||||
@ -1009,6 +1235,34 @@ public int Native_StopTimer(Handle handler, int numParams)
|
|||||||
Call_Finish();
|
Call_Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Native_ChangeClientStyle(Handle handler, int numParams)
|
||||||
|
{
|
||||||
|
int client = GetNativeCell(1);
|
||||||
|
int style = GetNativeCell(2);
|
||||||
|
bool force = view_as<bool>(GetNativeCell(3));
|
||||||
|
bool manual = view_as<bool>(GetNativeCell(4));
|
||||||
|
bool noforward = view_as<bool>(GetNativeCell(5));
|
||||||
|
|
||||||
|
if(force || Shavit_HasStyleAccess(client, style))
|
||||||
|
{
|
||||||
|
if(noforward)
|
||||||
|
{
|
||||||
|
gA_Timers[client].iStyle = style;
|
||||||
|
|
||||||
|
UpdateStyleSettings(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CallOnStyleChanged(client, gA_Timers[client].iStyle, style, manual);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public int Native_FinishMap(Handle handler, int numParams)
|
public int Native_FinishMap(Handle handler, int numParams)
|
||||||
{
|
{
|
||||||
int client = GetNativeCell(1);
|
int client = GetNativeCell(1);
|
||||||
@ -1101,19 +1355,26 @@ public int Native_PrintToChat(Handle handler, int numParams)
|
|||||||
{
|
{
|
||||||
int client = GetNativeCell(1);
|
int client = GetNativeCell(1);
|
||||||
|
|
||||||
if(!IsClientInGame(client))
|
|
||||||
{
|
|
||||||
gB_StopChatSound = false;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int iWritten = 0; // useless?
|
static int iWritten = 0; // useless?
|
||||||
|
|
||||||
char sBuffer[300];
|
char sBuffer[300];
|
||||||
FormatNativeString(0, 2, 3, 300, iWritten, sBuffer);
|
FormatNativeString(0, 2, 3, 300, iWritten, sBuffer);
|
||||||
Format(sBuffer, 300, "%s %s%s", gS_ChatStrings.sPrefix, gS_ChatStrings.sText, sBuffer);
|
Format(sBuffer, 300, "%s %s%s", gS_ChatStrings.sPrefix, gS_ChatStrings.sText, sBuffer);
|
||||||
|
|
||||||
|
if(client == 0)
|
||||||
|
{
|
||||||
|
PrintToServer("%s", sBuffer);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!IsClientInGame(client))
|
||||||
|
{
|
||||||
|
gB_StopChatSound = false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Handle hSayText2 = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS);
|
Handle hSayText2 = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS);
|
||||||
|
|
||||||
if(gB_Protobuf)
|
if(gB_Protobuf)
|
||||||
@ -1144,6 +1405,8 @@ public int Native_PrintToChat(Handle handler, int numParams)
|
|||||||
EndMessage();
|
EndMessage();
|
||||||
|
|
||||||
gB_StopChatSound = false;
|
gB_StopChatSound = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Native_RestartTimer(Handle handler, int numParams)
|
public int Native_RestartTimer(Handle handler, int numParams)
|
||||||
@ -1240,6 +1503,11 @@ public int Native_SetPracticeMode(Handle handler, int numParams)
|
|||||||
gA_Timers[client].bPracticeMode = practice;
|
gA_Timers[client].bPracticeMode = practice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Native_IsPaused(Handle handler, int numParams)
|
||||||
|
{
|
||||||
|
return view_as<int>(gA_Timers[GetNativeCell(1)].bPaused);
|
||||||
|
}
|
||||||
|
|
||||||
public int Native_IsPracticeMode(Handle handler, int numParams)
|
public int Native_IsPracticeMode(Handle handler, int numParams)
|
||||||
{
|
{
|
||||||
return view_as<int>(gA_Timers[GetNativeCell(1)].bPracticeMode);
|
return view_as<int>(gA_Timers[GetNativeCell(1)].bPracticeMode);
|
||||||
@ -1618,6 +1886,7 @@ bool LoadStyles()
|
|||||||
gA_StyleSettings[i].bStrafeCountD = view_as<bool>(kv.GetNum("strafe_count_d", true));
|
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].fRankingMultiplier = kv.GetFloat("rankingmultiplier", 1.00);
|
||||||
gA_StyleSettings[i].iSpecial = kv.GetNum("special", 0);
|
gA_StyleSettings[i].iSpecial = kv.GetNum("special", 0);
|
||||||
|
gA_StyleSettings[i].iOrdering = kv.GetNum("ordering", i);
|
||||||
|
|
||||||
if(!gB_Registered && strlen(gS_StyleStrings[i].sChangeCommand) > 0)
|
if(!gB_Registered && strlen(gS_StyleStrings[i].sChangeCommand) > 0)
|
||||||
{
|
{
|
||||||
@ -1656,7 +1925,7 @@ bool LoadStyles()
|
|||||||
strcopy(gS_StyleOverride[i], 32, (iCount >= 2)? sText[1]:"");
|
strcopy(gS_StyleOverride[i], 32, (iCount >= 2)? sText[1]:"");
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
gI_OrderedStyles[i] = i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(kv.GotoNextKey());
|
while(kv.GotoNextKey());
|
||||||
@ -1666,6 +1935,8 @@ bool LoadStyles()
|
|||||||
gI_Styles = i;
|
gI_Styles = i;
|
||||||
gB_Registered = true;
|
gB_Registered = true;
|
||||||
|
|
||||||
|
SortCustom1D(gI_OrderedStyles, gI_Styles, SortAscending_StyleOrder);
|
||||||
|
|
||||||
Call_StartForward(gH_Forwards_OnStyleConfigLoaded);
|
Call_StartForward(gH_Forwards_OnStyleConfigLoaded);
|
||||||
Call_PushCell(gI_Styles);
|
Call_PushCell(gI_Styles);
|
||||||
Call_Finish();
|
Call_Finish();
|
||||||
@ -1673,6 +1944,27 @@ bool LoadStyles()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int SortAscending_StyleOrder(int index1, int index2, const int[] array, any hndl)
|
||||||
|
{
|
||||||
|
int order1 = gA_StyleSettings[index1].iOrdering;
|
||||||
|
int order2 = gA_StyleSettings[index2].iOrdering;
|
||||||
|
|
||||||
|
if(order1 < order2)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(order1 == order2)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Action Command_StyleChange(int client, int args)
|
public Action Command_StyleChange(int client, int args)
|
||||||
{
|
{
|
||||||
char sCommand[128];
|
char sCommand[128];
|
||||||
@ -2397,3 +2689,17 @@ void UpdateStyleSettings(int client)
|
|||||||
|
|
||||||
SetEntityGravity(client, view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fGravityMultiplier));
|
SetEntityGravity(client, view_as<float>(gA_StyleSettings[gA_Timers[client].iStyle].fGravityMultiplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetTrackName(int client, int track, char[] output, int size)
|
||||||
|
{
|
||||||
|
if(track < 0 || track >= TRACKS_SIZE)
|
||||||
|
{
|
||||||
|
FormatEx(output, size, "%T", "Track_Unknown", client);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char sTrack[16];
|
||||||
|
FormatEx(sTrack, 16, "Track_%d", track);
|
||||||
|
FormatEx(output, size, "%T", sTrack, client);
|
||||||
|
}
|
||||||
|
|||||||
@ -39,6 +39,8 @@
|
|||||||
#define HUD2_STYLE (1 << 5)
|
#define HUD2_STYLE (1 << 5)
|
||||||
#define HUD2_RANK (1 << 6)
|
#define HUD2_RANK (1 << 6)
|
||||||
#define HUD2_TRACK (1 << 7)
|
#define HUD2_TRACK (1 << 7)
|
||||||
|
#define HUD2_SPLITPB (1 << 8)
|
||||||
|
#define HUD2_MAPTIER (1 << 9)
|
||||||
|
|
||||||
#define HUD_DEFAULT (HUD_MASTER|HUD_CENTER|HUD_ZONEHUD|HUD_OBSERVE|HUD_TOPLEFT|HUD_SYNC|HUD_TIMELEFT|HUD_2DVEL|HUD_SPECTATORS)
|
#define HUD_DEFAULT (HUD_MASTER|HUD_CENTER|HUD_ZONEHUD|HUD_OBSERVE|HUD_TOPLEFT|HUD_SYNC|HUD_TIMELEFT|HUD_2DVEL|HUD_SPECTATORS)
|
||||||
#define HUD_DEFAULT2 0
|
#define HUD_DEFAULT2 0
|
||||||
@ -83,6 +85,7 @@ EngineVersion gEV_Type = Engine_Unknown;
|
|||||||
bool gB_Replay = false;
|
bool gB_Replay = false;
|
||||||
bool gB_Zones = false;
|
bool gB_Zones = false;
|
||||||
bool gB_Sounds = false;
|
bool gB_Sounds = false;
|
||||||
|
bool gB_Rankings = false;
|
||||||
bool gB_BhopStats = false;
|
bool gB_BhopStats = false;
|
||||||
|
|
||||||
// cache
|
// cache
|
||||||
@ -90,6 +93,7 @@ int gI_Cycle = 0;
|
|||||||
color_t gI_Gradient;
|
color_t gI_Gradient;
|
||||||
int gI_GradientDirection = -1;
|
int gI_GradientDirection = -1;
|
||||||
int gI_Styles = 0;
|
int gI_Styles = 0;
|
||||||
|
char gS_Map[160];
|
||||||
|
|
||||||
Handle gH_HUDCookie = null;
|
Handle gH_HUDCookie = null;
|
||||||
Handle gH_HUDCookieMain = null;
|
Handle gH_HUDCookieMain = null;
|
||||||
@ -171,6 +175,7 @@ public void OnPluginStart()
|
|||||||
gB_Replay = LibraryExists("shavit-replay");
|
gB_Replay = LibraryExists("shavit-replay");
|
||||||
gB_Zones = LibraryExists("shavit-zones");
|
gB_Zones = LibraryExists("shavit-zones");
|
||||||
gB_Sounds = LibraryExists("shavit-sounds");
|
gB_Sounds = LibraryExists("shavit-sounds");
|
||||||
|
gB_Rankings = LibraryExists("shavit-rankings");
|
||||||
gB_BhopStats = LibraryExists("bhopstats");
|
gB_BhopStats = LibraryExists("bhopstats");
|
||||||
|
|
||||||
// HUD handle
|
// HUD handle
|
||||||
@ -231,6 +236,9 @@ public void OnPluginStart()
|
|||||||
|
|
||||||
public void OnMapStart()
|
public void OnMapStart()
|
||||||
{
|
{
|
||||||
|
GetCurrentMap(gS_Map, 160);
|
||||||
|
GetMapDisplayName(gS_Map, gS_Map, 160);
|
||||||
|
|
||||||
if(gB_Late)
|
if(gB_Late)
|
||||||
{
|
{
|
||||||
Shavit_OnStyleConfigLoaded(-1);
|
Shavit_OnStyleConfigLoaded(-1);
|
||||||
@ -255,6 +263,11 @@ public void OnLibraryAdded(const char[] name)
|
|||||||
gB_Sounds = true;
|
gB_Sounds = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if(StrEqual(name, "shavit-rankings"))
|
||||||
|
{
|
||||||
|
gB_Rankings = true;
|
||||||
|
}
|
||||||
|
|
||||||
else if(StrEqual(name, "bhopstats"))
|
else if(StrEqual(name, "bhopstats"))
|
||||||
{
|
{
|
||||||
gB_BhopStats = true;
|
gB_BhopStats = true;
|
||||||
@ -278,6 +291,11 @@ public void OnLibraryRemoved(const char[] name)
|
|||||||
gB_Sounds = false;
|
gB_Sounds = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if(StrEqual(name, "shavit-rankings"))
|
||||||
|
{
|
||||||
|
gB_Rankings = false;
|
||||||
|
}
|
||||||
|
|
||||||
else if(StrEqual(name, "bhopstats"))
|
else if(StrEqual(name, "bhopstats"))
|
||||||
{
|
{
|
||||||
gB_BhopStats = false;
|
gB_BhopStats = false;
|
||||||
@ -645,6 +663,17 @@ Action ShowHUDMenu(int client, int item)
|
|||||||
FormatEx(sHudItem, 64, "%T", "HudTrackText", client);
|
FormatEx(sHudItem, 64, "%T", "HudTrackText", client);
|
||||||
menu.AddItem(sInfo, sHudItem);
|
menu.AddItem(sInfo, sHudItem);
|
||||||
|
|
||||||
|
FormatEx(sInfo, 16, "@%d", HUD2_SPLITPB);
|
||||||
|
FormatEx(sHudItem, 64, "%T", "HudSplitPbText", client);
|
||||||
|
menu.AddItem(sInfo, sHudItem);
|
||||||
|
|
||||||
|
if(gB_Rankings)
|
||||||
|
{
|
||||||
|
FormatEx(sInfo, 16, "@%d", HUD2_MAPTIER);
|
||||||
|
FormatEx(sHudItem, 64, "%T", "HudMapTierText", client);
|
||||||
|
menu.AddItem(sInfo, sHudItem);
|
||||||
|
}
|
||||||
|
|
||||||
menu.ExitButton = true;
|
menu.ExitButton = true;
|
||||||
menu.DisplayAt(client, item, 60);
|
menu.DisplayAt(client, item, 60);
|
||||||
|
|
||||||
@ -966,7 +995,23 @@ int AddHUDToBuffer_Source2013(int client, huddata_t data, char[] buffer, int max
|
|||||||
|
|
||||||
if((gI_HUDSettings[client] & HUD_ZONEHUD) > 0 && data.iZoneHUD != ZoneHUD_None)
|
if((gI_HUDSettings[client] & HUD_ZONEHUD) > 0 && data.iZoneHUD != ZoneHUD_None)
|
||||||
{
|
{
|
||||||
FormatEx(sLine, 128, "%T ", (data.iZoneHUD == ZoneHUD_Start)? "HudInStartZone":"HudInEndZone", client, data.iSpeed);
|
if(gB_Rankings && (gI_HUD2Settings[client] & HUD2_MAPTIER) == 0)
|
||||||
|
{
|
||||||
|
FormatEx(sLine, 128, "%T", "HudZoneTier", client, Shavit_GetMapTier(gS_Map));
|
||||||
|
AddHUDLine(buffer, maxlen, sLine, iLines);
|
||||||
|
iLines++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.iZoneHUD == ZoneHUD_Start)
|
||||||
|
{
|
||||||
|
FormatEx(sLine, 128, "%T ", "HudInStartZone", client, data.iSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FormatEx(sLine, 128, "%T ", "HudInEndZone", client, data.iSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
AddHUDLine(buffer, maxlen, sLine, iLines);
|
AddHUDLine(buffer, maxlen, sLine, iLines);
|
||||||
|
|
||||||
return ++iLines;
|
return ++iLines;
|
||||||
@ -1095,6 +1140,7 @@ int AddHUDToBuffer_CSGO(int client, huddata_t data, char[] buffer, int maxlen)
|
|||||||
{
|
{
|
||||||
FormatEx(sLine, 128, "%d u/s", data.iSpeed);
|
FormatEx(sLine, 128, "%d u/s", data.iSpeed);
|
||||||
AddHUDLine(buffer, maxlen, sLine, iLines);
|
AddHUDLine(buffer, maxlen, sLine, iLines);
|
||||||
|
iLines++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1115,8 +1161,24 @@ int AddHUDToBuffer_CSGO(int client, huddata_t data, char[] buffer, int maxlen)
|
|||||||
char sZoneHUD[64];
|
char sZoneHUD[64];
|
||||||
FormatEx(sZoneHUD, 64, "<span class='fontSize-xxl' color='#%06X'>", ((gI_Gradient.r << 16) + (gI_Gradient.g << 8) + (gI_Gradient.b)));
|
FormatEx(sZoneHUD, 64, "<span class='fontSize-xxl' color='#%06X'>", ((gI_Gradient.r << 16) + (gI_Gradient.g << 8) + (gI_Gradient.b)));
|
||||||
StrCat(buffer, maxlen, sZoneHUD);
|
StrCat(buffer, maxlen, sZoneHUD);
|
||||||
|
|
||||||
|
if(data.iZoneHUD == ZoneHUD_Start)
|
||||||
|
{
|
||||||
|
if(gB_Rankings && (gI_HUD2Settings[client] & HUD2_MAPTIER) == 0)
|
||||||
|
{
|
||||||
|
FormatEx(sZoneHUD, 32, "%T\n\n", "HudZoneTier", client, Shavit_GetMapTier(gS_Map));
|
||||||
|
AddHUDLine(buffer, maxlen, sZoneHUD, iLines);
|
||||||
|
iLines++;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatEx(sZoneHUD, 64, "%T</span>", "HudInStartZoneCSGO", client, data.iSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FormatEx(sZoneHUD, 64, "%T</span>", "HudInEndZoneCSGO", client, data.iSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
FormatEx(sZoneHUD, 64, "%T</span>", (data.iZoneHUD == ZoneHUD_Start)? "HudInStartZoneCSGO":"HudInEndZoneCSGO", client, data.iSpeed);
|
|
||||||
StrCat(buffer, maxlen, sZoneHUD);
|
StrCat(buffer, maxlen, sZoneHUD);
|
||||||
|
|
||||||
return ++iLines;
|
return ++iLines;
|
||||||
@ -1219,7 +1281,7 @@ int AddHUDToBuffer_CSGO(int client, huddata_t data, char[] buffer, int maxlen)
|
|||||||
StrCat(buffer, maxlen, "</span>");
|
StrCat(buffer, maxlen, "</span>");
|
||||||
|
|
||||||
return iLines;
|
return iLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateMainHUD(int client)
|
void UpdateMainHUD(int client)
|
||||||
{
|
{
|
||||||
@ -1262,7 +1324,7 @@ void UpdateMainHUD(int client)
|
|||||||
|
|
||||||
if(iReplayStyle != -1)
|
if(iReplayStyle != -1)
|
||||||
{
|
{
|
||||||
fReplayTime = (Shavit_GetReplayTime(iReplayStyle, iReplayTrack) * gA_StyleSettings[iReplayStyle].fTimescale);
|
fReplayTime = Shavit_GetReplayTime(iReplayStyle, iReplayTrack);
|
||||||
fReplayLength = Shavit_GetReplayLength(iReplayStyle, iReplayTrack);
|
fReplayLength = Shavit_GetReplayLength(iReplayStyle, iReplayTrack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1492,21 +1554,35 @@ void UpdateTopLeftHUD(int client, bool wait)
|
|||||||
char sWRName[MAX_NAME_LENGTH];
|
char sWRName[MAX_NAME_LENGTH];
|
||||||
Shavit_GetWRName(style, sWRName, MAX_NAME_LENGTH, track);
|
Shavit_GetWRName(style, sWRName, MAX_NAME_LENGTH, track);
|
||||||
|
|
||||||
float fPBTime = Shavit_GetClientPB(target, style, track);
|
|
||||||
|
|
||||||
char sPBTime[16];
|
|
||||||
FormatSeconds(fPBTime, sPBTime, MAX_NAME_LENGTH);
|
|
||||||
|
|
||||||
char sTopLeft[128];
|
char sTopLeft[128];
|
||||||
|
FormatEx(sTopLeft, 128, "WR: %s (%s)", sWRTime, sWRName);
|
||||||
|
|
||||||
if(fPBTime != 0.0)
|
float fTargetPB = Shavit_GetClientPB(target, style, track);
|
||||||
|
char sTargetPB[64];
|
||||||
|
FormatSeconds(fTargetPB, sTargetPB, 64);
|
||||||
|
Format(sTargetPB, 64, "%T: %s", "HudBestText", client, sTargetPB);
|
||||||
|
|
||||||
|
float fSelfPB = Shavit_GetClientPB(client, style, track);
|
||||||
|
char sSelfPB[64];
|
||||||
|
FormatSeconds(fSelfPB, sSelfPB, 64);
|
||||||
|
Format(sSelfPB, 64, "%T: %s", "HudBestText", client, sSelfPB);
|
||||||
|
|
||||||
|
if((gI_HUD2Settings[client] & HUD2_SPLITPB) == 0 && target != client)
|
||||||
{
|
{
|
||||||
FormatEx(sTopLeft, 128, "WR: %s (%s)\n%T: %s (#%d)", sWRTime, sWRName, "HudBestText", client, sPBTime, Shavit_GetRankForTime(style, fPBTime, track));
|
if(fTargetPB != 0.0)
|
||||||
|
{
|
||||||
|
Format(sTopLeft, 128, "%s\n%s (%N)", sTopLeft, sTargetPB, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fSelfPB != 0.0)
|
||||||
|
{
|
||||||
|
Format(sTopLeft, 128, "%s\n%s (%N)", sTopLeft, sSelfPB, client);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else if(fSelfPB != 0.0)
|
||||||
{
|
{
|
||||||
FormatEx(sTopLeft, 128, "WR: %s (%s)", sWRTime, sWRName);
|
Format(sTopLeft, 128, "%s\n%s (#%d)", sTopLeft, sSelfPB, Shavit_GetRankForTime(style, fSelfPB, track));
|
||||||
}
|
}
|
||||||
|
|
||||||
SetHudTextParams(0.01, 0.01, 2.5, 255, 255, 255, 255, 0, 0.0, 0.0, 0.0);
|
SetHudTextParams(0.01, 0.01, 2.5, 255, 255, 255, 255, 0, 0.0, 0.0, 0.0);
|
||||||
|
|||||||
@ -286,7 +286,7 @@ public void OnPluginStart()
|
|||||||
gCV_AdvertisementInterval = CreateConVar("shavit_misc_advertisementinterval", "600.0", "Interval between each chat advertisement.\nConfiguration file for those is configs/shavit-advertisements.cfg.\nSet to 0.0 to disable.\nRequires server restart for changes to take effect.", 0, true, 0.0);
|
gCV_AdvertisementInterval = CreateConVar("shavit_misc_advertisementinterval", "600.0", "Interval between each chat advertisement.\nConfiguration file for those is configs/shavit-advertisements.cfg.\nSet to 0.0 to disable.\nRequires server restart for changes to take effect.", 0, true, 0.0);
|
||||||
gCV_Checkpoints = CreateConVar("shavit_misc_checkpoints", "1", "Allow players to save and teleport to checkpoints.", 0, true, 0.0, true, 1.0);
|
gCV_Checkpoints = CreateConVar("shavit_misc_checkpoints", "1", "Allow players to save and teleport to checkpoints.", 0, true, 0.0, true, 1.0);
|
||||||
gCV_RemoveRagdolls = CreateConVar("shavit_misc_removeragdolls", "1", "Remove ragdolls after death?\n0 - Disabled\n1 - Only remove replay bot ragdolls.\n2 - Remove all ragdolls.", 0, true, 0.0, true, 2.0);
|
gCV_RemoveRagdolls = CreateConVar("shavit_misc_removeragdolls", "1", "Remove ragdolls after death?\n0 - Disabled\n1 - Only remove replay bot ragdolls.\n2 - Remove all ragdolls.", 0, true, 0.0, true, 2.0);
|
||||||
gCV_ClanTag = CreateConVar("shavit_misc_clantag", "{tr}{styletag} :: {time}", "Custom clantag for players.\n0 - Disabled\n{styletag} - style settings from shavit-styles.cfg.\n{style} - style name.\n{time} - formatted time.\n{tr} - first letter of track, if not default.", 0);
|
gCV_ClanTag = CreateConVar("shavit_misc_clantag", "{tr}{styletag} :: {time}", "Custom clantag for players.\n0 - Disabled\n{styletag} - style tag.\n{style} - style name.\n{time} - formatted time.\n{tr} - first letter of track.\n{rank} - player rank.", 0);
|
||||||
gCV_DropAll = CreateConVar("shavit_misc_dropall", "1", "Allow all weapons to be dropped?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0);
|
gCV_DropAll = CreateConVar("shavit_misc_dropall", "1", "Allow all weapons to be dropped?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0);
|
||||||
gCV_ResetTargetname = CreateConVar("shavit_misc_resettargetname", "0", "Reset the player's targetname upon timer start?\nRecommended to leave disabled. Enable via per-map configs when necessary.\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0);
|
gCV_ResetTargetname = CreateConVar("shavit_misc_resettargetname", "0", "Reset the player's targetname upon timer start?\nRecommended to leave disabled. Enable via per-map configs when necessary.\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0);
|
||||||
gCV_RestoreStates = CreateConVar("shavit_misc_restorestates", "0", "Save the players' timer/position etc.. when they die/change teams,\nand load the data when they spawn?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0);
|
gCV_RestoreStates = CreateConVar("shavit_misc_restorestates", "0", "Save the players' timer/position etc.. when they die/change teams,\nand load the data when they spawn?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0);
|
||||||
@ -873,12 +873,20 @@ void UpdateClanTag(int client)
|
|||||||
GetTrackName(client, track, sTrack, 3);
|
GetTrackName(client, track, sTrack, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char sRank[8];
|
||||||
|
|
||||||
|
if(gB_Rankings)
|
||||||
|
{
|
||||||
|
IntToString(Shavit_GetRank(client), sRank, 8);
|
||||||
|
}
|
||||||
|
|
||||||
char sCustomTag[32];
|
char sCustomTag[32];
|
||||||
strcopy(sCustomTag, 32, sTag);
|
strcopy(sCustomTag, 32, sTag);
|
||||||
ReplaceString(sCustomTag, 32, "{style}", gS_StyleStrings[gI_Style[client]].sStyleName);
|
ReplaceString(sCustomTag, 32, "{style}", gS_StyleStrings[gI_Style[client]].sStyleName);
|
||||||
ReplaceString(sCustomTag, 32, "{styletag}", gS_StyleStrings[gI_Style[client]].sClanTag);
|
ReplaceString(sCustomTag, 32, "{styletag}", gS_StyleStrings[gI_Style[client]].sClanTag);
|
||||||
ReplaceString(sCustomTag, 32, "{time}", sTime);
|
ReplaceString(sCustomTag, 32, "{time}", sTime);
|
||||||
ReplaceString(sCustomTag, 32, "{tr}", sTrack);
|
ReplaceString(sCustomTag, 32, "{tr}", sTrack);
|
||||||
|
ReplaceString(sCustomTag, 32, "{rank}", sRank);
|
||||||
|
|
||||||
CS_SetClientClanTag(client, sCustomTag);
|
CS_SetClientClanTag(client, sCustomTag);
|
||||||
}
|
}
|
||||||
@ -1454,13 +1462,10 @@ public Action Command_Save(int client, int args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else if(SaveCheckpoint(client, index, bOverflow))
|
||||||
{
|
{
|
||||||
if(SaveCheckpoint(client, index, bOverflow))
|
gA_CheckpointsCache[client].iCurrentCheckpoint = (bOverflow)? iMaxCPs:++gA_CheckpointsCache[client].iCheckpoints;
|
||||||
{
|
Shavit_PrintToChat(client, "%T", "MiscCheckpointsSaved", client, gA_CheckpointsCache[client].iCurrentCheckpoint, gS_ChatStrings.sVariable, gS_ChatStrings.sText);
|
||||||
gA_CheckpointsCache[client].iCurrentCheckpoint = (bOverflow)? iMaxCPs:++gA_CheckpointsCache[client].iCheckpoints;
|
|
||||||
Shavit_PrintToChat(client, "%T", "MiscCheckpointsSaved", client, gA_CheckpointsCache[client].iCurrentCheckpoint, gS_ChatStrings.sVariable, gS_ChatStrings.sText);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
@ -1591,8 +1596,10 @@ public int MenuHandler_Checkpoints(Menu menu, MenuAction action, int param1, int
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveCheckpoint(param1, ++gA_CheckpointsCache[param1].iCheckpoints);
|
if(SaveCheckpoint(param1, gA_CheckpointsCache[param1].iCheckpoints + 1))
|
||||||
gA_CheckpointsCache[param1].iCurrentCheckpoint = gA_CheckpointsCache[param1].iCheckpoints;
|
{
|
||||||
|
gA_CheckpointsCache[param1].iCurrentCheckpoint = ++gA_CheckpointsCache[param1].iCheckpoints;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -1692,6 +1699,13 @@ bool SaveCheckpoint(int client, int index, bool overflow = false)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if(Shavit_IsPaused(client) || Shavit_IsPaused(target))
|
||||||
|
{
|
||||||
|
Shavit_PrintToChat(client, "%T", "CommandNoPause", client, gS_ChatStrings.sVariable, gS_ChatStrings.sText);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
char sKey[32];
|
char sKey[32];
|
||||||
int iSerial = GetClientSerial(client);
|
int iSerial = GetClientSerial(client);
|
||||||
FormatEx(sKey, 32, "%d_%d", iSerial, index);
|
FormatEx(sKey, 32, "%d_%d", iSerial, index);
|
||||||
@ -1893,6 +1907,13 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if(Shavit_IsPaused(client))
|
||||||
|
{
|
||||||
|
Shavit_PrintToChat(client, "%T", "CommandNoPause", client, gS_ChatStrings.sVariable, gS_ChatStrings.sText);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float pos[3];
|
float pos[3];
|
||||||
CopyArray(cpcache.fPosition, pos, 3);
|
CopyArray(cpcache.fPosition, pos, 3);
|
||||||
|
|
||||||
@ -1916,6 +1937,7 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
|
|||||||
timer_snapshot_t snapshot;
|
timer_snapshot_t snapshot;
|
||||||
CopyArray(cpcache.aSnapshot, snapshot, sizeof(timer_snapshot_t));
|
CopyArray(cpcache.aSnapshot, snapshot, sizeof(timer_snapshot_t));
|
||||||
Shavit_LoadSnapshot(client, snapshot);
|
Shavit_LoadSnapshot(client, snapshot);
|
||||||
|
Shavit_ResumeTimer(client);
|
||||||
|
|
||||||
float ang[3];
|
float ang[3];
|
||||||
CopyArray(cpcache.fAngles, ang, 3);
|
CopyArray(cpcache.fAngles, ang, 3);
|
||||||
@ -1936,6 +1958,22 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
|
|||||||
vel = NULL_VECTOR;
|
vel = NULL_VECTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(cpcache.iTargetname != -1)
|
||||||
|
{
|
||||||
|
char sTargetname[64];
|
||||||
|
gA_Targetnames.GetString(cpcache.iTargetname, sTargetname, 64);
|
||||||
|
|
||||||
|
SetEntPropString(client, Prop_Data, "m_iName", sTargetname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cpcache.iClassname != -1)
|
||||||
|
{
|
||||||
|
char sClassname[64];
|
||||||
|
gA_Classnames.GetString(cpcache.iClassname, sClassname, 64);
|
||||||
|
|
||||||
|
SetEntPropString(client, Prop_Data, "m_iClassname", sClassname);
|
||||||
|
}
|
||||||
|
|
||||||
TeleportEntity(client, pos,
|
TeleportEntity(client, pos,
|
||||||
((gI_CheckpointsSettings[client] & CP_ANGLES) > 0 || cpcache.bSegmented)? ang:NULL_VECTOR,
|
((gI_CheckpointsSettings[client] & CP_ANGLES) > 0 || cpcache.bSegmented)? ang:NULL_VECTOR,
|
||||||
vel);
|
vel);
|
||||||
@ -1958,26 +1996,6 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
|
|||||||
SetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue", cpcache.fSpeed);
|
SetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue", cpcache.fSpeed);
|
||||||
SetEntPropEnt(client, Prop_Data, "m_hGroundEntity", cpcache.iGroundEntity);
|
SetEntPropEnt(client, Prop_Data, "m_hGroundEntity", cpcache.iGroundEntity);
|
||||||
|
|
||||||
int iTargetname = gA_Targetnames.FindValue(cpcache.iTargetname);
|
|
||||||
|
|
||||||
if(iTargetname != -1)
|
|
||||||
{
|
|
||||||
char sTargetname[64];
|
|
||||||
gA_Targetnames.GetString(iTargetname, sTargetname, 64);
|
|
||||||
|
|
||||||
SetEntPropString(client, Prop_Data, "m_iName", sTargetname);
|
|
||||||
}
|
|
||||||
|
|
||||||
int iClassname = gA_Classnames.FindValue(cpcache.iClassname);
|
|
||||||
|
|
||||||
if(iClassname != -1)
|
|
||||||
{
|
|
||||||
char sClassname[64];
|
|
||||||
gA_Classnames.GetString(iClassname, sClassname, 64);
|
|
||||||
|
|
||||||
SetEntPropString(client, Prop_Data, "m_iClassname", sClassname);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gEV_Type != Engine_TF2)
|
if(gEV_Type != Engine_TF2)
|
||||||
{
|
{
|
||||||
SetEntPropFloat(client, Prop_Send, "m_flStamina", cpcache.fStamina);
|
SetEntPropFloat(client, Prop_Send, "m_flStamina", cpcache.fStamina);
|
||||||
@ -2703,6 +2721,7 @@ void LoadState(int client)
|
|||||||
|
|
||||||
Shavit_LoadSnapshot(client, gA_SaveStates[client]);
|
Shavit_LoadSnapshot(client, gA_SaveStates[client]);
|
||||||
Shavit_SetPracticeMode(client, gB_SaveStatesSegmented[client], false);
|
Shavit_SetPracticeMode(client, gB_SaveStatesSegmented[client], false);
|
||||||
|
Shavit_ResumeTimer(client);
|
||||||
|
|
||||||
if(gB_Replay && gA_SaveFrames[client] != null)
|
if(gB_Replay && gA_SaveFrames[client] != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -73,6 +73,7 @@ int gI_RankedPlayers = 0;
|
|||||||
Menu gH_Top100Menu = null;
|
Menu gH_Top100Menu = null;
|
||||||
|
|
||||||
Handle gH_Forwards_OnTierAssigned = null;
|
Handle gH_Forwards_OnTierAssigned = null;
|
||||||
|
Handle gH_Forwards_OnRankAssigned = null;
|
||||||
|
|
||||||
// Timer settings.
|
// Timer settings.
|
||||||
chatstrings_t gS_ChatStrings;
|
chatstrings_t gS_ChatStrings;
|
||||||
@ -127,6 +128,7 @@ public void OnAllPluginsLoaded()
|
|||||||
public void OnPluginStart()
|
public void OnPluginStart()
|
||||||
{
|
{
|
||||||
gH_Forwards_OnTierAssigned = CreateGlobalForward("Shavit_OnTierAssigned", ET_Event, Param_String, Param_Cell);
|
gH_Forwards_OnTierAssigned = CreateGlobalForward("Shavit_OnTierAssigned", ET_Event, Param_String, Param_Cell);
|
||||||
|
gH_Forwards_OnRankAssigned = CreateGlobalForward("Shavit_OnRankAssigned", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
||||||
|
|
||||||
RegConsoleCmd("sm_tier", Command_Tier, "Prints the map's tier to chat.");
|
RegConsoleCmd("sm_tier", Command_Tier, "Prints the map's tier to chat.");
|
||||||
RegConsoleCmd("sm_maptier", Command_Tier, "Prints the map's tier to chat. (sm_tier alias)");
|
RegConsoleCmd("sm_maptier", Command_Tier, "Prints the map's tier to chat. (sm_tier alias)");
|
||||||
@ -387,7 +389,7 @@ public void OnClientPostAdminCheck(int client)
|
|||||||
{
|
{
|
||||||
if(!IsFakeClient(client))
|
if(!IsFakeClient(client))
|
||||||
{
|
{
|
||||||
UpdatePlayerRank(client);
|
UpdatePlayerRank(client, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -705,7 +707,7 @@ public void Trans_OnRecalcSuccess(Database db, any data, int numQueries, DBResul
|
|||||||
{
|
{
|
||||||
if(IsClientInGame(i) && IsClientAuthorized(i))
|
if(IsClientInGame(i) && IsClientAuthorized(i))
|
||||||
{
|
{
|
||||||
UpdatePlayerRank(i);
|
UpdatePlayerRank(i, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,7 +782,9 @@ void UpdateAllPoints()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
char sQuery[128];
|
char sQuery[128];
|
||||||
FormatEx(sQuery, 128, "UPDATE %susers SET points = GetWeightedPoints(auth);", gS_MySQLPrefix);
|
FormatEx(sQuery, 128, "UPDATE %susers SET points = GetWeightedPoints(auth);",
|
||||||
|
gS_MySQLPrefix);
|
||||||
|
|
||||||
gH_SQL.Query(SQL_UpdateAllPoints_Callback, sQuery);
|
gH_SQL.Query(SQL_UpdateAllPoints_Callback, sQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,7 +798,7 @@ public void SQL_UpdateAllPoints_Callback(Database db, DBResultSet results, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdatePlayerRank(int client)
|
void UpdatePlayerRank(int client, bool first)
|
||||||
{
|
{
|
||||||
gI_Rank[client] = 0;
|
gI_Rank[client] = 0;
|
||||||
gF_Points[client] = 0.0;
|
gF_Points[client] = 0.0;
|
||||||
@ -809,12 +813,23 @@ void UpdatePlayerRank(int client)
|
|||||||
FormatEx(sQuery, 512, "SELECT p.points, COUNT(*) rank FROM %susers u JOIN (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) p WHERE u.points >= p.points LIMIT 1;",
|
FormatEx(sQuery, 512, "SELECT p.points, COUNT(*) rank FROM %susers u JOIN (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) p WHERE u.points >= p.points LIMIT 1;",
|
||||||
gS_MySQLPrefix, gS_MySQLPrefix, sAuthID);
|
gS_MySQLPrefix, gS_MySQLPrefix, sAuthID);
|
||||||
|
|
||||||
gH_SQL.Query(SQL_UpdatePlayerRank_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
|
DataPack hPack = new DataPack();
|
||||||
|
hPack.WriteCell(GetClientSerial(client));
|
||||||
|
hPack.WriteCell(first);
|
||||||
|
|
||||||
|
gH_SQL.Query(SQL_UpdatePlayerRank_Callback, sQuery, hPack, DBPrio_Low);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, const char[] error, any data)
|
public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||||
{
|
{
|
||||||
|
DataPack hPack = view_as<DataPack>(data);
|
||||||
|
hPack.Reset();
|
||||||
|
|
||||||
|
int iSerial = hPack.ReadCell();
|
||||||
|
bool bFirst = view_as<bool>(hPack.ReadCell());
|
||||||
|
delete hPack;
|
||||||
|
|
||||||
if(results == null)
|
if(results == null)
|
||||||
{
|
{
|
||||||
LogError("Timer (rankings, update player rank) error! Reason: %s", error);
|
LogError("Timer (rankings, update player rank) error! Reason: %s", error);
|
||||||
@ -822,7 +837,7 @@ public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, cons
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int client = GetClientFromSerial(data);
|
int client = GetClientFromSerial(iSerial);
|
||||||
|
|
||||||
if(client == 0)
|
if(client == 0)
|
||||||
{
|
{
|
||||||
@ -833,13 +848,22 @@ public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, cons
|
|||||||
{
|
{
|
||||||
gF_Points[client] = results.FetchFloat(0);
|
gF_Points[client] = results.FetchFloat(0);
|
||||||
gI_Rank[client] = (gF_Points[client] > 0.0)? results.FetchInt(1):0;
|
gI_Rank[client] = (gF_Points[client] > 0.0)? results.FetchInt(1):0;
|
||||||
|
|
||||||
|
Call_StartForward(gH_Forwards_OnRankAssigned);
|
||||||
|
Call_PushCell(client);
|
||||||
|
Call_PushCell(gI_Rank[client]);
|
||||||
|
Call_PushCell(gF_Points[client]);
|
||||||
|
Call_PushCell(bFirst);
|
||||||
|
Call_Finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateRankedPlayers()
|
void UpdateRankedPlayers()
|
||||||
{
|
{
|
||||||
char sQuery[512];
|
char sQuery[512];
|
||||||
FormatEx(sQuery, 512, "SELECT COUNT(*) count FROM %susers WHERE points > 0.0;", gS_MySQLPrefix);
|
FormatEx(sQuery, 512, "SELECT COUNT(*) count FROM %susers WHERE points > 0.0;",
|
||||||
|
gS_MySQLPrefix);
|
||||||
|
|
||||||
gH_SQL.Query(SQL_UpdateRankedPlayers_Callback, sQuery, 0, DBPrio_High);
|
gH_SQL.Query(SQL_UpdateRankedPlayers_Callback, sQuery, 0, DBPrio_High);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
#undef REQUIRE_EXTENSIONS
|
#undef REQUIRE_EXTENSIONS
|
||||||
#include <cstrike>
|
#include <cstrike>
|
||||||
#include <tf2>
|
#include <tf2>
|
||||||
|
#include <tf2_stocks>
|
||||||
|
|
||||||
#define REPLAY_FORMAT_V2 "{SHAVITREPLAYFORMAT}{V2}"
|
#define REPLAY_FORMAT_V2 "{SHAVITREPLAYFORMAT}{V2}"
|
||||||
#define REPLAY_FORMAT_FINAL "{SHAVITREPLAYFORMAT}{FINAL}"
|
#define REPLAY_FORMAT_FINAL "{SHAVITREPLAYFORMAT}{FINAL}"
|
||||||
@ -48,6 +49,7 @@ enum struct centralbot_cache_t
|
|||||||
int iStyle;
|
int iStyle;
|
||||||
ReplayStatus iReplayStatus;
|
ReplayStatus iReplayStatus;
|
||||||
int iTrack;
|
int iTrack;
|
||||||
|
int iPlaybackSerial;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum struct replaystrings_t
|
enum struct replaystrings_t
|
||||||
@ -87,12 +89,15 @@ ArrayList gA_Frames[STYLE_LIMIT][TRACKS_SIZE];
|
|||||||
float gF_StartTick[STYLE_LIMIT];
|
float gF_StartTick[STYLE_LIMIT];
|
||||||
ReplayStatus gRS_ReplayStatus[STYLE_LIMIT];
|
ReplayStatus gRS_ReplayStatus[STYLE_LIMIT];
|
||||||
framecache_t gA_FrameCache[STYLE_LIMIT][TRACKS_SIZE];
|
framecache_t gA_FrameCache[STYLE_LIMIT][TRACKS_SIZE];
|
||||||
|
|
||||||
bool gB_ForciblyStopped = false;
|
bool gB_ForciblyStopped = false;
|
||||||
|
Handle gH_ReplayTimers[STYLE_LIMIT];
|
||||||
|
|
||||||
bool gB_Button[MAXPLAYERS+1];
|
bool gB_Button[MAXPLAYERS+1];
|
||||||
int gI_PlayerFrames[MAXPLAYERS+1];
|
int gI_PlayerFrames[MAXPLAYERS+1];
|
||||||
ArrayList gA_PlayerFrames[MAXPLAYERS+1];
|
ArrayList gA_PlayerFrames[MAXPLAYERS+1];
|
||||||
int gI_Track[MAXPLAYERS+1];
|
int gI_Track[MAXPLAYERS+1];
|
||||||
|
float gF_LastInteraction[MAXPLAYERS+1];
|
||||||
|
|
||||||
bool gB_Late = false;
|
bool gB_Late = false;
|
||||||
|
|
||||||
@ -122,6 +127,8 @@ ConVar gCV_CentralBot = null;
|
|||||||
ConVar gCV_BotShooting = null;
|
ConVar gCV_BotShooting = null;
|
||||||
ConVar gCV_BotPlusUse = null;
|
ConVar gCV_BotPlusUse = null;
|
||||||
ConVar gCV_BotWeapon = null;
|
ConVar gCV_BotWeapon = null;
|
||||||
|
ConVar gCV_PlaybackCanStop = null;
|
||||||
|
ConVar gCV_PlaybackCooldown = null;
|
||||||
|
|
||||||
// timer settings
|
// timer settings
|
||||||
int gI_Styles = 0;
|
int gI_Styles = 0;
|
||||||
@ -153,6 +160,7 @@ public Plugin myinfo =
|
|||||||
|
|
||||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
||||||
{
|
{
|
||||||
|
CreateNative("Shavit_DeleteReplay", Native_DeleteReplay);
|
||||||
CreateNative("Shavit_GetReplayBotCurrentFrame", Native_GetReplayBotIndex);
|
CreateNative("Shavit_GetReplayBotCurrentFrame", Native_GetReplayBotIndex);
|
||||||
CreateNative("Shavit_GetReplayBotFirstFrame", Native_GetReplayBotFirstFrame);
|
CreateNative("Shavit_GetReplayBotFirstFrame", Native_GetReplayBotFirstFrame);
|
||||||
CreateNative("Shavit_GetReplayBotIndex", Native_GetReplayBotIndex);
|
CreateNative("Shavit_GetReplayBotIndex", Native_GetReplayBotIndex);
|
||||||
@ -223,6 +231,8 @@ public void OnPluginStart()
|
|||||||
gCV_BotShooting = CreateConVar("shavit_replay_botshooting", "3", "Attacking buttons to allow for bots.\n0 - none\n1 - +attack\n2 - +attack2\n3 - both", 0, true, 0.0, true, 3.0);
|
gCV_BotShooting = CreateConVar("shavit_replay_botshooting", "3", "Attacking buttons to allow for bots.\n0 - none\n1 - +attack\n2 - +attack2\n3 - both", 0, true, 0.0, true, 3.0);
|
||||||
gCV_BotPlusUse = CreateConVar("shavit_replay_botplususe", "1", "Allow bots to use +use?", 0, true, 0.0, true, 1.0);
|
gCV_BotPlusUse = CreateConVar("shavit_replay_botplususe", "1", "Allow bots to use +use?", 0, true, 0.0, true, 1.0);
|
||||||
gCV_BotWeapon = CreateConVar("shavit_replay_botweapon", "", "Choose which weapon the bot will hold.\nLeave empty to use the default.\nSet to \"none\" to have none.\nExample: weapon_usp");
|
gCV_BotWeapon = CreateConVar("shavit_replay_botweapon", "", "Choose which weapon the bot will hold.\nLeave empty to use the default.\nSet to \"none\" to have none.\nExample: weapon_usp");
|
||||||
|
gCV_PlaybackCanStop = CreateConVar("shavit_replay_pbcanstop", "1", "Allow players to stop playback if they requested it?", 0, true, 0.0, true, 1.0);
|
||||||
|
gCV_PlaybackCooldown = CreateConVar("shavit_replay_pbcooldown", "10.0", "Cooldown in seconds to apply for players between each playback they request/stop.\nDoes not apply to RCON admins.", 0, true, 0.0);
|
||||||
|
|
||||||
gCV_CentralBot.AddChangeHook(OnConVarChanged);
|
gCV_CentralBot.AddChangeHook(OnConVarChanged);
|
||||||
|
|
||||||
@ -311,6 +321,53 @@ public void AdminMenu_DeleteReplay(Handle topmenu, TopMenuAction action, TopMenu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UnloadReplay(int style, int track)
|
||||||
|
{
|
||||||
|
if(gCV_CentralBot.BoolValue && gA_CentralCache.iStyle == style && gA_CentralCache.iTrack == track)
|
||||||
|
{
|
||||||
|
StopCentralReplay(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
gA_Frames[style][track].Clear();
|
||||||
|
gA_FrameCache[style][track].iFrameCount = 0;
|
||||||
|
gA_FrameCache[style][track].fTime = 0.0;
|
||||||
|
gA_FrameCache[style][track].bNewFormat = true;
|
||||||
|
strcopy(gA_FrameCache[style][track].sReplayName, MAX_NAME_LENGTH, "invalid");
|
||||||
|
gI_ReplayTick[style] = -1;
|
||||||
|
|
||||||
|
if(gI_ReplayBotClient[style] != 0)
|
||||||
|
{
|
||||||
|
UpdateReplayInfo(gI_ReplayBotClient[style], style, 0.0, track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Native_DeleteReplay(Handle handler, int numParams)
|
||||||
|
{
|
||||||
|
char sMap[160];
|
||||||
|
GetNativeString(1, sMap, 160);
|
||||||
|
|
||||||
|
int iStyle = GetNativeCell(2);
|
||||||
|
int iTrack = GetNativeCell(3);
|
||||||
|
|
||||||
|
char sTrack[4];
|
||||||
|
FormatEx(sTrack, 4, "_%d", iTrack);
|
||||||
|
|
||||||
|
char sPath[PLATFORM_MAX_PATH];
|
||||||
|
FormatEx(sPath, PLATFORM_MAX_PATH, "%s/%d/%s%s.replay", gS_ReplayFolder, iStyle, gS_Map, (iTrack > 0)? sTrack:"");
|
||||||
|
|
||||||
|
if(!FileExists(sPath) || !DeleteFile(sPath))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(StrEqual(sMap, gS_Map))
|
||||||
|
{
|
||||||
|
UnloadReplay(iStyle, iTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public int Native_GetReplayBotFirstFrame(Handle handler, int numParams)
|
public int Native_GetReplayBotFirstFrame(Handle handler, int numParams)
|
||||||
{
|
{
|
||||||
SetNativeCellRef(2, gF_StartTick[GetNativeCell(1)]);
|
SetNativeCellRef(2, gF_StartTick[GetNativeCell(1)]);
|
||||||
@ -362,7 +419,7 @@ public int Native_ReloadReplay(Handle handler, int numParams)
|
|||||||
gA_Frames[style][track] = new ArrayList(CELLS_PER_FRAME);
|
gA_Frames[style][track] = new ArrayList(CELLS_PER_FRAME);
|
||||||
gA_FrameCache[style][track].iFrameCount = 0;
|
gA_FrameCache[style][track].iFrameCount = 0;
|
||||||
gA_FrameCache[style][track].fTime = 0.0;
|
gA_FrameCache[style][track].fTime = 0.0;
|
||||||
gA_FrameCache[style][track].bNewFormat = false;
|
gA_FrameCache[style][track].bNewFormat = true;
|
||||||
strcopy(gA_FrameCache[style][track].sReplayName, MAX_NAME_LENGTH, "invalid");
|
strcopy(gA_FrameCache[style][track].sReplayName, MAX_NAME_LENGTH, "invalid");
|
||||||
|
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
@ -397,7 +454,9 @@ public int Native_ReloadReplay(Handle handler, int numParams)
|
|||||||
{
|
{
|
||||||
gI_ReplayTick[style] = 0;
|
gI_ReplayTick[style] = 0;
|
||||||
gRS_ReplayStatus[style] = Replay_Start;
|
gRS_ReplayStatus[style] = Replay_Start;
|
||||||
CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, style, TIMER_FLAG_NO_MAPCHANGE);
|
|
||||||
|
delete gH_ReplayTimers[style];
|
||||||
|
gH_ReplayTimers[style] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, style, TIMER_FLAG_NO_MAPCHANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +553,7 @@ public int Native_GetReplayTime(Handle handler, int numParams)
|
|||||||
return view_as<int>(GetReplayLength(Track_Main, track));
|
return view_as<int>(GetReplayLength(Track_Main, track));
|
||||||
}
|
}
|
||||||
|
|
||||||
return view_as<int>(float(gI_ReplayTick[style]) / gF_Tickrate);
|
return view_as<int>(float(gI_ReplayTick[style]) / gF_Tickrate * gA_StyleSettings[style].fTimescale);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Native_HijackAngles(Handle handler, int numParams)
|
public int Native_HijackAngles(Handle handler, int numParams)
|
||||||
@ -693,6 +752,13 @@ public void OnMapStart()
|
|||||||
SetFailState("Could not load the replay bots' configuration file. Make sure it exists (addons/sourcemod/configs/shavit-replay.cfg) and follows the proper syntax!");
|
SetFailState("Could not load the replay bots' configuration file. Make sure it exists (addons/sourcemod/configs/shavit-replay.cfg) and follows the proper syntax!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VERY RARE CASE
|
||||||
|
// this is required to not cause replays to break if we change map before playback starts, after it is requested
|
||||||
|
for(int i = 0; i < STYLE_LIMIT; i++)
|
||||||
|
{
|
||||||
|
gH_ReplayTimers[i] = null;
|
||||||
|
}
|
||||||
|
|
||||||
if(gB_Late)
|
if(gB_Late)
|
||||||
{
|
{
|
||||||
Shavit_OnStyleConfigLoaded(-1);
|
Shavit_OnStyleConfigLoaded(-1);
|
||||||
@ -703,6 +769,7 @@ public void OnMapStart()
|
|||||||
gA_CentralCache.iStyle = -1;
|
gA_CentralCache.iStyle = -1;
|
||||||
gA_CentralCache.iReplayStatus = Replay_Idle;
|
gA_CentralCache.iReplayStatus = Replay_Idle;
|
||||||
gA_CentralCache.iTrack = Track_Main;
|
gA_CentralCache.iTrack = Track_Main;
|
||||||
|
gA_CentralCache.iPlaybackSerial = 0;
|
||||||
|
|
||||||
gB_ForciblyStopped = false;
|
gB_ForciblyStopped = false;
|
||||||
|
|
||||||
@ -714,13 +781,6 @@ public void OnMapStart()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bot_quota = FindConVar((gEV_Type != Engine_TF2)? "bot_quota":"tf_bot_quota");
|
|
||||||
|
|
||||||
if(bot_quota != null)
|
|
||||||
{
|
|
||||||
bot_quota.Flags &= ~FCVAR_NOTIFY;
|
|
||||||
}
|
|
||||||
|
|
||||||
char sTempMap[PLATFORM_MAX_PATH];
|
char sTempMap[PLATFORM_MAX_PATH];
|
||||||
FormatEx(sTempMap, PLATFORM_MAX_PATH, "maps/%s.nav", gS_Map);
|
FormatEx(sTempMap, PLATFORM_MAX_PATH, "maps/%s.nav", gS_Map);
|
||||||
|
|
||||||
@ -743,60 +803,18 @@ public void OnMapStart()
|
|||||||
if(bot_controllable != null)
|
if(bot_controllable != null)
|
||||||
{
|
{
|
||||||
bot_controllable.BoolValue = false;
|
bot_controllable.BoolValue = false;
|
||||||
delete bot_controllable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConVar bot_stop = FindConVar("bot_stop");
|
FindConVar((gEV_Type != Engine_TF2)? "bot_quota":"tf_bot_quota").Flags &= ~FCVAR_NOTIFY;
|
||||||
|
FindConVar("bot_stop").Flags &= ~FCVAR_CHEAT;
|
||||||
if(bot_stop != null)
|
FindConVar("bot_stop").BoolValue = true;
|
||||||
{
|
FindConVar((gEV_Type != Engine_TF2)? "bot_quota_mode":"tf_bot_quota_mode").SetString("normal");
|
||||||
bot_stop.BoolValue = true;
|
FindConVar("mp_limitteams").IntValue = 0;
|
||||||
delete bot_stop;
|
FindConVar((gEV_Type != Engine_TF2)? "bot_join_after_player":"tf_bot_join_after_player").BoolValue = false;
|
||||||
}
|
FindConVar("bot_chatter").SetString("off");
|
||||||
|
FindConVar("bot_flipout").BoolValue = true;
|
||||||
ConVar bot_quota_mode = FindConVar((gEV_Type != Engine_TF2)? "bot_quota_mode":"tf_bot_quota_mode");
|
FindConVar("bot_zombie").BoolValue = true;
|
||||||
|
FindConVar("mp_autoteambalance").BoolValue = false;
|
||||||
if(bot_quota_mode != null)
|
|
||||||
{
|
|
||||||
bot_quota_mode.SetString("normal");
|
|
||||||
delete bot_quota_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConVar mp_limitteams = FindConVar("mp_limitteams");
|
|
||||||
|
|
||||||
if(mp_limitteams != null)
|
|
||||||
{
|
|
||||||
mp_limitteams.IntValue = 0;
|
|
||||||
delete mp_limitteams;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConVar bot_join_after_player = FindConVar((gEV_Type != Engine_TF2)? "bot_join_after_player":"tf_bot_join_after_player");
|
|
||||||
|
|
||||||
if(bot_join_after_player != null)
|
|
||||||
{
|
|
||||||
bot_join_after_player.BoolValue = false;
|
|
||||||
delete bot_join_after_player;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConVar bot_chatter = FindConVar("bot_chatter");
|
|
||||||
|
|
||||||
if(bot_chatter != null)
|
|
||||||
{
|
|
||||||
bot_chatter.SetString("off");
|
|
||||||
delete bot_chatter;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConVar bot_zombie = FindConVar("bot_zombie");
|
|
||||||
|
|
||||||
if(bot_zombie != null)
|
|
||||||
{
|
|
||||||
bot_zombie.BoolValue = true;
|
|
||||||
delete bot_zombie;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConVar mp_autoteambalance = FindConVar("mp_autoteambalance");
|
|
||||||
mp_autoteambalance.BoolValue = false;
|
|
||||||
delete mp_autoteambalance;
|
|
||||||
|
|
||||||
ServerCommand((gEV_Type != Engine_TF2)? "bot_kick":"tf_bot_kick all");
|
ServerCommand((gEV_Type != Engine_TF2)? "bot_kick":"tf_bot_kick all");
|
||||||
|
|
||||||
@ -834,7 +852,7 @@ public void OnMapStart()
|
|||||||
gA_Frames[i][j] = new ArrayList(CELLS_PER_FRAME);
|
gA_Frames[i][j] = new ArrayList(CELLS_PER_FRAME);
|
||||||
gA_FrameCache[i][j].iFrameCount = 0;
|
gA_FrameCache[i][j].iFrameCount = 0;
|
||||||
gA_FrameCache[i][j].fTime = 0.0;
|
gA_FrameCache[i][j].fTime = 0.0;
|
||||||
gA_FrameCache[i][j].bNewFormat = false;
|
gA_FrameCache[i][j].bNewFormat = true;
|
||||||
strcopy(gA_FrameCache[i][j].sReplayName, MAX_NAME_LENGTH, "invalid");
|
strcopy(gA_FrameCache[i][j].sReplayName, MAX_NAME_LENGTH, "invalid");
|
||||||
|
|
||||||
loaded = DefaultLoadReplay(i, j);
|
loaded = DefaultLoadReplay(i, j);
|
||||||
@ -849,7 +867,9 @@ public void OnMapStart()
|
|||||||
{
|
{
|
||||||
gI_ReplayTick[i] = 0;
|
gI_ReplayTick[i] = 0;
|
||||||
gRS_ReplayStatus[i] = Replay_Start;
|
gRS_ReplayStatus[i] = Replay_Start;
|
||||||
CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, i, TIMER_FLAG_NO_MAPCHANGE);
|
|
||||||
|
delete gH_ReplayTimers[i];
|
||||||
|
gH_ReplayTimers[i] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, i, TIMER_FLAG_NO_MAPCHANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1111,22 +1131,7 @@ bool DeleteReplay(int style, int track)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gCV_CentralBot.BoolValue && gA_CentralCache.iStyle == style && gA_CentralCache.iTrack == track)
|
UnloadReplay(style, track);
|
||||||
{
|
|
||||||
StopCentralReplay(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
gA_Frames[style][track].Clear();
|
|
||||||
gA_FrameCache[style][track].iFrameCount = 0;
|
|
||||||
gA_FrameCache[style][track].fTime = 0.0;
|
|
||||||
gA_FrameCache[style][track].bNewFormat = false;
|
|
||||||
strcopy(gA_FrameCache[style][track].sReplayName, MAX_NAME_LENGTH, "invalid");
|
|
||||||
gI_ReplayTick[style] = -1;
|
|
||||||
|
|
||||||
if(gI_ReplayBotClient[style] != 0)
|
|
||||||
{
|
|
||||||
UpdateReplayInfo(gI_ReplayBotClient[style], style, 0.0, track);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1616,7 +1621,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
|||||||
float vecVelocity[3];
|
float vecVelocity[3];
|
||||||
MakeVectorFromPoints(vecCurrentPosition, vecPosition, vecVelocity);
|
MakeVectorFromPoints(vecCurrentPosition, vecPosition, vecVelocity);
|
||||||
ScaleVector(vecVelocity, gF_Tickrate);
|
ScaleVector(vecVelocity, gF_Tickrate);
|
||||||
TeleportEntity(client, NULL_VECTOR, vecAngles, vecVelocity);
|
TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, vecVelocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Plugin_Changed;
|
return Plugin_Changed;
|
||||||
@ -1627,7 +1632,9 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
|||||||
gI_ReplayTick[style] = 0;
|
gI_ReplayTick[style] = 0;
|
||||||
gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_End;
|
gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_End;
|
||||||
|
|
||||||
CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_EndReplay, style, TIMER_FLAG_NO_MAPCHANGE);
|
delete gH_ReplayTimers[style];
|
||||||
|
gH_ReplayTimers[style] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_EndReplay, style, TIMER_FLAG_NO_MAPCHANGE);
|
||||||
|
gA_CentralCache.iPlaybackSerial = 0;
|
||||||
|
|
||||||
return Plugin_Changed;
|
return Plugin_Changed;
|
||||||
}
|
}
|
||||||
@ -1677,9 +1684,9 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
|||||||
|
|
||||||
MoveType movetype = gA_Frames[style][track].Get(gI_ReplayTick[style], 7);
|
MoveType movetype = gA_Frames[style][track].Get(gI_ReplayTick[style], 7);
|
||||||
|
|
||||||
if(movetype == MOVETYPE_LADDER)
|
if(movetype == MOVETYPE_LADDER || (movetype == MOVETYPE_WALK && (iReplayFlags & FL_ONGROUND) > 0))
|
||||||
{
|
{
|
||||||
mt = MOVETYPE_LADDER;
|
mt = movetype;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1689,33 +1696,16 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
|||||||
MakeVectorFromPoints(vecCurrentPosition, vecPosition, vecVelocity);
|
MakeVectorFromPoints(vecCurrentPosition, vecPosition, vecVelocity);
|
||||||
ScaleVector(vecVelocity, gF_Tickrate);
|
ScaleVector(vecVelocity, gF_Tickrate);
|
||||||
|
|
||||||
if(gI_ReplayTick[style] > 1)
|
if(gI_ReplayTick[style] > 1 &&
|
||||||
|
// replay is going above 50k speed, just teleport at this point
|
||||||
|
(GetVectorLength(vecVelocity) > 50000.0 ||
|
||||||
|
// bot is on ground.. if the distance between the previous position is much bigger (1.5x) than the expected according
|
||||||
|
// to the bot's velocity, teleport to avoid sync issues
|
||||||
|
(mt == MOVETYPE_WALK && GetVectorDistance(vecCurrentPosition, vecPosition) > GetVectorLength(vecVelocity) / gF_Tickrate * 1.5)))
|
||||||
{
|
{
|
||||||
float vecLastPosition[3];
|
TeleportEntity(client, vecPosition, vecAngles, NULL_VECTOR);
|
||||||
vecLastPosition[0] = gA_Frames[style][track].Get(gI_ReplayTick[style] - 1, 0);
|
|
||||||
vecLastPosition[1] = gA_Frames[style][track].Get(gI_ReplayTick[style] - 1, 1);
|
|
||||||
vecLastPosition[2] = gA_Frames[style][track].Get(gI_ReplayTick[style] - 1, 2);
|
|
||||||
|
|
||||||
// fix for replay not syncing
|
return Plugin_Changed;
|
||||||
if(GetVectorDistance(vecLastPosition, vecCurrentPosition) >= 100.0 && IsWallBetween(vecLastPosition, vecCurrentPosition, client))
|
|
||||||
{
|
|
||||||
TeleportEntity(client, vecPosition, NULL_VECTOR, NULL_VECTOR);
|
|
||||||
|
|
||||||
return Plugin_Handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined DEBUG
|
|
||||||
PrintToChatAll("vecVelocity: %.02f | dist %.02f", GetVectorLength(vecVelocity), GetVectorDistance(vecLastPosition, vecPosition) * gF_Tickrate);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(GetVectorLength(vecVelocity) / (GetVectorDistance(vecLastPosition, vecPosition) * gF_Tickrate) > 2.0)
|
|
||||||
{
|
|
||||||
MakeVectorFromPoints(vecLastPosition, vecPosition, vecVelocity);
|
|
||||||
ScaleVector(vecVelocity, gF_Tickrate);
|
|
||||||
TeleportEntity(client, vecLastPosition, vecAngles, vecVelocity);
|
|
||||||
|
|
||||||
return Plugin_Changed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TeleportEntity(client, NULL_VECTOR, vecAngles, vecVelocity);
|
TeleportEntity(client, NULL_VECTOR, vecAngles, vecVelocity);
|
||||||
@ -1770,20 +1760,19 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
|||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Filter_Clients(int entity, int contentsMask, any data)
|
|
||||||
{
|
|
||||||
return (1 <= entity <= MaxClients && entity != data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsWallBetween(float pos1[3], float pos2[3], int bot)
|
|
||||||
{
|
|
||||||
TR_TraceRayFilter(pos1, pos2, MASK_SOLID, RayType_EndPoint, Filter_Clients, bot);
|
|
||||||
|
|
||||||
return !TR_DidHit();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Action Timer_EndReplay(Handle Timer, any data)
|
public Action Timer_EndReplay(Handle Timer, any data)
|
||||||
{
|
{
|
||||||
|
gH_ReplayTimers[data] = null;
|
||||||
|
|
||||||
|
int client = GetClientFromSerial(gA_CentralCache.iPlaybackSerial);
|
||||||
|
|
||||||
|
if(client != 0)
|
||||||
|
{
|
||||||
|
gF_LastInteraction[client] = GetEngineTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
gA_CentralCache.iPlaybackSerial = 0;
|
||||||
|
|
||||||
if(gCV_CentralBot.BoolValue && gB_ForciblyStopped)
|
if(gCV_CentralBot.BoolValue && gB_ForciblyStopped)
|
||||||
{
|
{
|
||||||
gB_ForciblyStopped = false;
|
gB_ForciblyStopped = false;
|
||||||
@ -1801,7 +1790,8 @@ public Action Timer_EndReplay(Handle Timer, any data)
|
|||||||
{
|
{
|
||||||
gRS_ReplayStatus[data] = Replay_Start;
|
gRS_ReplayStatus[data] = Replay_Start;
|
||||||
|
|
||||||
CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, data, TIMER_FLAG_NO_MAPCHANGE);
|
delete gH_ReplayTimers[data];
|
||||||
|
gH_ReplayTimers[data] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, data, TIMER_FLAG_NO_MAPCHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -1815,6 +1805,8 @@ public Action Timer_EndReplay(Handle Timer, any data)
|
|||||||
|
|
||||||
public Action Timer_StartReplay(Handle Timer, any data)
|
public Action Timer_StartReplay(Handle Timer, any data)
|
||||||
{
|
{
|
||||||
|
gH_ReplayTimers[data] = null;
|
||||||
|
|
||||||
if(gRS_ReplayStatus[data] == Replay_Running || (gCV_CentralBot.BoolValue && gB_ForciblyStopped))
|
if(gRS_ReplayStatus[data] == Replay_Running || (gCV_CentralBot.BoolValue && gB_ForciblyStopped))
|
||||||
{
|
{
|
||||||
return Plugin_Stop;
|
return Plugin_Stop;
|
||||||
@ -1964,24 +1956,29 @@ public Action Command_DeleteReplay(int client, int args)
|
|||||||
Menu menu = new Menu(DeleteReplay_Callback);
|
Menu menu = new Menu(DeleteReplay_Callback);
|
||||||
menu.SetTitle("%T", "DeleteReplayMenuTitle", client);
|
menu.SetTitle("%T", "DeleteReplayMenuTitle", client);
|
||||||
|
|
||||||
|
int[] styles = new int[gI_Styles];
|
||||||
|
Shavit_GetOrderedStyles(styles, gI_Styles);
|
||||||
|
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
for(int i = 0; i < gI_Styles; i++)
|
||||||
{
|
{
|
||||||
if(!ReplayEnabled(i))
|
int iStyle = styles[i];
|
||||||
|
|
||||||
|
if(!ReplayEnabled(iStyle))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int j = 0; j < TRACKS_SIZE; j++)
|
for(int j = 0; j < TRACKS_SIZE; j++)
|
||||||
{
|
{
|
||||||
if(gA_FrameCache[i][j].iFrameCount == 0)
|
if(gA_FrameCache[iStyle][j].iFrameCount == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char sInfo[8];
|
char sInfo[8];
|
||||||
FormatEx(sInfo, 8, "%d;%d", i, j);
|
FormatEx(sInfo, 8, "%d;%d", iStyle, j);
|
||||||
|
|
||||||
float time = GetReplayLength(i, j);
|
float time = GetReplayLength(iStyle, j);
|
||||||
|
|
||||||
char sTrack[32];
|
char sTrack[32];
|
||||||
GetTrackName(client, j, sTrack, 32);
|
GetTrackName(client, j, sTrack, 32);
|
||||||
@ -1993,12 +1990,12 @@ public Action Command_DeleteReplay(int client, int args)
|
|||||||
char sTime[32];
|
char sTime[32];
|
||||||
FormatSeconds(time, sTime, 32, false);
|
FormatSeconds(time, sTime, 32, false);
|
||||||
|
|
||||||
FormatEx(sDisplay, 64, "%s (%s) - %s", gS_StyleStrings[i].sStyleName, sTrack, sTime);
|
FormatEx(sDisplay, 64, "%s (%s) - %s", gS_StyleStrings[iStyle].sStyleName, sTrack, sTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FormatEx(sDisplay, 64, "%s (%s)", gS_StyleStrings[i].sStyleName, sTrack);
|
FormatEx(sDisplay, 64, "%s (%s)", gS_StyleStrings[iStyle].sStyleName, sTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.AddItem(sInfo, sDisplay);
|
menu.AddItem(sInfo, sDisplay);
|
||||||
@ -2108,14 +2105,29 @@ public Action Command_Replay(int client, int args)
|
|||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetClientTeam(client) != 1 || GetSpectatorTarget(client) != gA_CentralCache.iClient)
|
if(GetClientTeam(client) > 1)
|
||||||
|
{
|
||||||
|
if(gEV_Type == Engine_TF2)
|
||||||
|
{
|
||||||
|
TF2_ChangeClientTeam(client, TFTeam_Spectator);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ChangeClientTeam(client, CS_TEAM_SPECTATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetEntPropEnt(client, Prop_Send, "m_hObserverTarget", gA_CentralCache.iClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(GetSpectatorTarget(client) != gA_CentralCache.iClient)
|
||||||
{
|
{
|
||||||
Shavit_PrintToChat(client, "%T", "CentralReplaySpectator", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText, gS_ChatStrings.sVariable, gS_ChatStrings.sText);
|
Shavit_PrintToChat(client, "%T", "CentralReplaySpectator", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText, gS_ChatStrings.sVariable, gS_ChatStrings.sText);
|
||||||
|
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CheckCommandAccess(client, "sm_deletereplay", ADMFLAG_RCON))
|
if(CanStopCentral(client))
|
||||||
{
|
{
|
||||||
char arg[8];
|
char arg[8];
|
||||||
GetCmdArg(1, arg, 8);
|
GetCmdArg(1, arg, 8);
|
||||||
@ -2194,7 +2206,7 @@ void OpenReplaySubMenu(int client, int track)
|
|||||||
Menu menu = new Menu(MenuHandler_ReplaySubmenu);
|
Menu menu = new Menu(MenuHandler_ReplaySubmenu);
|
||||||
menu.SetTitle("%T (%s)\n ", "CentralReplayTitle", client, sTrack);
|
menu.SetTitle("%T (%s)\n ", "CentralReplayTitle", client, sTrack);
|
||||||
|
|
||||||
if(CheckCommandAccess(client, "sm_deletereplay", ADMFLAG_RCON))
|
if(CanStopCentral(client))
|
||||||
{
|
{
|
||||||
char sDisplay[64];
|
char sDisplay[64];
|
||||||
FormatEx(sDisplay, 64, "%T", "CentralReplayStop", client);
|
FormatEx(sDisplay, 64, "%T", "CentralReplayStop", client);
|
||||||
@ -2202,17 +2214,22 @@ void OpenReplaySubMenu(int client, int track)
|
|||||||
menu.AddItem("stop", sDisplay, (gA_CentralCache.iReplayStatus != Replay_Idle)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
menu.AddItem("stop", sDisplay, (gA_CentralCache.iReplayStatus != Replay_Idle)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int[] styles = new int[gI_Styles];
|
||||||
|
Shavit_GetOrderedStyles(styles, gI_Styles);
|
||||||
|
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
for(int i = 0; i < gI_Styles; i++)
|
||||||
{
|
{
|
||||||
if(!ReplayEnabled(i))
|
int iStyle = styles[i];
|
||||||
|
|
||||||
|
if(!ReplayEnabled(iStyle))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char sInfo[8];
|
char sInfo[8];
|
||||||
IntToString(i, sInfo, 8);
|
IntToString(iStyle, sInfo, 8);
|
||||||
|
|
||||||
float time = GetReplayLength(i, track);
|
float time = GetReplayLength(iStyle, track);
|
||||||
|
|
||||||
char sDisplay[64];
|
char sDisplay[64];
|
||||||
|
|
||||||
@ -2221,15 +2238,15 @@ void OpenReplaySubMenu(int client, int track)
|
|||||||
char sTime[32];
|
char sTime[32];
|
||||||
FormatSeconds(time, sTime, 32, false);
|
FormatSeconds(time, sTime, 32, false);
|
||||||
|
|
||||||
FormatEx(sDisplay, 64, "%s - %s", gS_StyleStrings[i].sStyleName, sTime);
|
FormatEx(sDisplay, 64, "%s - %s", gS_StyleStrings[iStyle].sStyleName, sTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcopy(sDisplay, 64, gS_StyleStrings[i].sStyleName);
|
strcopy(sDisplay, 64, gS_StyleStrings[iStyle].sStyleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.AddItem(sInfo, sDisplay, (gA_FrameCache[i][track].iFrameCount > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
menu.AddItem(sInfo, sDisplay, (gA_FrameCache[iStyle][track].iFrameCount > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(menu.ItemCount == 0)
|
if(menu.ItemCount == 0)
|
||||||
@ -2253,7 +2270,7 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i
|
|||||||
char info[16];
|
char info[16];
|
||||||
menu.GetItem(param2, info, 16);
|
menu.GetItem(param2, info, 16);
|
||||||
|
|
||||||
if(StrEqual(info, "stop"))
|
if(StrEqual(info, "stop") && CanStopCentral(param1))
|
||||||
{
|
{
|
||||||
StopCentralReplay(param1);
|
StopCentralReplay(param1);
|
||||||
OpenReplaySubMenu(param1, gI_Track[param1]);
|
OpenReplaySubMenu(param1, gI_Track[param1]);
|
||||||
@ -2280,6 +2297,8 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i
|
|||||||
gI_ReplayTick[style] = 0;
|
gI_ReplayTick[style] = 0;
|
||||||
gA_CentralCache.iStyle = style;
|
gA_CentralCache.iStyle = style;
|
||||||
gA_CentralCache.iTrack = gI_Track[param1];
|
gA_CentralCache.iTrack = gI_Track[param1];
|
||||||
|
gA_CentralCache.iPlaybackSerial = GetClientSerial(param1);
|
||||||
|
gF_LastInteraction[param1] = GetEngineTime();
|
||||||
gI_ReplayBotClient[style] = gA_CentralCache.iClient;
|
gI_ReplayBotClient[style] = gA_CentralCache.iClient;
|
||||||
gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_Start;
|
gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_Start;
|
||||||
TeleportToStart(gA_CentralCache.iClient, style, gI_Track[param1]);
|
TeleportToStart(gA_CentralCache.iClient, style, gI_Track[param1]);
|
||||||
@ -2289,7 +2308,8 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i
|
|||||||
|
|
||||||
UpdateReplayInfo(gA_CentralCache.iClient, style, time, gI_Track[param1]);
|
UpdateReplayInfo(gA_CentralCache.iClient, style, time, gI_Track[param1]);
|
||||||
|
|
||||||
CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, style, TIMER_FLAG_NO_MAPCHANGE);
|
delete gH_ReplayTimers[style];
|
||||||
|
gH_ReplayTimers[style] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, style, TIMER_FLAG_NO_MAPCHANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2306,6 +2326,14 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CanStopCentral(int client)
|
||||||
|
{
|
||||||
|
return (CheckCommandAccess(client, "sm_deletereplay", ADMFLAG_RCON) ||
|
||||||
|
(gCV_PlaybackCanStop.BoolValue &&
|
||||||
|
GetClientSerial(client) == gA_CentralCache.iPlaybackSerial &&
|
||||||
|
GetEngineTime() - gF_LastInteraction[client] > gCV_PlaybackCooldown.FloatValue));
|
||||||
|
}
|
||||||
|
|
||||||
void TeleportToStart(int client, int style, int track)
|
void TeleportToStart(int client, int style, int track)
|
||||||
{
|
{
|
||||||
if(gA_FrameCache[style][track].iFrameCount == 0)
|
if(gA_FrameCache[style][track].iFrameCount == 0)
|
||||||
@ -2333,6 +2361,12 @@ void StopCentralReplay(int client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int style = gA_CentralCache.iStyle;
|
int style = gA_CentralCache.iStyle;
|
||||||
|
int player = GetClientFromSerial(gA_CentralCache.iPlaybackSerial);
|
||||||
|
|
||||||
|
if(player != 0)
|
||||||
|
{
|
||||||
|
gF_LastInteraction[player] = GetEngineTime();
|
||||||
|
}
|
||||||
|
|
||||||
gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_Idle;
|
gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_Idle;
|
||||||
gI_ReplayTick[style] = 0;
|
gI_ReplayTick[style] = 0;
|
||||||
@ -2340,6 +2374,7 @@ void StopCentralReplay(int client)
|
|||||||
gF_StartTick[style] = -65535.0;
|
gF_StartTick[style] = -65535.0;
|
||||||
gA_CentralCache.iStyle = 0;
|
gA_CentralCache.iStyle = 0;
|
||||||
gB_ForciblyStopped = true;
|
gB_ForciblyStopped = true;
|
||||||
|
gA_CentralCache.iPlaybackSerial = 0;
|
||||||
|
|
||||||
if(gA_CentralCache.iClient != -1)
|
if(gA_CentralCache.iClient != -1)
|
||||||
{
|
{
|
||||||
@ -2425,14 +2460,17 @@ void GetTrackName(int client, int track, char[] output, int size)
|
|||||||
|
|
||||||
float GetReplayLength(int style, int track)
|
float GetReplayLength(int style, int track)
|
||||||
{
|
{
|
||||||
|
if(gA_FrameCache[style][track].iFrameCount == 0)
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
if(gA_FrameCache[style][track].bNewFormat)
|
if(gA_FrameCache[style][track].bNewFormat)
|
||||||
{
|
{
|
||||||
return gA_FrameCache[style][track].fTime;
|
return gA_FrameCache[style][track].fTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
float fWRTime = Shavit_GetWorldRecord(style, track);
|
return Shavit_GetWorldRecord(style, track) * gA_StyleSettings[style].fTimescale;
|
||||||
|
|
||||||
return fWRTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetReplayName(int style, int track, char[] buffer, int length)
|
void GetReplayName(int style, int track, char[] buffer, int length)
|
||||||
|
|||||||
@ -462,17 +462,22 @@ public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[]
|
|||||||
gS_TargetName[client], "Profile", client, gS_TargetAuth[client], "Country", client, sCountry, sLastLogin, sClearString,
|
gS_TargetName[client], "Profile", client, gS_TargetAuth[client], "Country", client, sCountry, sLastLogin, sClearString,
|
||||||
gS_StyleStrings[0].sStyleName, "WorldRecords", client, iWRs, sRankingString);
|
gS_StyleStrings[0].sStyleName, "WorldRecords", client, iWRs, sRankingString);
|
||||||
|
|
||||||
|
int[] styles = new int[gI_Styles];
|
||||||
|
Shavit_GetOrderedStyles(styles, gI_Styles);
|
||||||
|
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
for(int i = 0; i < gI_Styles; i++)
|
||||||
{
|
{
|
||||||
if(gA_StyleSettings[i].bUnranked)
|
int iStyle = styles[i];
|
||||||
|
|
||||||
|
if(gA_StyleSettings[iStyle].bUnranked)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char sInfo[4];
|
char sInfo[4];
|
||||||
IntToString(i, sInfo, 4);
|
IntToString(iStyle, sInfo, 4);
|
||||||
|
|
||||||
menu.AddItem(sInfo, gS_StyleStrings[i].sStyleName);
|
menu.AddItem(sInfo, gS_StyleStrings[iStyle].sStyleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// should NEVER happen
|
// should NEVER happen
|
||||||
|
|||||||
@ -107,6 +107,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
|
|||||||
CreateNative("Shavit_GetWRName", Native_GetWRName);
|
CreateNative("Shavit_GetWRName", Native_GetWRName);
|
||||||
CreateNative("Shavit_GetWRRecordID", Native_GetWRRecordID);
|
CreateNative("Shavit_GetWRRecordID", Native_GetWRRecordID);
|
||||||
CreateNative("Shavit_GetWRTime", Native_GetWRTime);
|
CreateNative("Shavit_GetWRTime", Native_GetWRTime);
|
||||||
|
CreateNative("Shavit_ReloadLeaderboards", Native_ReloadLeaderboards);
|
||||||
CreateNative("Shavit_WR_DeleteMap", Native_WR_DeleteMap);
|
CreateNative("Shavit_WR_DeleteMap", Native_WR_DeleteMap);
|
||||||
|
|
||||||
// registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins
|
// registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins
|
||||||
@ -507,13 +508,6 @@ public void SQL_UpdateWRCache_Callback(Database db, DBResultSet results, const c
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// resultset structure
|
|
||||||
// FIELD 0: style
|
|
||||||
// FIELD 1: id
|
|
||||||
// FIELD 2: time - sorted
|
|
||||||
// FIELD 3: name
|
|
||||||
// FIELD 4: track
|
|
||||||
|
|
||||||
// reset cache
|
// reset cache
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
for(int i = 0; i < gI_Styles; i++)
|
||||||
{
|
{
|
||||||
@ -556,6 +550,12 @@ public int Native_GetWRTime(Handle handler, int numParams)
|
|||||||
SetNativeCellRef(2, gF_WRTime[GetNativeCell(1)][GetNativeCell(3)]);
|
SetNativeCellRef(2, gF_WRTime[GetNativeCell(1)][GetNativeCell(3)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Native_ReloadLeaderboards(Handle handler, int numParams)
|
||||||
|
{
|
||||||
|
UpdateLeaderboards();
|
||||||
|
UpdateWRCache();
|
||||||
|
}
|
||||||
|
|
||||||
public int Native_GetWRRecordID(Handle handler, int numParams)
|
public int Native_GetWRRecordID(Handle handler, int numParams)
|
||||||
{
|
{
|
||||||
SetNativeCellRef(2, gI_WRRecordID[GetNativeCell(1)][GetNativeCell(3)]);
|
SetNativeCellRef(2, gI_WRRecordID[GetNativeCell(1)][GetNativeCell(3)]);
|
||||||
@ -745,15 +745,20 @@ void DeleteSubmenu(int client)
|
|||||||
Menu menu = new Menu(MenuHandler_Delete);
|
Menu menu = new Menu(MenuHandler_Delete);
|
||||||
menu.SetTitle("%T\n ", "DeleteMenuTitle", client);
|
menu.SetTitle("%T\n ", "DeleteMenuTitle", client);
|
||||||
|
|
||||||
|
int[] styles = new int[gI_Styles];
|
||||||
|
Shavit_GetOrderedStyles(styles, gI_Styles);
|
||||||
|
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
for(int i = 0; i < gI_Styles; i++)
|
||||||
{
|
{
|
||||||
|
int iStyle = styles[i];
|
||||||
|
|
||||||
char sInfo[8];
|
char sInfo[8];
|
||||||
IntToString(i, sInfo, 8);
|
IntToString(iStyle, sInfo, 8);
|
||||||
|
|
||||||
char sDisplay[64];
|
char sDisplay[64];
|
||||||
FormatEx(sDisplay, 64, "%s (%T: %d)", gS_StyleStrings[i].sStyleName, "WRRecord", client, gI_RecordAmount[i][gA_WRCache[client].iLastTrack]);
|
FormatEx(sDisplay, 64, "%s (%T: %d)", gS_StyleStrings[iStyle].sStyleName, "WRRecord", client, gI_RecordAmount[iStyle][gA_WRCache[client].iLastTrack]);
|
||||||
|
|
||||||
menu.AddItem(sInfo, sDisplay, (gI_RecordAmount[i][gA_WRCache[client].iLastTrack] > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
menu.AddItem(sInfo, sDisplay, (gI_RecordAmount[iStyle][gA_WRCache[client].iLastTrack] > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.ExitButton = true;
|
menu.ExitButton = true;
|
||||||
@ -775,17 +780,17 @@ public Action Command_DeleteAll(int client, int args)
|
|||||||
char sInfo[8];
|
char sInfo[8];
|
||||||
IntToString(i, sInfo, 8);
|
IntToString(i, sInfo, 8);
|
||||||
|
|
||||||
int records = GetTrackRecordCount(i);
|
int iRecords = GetTrackRecordCount(i);
|
||||||
|
|
||||||
char sTrack[64];
|
char sTrack[64];
|
||||||
GetTrackName(client, i, sTrack, 64);
|
GetTrackName(client, i, sTrack, 64);
|
||||||
|
|
||||||
if(records > 0)
|
if(iRecords > 0)
|
||||||
{
|
{
|
||||||
Format(sTrack, 64, "%s (%T: %d)", sTrack, "WRRecord", client, records);
|
Format(sTrack, 64, "%s (%T: %d)", sTrack, "WRRecord", client, iRecords);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.AddItem(sInfo, sTrack, (records > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
menu.AddItem(sInfo, sTrack, (iRecords > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.ExitButton = true;
|
menu.ExitButton = true;
|
||||||
@ -798,9 +803,57 @@ public int MenuHandler_DeleteAll_First(Menu menu, MenuAction action, int param1,
|
|||||||
{
|
{
|
||||||
if(action == MenuAction_Select)
|
if(action == MenuAction_Select)
|
||||||
{
|
{
|
||||||
char info[16];
|
char sInfo[8];
|
||||||
menu.GetItem(param2, info, 16);
|
menu.GetItem(param2, sInfo, 8);
|
||||||
gA_WRCache[param1].iLastTrack = StringToInt(info);
|
int iTrack = gA_WRCache[param1].iLastTrack = StringToInt(sInfo);
|
||||||
|
|
||||||
|
char sTrack[64];
|
||||||
|
GetTrackName(param1, iTrack, sTrack, 64);
|
||||||
|
|
||||||
|
Menu subMenu = new Menu(MenuHandler_DeleteAll_Second);
|
||||||
|
subMenu.SetTitle("%T\n ", "DeleteTrackAllStyle", param1, sTrack);
|
||||||
|
|
||||||
|
int[] styles = new int[gI_Styles];
|
||||||
|
Shavit_GetOrderedStyles(styles, gI_Styles);
|
||||||
|
|
||||||
|
for(int i = 0; i < gI_Styles; i++)
|
||||||
|
{
|
||||||
|
int iStyle = styles[i];
|
||||||
|
|
||||||
|
char sStyle[64];
|
||||||
|
strcopy(sStyle, 64, gS_StyleStrings[iStyle].sStyleName);
|
||||||
|
|
||||||
|
IntToString(iStyle, sInfo, 8);
|
||||||
|
|
||||||
|
int iRecords = gI_RecordAmount[iStyle][iTrack];
|
||||||
|
|
||||||
|
if(iRecords > 0)
|
||||||
|
{
|
||||||
|
Format(sStyle, 64, "%s (%T: %d)", sStyle, "WRRecord", param1, iRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
subMenu.AddItem(sInfo, sStyle, (iRecords > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
subMenu.ExitButton = true;
|
||||||
|
subMenu.Display(param1, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(action == MenuAction_End)
|
||||||
|
{
|
||||||
|
delete menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MenuHandler_DeleteAll_Second(Menu menu, MenuAction action, int param1, int param2)
|
||||||
|
{
|
||||||
|
if(action == MenuAction_Select)
|
||||||
|
{
|
||||||
|
char sInfo[8];
|
||||||
|
menu.GetItem(param2, sInfo, 8);
|
||||||
|
gA_WRCache[param1].iLastStyle = StringToInt(sInfo);
|
||||||
|
|
||||||
DeleteAllSubmenu(param1);
|
DeleteAllSubmenu(param1);
|
||||||
}
|
}
|
||||||
@ -819,7 +872,7 @@ void DeleteAllSubmenu(int client)
|
|||||||
GetTrackName(client, gA_WRCache[client].iLastTrack, sTrack, 32);
|
GetTrackName(client, gA_WRCache[client].iLastTrack, sTrack, 32);
|
||||||
|
|
||||||
Menu menu = new Menu(MenuHandler_DeleteAll);
|
Menu menu = new Menu(MenuHandler_DeleteAll);
|
||||||
menu.SetTitle("%T\n ", "DeleteAllRecordsMenuTitle", client, gS_Map, sTrack);
|
menu.SetTitle("%T\n ", "DeleteAllRecordsMenuTitle", client, gS_Map, sTrack, gS_StyleStrings[gA_WRCache[client].iLastStyle].sStyleName);
|
||||||
|
|
||||||
char sMenuItem[64];
|
char sMenuItem[64];
|
||||||
|
|
||||||
@ -859,10 +912,12 @@ public int MenuHandler_DeleteAll(Menu menu, MenuAction action, int param1, int p
|
|||||||
char sTrack[32];
|
char sTrack[32];
|
||||||
GetTrackName(LANG_SERVER, gA_WRCache[param1].iLastTrack, sTrack, 32);
|
GetTrackName(LANG_SERVER, gA_WRCache[param1].iLastTrack, sTrack, 32);
|
||||||
|
|
||||||
Shavit_LogMessage("%L - deleted all %s track records from map `%s`.", param1, sTrack, gS_Map);
|
Shavit_LogMessage("%L - deleted all %s track and %s style records from map `%s`.",
|
||||||
|
param1, sTrack, gS_StyleStrings[gA_WRCache[param1].iLastStyle].sStyleName, gS_Map);
|
||||||
|
|
||||||
char sQuery[256];
|
char sQuery[256];
|
||||||
FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE map = '%s' AND track = %d;", gS_MySQLPrefix, gS_Map, gA_WRCache[param1].iLastTrack);
|
FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE map = '%s' AND style = %d AND track = %d;",
|
||||||
|
gS_MySQLPrefix, gS_Map, gA_WRCache[param1].iLastStyle, gA_WRCache[param1].iLastTrack);
|
||||||
|
|
||||||
gH_SQL.Query(DeleteAll_Callback, sQuery, GetClientSerial(param1), DBPrio_High);
|
gH_SQL.Query(DeleteAll_Callback, sQuery, GetClientSerial(param1), DBPrio_High);
|
||||||
}
|
}
|
||||||
@ -885,24 +940,29 @@ public Action Command_DeleteStyleRecords(int client, int args)
|
|||||||
Menu menu = new Menu(MenuHandler_DeleteStyleRecords);
|
Menu menu = new Menu(MenuHandler_DeleteStyleRecords);
|
||||||
menu.SetTitle("%T\n ", "DeleteStyleRecordsRecordsMenuTitle", client, gS_Map);
|
menu.SetTitle("%T\n ", "DeleteStyleRecordsRecordsMenuTitle", client, gS_Map);
|
||||||
|
|
||||||
|
int[] styles = new int[gI_Styles];
|
||||||
|
Shavit_GetOrderedStyles(styles, gI_Styles);
|
||||||
|
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
for(int i = 0; i < gI_Styles; i++)
|
||||||
{
|
{
|
||||||
if(gA_StyleSettings[i].bUnranked)
|
int iStyle = styles[i];
|
||||||
|
|
||||||
|
if(gA_StyleSettings[iStyle].bUnranked)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char sInfo[8];
|
char sInfo[8];
|
||||||
IntToString(i, sInfo, 8);
|
IntToString(iStyle, sInfo, 8);
|
||||||
|
|
||||||
char sDisplay[64];
|
char sDisplay[64];
|
||||||
FormatEx(sDisplay, 64, "%s (%d %T)", gS_StyleStrings[i].sStyleName, gI_RecordAmount[i], "WRRecord", client);
|
FormatEx(sDisplay, 64, "%s (%d %T)", gS_StyleStrings[iStyle].sStyleName, gI_RecordAmount[iStyle], "WRRecord", client);
|
||||||
|
|
||||||
int iTotalAmount = 0;
|
int iTotalAmount = 0;
|
||||||
|
|
||||||
for(int j = 0; j < TRACKS_SIZE; j++)
|
for(int j = 0; j < TRACKS_SIZE; j++)
|
||||||
{
|
{
|
||||||
iTotalAmount += gI_RecordAmount[i][j];
|
iTotalAmount += gI_RecordAmount[iStyle][j];
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.AddItem(sInfo, sDisplay, (iTotalAmount > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
menu.AddItem(sInfo, sDisplay, (iTotalAmount > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
||||||
@ -1048,8 +1108,9 @@ public int MenuHandler_Delete(Menu menu, MenuAction action, int param1, int para
|
|||||||
{
|
{
|
||||||
char info[16];
|
char info[16];
|
||||||
menu.GetItem(param2, info, 16);
|
menu.GetItem(param2, info, 16);
|
||||||
|
gA_WRCache[param1].iLastStyle = StringToInt(info);
|
||||||
|
|
||||||
OpenDelete(param1, StringToInt(info));
|
OpenDelete(param1);
|
||||||
|
|
||||||
UpdateLeaderboards();
|
UpdateLeaderboards();
|
||||||
}
|
}
|
||||||
@ -1062,25 +1123,17 @@ public int MenuHandler_Delete(Menu menu, MenuAction action, int param1, int para
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenDelete(int client, int style)
|
void OpenDelete(int client)
|
||||||
{
|
{
|
||||||
char sQuery[512];
|
char sQuery[512];
|
||||||
|
FormatEx(sQuery, 512, "SELECT p.id, u.name, p.time, p.jumps FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE map = '%s' AND style = %d AND track = %d ORDER BY time ASC, date ASC LIMIT 1000;",
|
||||||
|
gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, gA_WRCache[client].iLastStyle, gA_WRCache[client].iLastTrack);
|
||||||
|
|
||||||
FormatEx(sQuery, 512, "SELECT p.id, u.name, p.time, p.jumps FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE map = '%s' AND style = %d AND track = %d ORDER BY time ASC, date ASC LIMIT 1000;", gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, style, gA_WRCache[client].iLastTrack);
|
gH_SQL.Query(SQL_OpenDelete_Callback, sQuery, GetClientSerial(client), DBPrio_High);
|
||||||
DataPack datapack = new DataPack();
|
|
||||||
datapack.WriteCell(GetClientSerial(client));
|
|
||||||
datapack.WriteCell(style);
|
|
||||||
|
|
||||||
gH_SQL.Query(SQL_OpenDelete_Callback, sQuery, datapack, DBPrio_High);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SQL_OpenDelete_Callback(Database db, DBResultSet results, const char[] error, DataPack data)
|
public void SQL_OpenDelete_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||||
{
|
{
|
||||||
data.Reset();
|
|
||||||
int client = GetClientFromSerial(data.ReadCell());
|
|
||||||
int style = data.ReadCell();
|
|
||||||
delete data;
|
|
||||||
|
|
||||||
if(results == null)
|
if(results == null)
|
||||||
{
|
{
|
||||||
LogError("Timer (WR OpenDelete) SQL query failed. Reason: %s", error);
|
LogError("Timer (WR OpenDelete) SQL query failed. Reason: %s", error);
|
||||||
@ -1088,13 +1141,17 @@ public void SQL_OpenDelete_Callback(Database db, DBResultSet results, const char
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int client = GetClientFromSerial(data);
|
||||||
|
|
||||||
if(client == 0)
|
if(client == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int iStyle = gA_WRCache[client].iLastStyle;
|
||||||
|
|
||||||
Menu menu = new Menu(OpenDelete_Handler);
|
Menu menu = new Menu(OpenDelete_Handler);
|
||||||
menu.SetTitle("%t", "ListClientRecords", gS_Map, gS_StyleStrings[style].sStyleName);
|
menu.SetTitle("%t", "ListClientRecords", gS_Map, gS_StyleStrings[iStyle].sStyleName);
|
||||||
|
|
||||||
int iCount = 0;
|
int iCount = 0;
|
||||||
|
|
||||||
@ -1140,10 +1197,10 @@ public int OpenDelete_Handler(Menu menu, MenuAction action, int param1, int para
|
|||||||
{
|
{
|
||||||
if(action == MenuAction_Select)
|
if(action == MenuAction_Select)
|
||||||
{
|
{
|
||||||
char info[16];
|
char sInfo[16];
|
||||||
menu.GetItem(param2, info, 16);
|
menu.GetItem(param2, sInfo, 16);
|
||||||
|
|
||||||
int id = StringToInt(info);
|
int id = StringToInt(sInfo);
|
||||||
|
|
||||||
if(id != -1)
|
if(id != -1)
|
||||||
{
|
{
|
||||||
@ -1174,9 +1231,9 @@ void OpenDeleteMenu(int client, int id)
|
|||||||
|
|
||||||
FormatEx(sMenuItem, 64, "%T", "MenuResponseYesSingle", client);
|
FormatEx(sMenuItem, 64, "%T", "MenuResponseYesSingle", client);
|
||||||
|
|
||||||
char info[16];
|
char sInfo[16];
|
||||||
IntToString(id, info, 16);
|
IntToString(id, sInfo, 16);
|
||||||
menu.AddItem(info, sMenuItem);
|
menu.AddItem(sInfo, sMenuItem);
|
||||||
|
|
||||||
for(int i = 1; i <= GetRandomInt(1, 3); i++)
|
for(int i = 1; i <= GetRandomInt(1, 3); i++)
|
||||||
{
|
{
|
||||||
@ -1192,9 +1249,10 @@ public int DeleteConfirm_Handler(Menu menu, MenuAction action, int param1, int p
|
|||||||
{
|
{
|
||||||
if(action == MenuAction_Select)
|
if(action == MenuAction_Select)
|
||||||
{
|
{
|
||||||
char info[16];
|
char sInfo[16];
|
||||||
menu.GetItem(param2, info, 16);
|
menu.GetItem(param2, sInfo, 16);
|
||||||
int iRecordID = StringToInt(info);
|
|
||||||
|
int iRecordID = StringToInt(sInfo);
|
||||||
|
|
||||||
if(iRecordID == -1)
|
if(iRecordID == -1)
|
||||||
{
|
{
|
||||||
@ -1203,35 +1261,11 @@ public int DeleteConfirm_Handler(Menu menu, MenuAction action, int param1, int p
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
|
||||||
{
|
|
||||||
if(gA_StyleSettings[i].bUnranked)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int j = 0; j < TRACKS_SIZE; j++)
|
|
||||||
{
|
|
||||||
if(gI_WRRecordID[i][j] != iRecordID)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Call_StartForward(gH_OnWRDeleted);
|
|
||||||
Call_PushCell(i);
|
|
||||||
Call_PushCell(iRecordID);
|
|
||||||
Call_PushCell(j);
|
|
||||||
Call_Finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: display record details here (map name, player name/authid, time, rank on map) without dropping threaded queries
|
|
||||||
Shavit_LogMessage("%L - deleted record id %d.", param1, iRecordID);
|
|
||||||
|
|
||||||
char sQuery[256];
|
char sQuery[256];
|
||||||
FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE id = %d;", gS_MySQLPrefix, iRecordID);
|
FormatEx(sQuery, 256, "SELECT u.auth, u.name, p.map, p.time, p.sync, p.perfs, p.jumps, p.strafes, p.id, p.date FROM %susers u LEFT JOIN %splayertimes p ON u.auth = p.auth WHERE p.id = %d;",
|
||||||
|
gS_MySQLPrefix, gS_MySQLPrefix, iRecordID);
|
||||||
|
|
||||||
gH_SQL.Query(DeleteConfirm_Callback, sQuery, GetClientSerial(param1), DBPrio_High);
|
gH_SQL.Query(GetRecordDetails_Callback, sQuery, GetClientSerial(param1), DBPrio_High);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(action == MenuAction_End)
|
else if(action == MenuAction_End)
|
||||||
@ -1242,8 +1276,101 @@ public int DeleteConfirm_Handler(Menu menu, MenuAction action, int param1, int p
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void GetRecordDetails_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||||
|
{
|
||||||
|
if(results == null)
|
||||||
|
{
|
||||||
|
LogError("Timer (WR GetRecordDetails) SQL query failed. Reason: %s", error);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int client = GetClientFromSerial(data);
|
||||||
|
|
||||||
|
if(client == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(results.FetchRow())
|
||||||
|
{
|
||||||
|
char sAuthID[32];
|
||||||
|
results.FetchString(0, sAuthID, 32);
|
||||||
|
|
||||||
|
char sName[MAX_NAME_LENGTH];
|
||||||
|
results.FetchString(1, sName, MAX_NAME_LENGTH);
|
||||||
|
|
||||||
|
char sMap[160];
|
||||||
|
results.FetchString(2, sMap, 160);
|
||||||
|
|
||||||
|
float fTime = results.FetchFloat(3);
|
||||||
|
float fSync = results.FetchFloat(4);
|
||||||
|
float fPerfectJumps = results.FetchFloat(5);
|
||||||
|
|
||||||
|
int iJumps = results.FetchInt(6);
|
||||||
|
int iStrafes = results.FetchInt(7);
|
||||||
|
int iRecordID = results.FetchInt(8);
|
||||||
|
int iTimestamp = results.FetchInt(9);
|
||||||
|
|
||||||
|
int iStyle = gA_WRCache[client].iLastStyle;
|
||||||
|
int iTrack = gA_WRCache[client].iLastTrack;
|
||||||
|
bool bWRDeleted = (gI_WRRecordID[iStyle][iTrack] == iRecordID);
|
||||||
|
|
||||||
|
// that's a big datapack ya yeet
|
||||||
|
DataPack hPack = new DataPack();
|
||||||
|
hPack.WriteCell(GetClientSerial(client));
|
||||||
|
hPack.WriteString(sAuthID);
|
||||||
|
hPack.WriteString(sName);
|
||||||
|
hPack.WriteString(sMap);
|
||||||
|
hPack.WriteCell(fTime);
|
||||||
|
hPack.WriteCell(fSync);
|
||||||
|
hPack.WriteCell(fPerfectJumps);
|
||||||
|
hPack.WriteCell(iJumps);
|
||||||
|
hPack.WriteCell(iStrafes);
|
||||||
|
hPack.WriteCell(iRecordID);
|
||||||
|
hPack.WriteCell(iTimestamp);
|
||||||
|
hPack.WriteCell(iStyle);
|
||||||
|
hPack.WriteCell(iTrack);
|
||||||
|
hPack.WriteCell(bWRDeleted);
|
||||||
|
|
||||||
|
char sQuery[256];
|
||||||
|
FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE id = %d;",
|
||||||
|
gS_MySQLPrefix, iRecordID);
|
||||||
|
|
||||||
|
gH_SQL.Query(DeleteConfirm_Callback, sQuery, hPack, DBPrio_High);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteConfirm_Callback(Database db, DBResultSet results, const char[] error, any data)
|
public void DeleteConfirm_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||||
{
|
{
|
||||||
|
DataPack hPack = view_as<DataPack>(data);
|
||||||
|
hPack.Reset();
|
||||||
|
|
||||||
|
int iSerial = hPack.ReadCell();
|
||||||
|
|
||||||
|
char sAuthID[32];
|
||||||
|
hPack.ReadString(sAuthID, 32);
|
||||||
|
|
||||||
|
char sName[MAX_NAME_LENGTH];
|
||||||
|
hPack.ReadString(sName, MAX_NAME_LENGTH);
|
||||||
|
|
||||||
|
char sMap[160];
|
||||||
|
hPack.ReadString(sMap, 160);
|
||||||
|
|
||||||
|
float fTime = view_as<float>(hPack.ReadCell());
|
||||||
|
float fSync = view_as<float>(hPack.ReadCell());
|
||||||
|
float fPerfectJumps = view_as<float>(hPack.ReadCell());
|
||||||
|
|
||||||
|
int iJumps = hPack.ReadCell();
|
||||||
|
int iStrafes = hPack.ReadCell();
|
||||||
|
int iRecordID = hPack.ReadCell();
|
||||||
|
int iTimestamp = hPack.ReadCell();
|
||||||
|
int iStyle = hPack.ReadCell();
|
||||||
|
int iTrack = hPack.ReadCell();
|
||||||
|
|
||||||
|
bool bWRDeleted = view_as<bool>(hPack.ReadCell());
|
||||||
|
delete hPack;
|
||||||
|
|
||||||
if(results == null)
|
if(results == null)
|
||||||
{
|
{
|
||||||
LogError("Timer (WR DeleteConfirm) SQL query failed. Reason: %s", error);
|
LogError("Timer (WR DeleteConfirm) SQL query failed. Reason: %s", error);
|
||||||
@ -1251,6 +1378,15 @@ public void DeleteConfirm_Callback(Database db, DBResultSet results, const char[
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(bWRDeleted)
|
||||||
|
{
|
||||||
|
Call_StartForward(gH_OnWRDeleted);
|
||||||
|
Call_PushCell(iStyle);
|
||||||
|
Call_PushCell(iRecordID);
|
||||||
|
Call_PushCell(iTrack);
|
||||||
|
Call_Finish();
|
||||||
|
}
|
||||||
|
|
||||||
UpdateWRCache();
|
UpdateWRCache();
|
||||||
|
|
||||||
for(int i = 1; i <= MaxClients; i++)
|
for(int i = 1; i <= MaxClients; i++)
|
||||||
@ -1258,7 +1394,17 @@ public void DeleteConfirm_Callback(Database db, DBResultSet results, const char[
|
|||||||
OnClientPutInServer(i);
|
OnClientPutInServer(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int client = GetClientFromSerial(data);
|
int client = GetClientFromSerial(iSerial);
|
||||||
|
|
||||||
|
char sTrack[32];
|
||||||
|
GetTrackName(LANG_SERVER, iTrack, sTrack, 32);
|
||||||
|
|
||||||
|
char sDate[32];
|
||||||
|
FormatTime(sDate, 32, "%Y-%m-%d %H:%M:%S", iTimestamp);
|
||||||
|
|
||||||
|
// above the client == 0 so log doesn't get lost if admin disconnects between deleting record and query execution
|
||||||
|
Shavit_LogMessage("%L - deleted record. Runner: %s (%s) | Map: %s | Style: %s | Track: %s | Time: %.2f (%s) | Strafes: %d (%.1f%%) | Jumps: %d (%.1f%%) | Run date: %s | Record ID: %d",
|
||||||
|
client, sName, sAuthID, sMap, gS_StyleStrings[iStyle].sStyleName, sTrack, fTime, (bWRDeleted)? "WR":"not WR", iStrafes, fSync, iJumps, fPerfectJumps, sDate, iRecordID);
|
||||||
|
|
||||||
if(client == 0)
|
if(client == 0)
|
||||||
{
|
{
|
||||||
@ -1291,19 +1437,11 @@ public void DeleteAll_Callback(Database db, DBResultSet results, const char[] er
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
Call_StartForward(gH_OnWRDeleted);
|
||||||
{
|
Call_PushCell(gA_WRCache[client].iLastStyle);
|
||||||
if(gA_StyleSettings[i].bUnranked)
|
Call_PushCell(-1);
|
||||||
{
|
Call_PushCell(gA_WRCache[client].iLastTrack);
|
||||||
continue;
|
Call_Finish();
|
||||||
}
|
|
||||||
|
|
||||||
Call_StartForward(gH_OnWRDeleted);
|
|
||||||
Call_PushCell(i);
|
|
||||||
Call_PushCell(-1);
|
|
||||||
Call_PushCell(gA_WRCache[client].iLastTrack);
|
|
||||||
Call_Finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
Shavit_PrintToChat(client, "%T", "DeletedRecordsMap", client, gS_ChatStrings.sVariable, gS_Map, gS_ChatStrings.sText);
|
Shavit_PrintToChat(client, "%T", "DeletedRecordsMap", client, gS_ChatStrings.sVariable, gS_Map, gS_ChatStrings.sText);
|
||||||
}
|
}
|
||||||
@ -1357,32 +1495,37 @@ Action ShowWRStyleMenu(int client, int track)
|
|||||||
Menu menu = new Menu(MenuHandler_StyleChooser);
|
Menu menu = new Menu(MenuHandler_StyleChooser);
|
||||||
menu.SetTitle("%T", "WRMenuTitle", client);
|
menu.SetTitle("%T", "WRMenuTitle", client);
|
||||||
|
|
||||||
|
int[] styles = new int[gI_Styles];
|
||||||
|
Shavit_GetOrderedStyles(styles, gI_Styles);
|
||||||
|
|
||||||
for(int i = 0; i < gI_Styles; i++)
|
for(int i = 0; i < gI_Styles; i++)
|
||||||
{
|
{
|
||||||
if(gA_StyleSettings[i].bUnranked)
|
int iStyle = styles[i];
|
||||||
|
|
||||||
|
if(gA_StyleSettings[iStyle].bUnranked)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char sInfo[8];
|
char sInfo[8];
|
||||||
IntToString(i, sInfo, 8);
|
IntToString(iStyle, sInfo, 8);
|
||||||
|
|
||||||
char sDisplay[64];
|
char sDisplay[64];
|
||||||
|
|
||||||
if(StrEqual(gA_WRCache[client].sClientMap, gS_Map) && gF_WRTime[i][track] > 0.0)
|
if(StrEqual(gA_WRCache[client].sClientMap, gS_Map) && gF_WRTime[iStyle][track] > 0.0)
|
||||||
{
|
{
|
||||||
char sTime[32];
|
char sTime[32];
|
||||||
FormatSeconds(gF_WRTime[i][track], sTime, 32, false);
|
FormatSeconds(gF_WRTime[iStyle][track], sTime, 32, false);
|
||||||
|
|
||||||
FormatEx(sDisplay, 64, "%s - WR: %s", gS_StyleStrings[i].sStyleName, sTime);
|
FormatEx(sDisplay, 64, "%s - WR: %s", gS_StyleStrings[iStyle].sStyleName, sTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcopy(sDisplay, 64, gS_StyleStrings[i].sStyleName);
|
strcopy(sDisplay, 64, gS_StyleStrings[iStyle].sStyleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.AddItem(sInfo, sDisplay, (gI_RecordAmount[i][track] > 0 || !StrEqual(gA_WRCache[client].sClientMap, gS_Map))? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
menu.AddItem(sInfo, sDisplay, (gI_RecordAmount[iStyle][track] > 0 || !StrEqual(gA_WRCache[client].sClientMap, gS_Map))? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// should NEVER happen
|
// should NEVER happen
|
||||||
@ -2309,7 +2452,7 @@ public void SQL_OnFinish_Callback(Database db, DBResultSet results, const char[]
|
|||||||
void UpdateLeaderboards()
|
void UpdateLeaderboards()
|
||||||
{
|
{
|
||||||
char sQuery[192];
|
char sQuery[192];
|
||||||
FormatEx(sQuery, 192, "SELECT style, time, track FROM %splayertimes WHERE map = '%s' ORDER BY time ASC, date ASC;", gS_MySQLPrefix, gS_Map);
|
FormatEx(sQuery, 192, "SELECT style, time, track FROM %splayertimes WHERE map = '%s' ORDER BY time ASC, date ASC LIMIT 1000;", gS_MySQLPrefix, gS_Map);
|
||||||
gH_SQL.Query(SQL_UpdateLeaderboards_Callback, sQuery, 0);
|
gH_SQL.Query(SQL_UpdateLeaderboards_Callback, sQuery, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -113,8 +113,8 @@
|
|||||||
// ---------- Zones ---------- //
|
// ---------- Zones ---------- //
|
||||||
"StartZoneUndefined"
|
"StartZoneUndefined"
|
||||||
{
|
{
|
||||||
"#format" "{1:s},{2:s}"
|
"#format" "{1:s},{2:s},{3:s},{4:s},{5:s}"
|
||||||
"en" "Your timer {1}will not{2} start as a start zone for the map is not defined."
|
"en" "Your timer {1}will not{2} start because the {3}{4}{5} start zone is not set."
|
||||||
}
|
}
|
||||||
"EndZoneUndefined"
|
"EndZoneUndefined"
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,6 +6,11 @@
|
|||||||
{
|
{
|
||||||
"en" "Start Zone"
|
"en" "Start Zone"
|
||||||
}
|
}
|
||||||
|
"HudZoneTier"
|
||||||
|
{
|
||||||
|
"#format" "{1:d}"
|
||||||
|
"en" "Tier {1}"
|
||||||
|
}
|
||||||
"HudInStartZone"
|
"HudInStartZone"
|
||||||
{
|
{
|
||||||
"#format" "{1:d}"
|
"#format" "{1:d}"
|
||||||
@ -131,6 +136,14 @@
|
|||||||
{
|
{
|
||||||
"en" "Timer track"
|
"en" "Timer track"
|
||||||
}
|
}
|
||||||
|
"HudSplitPbText"
|
||||||
|
{
|
||||||
|
"en" "Split PB"
|
||||||
|
}
|
||||||
|
"HudMapTierText"
|
||||||
|
{
|
||||||
|
"en" "Map tier"
|
||||||
|
}
|
||||||
// ---------- Record Bots ---------- //
|
// ---------- Record Bots ---------- //
|
||||||
"ReplayText"
|
"ReplayText"
|
||||||
{
|
{
|
||||||
|
|||||||
@ -11,6 +11,11 @@
|
|||||||
"#format" "{1:s},{2:s},{3:s},{4:s}"
|
"#format" "{1:s},{2:s},{3:s},{4:s}"
|
||||||
"en" "You have to be {1}alive{2} or {3}spectate a player{4} to use this command."
|
"en" "You have to be {1}alive{2} or {3}spectate a player{4} to use this command."
|
||||||
}
|
}
|
||||||
|
"CommandNoPause"
|
||||||
|
{
|
||||||
|
"#format" "{1:s},{2:s}"
|
||||||
|
"en" "Your timer has to be {1}resumed{2} to use this command."
|
||||||
|
}
|
||||||
"CommandDisabled"
|
"CommandDisabled"
|
||||||
{
|
{
|
||||||
"#format" "{1:s},{2:s}"
|
"#format" "{1:s},{2:s}"
|
||||||
|
|||||||
@ -53,8 +53,8 @@
|
|||||||
}
|
}
|
||||||
"DeleteAllRecordsMenuTitle"
|
"DeleteAllRecordsMenuTitle"
|
||||||
{
|
{
|
||||||
"#format" "{1:s},{2:s}"
|
"#format" "{1:s},{2:s},{3:s}"
|
||||||
"en" "Delete ALL the records for '{1}'? (Track: {2})"
|
"en" "Delete ALL the records for '{1}'? (Track: {2} | Style: {3})"
|
||||||
}
|
}
|
||||||
"DeleteConfirm"
|
"DeleteConfirm"
|
||||||
{
|
{
|
||||||
@ -107,6 +107,11 @@
|
|||||||
{
|
{
|
||||||
"en" "Choose a track to delete a ALL records from:"
|
"en" "Choose a track to delete a ALL records from:"
|
||||||
}
|
}
|
||||||
|
"DeleteTrackAllStyle"
|
||||||
|
{
|
||||||
|
"#format" "{1:s}"
|
||||||
|
"en" "Choose a style to delete all the records for ({1}):"
|
||||||
|
}
|
||||||
// ---------- Errors ---------- //
|
// ---------- Errors ---------- //
|
||||||
"DatabaseError"
|
"DatabaseError"
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user