mirror of
https://github.com/shavitush/bhoptimer.git
synced 2025-12-07 18:38:26 +00:00
commit
398c9ee84e
@ -26,7 +26,7 @@
|
||||
"runspeed" "260.00" // Running speed. Requires DHooks, shavit-misc and shavit_misc_staticprestrafe set to 1.
|
||||
"gravity" "1.0" // Gravity setting, 1.0 for default. Standard for low gravity styles is 0.6.
|
||||
"speed" "1.0" // Speed multiplier, 1.0 for default. Standard for slowmo styles is 0.5.
|
||||
"halftime" "0" // Calculation of times will be halved, replays WILL NOT function properly.
|
||||
"timescale" "1.0" // Timing will scale with this setting.
|
||||
"velocity" "1.0" // % of horizontal velocity to keep per jump. a value 0.9 will make the player lose 10% of their velocity per jump. Likewise, values above 1 will result in speed gains.
|
||||
"bonus_velocity" "0.0" // Bonus velocity to gain per jump. If set to e.g. 100.0, the player will gain 100 bonus velocity per jump.
|
||||
"min_velocity" "0.0" // Minimum amount of horizontal velocity to keep per jump. If set to 600.0, the player can't have less than 600 velocity per jump.
|
||||
@ -220,7 +220,7 @@
|
||||
"clantag" "SLOW"
|
||||
|
||||
"speed" "0.5"
|
||||
"halftime" "1"
|
||||
"timescale" "0.5"
|
||||
|
||||
"unranked" "1"
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#endif
|
||||
#define _shavit_included
|
||||
|
||||
#define SHAVIT_VERSION "2.3.3"
|
||||
#define SHAVIT_VERSION "2.3.4"
|
||||
#define STYLE_LIMIT 256
|
||||
#define MAX_ZONES 64
|
||||
#define MAX_NAME_LENGTH_SQL 32
|
||||
@ -42,6 +42,7 @@
|
||||
#define HUD_TIMELEFT (1 << 9) // shows time left at right tside of the screen (css only)
|
||||
#define HUD_2DVEL (1 << 10) // shows 2d velocity
|
||||
#define HUD_NOSOUNDS (1 << 11) // disables sounds on personal best, world record etc
|
||||
#define HUD_NOPRACALERT (1 << 12) // hides practice mode chat alert
|
||||
|
||||
// for reference, not used anymore
|
||||
// game types
|
||||
@ -97,7 +98,7 @@ enum
|
||||
fRunspeed,
|
||||
fGravityMultiplier,
|
||||
fSpeedMultiplier,
|
||||
bHalftime,
|
||||
fTimescale,
|
||||
fVelocity,
|
||||
fBonusVelocity,
|
||||
fMinVelocity,
|
||||
|
||||
@ -1349,7 +1349,7 @@ void SQL_DBConnect()
|
||||
bool bMySQL = StrEqual(sDriver, "mysql", false);
|
||||
|
||||
char sQuery[512];
|
||||
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%schat` (`auth` CHAR(32) NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` CHAR(128), `message` INT NOT NULL DEFAULT 0, `ccmessage` CHAR(16), PRIMARY KEY (`auth`))%s;", gS_MySQLPrefix, (bMySQL)? " ENGINE=INNODB":"");
|
||||
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%schat` (`auth` CHAR(32) NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` CHAR(128) COLLATE 'utf8mb4_unicode_ci', `message` INT NOT NULL DEFAULT 0, `ccmessage` CHAR(16) COLLATE 'utf8mb4_unicode_ci', PRIMARY KEY (`auth`))%s;", gS_MySQLPrefix, (bMySQL)? " ENGINE=INNODB":"");
|
||||
|
||||
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
|
||||
}
|
||||
|
||||
@ -93,6 +93,7 @@ bool gB_Zones = false;
|
||||
bool gB_WR = false;
|
||||
bool gB_Replay = false;
|
||||
bool gB_Rankings = false;
|
||||
bool gB_HUD = false;
|
||||
|
||||
// cvars
|
||||
ConVar gCV_Restart = null;
|
||||
@ -349,6 +350,7 @@ public void OnPluginStart()
|
||||
gB_WR = LibraryExists("shavit-wr");
|
||||
gB_Replay = LibraryExists("shavit-replay");
|
||||
gB_Rankings = LibraryExists("shavit-rankings");
|
||||
gB_HUD = LibraryExists("shavit-hud");
|
||||
}
|
||||
|
||||
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
|
||||
@ -388,6 +390,11 @@ public void OnLibraryAdded(const char[] name)
|
||||
{
|
||||
gB_Rankings = true;
|
||||
}
|
||||
|
||||
else if(StrEqual(name, "shavit-hud"))
|
||||
{
|
||||
gB_HUD = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnLibraryRemoved(const char[] name)
|
||||
@ -411,6 +418,11 @@ public void OnLibraryRemoved(const char[] name)
|
||||
{
|
||||
gB_Rankings = false;
|
||||
}
|
||||
|
||||
else if(StrEqual(name, "shavit-hud"))
|
||||
{
|
||||
gB_HUD = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMapStart()
|
||||
@ -1199,7 +1211,7 @@ public int Native_SetPracticeMode(Handle handler, int numParams)
|
||||
bool practice = view_as<bool>(GetNativeCell(2));
|
||||
bool alert = view_as<bool>(GetNativeCell(3));
|
||||
|
||||
if(alert && practice && !gB_PracticeMode[client])
|
||||
if(alert && practice && !gB_PracticeMode[client] && (!gB_HUD || (Shavit_GetHUDSettings(client) & HUD_NOPRACALERT) == 0))
|
||||
{
|
||||
Shavit_PrintToChat(client, "%T", "PracticeModeAlert", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
|
||||
}
|
||||
@ -1564,7 +1576,7 @@ bool LoadStyles()
|
||||
gA_StyleSettings[i][fRunspeed] = kv.GetFloat("runspeed", 260.00);
|
||||
gA_StyleSettings[i][fGravityMultiplier] = kv.GetFloat("gravity", 1.0);
|
||||
gA_StyleSettings[i][fSpeedMultiplier] = kv.GetFloat("speed", 1.0);
|
||||
gA_StyleSettings[i][bHalftime] = view_as<bool>(kv.GetNum("halftime", 0));
|
||||
gA_StyleSettings[i][fTimescale] = view_as<bool>(kv.GetNum("halftime", 0))? 0.5:kv.GetFloat("timescale", 1.0); // backwards compat for old halftime setting
|
||||
gA_StyleSettings[i][fVelocity] = kv.GetFloat("velocity", 1.0);
|
||||
gA_StyleSettings[i][fBonusVelocity] = kv.GetFloat("bonus_velocity", 0.0);
|
||||
gA_StyleSettings[i][fMinVelocity] = kv.GetFloat("min_velocity", 0.0);
|
||||
@ -1755,7 +1767,10 @@ void SQL_DBConnect()
|
||||
}
|
||||
|
||||
// support unicode names
|
||||
gH_SQL.SetCharset("utf8");
|
||||
if(!gH_SQL.SetCharset("utf8mb4"))
|
||||
{
|
||||
gH_SQL.SetCharset("utf8");
|
||||
}
|
||||
|
||||
char sDriver[8];
|
||||
gH_SQL.Driver.GetIdentifier(sDriver, 8);
|
||||
@ -1765,7 +1780,7 @@ void SQL_DBConnect()
|
||||
|
||||
if(gB_MySQL)
|
||||
{
|
||||
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%susers` (`auth` CHAR(32) NOT NULL, `name` VARCHAR(32), `country` CHAR(32), `ip` CHAR(64), `lastlogin` INT NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), INDEX `points` (`points`)) ENGINE=INNODB;", gS_MySQLPrefix);
|
||||
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%susers` (`auth` CHAR(32) NOT NULL, `name` VARCHAR(32) COLLATE 'utf8mb4_unicode_ci', `country` CHAR(32), `ip` CHAR(64), `lastlogin` INT NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), INDEX `points` (`points`)) ENGINE=INNODB;", gS_MySQLPrefix);
|
||||
}
|
||||
|
||||
else
|
||||
@ -1926,12 +1941,7 @@ public void OnGameFrame()
|
||||
continue;
|
||||
}
|
||||
|
||||
float time = frametime;
|
||||
|
||||
if(gA_StyleSettings[gI_Style[i]][bHalftime])
|
||||
{
|
||||
time /= 2.0;
|
||||
}
|
||||
float time = frametime * view_as<float>(gA_StyleSettings[gI_Style[i]][fTimescale]);
|
||||
|
||||
any[] snapshot = new any[TIMERSNAPSHOT_SIZE];
|
||||
snapshot[bTimerEnabled] = gB_TimerEnabled[i];
|
||||
|
||||
@ -437,6 +437,10 @@ Action ShowHUDMenu(int client, int item)
|
||||
menu.AddItem(sInfo, sHudItem);
|
||||
}
|
||||
|
||||
IntToString(HUD_NOPRACALERT, sInfo, 16);
|
||||
FormatEx(sHudItem, 64, "%T", "HudPracticeModeAlert", client);
|
||||
menu.AddItem(sInfo, sHudItem);
|
||||
|
||||
menu.ExitButton = true;
|
||||
menu.DisplayAt(client, item, 60);
|
||||
|
||||
@ -835,7 +839,7 @@ void UpdateHUD(int client)
|
||||
iSpeed = RoundToNearest(float(iSpeed) / view_as<float>(gA_StyleSettings[style][fSpeedMultiplier]));
|
||||
track = Shavit_GetReplayBotTrack(target);
|
||||
|
||||
float fReplayTime = Shavit_GetReplayTime(style, track);
|
||||
float fReplayTime = Shavit_GetReplayTime(style, track) * view_as<float>(gA_StyleSettings[style][fTimescale]);
|
||||
float fReplayLength = Shavit_GetReplayLength(style, track);
|
||||
|
||||
if(fReplayTime < 0.0 || fReplayTime > fReplayLength || !Shavit_IsReplayDataLoaded(style, track))
|
||||
|
||||
@ -1713,7 +1713,7 @@ public int MenuHandler_Checkpoints(Menu menu, MenuAction action, int param1, int
|
||||
{
|
||||
CheckpointsCache cpcache[PCPCACHE_SIZE];
|
||||
|
||||
if(iCurrent < iMaxCPs && GetCheckpoint(param1, iCurrent, cpcache))
|
||||
if(iCurrent++ < iMaxCPs && GetCheckpoint(param1, iCurrent, cpcache))
|
||||
{
|
||||
gI_CheckpointsCache[param1][iCurrentCheckpoint]++;
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#define REPLAY_FORMAT_FINAL "{SHAVITREPLAYFORMAT}{FINAL}"
|
||||
#define REPLAY_FORMAT_SUBVERSION 0x02
|
||||
#define CELLS_PER_FRAME 8 // origin[3], angles[2], buttons, flags, movetype
|
||||
#define FRAMES_PER_WRITE 100 // amounts of frames to write per read/write call
|
||||
|
||||
// #define DEBUG
|
||||
|
||||
@ -972,7 +973,7 @@ bool LoadReplay(int style, int track, const char[] path)
|
||||
gH_SQL.Query(SQL_GetUserName_Callback, sQuery, pack, DBPrio_High);
|
||||
}
|
||||
|
||||
int cells = 8;
|
||||
int cells = CELLS_PER_FRAME;
|
||||
|
||||
// backwards compatibility
|
||||
if(gA_FrameCache[style][track][3] == 0x01)
|
||||
@ -1087,12 +1088,25 @@ bool SaveReplay(int style, int track, float time, char[] authid, char[] name)
|
||||
|
||||
// if REPLAY_FORMAT_SUBVERSION is over 0x01 i'll add variables here
|
||||
|
||||
any[] aFrameData = new any[CELLS_PER_FRAME];
|
||||
any aFrameData[CELLS_PER_FRAME];
|
||||
any aWriteData[CELLS_PER_FRAME * FRAMES_PER_WRITE];
|
||||
int iFramesWritten = 0;
|
||||
|
||||
for(int i = 0; i < iSize; i++)
|
||||
{
|
||||
gA_Frames[style][track].GetArray(i, aFrameData, CELLS_PER_FRAME);
|
||||
fFile.Write(aFrameData, CELLS_PER_FRAME, 4);
|
||||
|
||||
for(int j = 0; j < CELLS_PER_FRAME; j++)
|
||||
{
|
||||
aWriteData[(CELLS_PER_FRAME * iFramesWritten) + j] = aFrameData[j];
|
||||
}
|
||||
|
||||
if(++iFramesWritten == FRAMES_PER_WRITE || i == iSize - 1)
|
||||
{
|
||||
fFile.Write(aWriteData, CELLS_PER_FRAME * iFramesWritten, 4);
|
||||
|
||||
iFramesWritten = 0;
|
||||
}
|
||||
}
|
||||
|
||||
delete fFile;
|
||||
@ -1196,6 +1210,29 @@ public void OnClientPutInServer(int client)
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEntityCreated(int entity, const char[] classname)
|
||||
{
|
||||
// trigger_once | trigger_multiple.. etc
|
||||
// func_door | func_door_rotating
|
||||
if(StrContains(classname, "trigger_") != -1 || StrContains(classname, "_door") != -1)
|
||||
{
|
||||
SDKHook(entity, SDKHook_StartTouch, HookTriggers);
|
||||
SDKHook(entity, SDKHook_EndTouch, HookTriggers);
|
||||
SDKHook(entity, SDKHook_Touch, HookTriggers);
|
||||
SDKHook(entity, SDKHook_Use, HookTriggers);
|
||||
}
|
||||
}
|
||||
|
||||
public Action HookTriggers(int entity, int other)
|
||||
{
|
||||
if(gB_Enabled && 1 <= other <= MaxClients && IsFakeClient(other))
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
void FormatStyle(const char[] source, int style, bool central, float time, int track, char[] dest, int size)
|
||||
{
|
||||
float fWRTime = GetReplayLength(style, track);
|
||||
@ -1370,6 +1407,11 @@ void UpdateReplayInfo(int client, int style, float time, int track)
|
||||
|
||||
public void OnClientDisconnect(int client)
|
||||
{
|
||||
if(IsClientSourceTV(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!IsFakeClient(client))
|
||||
{
|
||||
if(gA_PlayerFrames[client] != null)
|
||||
@ -1661,13 +1703,21 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
||||
MakeVectorFromPoints(vecCurrentPosition, vecPosition, vecVelocity);
|
||||
ScaleVector(vecVelocity, gF_Tickrate);
|
||||
|
||||
if((gI_ReplayTick[style] % RoundToFloor(gF_Tickrate * 1.5)) == 0)
|
||||
if(gI_ReplayTick[style] > 1)
|
||||
{
|
||||
float vecLastPosition[3];
|
||||
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
|
||||
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
|
||||
@ -1734,6 +1784,18 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
|
||||
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)
|
||||
{
|
||||
if(gB_CentralBot && gB_ForciblyStopped)
|
||||
@ -2300,7 +2362,7 @@ void StopCentralReplay(int client)
|
||||
|
||||
int GetReplayStyle(int client)
|
||||
{
|
||||
if(!IsFakeClient(client))
|
||||
if(!IsFakeClient(client) || IsClientSourceTV(client))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -2328,7 +2390,7 @@ int GetReplayStyle(int client)
|
||||
|
||||
int GetReplayTrack(int client)
|
||||
{
|
||||
if(!IsFakeClient(client))
|
||||
if(!IsFakeClient(client) || IsClientSourceTV(client))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -378,19 +378,19 @@ Action OpenStatsMenu(int client, const char[] authid)
|
||||
if(gB_Rankings)
|
||||
{
|
||||
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin, d.points, e.rank FROM " ...
|
||||
"(SELECT COUNT(*) clears FROM (SELECT id FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map) s) a " ...
|
||||
"JOIN (SELECT COUNT(*) maps FROM (SELECT id FROM %smapzones WHERE track = 0 GROUP BY map) s) b " ...
|
||||
"(SELECT COUNT(*) clears FROM (SELECT id FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map, id) s) a " ...
|
||||
"JOIN (SELECT COUNT(*) maps FROM (SELECT id FROM %smapzones WHERE track = 0 GROUP BY map, id) s) b " ...
|
||||
"JOIN (SELECT COUNT(*) wrs FROM %splayertimes a JOIN (SELECT MIN(time) time FROM %splayertimes WHERE style = 0 AND track = 0 GROUP by map) b ON a.time = b.time WHERE auth = '%s') c " ...
|
||||
"JOIN (SELECT name, country, lastlogin, FORMAT(points, 2) points FROM %susers WHERE auth = '%s' LIMIT 1) d " ...
|
||||
"JOIN (SELECT FORMAT(COUNT(*), 0) rank FROM %susers WHERE points >= (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) ORDER BY points DESC LIMIT 1) e " ...
|
||||
"JOIN (SELECT FORMAT(COUNT(*), 0) rank FROM %susers WHERE points >= (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) GROUP BY points ORDER BY points DESC LIMIT 1) e " ...
|
||||
"LIMIT 1;", gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, authid);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin FROM " ...
|
||||
"(SELECT COUNT(*) clears FROM (SELECT id FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map) s) a " ...
|
||||
"JOIN (SELECT COUNT(*) maps FROM (SELECT id FROM %smapzones WHERE track = 0 GROUP BY map) s) b " ...
|
||||
"(SELECT COUNT(*) clears FROM (SELECT id FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map, id) s) a " ...
|
||||
"JOIN (SELECT COUNT(*) maps FROM (SELECT id FROM %smapzones WHERE track = 0 GROUP BY map, id) s) b " ...
|
||||
"JOIN (SELECT COUNT(*) wrs FROM %splayertimes a JOIN (SELECT MIN(time) time FROM %splayertimes WHERE style = 0 AND track = 0 GROUP by map) b ON a.time = b.time WHERE auth = '%s') c " ...
|
||||
"JOIN (SELECT name, country, lastlogin FROM %susers WHERE auth = '%s' LIMIT 1) d " ...
|
||||
"LIMIT 1;", gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid);
|
||||
@ -600,7 +600,7 @@ void ShowMaps(int client)
|
||||
|
||||
if(gI_MapType[client] == MAPSDONE)
|
||||
{
|
||||
FormatEx(sQuery, 512, "SELECT a.map, a.time, a.jumps, a.id, COUNT(b.map) + 1 rank, a.points FROM %splayertimes a LEFT JOIN %splayertimes b ON a.time > b.time AND a.map = b.map AND a.style = b.style AND a.track = b.track WHERE a.auth = '%s' AND a.style = %d AND a.track = %d GROUP BY a.map ORDER BY a.%s;", gS_MySQLPrefix, gS_MySQLPrefix, gS_TargetAuth[client], gBS_Style[client], gI_Track[client], (gB_Rankings)? "points DESC":"map");
|
||||
FormatEx(sQuery, 512, "SELECT a.map, a.time, a.jumps, a.id, COUNT(b.map) + 1 rank, a.points FROM %splayertimes a LEFT JOIN %splayertimes b ON a.time > b.time AND a.map = b.map AND a.style = b.style AND a.track = b.track WHERE a.auth = '%s' AND a.style = %d AND a.track = %d GROUP BY a.map, a.time, a.jumps, a.id, a.points ORDER BY a.%s;", gS_MySQLPrefix, gS_MySQLPrefix, gS_TargetAuth[client], gBS_Style[client], gI_Track[client], (gB_Rankings)? "points DESC":"map");
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
@ -490,7 +490,7 @@ void UpdateWRCache()
|
||||
|
||||
if(gB_MySQL)
|
||||
{
|
||||
FormatEx(sQuery, 512, "SELECT p.style, p.id, TRUNCATE(LEAST(s.time, p.time), 3), u.name, p.track FROM %splayertimes p JOIN(SELECT style, MIN(time) time, map, track FROM %splayertimes WHERE map = '%s' GROUP BY style, track ORDER BY date ASC) s ON p.style = s.style AND p.time = s.time AND p.map = s.map JOIN %susers u ON p.auth = u.auth GROUP BY p.style, p.track ORDER BY date ASC;", gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, gS_MySQLPrefix);
|
||||
FormatEx(sQuery, 512, "SELECT p.style, p.id, TRUNCATE(LEAST(s.time, p.time), 3), u.name, p.track FROM %splayertimes p JOIN(SELECT style, MIN(time) time, map, track FROM %splayertimes WHERE map = '%s' GROUP BY style, track, map ORDER BY date ASC) s ON p.style = s.style AND p.time = s.time AND p.map = s.map JOIN %susers u ON p.auth = u.auth GROUP BY p.style, p.track, p.id, p.time, s.time, u.name ORDER BY date ASC;", gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, gS_MySQLPrefix);
|
||||
}
|
||||
|
||||
// sorry, LEAST() isn't available for SQLITE!
|
||||
|
||||
@ -109,6 +109,10 @@
|
||||
{
|
||||
"en" "Disable record sounds"
|
||||
}
|
||||
"HudPracticeModeAlert"
|
||||
{
|
||||
"en" "Disable practice mode alert"
|
||||
}
|
||||
// ---------- Record Bots ---------- //
|
||||
"ReplayText"
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user