Merge pull request #583 from shavitush/chat

Some updates after a while with none
This commit is contained in:
shavit 2018-02-04 10:51:52 +02:00 committed by GitHub
commit d0eba8fd71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 752 additions and 539 deletions

View File

@ -1,6 +1,3 @@
# i have no idea AT ALL on how to use travis,
# stolen from splewis: https://raw.githubusercontent.com/splewis/csgo-pug-setup/master/.travis.yml
# i'll fail anyways, right? :(
sudo: false
addons:
@ -8,7 +5,7 @@ addons:
- lib32stdc++6 # needed for spcomp
env:
- SMVERSION=1.8
- SMVERSION=1.9
before_script:
# install smbuilder
@ -26,7 +23,6 @@ before_script:
- chmod +x spcomp
- PATH+=":$PWD"
# - cp ../../../scripting/include/* include/ # i don't think this is necessary anymore
- cd ../../..
script:

View File

@ -18,10 +18,10 @@ Including a records system, map zones (start/end marks etc), bonuses, HUD with u
# Requirements:
* Steam version of Counter-Strike: Source or Counter-Strike: Global Offensive.
* [SourceMod 1.8 or above](http://www.sourcemod.net/downloads.php)
* [SourceMod 1.9 or above](http://www.sourcemod.net/downloads.php)
# Optional requirements:
* [DHooks](http://users.alliedmods.net/~drifter/builds/dhooks/2.0/) - required for 250/260 runspeed for all weapons.
* [DHooks](http://users.alliedmods.net/~drifter/builds/dhooks/2.1/) - required for 250/260 runspeed for all weapons.
* [Bunnyhop Statistics](https://forums.alliedmods.net/showthread.php?t=286135) - to show amount of scrolls for non-auto styles in the key display. Required for TF2 servers.
* [SteamWorks](https://forums.alliedmods.net/showthread.php?t=229556) - for the `{serverip}` advertisement variable.
* [Chat-Processor](https://github.com/Drixevel/Chat-Processor) - if you're enabling the `shavit-chat` module.

View File

@ -30,4 +30,12 @@
"centralstyle" "!replay"
"centralstyletag" "!replay"
"unloaded" "{style} - N/A"
// Replay data folder. This is where replays are loaded from and saved to.
// Note: To use a path outside of the game directory, you will have to get out of it with "../".
// Edit at your own risk.
//
// Variables:
// {SM} - SourceMod folder. If this variable isn't included, you will have to specify the full path.
"replayfolder" "{SM}/data/replaybot"
}

View File

@ -40,7 +40,7 @@
"force_hsw" "0" // Force half-sideways gameplay. 1 for regular HSW and 2 for surf-HSW.
"block_pleft" "0" // Block +left (requires shavit_core_blockleftright 1).
"block_pright" "0" // Block +right (requires shavit_core_blockleftright 1).
"block_pstrafe" "0" // Stops timer on +strafe usage. May have false positives when players lag. Will prvent some strafe hacks too.
"block_pstrafe" "0" // Prevent button inconsistencies (including +pstrafe). May have false positives when players lag. Will prevent some strafe hacks too. Set this to 2 to also stop the timer.
// Feature excluding
"unranked" "0" // Unranked style. No ranking points and no records.

View File

@ -44,7 +44,7 @@
// for reference, not used anymore
// game types
enum ServerGame(+=1)
enum ServerGame
{
Game_CSS = 0,
Game_CSGO,
@ -52,14 +52,14 @@ enum ServerGame(+=1)
};
// status
enum TimerStatus(+=1)
enum TimerStatus
{
Timer_Stopped = 0,
Timer_Running,
Timer_Paused
};
enum ReplayStatus(+=1)
enum ReplayStatus
{
Replay_Start = 0,
Replay_Running,
@ -67,6 +67,12 @@ enum ReplayStatus(+=1)
Replay_Idle
};
enum ReplayBotType
{
Replay_Central = 0,
Replay_Legacy
};
enum
{
sStyleName,
@ -101,7 +107,7 @@ enum
iForceHSW,
bBlockPLeft,
bBlockPRight,
bBlockPStrafe,
iBlockPStrafe,
bUnranked,
bNoReplay,
bSync,
@ -128,10 +134,7 @@ enum
enum
{
bTimerEnabled,
fStartTime,
fCurrentTime,
fPauseStartTime,
fPauseTotalTime,
bClientPaused,
iJumps,
bsStyle,
@ -294,9 +297,36 @@ stock void FormatSeconds(float time, char[] newtime, int newtimesize, bool preci
* @param track The player's timer track.
* @param style The player's bhop style.
* @param stylesettings An array that contains the player's bhop style's settings.
* @param mouse Mouse direction (x, y).
* @return Plugin_Continue to let shavit-core keep doing what it does, Plugin_Changed to pass different values.
*/
forward Action Shavit_OnUserCmdPre(int client, int &buttons, int &impulse, float vel[3], float angles[3], TimerStatus status, int track, int style, any stylesettings[STYLESETTINGS_SIZE]);
forward Action Shavit_OnUserCmdPre(int client, int &buttons, int &impulse, float vel[3], float angles[3], TimerStatus status, int track, int style, any stylesettings[STYLESETTINGS_SIZE], int mouse[2]);
/**
* Called just before shavit-core adds time to a player's timer.
* This is the forward you should use to modify the player's timer smoothly.
* A good example use case is timescaling.
*
* @param client Client index.
* @param snapshot A snapshot with the player's current timer. You cannot manipulate it here.
* @param time The time to be added to the player's timer.
* @param stylesettings An array that contains the player's bhop style's settings.
* @noreturn
*/
forward void Shavit_OnTimeIncrement(int client, any snapshot[TIMERSNAPSHOT_SIZE], float &time, any stylesettings[STYLESETTINGS_SIZE]);
/**
* Called just before shavit-core adds time to a player's timer.
* This is the forward you should use to modify the player's timer smoothly.
* A good example use case is timescaling.
*
* @param client Client index.
* @param snapshot A snapshot with the player's current timer. Read above in shavit.inc for more information.
* @param time The time to be added to the player's timer.
* @param stylesettings An array that contains the player's bhop style's settings.
* @noreturn
*/
forward void Shavit_OnTimeIncrementPost(int client, float time, any stylesettings[STYLESETTINGS_SIZE]);
/**
* Called when a player's timer starts.
@ -354,9 +384,10 @@ forward Action Shavit_OnFinishPre(int client, any snapshot[TIMERSNAPSHOT_SIZE]);
* @param strafes Amount of strafes.
* @param sync Sync percentage (0.0 to 100.0) or -1.0 when not measured.
* @param track Timer track.
* @param oldtime The player's best time on the map before this finish.
* @noreturn
*/
forward void Shavit_OnFinish(int client, int style, float time, int jumps, int strafes, float sync, int track);
forward void Shavit_OnFinish(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime);
/**
* Like Shavit_OnFinish, but after the insertion query was called.
@ -786,6 +817,13 @@ native int Shavit_GetReplayBotStyle(int client);
*/
native int Shavit_GetReplayBotTrack(int client);
/**
* Gets the replay bot type setting of the server.
*
* @return See ReplayBotType enum.
*/
native ReplayBotType Shavit_GetReplayBotType();
/**
* Retrieve the replay bot's current played frame.
*
@ -1125,6 +1163,7 @@ public void __pl_shavit_SetNTVOptional()
MarkNativeAsOptional("Shavit_GetReplayBotIndex");
MarkNativeAsOptional("Shavit_GetReplayBotStyle");
MarkNativeAsOptional("Shavit_GetReplayBotTrack");
MarkNativeAsOptional("Shavit_GetReplayBotType");
MarkNativeAsOptional("Shavit_GetReplayData");
MarkNativeAsOptional("Shavit_GetReplayFrameCount");
MarkNativeAsOptional("Shavit_GetReplayLength");

View File

@ -363,6 +363,7 @@ public Action CP_OnChatMessage(int &author, ArrayList recipients, char[] flagstr
// proper colors with rtler
if(gB_RTLer && RTLify(sTemp, MAXLENGTH_MESSAGE, message) > 0)
{
TrimString(message);
Format(message, MAXLENGTH_MESSAGE, "%s%s", message, gS_CustomMessage[author]);
}

View File

@ -58,12 +58,13 @@ Handle gH_Forwards_OnStyleConfigLoaded = null;
Handle gH_Forwards_OnDatabaseLoaded = null;
Handle gH_Forwards_OnChatConfigLoaded = null;
Handle gH_Forwards_OnUserCmdPre = null;
Handle gH_Forwards_OnTimerIncrement = null;
Handle gH_Forwards_OnTimerIncrementPost = null;
// timer variables
bool gB_TimerEnabled[MAXPLAYERS+1];
float gF_StartTime[MAXPLAYERS+1];
float gF_PauseStartTime[MAXPLAYERS+1];
float gF_PauseTotalTime[MAXPLAYERS+1];
float gF_PlayerTimer[MAXPLAYERS+1];
float gF_PausePosition[MAXPLAYERS+1][3][3];
bool gB_ClientPaused[MAXPLAYERS+1];
int gI_Jumps[MAXPLAYERS+1];
int gBS_Style[MAXPLAYERS+1];
@ -193,7 +194,7 @@ public void OnPluginStart()
gH_Forwards_Start = CreateGlobalForward("Shavit_OnStart", ET_Event, Param_Cell, Param_Cell);
gH_Forwards_Stop = CreateGlobalForward("Shavit_OnStop", ET_Event, Param_Cell, Param_Cell);
gH_Forwards_FinishPre = CreateGlobalForward("Shavit_OnFinishPre", ET_Event, Param_Cell, Param_Array);
gH_Forwards_Finish = CreateGlobalForward("Shavit_OnFinish", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
gH_Forwards_Finish = CreateGlobalForward("Shavit_OnFinish", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
gH_Forwards_OnRestart = CreateGlobalForward("Shavit_OnRestart", ET_Event, Param_Cell, Param_Cell);
gH_Forwards_OnEnd = CreateGlobalForward("Shavit_OnEnd", ET_Event, Param_Cell, Param_Cell);
gH_Forwards_OnPause = CreateGlobalForward("Shavit_OnPause", ET_Event, Param_Cell, Param_Cell);
@ -202,7 +203,9 @@ public void OnPluginStart()
gH_Forwards_OnStyleConfigLoaded = CreateGlobalForward("Shavit_OnStyleConfigLoaded", ET_Event, Param_Cell);
gH_Forwards_OnDatabaseLoaded = CreateGlobalForward("Shavit_OnDatabaseLoaded", ET_Event);
gH_Forwards_OnChatConfigLoaded = CreateGlobalForward("Shavit_OnChatConfigLoaded", ET_Event);
gH_Forwards_OnUserCmdPre = CreateGlobalForward("Shavit_OnUserCmdPre", ET_Event, Param_Cell, Param_CellByRef, Param_CellByRef, Param_Array, Param_Array, Param_Cell, Param_Cell, Param_Cell, Param_Array);
gH_Forwards_OnUserCmdPre = CreateGlobalForward("Shavit_OnUserCmdPre", ET_Event, Param_Cell, Param_CellByRef, Param_CellByRef, Param_Array, Param_Array, Param_Cell, Param_Cell, Param_Cell, Param_Array, Param_Array);
gH_Forwards_OnTimerIncrement = CreateGlobalForward("Shavit_OnTimeIncrement", ET_Event, Param_Cell, Param_Array, Param_CellByRef, Param_Array);
gH_Forwards_OnTimerIncrementPost = CreateGlobalForward("Shavit_OnTimeIncrementPost", ET_Event, Param_Cell, Param_Cell, Param_Array);
LoadTranslations("shavit-core.phrases");
@ -251,13 +254,14 @@ public void OnPluginStart()
RegConsoleCmd("sm_r", Command_StartTimer, "Start your timer.");
RegConsoleCmd("sm_restart", Command_StartTimer, "Start your timer.");
RegConsoleCmd("sm_b", Command_StartTimer_Bonus, "Start your timer on the bonus track.");
RegConsoleCmd("sm_bonus", Command_StartTimer_Bonus, "Start your timer on the bonus track.");
RegConsoleCmd("sm_b", Command_StartTimer, "Start your timer on the bonus track.");
RegConsoleCmd("sm_bonus", Command_StartTimer, "Start your timer on the bonus track.");
// teleport to end
RegConsoleCmd("sm_end", Command_TeleportEnd, "Teleport to endzone.");
RegConsoleCmd("sm_bend", Command_TeleportEnd_Bonus, "Teleport to endzone of the bonus track.");
RegConsoleCmd("sm_bonusend", Command_TeleportEnd_Bonus, "Teleport to endzone of the bonus track.");
RegConsoleCmd("sm_bend", Command_TeleportEnd, "Teleport to endzone of the bonus track.");
RegConsoleCmd("sm_bonusend", Command_TeleportEnd, "Teleport to endzone of the bonus track.");
// timer stop
RegConsoleCmd("sm_stop", Command_StopTimer, "Stop your timer.");
@ -438,70 +442,36 @@ public Action Command_StartTimer(int client, int args)
return Plugin_Handled;
}
char[] sCommand = new char[16];
GetCmdArg(0, sCommand, 16);
if(!gB_Restart)
{
if(args != -1)
{
char[] sCommand = new char[16];
GetCmdArg(0, sCommand, 16);
Shavit_PrintToChat(client, "%T", "CommandDisabled", client, gS_ChatStrings[sMessageVariable], sCommand, gS_ChatStrings[sMessageText]);
}
return Plugin_Handled;
}
if(gB_AllowTimerWithoutZone || (gB_Zones && (Shavit_ZoneExists(Zone_Start, Track_Main) || gB_KZMap)))
int track = Track_Main;
if(StrContains(sCommand, "sm_b", false) == 0)
{
track = Track_Bonus;
}
if(gB_AllowTimerWithoutZone || (gB_Zones && (Shavit_ZoneExists(Zone_Start, track) || gB_KZMap)))
{
Call_StartForward(gH_Forwards_OnRestart);
Call_PushCell(client);
Call_PushCell(Track_Main);
Call_PushCell(track);
Call_Finish();
if(gB_AllowTimerWithoutZone)
{
StartTimer(client, Track_Main);
}
}
else
{
Shavit_PrintToChat(client, "%T", "StartZoneUndefined", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
}
return Plugin_Handled;
}
public Action Command_StartTimer_Bonus(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
if(!gB_Restart)
{
if(args != -1)
{
char[] sCommand = new char[16];
GetCmdArg(0, sCommand, 16);
Shavit_PrintToChat(client, "%T", "CommandDisabled", client, gS_ChatStrings[sMessageVariable], sCommand, gS_ChatStrings[sMessageText]);
}
return Plugin_Handled;
}
if(gB_AllowTimerWithoutZone || (gB_Zones && (Shavit_ZoneExists(Zone_Start, Track_Bonus) || gB_KZMap)))
{
Call_StartForward(gH_Forwards_OnRestart);
Call_PushCell(client);
Call_PushCell(Track_Bonus);
Call_Finish();
if(gB_AllowTimerWithoutZone)
{
StartTimer(client, Track_Bonus);
StartTimer(client, track);
}
}
@ -520,38 +490,23 @@ public Action Command_TeleportEnd(int client, int args)
return Plugin_Handled;
}
if(gB_Zones && Shavit_ZoneExists(Zone_End, Track_Main))
char[] sCommand = new char[16];
GetCmdArg(0, sCommand, 16);
int track = Track_Main;
if(StrContains(sCommand, "sm_b", false) == 0)
{
track = Track_Bonus;
}
if(gB_Zones && (Shavit_ZoneExists(Zone_End, track) || gB_KZMap))
{
Shavit_StopTimer(client);
Call_StartForward(gH_Forwards_OnEnd);
Call_PushCell(client);
Call_PushCell(Track_Main); // sm_bend will be bonus end
Call_Finish();
}
else
{
Shavit_PrintToChat(client, "%T", "EndZoneUndefined", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
}
return Plugin_Handled;
}
public Action Command_TeleportEnd_Bonus(int client, int args)
{
if(!IsValidClient(client))
{
return Plugin_Handled;
}
if(gB_Zones && Shavit_ZoneExists(Zone_End, Track_Bonus))
{
Shavit_StopTimer(client);
Call_StartForward(gH_Forwards_OnEnd);
Call_PushCell(client);
Call_PushCell(Track_Bonus);
Call_PushCell(track);
Call_Finish();
}
@ -606,22 +561,22 @@ public Action Command_TogglePause(int client, int args)
return Plugin_Handled;
}
if(gB_PracticeMode[client])
{
Shavit_PrintToChat(client, "%T", "PausePractice", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
return Plugin_Handled;
}
if(gB_ClientPaused[client])
{
TeleportEntity(client, gF_PausePosition[client][0], gF_PausePosition[client][1], gF_PausePosition[client][2]);
ResumeTimer(client);
Shavit_PrintToChat(client, "%T", "MessageUnpause", client, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
}
else
{
GetClientAbsOrigin(client, gF_PausePosition[client][0]);
GetClientEyeAngles(client, gF_PausePosition[client][1]);
GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", gF_PausePosition[client][2]);
PauseTimer(client);
Shavit_PrintToChat(client, "%T", "MessagePause", client, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
}
@ -808,7 +763,7 @@ void ChangeClientStyle(int client, int style, bool manual)
StopTimer(client);
if(gB_AllowTimerWithoutZone || (gB_Zones && Shavit_ZoneExists(Zone_Start, Track_Main)))
if(gB_AllowTimerWithoutZone || (gB_Zones && (Shavit_ZoneExists(Zone_Start, gI_Track[client]) || gB_KZMap)))
{
Call_StartForward(gH_Forwards_OnRestart);
Call_PushCell(client);
@ -947,8 +902,7 @@ public int Native_GetTimer(Handle handler, int numParams)
int client = GetNativeCell(1);
// 2 - time
float time = CalculateTime(client);
SetNativeCellRef(2, time);
SetNativeCellRef(2, gF_PlayerTimer[client]);
SetNativeCellRef(3, gI_Jumps[client]);
SetNativeCellRef(4, gBS_Style[client]);
SetNativeCellRef(5, gB_TimerEnabled[client]);
@ -956,7 +910,7 @@ public int Native_GetTimer(Handle handler, int numParams)
public int Native_GetClientTime(Handle handler, int numParams)
{
return view_as<int>(CalculateTime(GetNativeCell(1)));
return view_as<int>(gF_PlayerTimer[GetNativeCell(1)]);
}
public int Native_GetClientTrack(Handle handler, int numParams)
@ -1005,11 +959,8 @@ public int Native_FinishMap(Handle handler, int numParams)
{
int client = GetNativeCell(1);
any snapshot[TIMERSNAPSHOT_SIZE];
any[] snapshot = new any[TIMERSNAPSHOT_SIZE];
snapshot[bTimerEnabled] = gB_TimerEnabled[client];
snapshot[fStartTime] = gF_StartTime[client];
snapshot[fPauseStartTime] = gF_PauseStartTime[client];
snapshot[fPauseTotalTime] = gF_PauseTotalTime[client];
snapshot[bClientPaused] = gB_ClientPaused[client];
snapshot[iJumps] = gI_Jumps[client];
snapshot[bsStyle] = gBS_Style[client];
@ -1017,7 +968,7 @@ public int Native_FinishMap(Handle handler, int numParams)
snapshot[iTotalMeasures] = gI_TotalMeasures[client];
snapshot[iGoodGains] = gI_GoodGains[client];
snapshot[fServerTime] = GetEngineTime();
snapshot[fCurrentTime] = CalculateTime(client);
snapshot[fCurrentTime] = gF_PlayerTimer[client];
snapshot[iSHSWCombination] = gI_SHSW_FirstCombination[client];
snapshot[iTimerTrack] = gI_Track[client];
@ -1035,25 +986,37 @@ public int Native_FinishMap(Handle handler, int numParams)
Call_StartForward(gH_Forwards_Finish);
Call_PushCell(client);
int style = 0;
int track = Track_Main;
if(result == Plugin_Continue)
{
Call_PushCell(gBS_Style[client]);
Call_PushCell(CalculateTime(client));
Call_PushCell(style = gBS_Style[client]);
Call_PushCell(gF_PlayerTimer[client]);
Call_PushCell(gI_Jumps[client]);
Call_PushCell(gI_Strafes[client]);
Call_PushCell((gA_StyleSettings[gBS_Style[client]][bSync])? (gI_GoodGains[client] == 0)? 0.0:(gI_GoodGains[client] / float(gI_TotalMeasures[client]) * 100.0):-1.0);
Call_PushCell(track = gI_Track[client]);
}
else
{
Call_PushCell(snapshot[bsStyle]);
Call_PushCell(style = snapshot[bsStyle]);
Call_PushCell(snapshot[fCurrentTime]);
Call_PushCell(snapshot[iJumps]);
Call_PushCell(snapshot[iStrafes]);
Call_PushCell((gA_StyleSettings[snapshot[bsStyle]][bSync])? (snapshot[iGoodGains] == 0)? 0.0:(snapshot[iGoodGains] / float(snapshot[iTotalMeasures]) * 100.0):-1.0);
Call_PushCell(track = snapshot[iTimerTrack]);
}
Call_PushCell(gI_Track[client]);
float oldtime = 0.0;
if(gB_WR)
{
Shavit_GetPlayerPB(client, style, oldtime, track);
}
Call_PushCell(oldtime);
Call_Finish();
StopTimer(client);
@ -1175,9 +1138,6 @@ public int Native_SaveSnapshot(Handle handler, int numParams)
any[] snapshot = new any[TIMERSNAPSHOT_SIZE];
snapshot[bTimerEnabled] = gB_TimerEnabled[client];
snapshot[fStartTime] = gF_StartTime[client];
snapshot[fPauseStartTime] = gF_PauseStartTime[client];
snapshot[fPauseTotalTime] = gF_PauseTotalTime[client];
snapshot[bClientPaused] = gB_ClientPaused[client];
snapshot[iJumps] = gI_Jumps[client];
snapshot[bsStyle] = gBS_Style[client];
@ -1185,7 +1145,7 @@ public int Native_SaveSnapshot(Handle handler, int numParams)
snapshot[iTotalMeasures] = gI_TotalMeasures[client];
snapshot[iGoodGains] = gI_GoodGains[client];
snapshot[fServerTime] = GetEngineTime();
snapshot[fCurrentTime] = CalculateTime(client);
snapshot[fCurrentTime] = gF_PlayerTimer[client];
snapshot[iSHSWCombination] = gI_SHSW_FirstCombination[client];
snapshot[iTimerTrack] = gI_Track[client];
@ -1207,16 +1167,14 @@ public int Native_LoadSnapshot(Handle handler, int numParams)
}
gB_TimerEnabled[client] = view_as<bool>(snapshot[bTimerEnabled]);
gF_PauseStartTime[client] = view_as<float>(snapshot[fPauseStartTime]);
gF_PauseTotalTime[client] = view_as<float>(snapshot[fPauseTotalTime]);
gB_ClientPaused[client] = false; // Pausing is disabled in practice mode.
gB_ClientPaused[client] = view_as<bool>(snapshot[bClientPaused]);
gI_Jumps[client] = view_as<int>(snapshot[iJumps]);
gBS_Style[client] = snapshot[bsStyle];
gI_Strafes[client] = view_as<int>(snapshot[iStrafes]);
gI_TotalMeasures[client] = view_as<int>(snapshot[iTotalMeasures]);
gI_GoodGains[client] = view_as<int>(snapshot[iGoodGains]);
gF_StartTime[client] = GetEngineTime() - view_as<float>(snapshot[fCurrentTime]);
gI_SHSW_FirstCombination[client] = view_as<int>(snapshot[iSHSWCombination]);\
gF_PlayerTimer[client] = snapshot[fCurrentTime];
gI_SHSW_FirstCombination[client] = view_as<int>(snapshot[iSHSWCombination]);
}
public int Native_MarkKZMap(Handle handler, int numParams)
@ -1251,13 +1209,6 @@ void StartTimer(int client, int track)
if(!gB_NoZAxisSpeed || gA_StyleSettings[gBS_Style[client]][bPrespeed] || (fSpeed[2] == 0.0 && SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0)) <= 290.0))
{
gI_Strafes[client] = 0;
gI_Jumps[client] = 0;
gI_TotalMeasures[client] = 0;
gI_GoodGains[client] = 0;
gF_StartTime[client] = GetEngineTime();
gI_Track[client] = track;
Action result = Plugin_Continue;
Call_StartForward(gH_Forwards_Start);
Call_PushCell(client);
@ -1266,11 +1217,15 @@ void StartTimer(int client, int track)
if(result == Plugin_Continue)
{
gI_Strafes[client] = 0;
gI_Jumps[client] = 0;
gI_TotalMeasures[client] = 0;
gI_GoodGains[client] = 0;
gF_PlayerTimer[client] = 0.0;
gI_Track[client] = track;
gB_TimerEnabled[client] = true;
gI_SHSW_FirstCombination[client] = -1;
gF_PauseTotalTime[client] = 0.0;
gB_ClientPaused[client] = false;
gF_PlayerTimer[client] = 0.0;
gB_PracticeMode[client] = false;
SetEntityGravity(client, view_as<float>(gA_StyleSettings[gBS_Style[client]][fGravityMultiplier]));
@ -1293,8 +1248,7 @@ void StopTimer(int client)
gB_TimerEnabled[client] = false;
gI_Jumps[client] = 0;
gF_StartTime[client] = 0.0;
gF_PauseTotalTime[client] = 0.0;
gF_PlayerTimer[client] = 0.0;
gB_ClientPaused[client] = false;
gI_Strafes[client] = 0;
gI_TotalMeasures[client] = 0;
@ -1313,7 +1267,6 @@ void PauseTimer(int client)
Call_PushCell(gI_Track[client]);
Call_Finish();
gF_PauseStartTime[client] = GetEngineTime();
gB_ClientPaused[client] = true;
}
@ -1329,32 +1282,9 @@ void ResumeTimer(int client)
Call_PushCell(gI_Track[client]);
Call_Finish();
gF_PauseTotalTime[client] += (GetEngineTime() - gF_PauseStartTime[client]);
gB_ClientPaused[client] = false;
}
float CalculateTime(int client)
{
float time = 0.0;
if(!gB_ClientPaused[client])
{
time = (GetEngineTime() - gF_StartTime[client] - gF_PauseTotalTime[client]);
}
else
{
time = (gF_PauseStartTime[client] - gF_StartTime[client] - gF_PauseTotalTime[client]);
}
if(gA_StyleSettings[gBS_Style[client]][bHalftime])
{
time /= 2.0;
}
return time;
}
public void OnClientDisconnect(int client)
{
StopTimer(client);
@ -1530,7 +1460,7 @@ bool LoadStyles()
gA_StyleSettings[i][iForceHSW] = kv.GetNum("force_hsw", 0);
gA_StyleSettings[i][bBlockPLeft] = view_as<bool>(kv.GetNum("block_pleft", 0));
gA_StyleSettings[i][bBlockPRight] = view_as<bool>(kv.GetNum("block_pright", 0));
gA_StyleSettings[i][bBlockPStrafe] = view_as<bool>(kv.GetNum("block_pstrafe", 0));
gA_StyleSettings[i][iBlockPStrafe] = kv.GetNum("block_pstrafe", 0);
gA_StyleSettings[i][bUnranked] = view_as<bool>(kv.GetNum("unranked", 0));
gA_StyleSettings[i][bNoReplay] = view_as<bool>(kv.GetNum("noreplay", 0));
gA_StyleSettings[i][bSync] = view_as<bool>(kv.GetNum("sync", 1));
@ -1836,21 +1766,75 @@ public void PreThinkPost(int client)
}
}
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3])
public void OnGameFrame()
{
float frametime = GetGameFrameTime();
for(int i = 1; i <= MaxClients; i++)
{
if(gB_ClientPaused[i] || !gB_TimerEnabled[i])
{
continue;
}
float time = frametime;
if(gA_StyleSettings[gBS_Style[i]][bHalftime])
{
time /= 2.0;
}
any[] snapshot = new any[TIMERSNAPSHOT_SIZE];
snapshot[bTimerEnabled] = gB_TimerEnabled[i];
snapshot[bClientPaused] = gB_ClientPaused[i];
snapshot[iJumps] = gI_Jumps[i];
snapshot[bsStyle] = gBS_Style[i];
snapshot[iStrafes] = gI_Strafes[i];
snapshot[iTotalMeasures] = gI_TotalMeasures[i];
snapshot[iGoodGains] = gI_GoodGains[i];
snapshot[fServerTime] = GetEngineTime();
snapshot[fCurrentTime] = gF_PlayerTimer[i];
snapshot[iSHSWCombination] = gI_SHSW_FirstCombination[i];
snapshot[iTimerTrack] = gI_Track[i];
Call_StartForward(gH_Forwards_OnTimerIncrement);
Call_PushCell(i);
Call_PushArray(snapshot, TIMERSNAPSHOT_SIZE);
Call_PushCellRef(time);
Call_PushArray(gA_StyleSettings[gBS_Style[i]], STYLESETTINGS_SIZE);
Call_Finish();
gF_PlayerTimer[i] += time;
Call_StartForward(gH_Forwards_OnTimerIncrementPost);
Call_PushCell(i);
Call_PushCell(time);
Call_PushArray(gA_StyleSettings[gBS_Style[i]], STYLESETTINGS_SIZE);
Call_Finish();
}
}
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2])
{
if(!IsPlayerAlive(client) || IsFakeClient(client))
{
return Plugin_Continue;
}
int flags = GetEntityFlags(client);
if(gB_ClientPaused[client])
{
buttons = 0;
vel = view_as<float>({0.0, 0.0, 0.0});
SetEntityFlags(client, (flags | FL_ATCONTROLS));
return Plugin_Changed;
}
SetEntityFlags(client, (flags & ~FL_ATCONTROLS));
Action result = Plugin_Continue;
Call_StartForward(gH_Forwards_OnUserCmdPre);
Call_PushCell(client);
@ -1862,6 +1846,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
Call_PushCell(gI_Track[client]);
Call_PushCell(gBS_Style[client]);
Call_PushArray(gA_StyleSettings[gBS_Style[client]], STYLESETTINGS_SIZE);
Call_PushArrayEx(mouse, 2, SM_PARAM_COPYBACK);
Call_Finish(result);
if(result != Plugin_Continue && result != Plugin_Changed)
@ -1885,19 +1870,25 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
}
// +strafe block
if(gA_StyleSettings[gBS_Style[client]][bBlockPStrafe] &&
if(gA_StyleSettings[gBS_Style[client]][iBlockPStrafe] > 0 &&
((vel[0] > 0.0 && (buttons & IN_FORWARD) == 0) || (vel[0] < 0.0 && (buttons & IN_BACK) == 0) ||
(vel[1] > 0.0 && (buttons & IN_MOVERIGHT) == 0) || (vel[1] < 0.0 && (buttons & IN_MOVELEFT) == 0)))
{
float fTime = GetEngineTime();
if(gF_StrafeWarning[client] < fTime)
if(gF_StrafeWarning[client] < gF_PlayerTimer[client])
{
if(gA_StyleSettings[gBS_Style[client]][iBlockPStrafe] >= 2)
{
FormatEx(sCheatDetected, 64, "%T", "Inconsistencies", client);
StopTimer_Cheat(client, sCheatDetected);
}
gF_StrafeWarning[client] = fTime + 0.20;
vel[0] = 0.0;
vel[1] = 0.0;
return Plugin_Changed;
}
gF_StrafeWarning[client] = gF_PlayerTimer[client] + 0.3;
}
}

View File

@ -63,9 +63,11 @@ Handle gH_HUD = null;
// plugin cvars
ConVar gCV_GradientStepSize = null;
ConVar gCV_TicksPerUpdate = null;
// cached cvars
int gI_GradientStepSize = 5;
int gI_TicksPerUpdate = 5;
// timer settings
char gS_StyleStrings[STYLE_LIMIT][STYLESTRINGS_SIZE][128];
@ -130,13 +132,13 @@ public void OnPluginStart()
// plugin convars
gCV_GradientStepSize = CreateConVar("shavit_hud_gradientstepsize", "15", "How fast should the start/end HUD gradient be?\nThe number is the amount of color change per 0.1 seconds.\nThe higher the number the faster the gradient.", 0, true, 1.0, true, 255.0);
gCV_TicksPerUpdate = CreateConVar("shavit_hud_ticksperupdate", "5", "How often (in ticks) should the HUD update?\nPlay around with this value until you find the best for your server.\nThe maximum value is your tickrate.", 0, true, 1.0, true, (1.0 / GetTickInterval()));
gCV_GradientStepSize.AddChangeHook(OnConVarChanged);
gCV_TicksPerUpdate.AddChangeHook(OnConVarChanged);
AutoExecConfig();
// cron
CreateTimer(0.10, UpdateHUD_Timer, INVALID_HANDLE, TIMER_REPEAT);
// commands
RegConsoleCmd("sm_hud", Command_HUD, "Opens the HUD settings menu");
RegConsoleCmd("sm_options", Command_HUD, "Opens the HUD settings menu (alias for sm_hud");
@ -164,6 +166,7 @@ public void OnPluginStart()
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
gI_GradientStepSize = gCV_GradientStepSize.IntValue;
gI_TicksPerUpdate = gCV_TicksPerUpdate.IntValue;
}
public void OnMapStart()
@ -476,7 +479,15 @@ public int MenuHandler_HUD(Menu menu, MenuAction action, int param1, int param2)
return 0;
}
public Action UpdateHUD_Timer(Handle Timer)
public void OnGameFrame()
{
if(GetGameTickCount() % gI_TicksPerUpdate == 0)
{
Cron();
}
}
void Cron()
{
if(++gI_Cycle >= 65535)
{
@ -567,8 +578,6 @@ public Action UpdateHUD_Timer(Handle Timer)
TriggerHUDUpdate(i);
}
return Plugin_Continue;
}
void TriggerHUDUpdate(int client, bool keysonly = false) // keysonly because CS:S lags when you send too many usermessages
@ -635,7 +644,7 @@ void UpdateHUD(int client)
{
if(gEV_Type == Engine_CSGO)
{
FormatEx(sHintText, 64, "<font size=\"38\" color=\"#%06X\">%T</font>\n\t%T: %d", ((gI_GradientColors[0] << 16) + (gI_GradientColors[1] << 8) + (gI_GradientColors[2])), "HudStartZone", client, "HudSpeedText", client, iSpeed);
FormatEx(sHintText, 128, " <font size='34' color='#%06X'>%T</font>\n\t %T: %d", ((gI_GradientColors[0] << 16) + (gI_GradientColors[1] << 8) + (gI_GradientColors[2])), "HudStartZone", client, "HudSpeedText", client, iSpeed);
}
else
@ -649,7 +658,7 @@ void UpdateHUD(int client)
{
if(gEV_Type == Engine_CSGO)
{
FormatEx(sHintText, 64, "<font size=\"38\" color=\"#%06X\">%T</font>\n\t%T: %d", ((gI_GradientColors[0] << 16) + (gI_GradientColors[1] << 8) + (gI_GradientColors[2])), "HudEndZone", client, "HudSpeedText", client, iSpeed);
FormatEx(sHintText, 128, " <font size='34' color='#%06X'>%T</font>\n\t %T: %d", ((gI_GradientColors[0] << 16) + (gI_GradientColors[1] << 8) + (gI_GradientColors[2])), "HudEndZone", client, "HudSpeedText", client, iSpeed);
}
else
@ -667,6 +676,7 @@ void UpdateHUD(int client)
else if((gI_HUDSettings[client] & HUD_CENTER) > 0)
{
int track = Shavit_GetClientTrack(target);
char[] sTrack = new char[32];
if(!IsFakeClient(target))
{
@ -690,7 +700,7 @@ void UpdateHUD(int client)
if(gEV_Type == Engine_CSGO)
{
strcopy(sHintText, 512, "<font size=\"18\" face=\"Stratum2\">");
strcopy(sHintText, 512, "<font size='18' face=''>");
if(status >= Timer_Running)
{
@ -698,7 +708,7 @@ void UpdateHUD(int client)
if(status == Timer_Paused)
{
strcopy(sColor, 8, "FF0000");
strcopy(sColor, 8, "A9C5E8");
}
else if(time < fWR || fWR == 0.0)
@ -716,16 +726,16 @@ void UpdateHUD(int client)
strcopy(sColor, 8, "FF0000");
}
char[] sPauseItem = new char[64];
FormatEx(sPauseItem, 64, "%T\t</font>", "HudPaused", client);
char[] sUnpausedItem = new char[64];
FormatEx(sUnpausedItem, 64, "%s</font> (%d)\t", sTime, rank);
Format(sHintText, 512, "%s%T: <font color='#%s'>%s", sHintText, "HudTimeText", client, sColor, (status == Timer_Paused)? sPauseItem:sUnpausedItem);
if(track != Track_Main)
{
GetTrackName(client, track, sTrack, 32);
Format(sHintText, 512, "%s[<font color='#FFFFFF'>%s</font>] ", sHintText, sTrack);
}
if(fPB > 0.0)
Format(sHintText, 512, "%s<font color='#%s'>%s</font> (%d)", sHintText, sColor, sTime, rank);
}
else if(fPB > 0.0)
{
Format(sHintText, 512, "%s%T: %s (#%d)", sHintText, "HudBestText", client, sPB, (Shavit_GetRankForTime(style, fPB, track) - 1));
}
@ -754,15 +764,11 @@ void UpdateHUD(int client)
Format(sHintText, 512, "%s%s\t%T: %d", sHintText, (iSpeed < 1000)? "\t":"", "HudStrafeText", client, strafes);
}
}
Format(sHintText, 512, "%s</font>", sHintText);
}
else
{
if(status != Timer_Stopped)
{
if(Shavit_GetTimerStatus(target) == Timer_Running)
{
char[] sFirstLine = new char[64];
strcopy(sFirstLine, 64, gS_StyleStrings[style][sStyleName]);
@ -773,18 +779,14 @@ void UpdateHUD(int client)
}
FormatEx(sHintText, 512, "%s\n%T: %s (%d)\n%T: %d\n%T: %d\n%T: %d%s", sFirstLine, "HudTimeText", client, sTime, rank, "HudJumpsText", client, jumps, "HudStrafeText", client, strafes, "HudSpeedText", client, iSpeed, (gA_StyleSettings[style][fVelocityLimit] > 0.0 && Shavit_InsideZone(target, Zone_NoVelLimit, -1))? "\nNo Speed Limit":"");
}
else
if(Shavit_GetTimerStatus(target) == Timer_Paused)
{
FormatEx(sHintText, 16, "%T", "HudPaused", client);
Format(sHintText, 512, "%s\n%T", sHintText, "HudPaused", client);
}
if(track != Track_Main)
{
char[] sTrack = new char[32];
GetTrackName(client, track, sTrack, 32);
Format(sHintText, 512, "%s\n%s", sHintText, sTrack);
}
}
@ -825,8 +827,6 @@ void UpdateHUD(int client)
char[] sReplayLength = new char[32];
FormatSeconds(fReplayLength, sReplayLength, 32, false);
char[] sTrack = new char[32];
if(track != Track_Main)
{
GetTrackName(client, track, sTrack, 32);
@ -835,11 +835,10 @@ void UpdateHUD(int client)
if(gEV_Type == Engine_CSGO)
{
FormatEx(sHintText, 512, "<font face='Stratum2'>");
FormatEx(sHintText, 512, "<font face=''>");
Format(sHintText, 512, "%s\t<u><font color='#%s'>%s %T</font></u>", sHintText, gS_StyleStrings[style][sHTMLColor], gS_StyleStrings[style][sStyleName], "ReplayText", client);
Format(sHintText, 512, "%s\n\t%T: <font color='#00FF00'>%s</font> / %s", sHintText, "HudTimeText", client, sReplayTime, sReplayLength);
Format(sHintText, 512, "%s\n\t%T: %d", sHintText, "HudSpeedText", client, iSpeed);
Format(sHintText, 512, "%s</font>", sHintText);
}
else
@ -876,7 +875,20 @@ void UpdateKeyOverlay(int client, Panel panel, bool &draw)
int buttons = gI_Buttons[target];
char[] sPanelLine = new char[128];
FormatEx(sPanelLine, 128, "%s %s\n   %s\n%s  %s  %s",
int style = (IsFakeClient(target))? Shavit_GetReplayBotStyle(target):Shavit_GetBhopStyle(target);
if(style < 0 || style > gI_Styles)
{
style = 0;
}
if(gB_BhopStats && !gA_StyleSettings[style][bAutobhop])
{
FormatEx(sPanelLine, 64, " %d%s%d\n", gI_ScrollCount[target], (gI_ScrollCount[target] > 9)? " ":" ", gI_LastScrollCount[target]);
}
Format(sPanelLine, 128, "%s%s %s\n   %s\n%s  %s  %s", sPanelLine,
(buttons & IN_JUMP) > 0? "":"", (buttons & IN_DUCK) > 0? "":"",
(buttons & IN_FORWARD) > 0? "":"", (buttons & IN_MOVELEFT) > 0? "":"",
(buttons & IN_BACK) > 0? "":"", (buttons & IN_MOVERIGHT) > 0? "":"");
@ -1022,20 +1034,20 @@ void UpdateTopLeftHUD(int client, bool wait)
char[] sPBTime = new char[16];
FormatSeconds(fPBTime, sPBTime, MAX_NAME_LENGTH);
char[] sTopLeft = new char[64];
char[] sTopLeft = new char[128];
if(fPBTime != 0.0)
{
FormatEx(sTopLeft, 64, "WR: %s (%s)\n%T: %s (#%d)", sWRTime, sWRName, "HudBestText", client, sPBTime, (Shavit_GetRankForTime(style, fPBTime, track) - 1));
FormatEx(sTopLeft, 128, "WR: %s (%s)\n%T: %s (#%d)", sWRTime, sWRName, "HudBestText", client, sPBTime, (Shavit_GetRankForTime(style, fPBTime, track) - 1));
}
else
{
FormatEx(sTopLeft, 64, "WR: %s (%s)", sWRTime, sWRName);
FormatEx(sTopLeft, 128, "WR: %s (%s)", sWRTime, sWRName);
}
SetHudTextParams(0.01, 0.01, 2.5, 255, 255, 255, 255);
ShowSyncHudText(client, gH_HUD, sTopLeft);
SetHudTextParams(0.01, 0.01, 2.5, 255, 255, 255, 255, 0, 0.0, 0.0, 0.0);
ShowSyncHudText(client, gH_HUD, "%s", sTopLeft);
}
}
}

View File

@ -33,15 +33,33 @@
#undef REQUIRE_PLUGIN
#include <shavit>
// this one is here because enum structs don't work with new syntax
enum CheckpointsCache
{
Float:fCPPosition[3],
Float:fCPAngles[3],
Float:fCPVelocity[3],
MoveType:mtCPMoveType,
Float:fCPGravity,
Float:fCPSpeed,
Float:fCPStamina,
bool:bCPDucking,
iCPFlags,
any:aCPSnapshot[TIMERSNAPSHOT_SIZE],
String:sCPTargetname[32],
PCPCACHE_SIZE
}
#pragma newdecls required
#pragma semicolon 1
#pragma dynamic 131072
#define CP_ANGLES (1 << 0)
#define CP_VELOCITY (1 << 1)
#define CP_DEFAULT (CP_ANGLES|CP_VELOCITY)
#define CP_MAX 64 // this is the amount i'm willing to go for
#define CP_MAX 1000 // segmented runs shouldn't even reach 1k jumps on any map anyways
// game specific
EngineVersion gEV_Type = Engine_Unknown;
@ -51,24 +69,6 @@ char gS_RadioCommands[][] = {"coverme", "takepoint", "holdpos", "regroup", "foll
"getinpos", "stormfront", "report", "roger", "enemyspot", "needbackup", "sectorclear", "inposition", "reportingin",
"getout", "negative", "enemydown", "compliment", "thanks", "cheer"};
// enums
enum
{
iCheckpoints,
iCurrentCheckpoint,
CHECKPOINTSCACHE_SIZE
};
enum
{
iCPMoveType,
fCPGravity,
fCPSpeed,
fCPStamina,
bCPDucking,
PCHECKPOINTSCACHE_SIZE
};
// cache
ConVar sv_disable_immunity_alpha = null;
ConVar sv_footsteps = null;
@ -84,12 +84,16 @@ int gI_AdvertisementsCycle = 0;
char gS_CurrentMap[192];
int gBS_Style[MAXPLAYERS+1];
float gF_Checkpoints[MAXPLAYERS+1][CP_MAX][3][3]; // 3 - position, angles, velocity
enum
{
iCheckpoints,
iCurrentCheckpoint,
CPCACHE_SIZE
};
int gI_CheckpointsCache[MAXPLAYERS+1][CPCACHE_SIZE];
int gI_CheckpointsSettings[MAXPLAYERS+1];
any gA_PlayerCheckPointsCache[MAXPLAYERS+1][CP_MAX][PCHECKPOINTSCACHE_SIZE];
any gA_CheckpointsSnapshots[MAXPLAYERS+1][CP_MAX][TIMERSNAPSHOT_SIZE];
any gA_CheckpointsCache[MAXPLAYERS+1][CHECKPOINTSCACHE_SIZE];
char gS_CheckpointsTargetname[MAXPLAYERS+1][CP_MAX][32];
StringMap gSM_Checkpoints = null;
// save states
float gF_SaveStateData[MAXPLAYERS+1][3][3];
@ -156,7 +160,7 @@ int gI_NoclipMe = true;
float gF_AdvertisementInterval = 600.0;
bool gB_Checkpoints = true;
int gI_RemoveRagdolls = 1;
char gS_ClanTag[32] = "{styletag} :: {time}";
char gS_ClanTag[32] = "{tr}{styletag} :: {time}";
bool gB_DropAll = true;
bool gB_ResetTargetname = false;
bool gB_RestoreStates = false;
@ -168,6 +172,7 @@ Handle gH_GetPlayerMaxSpeed = null;
// modules
bool gB_Rankings = false;
bool gB_Replay = false;
bool gB_Zones = false;
// timer settings
char gS_StyleStrings[STYLE_LIMIT][STYLESTRINGS_SIZE][128];
@ -232,6 +237,7 @@ public void OnPluginStart()
RegConsoleCmd("sm_save", Command_Save, "Saves checkpoint (default: 1). Usage: sm_save [number]");
RegConsoleCmd("sm_tele", Command_Tele, "Teleports to checkpoint (default: 1). Usage: sm_tele [number]");
gH_CheckpointsCookie = RegClientCookie("shavit_checkpoints", "Checkpoints settings", CookieAccess_Protected);
gSM_Checkpoints = new StringMap();
gI_Ammo = FindSendPropInfo("CCSPlayer", "m_iAmmo");
@ -301,7 +307,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_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_ClanTag = CreateConVar("shavit_misc_clantag", "{styletag} :: {time}", "Custom clantag for players.\n0 - Disabled\n{styletag} - style settings from shavit-styles.cfg.\n{style} - style name.\n{time} - formatted time.", 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_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_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);
@ -386,6 +392,7 @@ public void OnPluginStart()
// modules
gB_Rankings = LibraryExists("shavit-rankings");
gB_Replay = LibraryExists("shavit-replay");
gB_Zones = LibraryExists("shavit-zones");
}
public void OnClientCookiesCached(int client)
@ -503,6 +510,8 @@ public void OnConfigsExecuted()
public void OnMapStart()
{
gSM_Checkpoints.Clear();
GetCurrentMap(gS_CurrentMap, 192);
GetMapDisplayName(gS_CurrentMap, gS_CurrentMap, 192);
@ -511,12 +520,10 @@ public void OnMapStart()
int iEntity = -1;
float fOrigin[3];
if((iEntity = FindEntityByClassname(iEntity, "info_player_terrorist")) != INVALID_ENT_REFERENCE)
{
GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fOrigin);
}
else if((iEntity = FindEntityByClassname(iEntity, "info_player_counterterrorist")) != INVALID_ENT_REFERENCE)
if((iEntity = FindEntityByClassname(iEntity, "info_player_terrorist")) != INVALID_ENT_REFERENCE || // CS:S/CS:GO T
(iEntity = FindEntityByClassname(iEntity, "info_player_counterterrorist")) != INVALID_ENT_REFERENCE || // CS:S/CS:GO CT
(iEntity = FindEntityByClassname(iEntity, "info_player_teamspawn")) != INVALID_ENT_REFERENCE || // TF2 spawn point
(iEntity = FindEntityByClassname(iEntity, "info_player_start")) != INVALID_ENT_REFERENCE)
{
GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fOrigin);
}
@ -598,6 +605,11 @@ public void OnLibraryAdded(const char[] name)
{
gB_Replay = true;
}
else if(StrEqual(name, "shavit-zones"))
{
gB_Zones = true;
}
}
public void OnLibraryRemoved(const char[] name)
@ -611,6 +623,11 @@ public void OnLibraryRemoved(const char[] name)
{
gB_Replay = false;
}
else if(StrEqual(name, "shavit-zones"))
{
gB_Zones = false;
}
}
public Action Command_Jointeam(int client, const char[] command, int args)
@ -871,11 +888,20 @@ void UpdateClanTag(int client)
}
}
int track = Shavit_GetClientTrack(client);
char[] sTrack = new char[3];
if(track != Track_Main)
{
GetTrackName(client, track, sTrack, 3);
}
char[] sCustomTag = new char[32];
strcopy(sCustomTag, 32, gS_ClanTag);
ReplaceString(sCustomTag, 32, "{style}", gS_StyleStrings[gBS_Style[client]][sStyleName]);
ReplaceString(sCustomTag, 32, "{styletag}", gS_StyleStrings[gBS_Style[client]][sClanTag]);
ReplaceString(sCustomTag, 32, "{time}", sTime);
ReplaceString(sCustomTag, 32, "{tr}", sTrack);
CS_SetClientClanTag(client, sCustomTag);
}
@ -980,49 +1006,27 @@ public void OnClientPutInServer(int client)
gB_SaveStates[client] = false;
if(gA_SaveFrames[client] != null)
{
delete gA_SaveFrames[client];
gA_SaveFrames[client] = null;
}
public void OnClientDisconnect(int client)
{
ResetCheckpoints(client);
}
void ResetCheckpoints(int client)
{
for(int i = 0; i < sizeof(gF_Checkpoints[]); i++)
int serial = GetClientSerial(client);
char[] key = new char[32];
for(int i = 0; i < gI_CheckpointsCache[client][iCheckpoints]; i++)
{
for(int j = 0; j < sizeof(gF_Checkpoints[][]); j++)
{
gF_Checkpoints[client][i][j] = NULL_VECTOR;
}
FormatEx(key, 32, "%d_%d", serial, i);
gSM_Checkpoints.Remove(key);
}
for(int i = 0; i < CP_MAX; i++)
{
gA_CheckpointsSnapshots[client][i][bTimerEnabled] = false;
gA_CheckpointsSnapshots[client][i][fStartTime] = 0.0;
gA_CheckpointsSnapshots[client][i][fCurrentTime] = 0.0;
gA_CheckpointsSnapshots[client][i][fPauseStartTime] = 0.0;
gA_CheckpointsSnapshots[client][i][fPauseTotalTime] = 0.0;
gA_CheckpointsSnapshots[client][i][bClientPaused] = false;
gA_CheckpointsSnapshots[client][i][iJumps] = 0;
gA_CheckpointsSnapshots[client][i][bsStyle] = 0;
gA_CheckpointsSnapshots[client][i][iStrafes] = 0;
gA_CheckpointsSnapshots[client][i][iTotalMeasures] = 0;
gA_CheckpointsSnapshots[client][i][iGoodGains] = 0;
gA_CheckpointsSnapshots[client][i][iSHSWCombination] = -1;
gA_PlayerCheckPointsCache[client][i][iCPMoveType] = MOVETYPE_WALK;
gA_PlayerCheckPointsCache[client][i][fCPGravity] = 1.0;
gA_PlayerCheckPointsCache[client][i][fCPSpeed] = 1.0;
gA_PlayerCheckPointsCache[client][i][fCPStamina] = 1.0;
gA_PlayerCheckPointsCache[client][i][bCPDucking] = false;
strcopy(gS_CheckpointsTargetname[client][i], 32, "");
}
gA_CheckpointsCache[client][iCheckpoints] = 0;
gA_CheckpointsCache[client][iCurrentCheckpoint] = 1;
gI_CheckpointsCache[client][iCheckpoints] = 0;
gI_CheckpointsCache[client][iCurrentCheckpoint] = 1;
}
public Action OnTakeDamage(int victim, int attacker)
@ -1178,19 +1182,29 @@ public Action Command_Spec(int client, int args)
CleanSwitchTeam(client, 1, false);
int target = -1;
if(args > 0)
{
char[] sArgs = new char[MAX_TARGET_LENGTH];
GetCmdArgString(sArgs, MAX_TARGET_LENGTH);
int iTarget = FindTarget(client, sArgs, false, false);
target = FindTarget(client, sArgs, false, false);
if(iTarget == -1)
if(target == -1)
{
return Plugin_Handled;
}
}
SetEntPropEnt(client, Prop_Send, "m_hObserverTarget", iTarget);
else if(gB_Replay)
{
target = Shavit_GetReplayBotIndex(0);
}
if(IsValidClient(target, true))
{
SetEntPropEnt(client, Prop_Send, "m_hObserverTarget", target);
}
return Plugin_Handled;
@ -1434,11 +1448,11 @@ public Action Command_Save(int client, int args)
{
bool bSaved = false;
if(gA_CheckpointsCache[client][iCheckpoints] < CP_MAX)
if(gI_CheckpointsCache[client][iCheckpoints] < CP_MAX)
{
if((bSaved = SaveCheckpoint(client, gA_CheckpointsCache[client][iCheckpoints])))
if((bSaved = SaveCheckpoint(client, gI_CheckpointsCache[client][iCheckpoints])))
{
gA_CheckpointsCache[client][iCurrentCheckpoint] = ++gA_CheckpointsCache[client][iCheckpoints];
gI_CheckpointsCache[client][iCurrentCheckpoint] = ++gI_CheckpointsCache[client][iCheckpoints];
}
}
@ -1446,13 +1460,13 @@ public Action Command_Save(int client, int args)
{
if((bSaved = SaveCheckpoint(client, (CP_MAX - 1))))
{
gA_CheckpointsCache[client][iCurrentCheckpoint] = CP_MAX;
gI_CheckpointsCache[client][iCurrentCheckpoint] = CP_MAX;
}
}
if(bSaved)
{
Shavit_PrintToChat(client, "%T", "MiscCheckpointsSaved", client, gA_CheckpointsCache[client][iCurrentCheckpoint],
Shavit_PrintToChat(client, "%T", "MiscCheckpointsSaved", client, gI_CheckpointsCache[client][iCurrentCheckpoint],
gS_ChatStrings[sMessageVariable], gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], gS_ChatStrings[sMessageText]);
}
}
@ -1476,7 +1490,7 @@ public Action Command_Tele(int client, int args)
return Plugin_Handled;
}
int index = (gA_CheckpointsCache[client][iCurrentCheckpoint] - 1);
int index = (gI_CheckpointsCache[client][iCurrentCheckpoint] - 1);
if(args > 0)
{
@ -1491,7 +1505,13 @@ public Action Command_Tele(int client, int args)
}
}
if(IsNullVector(gF_Checkpoints[client][index][0]))
CheckpointsCache cpcache[PCPCACHE_SIZE];
GetCheckpoint(client, index, cpcache);
float pos[3];
CopyArray(cpcache[fCPPosition], pos, 3);
if(IsNullVector(pos))
{
Shavit_PrintToChat(client, "%T", "MiscCheckpointsEmpty", client, (index + 1), gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
@ -1516,12 +1536,12 @@ public Action OpenCheckpointsMenu(int client, int item)
menu.SetTitle("%T\n%T\n ", "MiscCheckpointMenu", client, "MiscCheckpointWarning", client);
char[] sDisplay = new char[64];
FormatEx(sDisplay, 64, "%T", "MiscCheckpointSave", client, (gA_CheckpointsCache[client][iCheckpoints] + 1));
menu.AddItem("save", sDisplay, (gA_CheckpointsCache[client][iCheckpoints] < CP_MAX)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
FormatEx(sDisplay, 64, "%T", "MiscCheckpointSave", client, (gI_CheckpointsCache[client][iCheckpoints] + 1));
menu.AddItem("save", sDisplay, (gI_CheckpointsCache[client][iCheckpoints] < CP_MAX)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED);
if(gA_CheckpointsCache[client][iCheckpoints] > 0)
if(gI_CheckpointsCache[client][iCheckpoints] > 0)
{
FormatEx(sDisplay, 64, "%T", "MiscCheckpointTeleport", client, gA_CheckpointsCache[client][iCurrentCheckpoint]);
FormatEx(sDisplay, 64, "%T", "MiscCheckpointTeleport", client, gI_CheckpointsCache[client][iCurrentCheckpoint]);
menu.AddItem("tele", sDisplay, ITEMDRAW_DEFAULT);
}
@ -1560,20 +1580,20 @@ public int MenuHandler_Checkpoints(Menu menu, MenuAction action, int param1, int
{
if(action == MenuAction_Select)
{
int current = gA_CheckpointsCache[param1][iCurrentCheckpoint];
int current = gI_CheckpointsCache[param1][iCurrentCheckpoint];
switch(param2)
{
case 0:
{
// fight an exploit
if(gA_CheckpointsCache[param1][iCheckpoints] >= CP_MAX)
if(gI_CheckpointsCache[param1][iCheckpoints] >= CP_MAX)
{
return 0;
}
SaveCheckpoint(param1, gA_CheckpointsCache[param1][iCheckpoints]);
gA_CheckpointsCache[param1][iCurrentCheckpoint] = ++gA_CheckpointsCache[param1][iCheckpoints];
SaveCheckpoint(param1, gI_CheckpointsCache[param1][iCheckpoints]);
gI_CheckpointsCache[param1][iCurrentCheckpoint] = ++gI_CheckpointsCache[param1][iCheckpoints];
}
case 1:
@ -1585,15 +1605,21 @@ public int MenuHandler_Checkpoints(Menu menu, MenuAction action, int param1, int
{
if(current > 1)
{
gA_CheckpointsCache[param1][iCurrentCheckpoint]--;
gI_CheckpointsCache[param1][iCurrentCheckpoint]--;
}
}
case 3:
{
if(current < CP_MAX && !IsNullVector(gF_Checkpoints[param1][current][0]))
CheckpointsCache cpcache[PCPCACHE_SIZE];
GetCheckpoint(param1, current, cpcache);
float pos[3];
CopyArray(cpcache[fCPPosition], pos, 3);
if(current < CP_MAX && !IsNullVector(pos))
{
gA_CheckpointsCache[param1][iCurrentCheckpoint]++;
gI_CheckpointsCache[param1][iCurrentCheckpoint]++;
}
}
@ -1657,25 +1683,50 @@ bool SaveCheckpoint(int client, int index)
return false;
}
GetClientAbsOrigin(target, gF_Checkpoints[client][index][0]);
GetClientEyeAngles(target, gF_Checkpoints[client][index][1]);
GetEntPropVector(target, Prop_Data, "m_vecAbsVelocity", gF_Checkpoints[client][index][2]);
GetEntPropString(target, Prop_Data, "m_iName", gS_CheckpointsTargetname[client][index], 32);
CheckpointsCache cpcache[PCPCACHE_SIZE];
float temp[3];
gA_PlayerCheckPointsCache[client][index][iCPMoveType] = GetEntityMoveType(target);
gA_PlayerCheckPointsCache[client][index][fCPGravity] = GetEntityGravity(target);
gA_PlayerCheckPointsCache[client][index][fCPSpeed] = GetEntPropFloat(target, Prop_Send, "m_flLaggedMovementValue");
gA_PlayerCheckPointsCache[client][index][fCPStamina] = GetEntPropFloat(target, Prop_Send, "m_flStamina");
gA_PlayerCheckPointsCache[client][index][bCPDucking] = (GetClientButtons(target) & IN_DUCK) > 0;
GetClientAbsOrigin(target, temp);
CopyArray(temp, cpcache[fCPPosition], 3);
Shavit_SaveSnapshot(target, gA_CheckpointsSnapshots[client][index]);
GetClientEyeAngles(target, temp);
CopyArray(temp, cpcache[fCPAngles], 3);
GetEntPropVector(target, Prop_Data, "m_vecAbsVelocity", temp);
CopyArray(temp, cpcache[fCPVelocity], 3);
GetEntPropString(target, Prop_Data, "m_iName", cpcache[sCPTargetname], 32);
cpcache[mtCPMoveType] = GetEntityMoveType(target);
cpcache[fCPGravity] = GetEntityGravity(target);
cpcache[fCPSpeed] = GetEntPropFloat(target, Prop_Send, "m_flLaggedMovementValue");
cpcache[fCPStamina] = (gEV_Type != Engine_TF2)? GetEntPropFloat(target, Prop_Send, "m_flStamina"):0.0;
cpcache[bCPDucking] = (GetClientButtons(target) & IN_DUCK) > 0;
cpcache[iCPFlags] = GetEntityFlags(target);
any snapshot[TIMERSNAPSHOT_SIZE];
Shavit_SaveSnapshot(target, snapshot);
CopyArray(snapshot, cpcache[aCPSnapshot], TIMERSNAPSHOT_SIZE);
SetCheckpoint(client, index, cpcache);
return true;
}
void TeleportToCheckpoint(int client, int index, bool suppressMessage)
{
if(index < 0 || index >= CP_MAX || IsNullVector(gF_Checkpoints[client][index][0]))
if(index < 0 || index >= CP_MAX)
{
return;
}
CheckpointsCache cpcache[PCPCACHE_SIZE];
GetCheckpoint(client, index, cpcache);
float pos[3];
CopyArray(cpcache[fCPPosition], pos, 3);
if(IsNullVector(pos))
{
return;
}
@ -1689,7 +1740,7 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
bool bDucking = (GetClientButtons(client) & IN_DUCK) > 0;
if(gA_PlayerCheckPointsCache[client][index][bCPDucking] != bDucking)
if(cpcache[bCPDucking] != bDucking)
{
Shavit_PrintToChat(client, "%T", (bDucking)? "MiscCheckpointsCrouchOff":"MiscCheckpointsCrouchOn", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
@ -1704,17 +1755,38 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage)
}
Shavit_SetPracticeMode(client, true, !bInStart);
Shavit_LoadSnapshot(client, gA_CheckpointsSnapshots[client][index]);
TeleportEntity(client, gF_Checkpoints[client][index][0],
((gI_CheckpointsSettings[client] & CP_ANGLES) > 0)? gF_Checkpoints[client][index][1]:NULL_VECTOR,
((gI_CheckpointsSettings[client] & CP_VELOCITY) > 0)? gF_Checkpoints[client][index][2]:NULL_VECTOR);
any snapshot[TIMERSNAPSHOT_SIZE];
CopyArray(cpcache[aCPSnapshot], snapshot, TIMERSNAPSHOT_SIZE);
Shavit_LoadSnapshot(client, snapshot);
SetEntityMoveType(client, view_as<MoveType>(gA_PlayerCheckPointsCache[client][index][iCPMoveType]));
SetEntityGravity(client, view_as<float>(gA_PlayerCheckPointsCache[client][index][fCPGravity]));
SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", view_as<float>(gA_PlayerCheckPointsCache[client][index][fCPSpeed]));
SetEntPropFloat(client, Prop_Send, "m_flStamina", view_as<float>(gA_PlayerCheckPointsCache[client][index][fCPStamina]));
DispatchKeyValue(client, "targetname", gS_CheckpointsTargetname[client][index]);
float ang[3];
CopyArray(cpcache[fCPAngles], ang, 3);
float vel[3];
CopyArray(cpcache[fCPVelocity], vel, 3);
TeleportEntity(client, pos,
((gI_CheckpointsSettings[client] & CP_ANGLES) > 0)? ang:NULL_VECTOR,
((gI_CheckpointsSettings[client] & CP_VELOCITY) > 0)? vel:NULL_VECTOR);
MoveType mt = cpcache[mtCPMoveType];
if(mt == MOVETYPE_LADDER || mt == MOVETYPE_WALK)
{
SetEntityMoveType(client, mt);
}
SetEntityGravity(client, cpcache[fCPGravity]);
SetEntityFlags(client, cpcache[iCPFlags]);
SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", cpcache[fCPSpeed]);
DispatchKeyValue(client, "targetname", cpcache[sCPTargetname]);
if(gEV_Type != Engine_TF2)
{
SetEntPropFloat(client, Prop_Send, "m_flStamina", cpcache[fCPStamina]);
}
if(!suppressMessage)
{
@ -1836,7 +1908,7 @@ public Action Command_Specs(int client, int args)
iObserverTarget = iNewTarget;
}
int iCount;
int iCount = 0;
char[] sSpecs = new char[192];
for(int i = 1; i <= MaxClients; i++)
@ -1969,21 +2041,6 @@ public void Shavit_OnRestart(int client, int track)
}
}
DataPack pack = null;
CreateDataTimer(0.1, Respawn, pack, TIMER_FLAG_NO_MAPCHANGE);
pack.WriteCell(GetClientSerial(client));
pack.WriteCell(track);
}
}
public Action Respawn(Handle Timer, DataPack pack)
{
pack.Reset();
int client = GetClientFromSerial(pack.ReadCell());
int track = pack.ReadCell();
if(IsValidClient(client) && !IsPlayerAlive(client) && GetClientTeam(client) >= 2)
{
if(gEV_Type == Engine_TF2)
{
TF2_RespawnPlayer(client);
@ -1999,13 +2056,36 @@ public Action Respawn(Handle Timer, DataPack pack)
RestartTimer(client, track);
}
}
}
public Action Respawn(Handle Timer, any data)
{
int client = GetClientFromSerial(data);
if(IsValidClient(client) && !IsPlayerAlive(client) && GetClientTeam(client) >= 2)
{
if(gEV_Type == Engine_TF2)
{
TF2_RespawnPlayer(client);
}
else
{
CS_RespawnPlayer(client);
}
if(gB_RespawnOnRestart)
{
RestartTimer(client, Track_Main);
}
}
return Plugin_Handled;
}
void RestartTimer(int client, int track)
{
if(Shavit_ZoneExists(Zone_Start, track))
if((gB_Zones && Shavit_ZoneExists(Zone_Start, track)) || Shavit_IsKZMap())
{
Shavit_RestartTimer(client, track);
}
@ -2092,6 +2172,14 @@ void RestoreState(any data)
return;
}
if(gA_SaveStates[client][bsStyle] != Shavit_GetBhopStyle(client) ||
gA_SaveStates[client][iTimerTrack] != Shavit_GetClientTrack(client))
{
gB_SaveStates[client] = false;
return;
}
LoadState(client);
}
@ -2209,7 +2297,7 @@ public Action Shotgun_Shot(const char[] te_name, const int[] Players, int numCli
TE_WriteFloat("m_vecAngles[0]", TE_ReadFloat("m_vecAngles[0]"));
TE_WriteFloat("m_vecAngles[1]", TE_ReadFloat("m_vecAngles[1]"));
if(gEV_Type == Engine_CSS)
if(IsSource2013(gEV_Type))
{
TE_WriteNum("m_iWeaponID", TE_ReadNum("m_iWeaponID"));
}
@ -2371,17 +2459,12 @@ void LoadState(int client)
Shavit_LoadSnapshot(client, gA_SaveStates[client]);
if(gA_SaveFrames[client] != null)
{
if(gB_Replay)
if(gB_Replay && gA_SaveFrames[client] != null)
{
Shavit_SetReplayData(client, gA_SaveFrames[client]);
}
delete gA_SaveFrames[client];
gA_SaveFrames[client] = null;
}
gB_SaveStates[client] = false;
}
@ -2407,6 +2490,22 @@ void SaveState(int client)
gB_SaveStates[client] = true;
}
bool GetCheckpoint(int client, int index, CheckpointsCache cpcache[PCPCACHE_SIZE])
{
char[] sKey = new char[32];
FormatEx(sKey, 32, "%d_%d", GetClientSerial(client), index);
return gSM_Checkpoints.GetArray(sKey, cpcache[0], view_as<int>(PCPCACHE_SIZE));
}
bool SetCheckpoint(int client, int index, CheckpointsCache cpcache[PCPCACHE_SIZE])
{
char[] sKey = new char[32];
FormatEx(sKey, 32, "%d_%d", GetClientSerial(client), index);
return gSM_Checkpoints.SetArray(sKey, cpcache[0], view_as<int>(PCPCACHE_SIZE));
}
void UpdateFootsteps(int client)
{
if(sv_footsteps != null)
@ -2417,9 +2516,10 @@ void UpdateFootsteps(int client)
}
}
#if SOURCEMOD_V_MAJOR == 1 && SOURCEMOD_V_MINOR < 9
bool IsNullVector(float vec[3])
void CopyArray(const any[] from, any[] to, int size)
{
return (vec[0] == NULL_VECTOR[0] && vec[1] == NULL_VECTOR[1] && vec[2] == NULL_VECTOR[2]);
for(int i = 0; i < size; i++)
{
to[i] = from[i];
}
}
#endif

View File

@ -19,8 +19,8 @@
*/
// Design idea:
// Rank 1 per map/style/track gets ((points per tier * tier) * 1.5) + ((amount of records * (tier / 10.0) * 0.25)) + (rank 1 time in seconds / 15.0) points.
// Records below rank 1 get points% relative to their time in comparison to rank 1 and a final multiplier of 0.85% to promote rank 1 hunting.
// Rank 1 per map/style/track gets ((points per tier * tier) * 1.5) + (rank 1 time in seconds / 15.0) points.
// Records below rank 1 get points% relative to their time in comparison to rank 1.
//
// Bonus track gets a 0.25* final mutliplier for points and is treated as tier 1.
//
@ -68,7 +68,6 @@ float gF_PointsPerTier = 50.0;
int gI_Rank[MAXPLAYERS+1];
float gF_Points[MAXPLAYERS+1];
int gI_Progress[MAXPLAYERS+1];
int gI_RankedPlayers = 0;
Menu gH_Top100Menu = null;
@ -82,7 +81,6 @@ char gS_TrackNames[TRACKS_SIZE][32];
any gA_StyleSettings[STYLE_LIMIT][STYLESETTINGS_SIZE];
int gI_Styles = 0;
int gI_RankedStyles = 0;
public Plugin myinfo =
{
@ -179,17 +177,10 @@ public void Shavit_OnStyleConfigLoaded(int styles)
gI_Styles = Shavit_GetStyleCount();
}
gI_RankedStyles = 0;
for(int i = 0; i < gI_Styles; i++)
{
Shavit_GetStyleSettings(i, gA_StyleSettings[i]);
Shavit_GetStyleStrings(i, sStyleName, gS_StyleNames[i], 64);
if(!gA_StyleSettings[i][bUnranked])
{
gI_RankedStyles++;
}
}
}
@ -305,9 +296,11 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
SQL_FastQuery(gH_SQL, "DELIMITER ;;");
SQL_FastQuery(gH_SQL, "DROP PROCEDURE IF EXISTS UpdateAllPoints;;"); // old (and very slow) deprecated method
SQL_FastQuery(gH_SQL, "DROP FUNCTION IF EXISTS GetWeightedPoints;;"); // this is here, just in case we ever choose to modify or optimize the calculation
SQL_FastQuery(gH_SQL, "DROP FUNCTION IF EXISTS GetRecordPoints;;");
char[] sQuery = new char[1024];
FormatEx(sQuery, 1024,
bool bSuccess = true;
RunLongFastQuery(bSuccess, "CREATE GetWeightedPoints",
"CREATE FUNCTION GetWeightedPoints(authid CHAR(32)) " ...
"RETURNS FLOAT " ...
"BEGIN " ...
@ -330,20 +323,21 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
"RETURN total; " ...
"END;;", gS_MySQLPrefix);
#if defined DEBUG
LogError("%s", sQuery);
#endif
bool bSuccess = true;
if(!SQL_FastQuery(gH_SQL, sQuery))
{
char[] sError = new char[255];
SQL_GetError(gH_SQL, sError, 255);
LogError("Timer (rankings, create GetWeightedPoints function) error! Reason: %s", sError);
bSuccess = false;
}
RunLongFastQuery(bSuccess, "CREATE GetRecordPoints",
"CREATE FUNCTION GetRecordPoints(rstyle INT, rtrack INT, rtime FLOAT, rmap CHAR(128), pointspertier FLOAT, stylemultiplier FLOAT) " ...
"RETURNS FLOAT " ...
"BEGIN " ...
"DECLARE pwr, ppoints FLOAT DEFAULT 0.0; " ...
"DECLARE ptier INT DEFAULT 1; " ...
"SELECT tier FROM %smaptiers WHERE map = rmap INTO ptier; " ...
"SELECT MIN(time) FROM %splayertimes WHERE map = rmap AND style = rstyle AND track = rtrack INTO pwr; " ...
"IF rtrack > 0 THEN SET ptier = 1; END IF; " ...
"SET ppoints = ((pointspertier * ptier) * 1.5) + (pwr / 15.0); " ...
"IF rtime > pwr THEN SET ppoints = ppoints * (pwr / rtime); END IF; " ...
"SET ppoints = ppoints * stylemultiplier; " ...
"IF rtrack > 0 THEN SET ppoints = ppoints * 0.25; END IF; " ...
"RETURN ppoints; " ...
"END;;", gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix);
SQL_FastQuery(gH_SQL, "DELIMITER ;");
SQL_UnlockDatabase(gH_SQL);
@ -364,6 +358,21 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
}
}
void RunLongFastQuery(bool &success, const char[] func, const char[] query, any ...)
{
char[] sQuery = new char[2048];
VFormat(sQuery, 2048, query, 4);
if(!SQL_FastQuery(gH_SQL, sQuery))
{
char[] sError = new char[255];
SQL_GetError(gH_SQL, sError, 255);
LogError("Timer (rankings, %s) error! Reason: %s", func, sError);
success = false;
}
}
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
gF_PointsPerTier = gCV_PointsPerTier.FloatValue;
@ -437,7 +446,7 @@ public void SQL_GetMapTier_Callback(Database db, DBResultSet results, const char
PrintToServer("DEBUG: 3 (tier: %d) (SQL_GetMapTier_Callback)", gI_Tier);
#endif
RecalculateAll(gS_Map, gI_Tier);
RecalculateAll(gS_Map);
UpdateAllPoints();
#if defined DEBUG
@ -515,7 +524,7 @@ void GuessBestMapName(const char[] input, char[] output, int size)
public void OnMapEnd()
{
RecalculateAll(gS_Map, gI_Tier);
RecalculateAll(gS_Map);
}
public Action Command_Tier(int client, int args)
@ -624,7 +633,7 @@ public Action Command_SetTier(int client, int args)
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "REPLACE INTO %smaptiers (map, tier) VALUES ('%s', %d);", gS_MySQLPrefix, gS_Map, tier);
gH_SQL.Query(SQL_SetMapTier_Callback, sQuery, tier, DBPrio_Low);
gH_SQL.Query(SQL_SetMapTier_Callback, sQuery);
return Plugin_Handled;
}
@ -638,12 +647,12 @@ public void SQL_SetMapTier_Callback(Database db, DBResultSet results, const char
return;
}
RecalculateAll(gS_Map, data);
RecalculateAll(gS_Map);
}
public Action Command_RecalcMap(int client, int args)
{
RecalculateAll(gS_Map, gI_Tier);
RecalculateAll(gS_Map);
UpdateAllPoints();
ReplyToCommand(client, "Done.");
@ -653,33 +662,63 @@ public Action Command_RecalcMap(int client, int args)
public Action Command_RecalcAll(int client, int args)
{
ReplyToCommand(client, "Check your console for information.\nDatabase related queries might not work until this is done.");
ReplyToCommand(client, "- [0.0%%] Started recalculating points for all maps.");
ReplyToCommand(client, "- Started recalculating points for all maps. Check console for output.");
gI_Progress[client] = 0;
Transaction trans = new Transaction();
int serial = (client == 0)? 0:GetClientSerial(client);
int size = gA_ValidMaps.Length;
for(int i = 0; i < size; i++)
for(int i = 0; i < gI_Styles; i++)
{
char[] sMap = new char[160];
gA_ValidMaps.GetString(i, sMap, 160);
char[] sQuery = new char[192];
int tier = 1;
gA_MapTiers.GetValue(sMap, tier);
RecalculateAll(sMap, tier, serial, true);
#if defined DEBUG
PrintToConsole(client, "size: %d | %d | %s", size, i, sMap);
#endif
if(gA_StyleSettings[i][bUnranked] || view_as<float>(gA_StyleSettings[i][fRankingMultiplier]) == 0.0)
{
FormatEx(sQuery, 192, "UPDATE %splayertimes SET points = 0 WHERE style = %d;", gS_MySQLPrefix, i);
}
else
{
FormatEx(sQuery, 192, "UPDATE %splayertimes SET points = GetRecordPoints(%d, track, time, map, %.1f, %.3f) WHERE style = %d;", gS_MySQLPrefix, i, gF_PointsPerTier, view_as<float>(gA_StyleSettings[i][fRankingMultiplier]), i);
}
trans.AddQuery(sQuery);
}
gH_SQL.Execute(trans, Trans_OnRecalcSuccess, Trans_OnRecalcFail, (client == 0)? 0:GetClientSerial(client));
return Plugin_Handled;
}
void RecalculateAll(const char[] map, const int tier, int serial = 0, bool print = false)
public void Trans_OnRecalcSuccess(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData)
{
int client = (data == 0)? 0:GetClientFromSerial(data);
if(client != 0)
{
SetCmdReplySource(SM_REPLY_TO_CONSOLE);
}
ReplyToCommand(client, "- Finished recalculating all points. Recalculating user points, top 100 and user cache.");
UpdateAllPoints();
UpdateTop100();
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i) && IsClientAuthorized(i))
{
UpdatePlayerRank(i);
}
}
ReplyToCommand(client, "- Done.");
}
public void Trans_OnRecalcFail(Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData)
{
LogError("Timer (rankings) error! Recalculation failed. Reason: %s", error);
}
void RecalculateAll(const char[] map)
{
#if defined DEBUG
LogError("DEBUG: 5 (RecalculateAll)");
@ -694,55 +733,26 @@ void RecalculateAll(const char[] map, const int tier, int serial = 0, bool print
continue;
}
RecalculateMap(map, i, j, tier, serial, print);
RecalculateMap(map, i, j);
}
}
}
public void Shavit_OnFinish_Post(int client, int style, float time, int jumps, int strafes, float sync, int rank, int overwrite, int track)
{
RecalculateMap(gS_Map, track, style, gI_Tier);
RecalculateMap(gS_Map, track, style);
}
void RecalculateMap(const char[] map, const int track, const int style, const int tier, int serial = -1, bool print = false)
void RecalculateMap(const char[] map, const int track, const int style)
{
#if defined DEBUG
PrintToServer("Recalculating points. (%s, %d, %d, %d)", map, track, style, tier);
PrintToServer("Recalculating points. (%s, %d, %d)", map, track, style);
#endif
char[] sQuery = new char[2048];
FormatEx(sQuery, 2048, "UPDATE %splayertimes t LEFT JOIN " ...
"(SELECT MIN(time) mintime, MAP, track, style FROM %splayertimes GROUP BY MAP, track, style) minjoin " ...
"ON t.time = minjoin.mintime AND t.MAP = minjoin.MAP AND t.track = minjoin.track AND t.style = minjoin.style " ...
"JOIN (SELECT ((%.01f * %d) * 1.5) points) best " ...
"JOIN (SELECT (COUNT(*) * (%d / 10.0)) points, MAP, track, style FROM %splayertimes GROUP BY MAP, track, style) additive " ...
"ON t.MAP = additive.MAP AND t.track = additive.track AND t.style = additive.style " ...
"JOIN (SELECT MIN(time) lowest, (MIN(time) / 15.0) points, MAP, track, style FROM %splayertimes GROUP BY MAP, track, style) FINAL " ...
"ON t.MAP = FINAL.MAP AND t.track = FINAL.track AND t.style = FINAL.style JOIN (SELECT (%.03f) style, (%.03f) track) multipliers " ...
char[] sQuery = new char[192];
FormatEx(sQuery, 192, "UPDATE %splayertimes SET points = GetRecordPoints(%d, %d, time, '%s', %.1f, %.3f) WHERE style = %d AND track = %d AND map = '%s';", gS_MySQLPrefix, style, track, map, gF_PointsPerTier, gA_StyleSettings[style][fRankingMultiplier], style, track, map);
"SET t.points = (CASE " ...
"WHEN minjoin.mintime IS NOT NULL THEN (((best.points + additive.points + FINAL.points) * multipliers.style) * multipliers.track) " ...
"ELSE (((((best.points + additive.points + FINAL.points) * multipliers.style) * multipliers.track) * (FINAL.lowest / t.time)) * 0.85) " ...
"END) " ...
"WHERE t.MAP = '%s' " ...
"AND t.track = %d " ...
"AND t.style = %d;",
gS_MySQLPrefix, gS_MySQLPrefix,
gF_PointsPerTier, (track == Track_Main)? tier:1, (track == Track_Main)? tier:1,
gS_MySQLPrefix, gS_MySQLPrefix,
gA_StyleSettings[style][fRankingMultiplier], (track == Track_Main)? 1.0:0.25,
map, track, style);
DataPack pack = new DataPack();
pack.WriteCell(serial);
pack.WriteCell(strlen(map));
pack.WriteString(map);
pack.WriteCell(track);
pack.WriteCell(style);
pack.WriteCell(print);
gH_SQL.Query(SQL_Recalculate_Callback, sQuery, pack, DBPrio_High);
gH_SQL.Query(SQL_Recalculate_Callback, sQuery, 0, DBPrio_High);
#if defined DEBUG
PrintToServer("Sent query.");
@ -751,18 +761,6 @@ void RecalculateMap(const char[] map, const int track, const int style, const in
public void SQL_Recalculate_Callback(Database db, DBResultSet results, const char[] error, DataPack data)
{
data.Reset();
int serial = data.ReadCell();
int size = data.ReadCell();
char[] sMap = new char[size + 1];
ReadPackString(data, sMap, size + 1);
int track = data.ReadCell();
int style = data.ReadCell();
bool print = view_as<bool>(data.ReadCell());
delete data;
if(results == null)
{
LogError("Timer (rankings, recalculate map points) error! Reason: %s", error);
@ -770,21 +768,6 @@ public void SQL_Recalculate_Callback(Database db, DBResultSet results, const cha
return;
}
if(print && serial != -1)
{
int client = (serial == 0)? 0:GetClientFromSerial(serial);
if(serial != 0 && client == 0)
{
return;
}
int max = ((gA_ValidMaps.Length * TRACKS_SIZE) * gI_RankedStyles);
float current = ((float(++gI_Progress[client]) / max) * 100.0);
PrintToConsole(client, "- [%.01f%%] Recalculated \"%s\" (%s | %s).", current, sMap, gS_TrackNames[track], gS_StyleNames[style]);
}
#if defined DEBUG
PrintToServer("Recalculated.");
#endif

View File

@ -31,8 +31,8 @@
#define REPLAY_FORMAT_V2 "{SHAVITREPLAYFORMAT}{V2}"
#define REPLAY_FORMAT_FINAL "{SHAVITREPLAYFORMAT}{FINAL}"
#define REPLAY_FORMAT_SUBVERSION 0x01 // for compatibility, if i ever update this code again
#define CELLS_PER_FRAME 6 // origin[3], angles[2], buttons
#define REPLAY_FORMAT_SUBVERSION 0x02
#define CELLS_PER_FRAME 8 // origin[3], angles[2], buttons, flags, movetype
// #define DEBUG
@ -64,12 +64,14 @@ enum
EngineVersion gEV_Type = Engine_Unknown;
// cache
char gS_ReplayFolder[PLATFORM_MAX_PATH];
int gI_ReplayTick[STYLE_LIMIT];
int gI_ReplayBotClient[STYLE_LIMIT];
ArrayList gA_Frames[STYLE_LIMIT][TRACKS_SIZE];
float gF_StartTick[STYLE_LIMIT];
ReplayStatus gRS_ReplayStatus[STYLE_LIMIT];
any gA_FrameCache[STYLE_LIMIT][TRACKS_SIZE][3]; // int frame_count, float time, bool new_format
any gA_FrameCache[STYLE_LIMIT][TRACKS_SIZE][4]; // int frame_count, float time, bool new_format, int replay_version
char gS_ReplayNames[STYLE_LIMIT][TRACKS_SIZE][MAX_NAME_LENGTH];
bool gB_ForciblyStopped = false;
@ -138,6 +140,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
CreateNative("Shavit_GetReplayBotIndex", Native_GetReplayBotIndex);
CreateNative("Shavit_GetReplayBotStyle", Native_GetReplayBotStyle);
CreateNative("Shavit_GetReplayBotTrack", Native_GetReplayBotTrack);
CreateNative("Shavit_GetReplayBotType", Native_GetReplayBotType);
CreateNative("Shavit_GetReplayData", Native_GetReplayData);
CreateNative("Shavit_GetReplayFrameCount", Native_GetReplayFrameCount);
CreateNative("Shavit_GetReplayLength", Native_GetReplayLength);
@ -247,6 +250,11 @@ public int Native_GetReplayBotCurrentFrame(Handle handler, int numParams)
public int Native_GetReplayBotIndex(Handle handler, int numParams)
{
if(gB_CentralBot)
{
return gA_CentralCache[iCentralClient];
}
return gI_ReplayBotClient[GetNativeCell(1)];
}
@ -419,6 +427,11 @@ public int Native_GetReplayBotTrack(Handle handler, int numParams)
return GetReplayTrack(GetNativeCell(1));
}
public int Native_GetReplayBotType(Handle handler, int numParams)
{
return view_as<int>((gB_CentralBot)? Replay_Central:Replay_Legacy);
}
public void Shavit_OnDatabaseLoaded()
{
gH_SQL = Shavit_GetDatabase();
@ -557,8 +570,19 @@ bool LoadStyling()
kv.GetString("centralstyletag", gS_ReplayStrings[sReplayCentralStyleTag], MAX_NAME_LENGTH, "<EMPTY CENTRALSTYLETAG>");
kv.GetString("unloaded", gS_ReplayStrings[sReplayUnloaded], MAX_NAME_LENGTH, "<EMPTY UNLOADED>");
char[] sFolder = new char[PLATFORM_MAX_PATH];
kv.GetString("replayfolder", sFolder, PLATFORM_MAX_PATH, "{SM}/data/replaybot");
delete kv;
if(StrContains(sFolder, "{SM}") != -1)
{
ReplaceString(sFolder, PLATFORM_MAX_PATH, "{SM}/", "");
BuildPath(Path_SM, sFolder, PLATFORM_MAX_PATH, "%s", sFolder);
}
strcopy(gS_ReplayFolder, PLATFORM_MAX_PATH, sFolder);
return true;
}
@ -678,12 +702,9 @@ public void OnMapStart()
gI_ExpectedBots = 0;
char[] sPath = new char[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "data/replaybot");
if(!DirExists(sPath))
if(!DirExists(gS_ReplayFolder))
{
CreateDirectory(sPath, 511);
CreateDirectory(gS_ReplayFolder, 511);
}
for(int i = 0; i < gI_Styles; i++)
@ -697,7 +718,8 @@ public void OnMapStart()
continue;
}
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "data/replaybot/%d", i);
char[] sPath = new char[PLATFORM_MAX_PATH];
FormatEx(sPath, PLATFORM_MAX_PATH, "%s/%d", gS_ReplayFolder, i);
if(!DirExists(sPath))
{
@ -772,7 +794,7 @@ bool DefaultLoadReplay(int style, int track)
FormatEx(sTrack, 4, "_%d", track);
char[] sPath = new char[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "data/replaybot/%d/%s%s.replay", style, gS_Map, (track > 0)? sTrack:"");
FormatEx(sPath, PLATFORM_MAX_PATH, "%s/%d/%s%s.replay", gS_ReplayFolder, style, gS_Map, (track > 0)? sTrack:"");
return LoadReplay(style, track, sPath);
}
@ -796,8 +818,7 @@ bool LoadReplay(int style, int track, const char[] path)
if(StrEqual(sExplodedHeader[1], REPLAY_FORMAT_FINAL)) // hopefully, the last of them
{
// uncomment if ever needed
// int iSubVersion = StringToInt(sExplodedHeader[0]);
gA_FrameCache[style][track][3] = StringToInt(sExplodedHeader[0]);
int iTemp = 0;
fFile.ReadInt32(iTemp);
@ -828,11 +849,19 @@ bool LoadReplay(int style, int track, const char[] path)
gH_SQL.Query(SQL_GetUserName_Callback, sQuery, pack, DBPrio_High);
}
any[] aReplayData = new any[CELLS_PER_FRAME];
int cells = 8;
// backwards compatibility
if(gA_FrameCache[style][track][3] == 0x01)
{
cells = 6;
}
any[] aReplayData = new any[cells];
for(int i = 0; i < gA_FrameCache[style][track][0]; i++)
{
if(fFile.Read(aReplayData, CELLS_PER_FRAME, 4) >= 0)
if(fFile.Read(aReplayData, cells, 4) >= 0)
{
gA_Frames[style][track].Set(i, view_as<float>(aReplayData[0]), 0);
gA_Frames[style][track].Set(i, view_as<float>(aReplayData[1]), 1);
@ -840,6 +869,12 @@ bool LoadReplay(int style, int track, const char[] path)
gA_Frames[style][track].Set(i, view_as<float>(aReplayData[3]), 3);
gA_Frames[style][track].Set(i, view_as<float>(aReplayData[4]), 4);
gA_Frames[style][track].Set(i, view_as<int>(aReplayData[5]), 5);
if(gA_FrameCache[style][track][3] >= 0x02)
{
gA_Frames[style][track].Set(i, view_as<int>(aReplayData[6]), 6);
gA_Frames[style][track].Set(i, view_as<int>(aReplayData[7]), 7);
}
}
}
@ -911,7 +946,7 @@ bool SaveReplay(int style, int track, float time, char[] authid, char[] name)
FormatEx(sTrack, 4, "_%d", track);
char[] sPath = new char[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "data/replaybot/%d/%s%s.replay", style, gS_Map, (track > 0)? sTrack:"");
FormatEx(sPath, PLATFORM_MAX_PATH, "%s/%d/%s%s.replay", gS_ReplayFolder, style, gS_Map, (track > 0)? sTrack:"");
if(FileExists(sPath))
{
@ -953,7 +988,7 @@ bool DeleteReplay(int style, int track)
FormatEx(sTrack, 4, "_%d", track);
char[] sPath = new char[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "data/replaybot/%d/%s%s.replay", style, gS_Map, (track > 0)? sTrack:"");
FormatEx(sPath, PLATFORM_MAX_PATH, "%s/%d/%s%s.replay", gS_ReplayFolder, style, gS_Map, (track > 0)? sTrack:"");
if(!FileExists(sPath) || !DeleteFile(sPath))
{
@ -1324,6 +1359,19 @@ public void Shavit_OnResume(int client)
gB_Record[client] = true;
}
void ModifyFlags(int &flags, int flag, bool add)
{
if(add)
{
flags |= flag;
}
else
{
flags &= flag;
}
}
// OnPlayerRunCmd instead of Shavit_OnUserCmdPre because bots are also used here.
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3])
{
@ -1430,6 +1478,30 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
buttons = gA_Frames[style][track].Get(gI_ReplayTick[style], 5);
MoveType mt = MOVETYPE_NOCLIP;
if(gA_FrameCache[style][track][3] >= 0x02)
{
int iReplayFlags = gA_Frames[style][track].Get(gI_ReplayTick[style], 6);
int iEntityFlags = GetEntityFlags(client);
ModifyFlags(iEntityFlags, FL_ONGROUND, (iReplayFlags & FL_ONGROUND) > 0);
ModifyFlags(iEntityFlags, FL_PARTIALGROUND, (iReplayFlags & FL_PARTIALGROUND) > 0);
ModifyFlags(iEntityFlags, FL_INWATER, (iReplayFlags & FL_INWATER) > 0);
ModifyFlags(iEntityFlags, FL_SWIM, (iReplayFlags & FL_SWIM) > 0);
SetEntityFlags(client, iEntityFlags);
MoveType movetype = gA_Frames[style][track].Get(gI_ReplayTick[style], 7);
if(movetype == MOVETYPE_WALK || movetype == MOVETYPE_LADDER)
{
mt = movetype;
}
}
SetEntityMoveType(client, mt);
float vecVelocity[3];
MakeVectorFromPoints(vecCurrentPosition, vecPosition, vecVelocity);
ScaleVector(vecVelocity, gF_Tickrate);
@ -1473,6 +1545,8 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], angles[1], 4);
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], buttons, 5);
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], GetEntityFlags(client), 6);
gA_PlayerFrames[client].Set(gI_PlayerFrames[client], GetEntityMoveType(client), 7);
gI_PlayerFrames[client]++;
}

View File

@ -84,7 +84,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
{
// natives
CreateNative("Shavit_OpenStatsMenu", Native_OpenStatsMenu);
CreateNative("Shavit_GetWRCount", Native_GetWRConut);
CreateNative("Shavit_GetWRCount", Native_GetWRCount);
RegPluginLibrary("shavit-stats");
@ -843,7 +843,7 @@ public int Native_OpenStatsMenu(Handle handler, int numParams)
OpenStatsMenu(client, gS_TargetAuth[client]);
}
public int Native_GetWRConut(Handle handler, int numParams)
public int Native_GetWRCount(Handle handler, int numParams)
{
return gI_WRAmount[GetNativeCell(1)];
}

View File

@ -1449,7 +1449,7 @@ public void SQL_WR_Callback(Database db, DBResultSet results, const char[] error
else
{
FormatEx(sRanks, 32, "(#%d/%d)", iMyRank, gI_RecordAmount[gBS_LastWR[client]]);
FormatEx(sRanks, 32, "(#%d/%d)", iMyRank, iRecords);
}
char[] sTrack = new char[32];
@ -1880,12 +1880,12 @@ void SQL_DBConnect()
if(gB_MySQL)
{
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `auth` CHAR(32), `map` CHAR(128), `time` FLOAT, `jumps` INT, `style` INT, `date` CHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` INT NOT NULL DEFAULT 0, PRIMARY KEY (`id`), INDEX `auth` (`auth`, `map`, `time`, `style`, `date`, `points`, `track`)) ENGINE=INNODB;", gS_MySQLPrefix);
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `auth` CHAR(32), `map` CHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` CHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`)) ENGINE=INNODB;", gS_MySQLPrefix);
}
else
{
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `auth` CHAR(32), `map` CHAR(128), `time` FLOAT, `jumps` INT, `style` INT, `date` CHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` INT NOT NULL DEFAULT 0);", gS_MySQLPrefix);
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `auth` CHAR(32), `map` CHAR(128), `time` FLOAT, `jumps` INT, `style` TINYINT, `date` CHAR(16), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0);", gS_MySQLPrefix);
}
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);

View File

@ -88,7 +88,7 @@ float gV_WallSnap[MAXPLAYERS+1][3];
bool gB_Button[MAXPLAYERS+1];
bool gB_InsideZone[MAXPLAYERS+1][ZONETYPES_SIZE][TRACKS_SIZE];
bool gB_InsideZoneID[MAXPLAYERS+1][MAX_ZONES];
float gF_CustomSpawn[TRACKS_SIZE][3];
float gF_CustomSpawns[TRACKS_SIZE][2][3];
int gI_ZoneTrack[MAXPLAYERS+1];
int gI_ZoneDatabaseID[MAXPLAYERS+1];
@ -667,8 +667,6 @@ public void Frame_HookTrigger(any data)
gI_KZButtons[track][zone] = entity;
Shavit_MarkKZMap();
if(zone == Zone_Start)
{
float maxs[3];
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", maxs);
@ -677,8 +675,7 @@ public void Frame_HookTrigger(any data)
origin[2] -= (maxs[2] - 2.0); // so you don't get stuck in the ground
gF_CustomSpawn[track] = origin;
}
gF_CustomSpawns[track][zone] = origin;
for(int i = 1; i <= MaxClients; i++)
{
@ -739,6 +736,14 @@ void KillZoneEntity(int index)
gB_InsideZoneID[i][index] = false;
}
char[] sTargetname = new char[32];
GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, 32);
if(StrContains(sTargetname, "shavit_zones_") == -1)
{
return;
}
UnhookEntity(entity);
AcceptEntityInput(entity, "Kill");
}
@ -772,21 +777,17 @@ void UnloadZones(int zone)
{
gB_ZonesCreated = false;
int iMaxEntities = GetMaxEntities();
char[] sClassname = new char[32];
char[] sTargetname = new char[32];
int iEntity = INVALID_ENT_REFERENCE;
for(int i = (MaxClients + 1); i < iMaxEntities; i++)
while((iEntity = FindEntityByClassname(iEntity, "trigger_multiple")) != INVALID_ENT_REFERENCE)
{
if(!IsValidEntity(i)
|| !GetEntityClassname(i, sClassname, 32) || !StrEqual(sClassname, "trigger_multiple")
|| GetEntPropString(i, Prop_Data, "m_iName", sTargetname, 32) == 0 || StrContains(sTargetname, "shavit_zones_") == -1)
GetEntPropString(iEntity, Prop_Data, "m_iName", sTargetname, 32);
if(StrContains(sTargetname, "shavit_zones_") != -1)
{
continue;
AcceptEntityInput(iEntity, "Kill");
}
AcceptEntityInput(i, "Kill");
}
}
@ -821,9 +822,9 @@ public void SQL_RefreshZones_Callback(Database db, DBResultSet results, const ch
{
int track = results.FetchInt(10);
gF_CustomSpawn[track][0] = results.FetchFloat(7);
gF_CustomSpawn[track][1] = results.FetchFloat(8);
gF_CustomSpawn[track][2] = results.FetchFloat(9);
gF_CustomSpawns[track][Zone_Start][0] = results.FetchFloat(7);
gF_CustomSpawns[track][Zone_Start][1] = results.FetchFloat(8);
gF_CustomSpawns[track][Zone_Start][2] = results.FetchFloat(9);
}
else
@ -933,7 +934,7 @@ public Action Command_AddSpawn(int client, int args)
return Plugin_Handled;
}
if(!EmptyVector(gF_CustomSpawn[Track_Main]))
if(!EmptyVector(gF_CustomSpawns[Track_Main][Zone_Start]))
{
Shavit_PrintToChat(client, "%T", "ZoneCustomSpawnExists", client);
@ -990,7 +991,8 @@ void ClearCustomSpawn()
{
for(int j = 0; j < 3; j++)
{
gF_CustomSpawn[i][j] = 0.0;
gF_CustomSpawns[i][Zone_Start][j] = 0.0;
gF_CustomSpawns[i][Zone_End][j] = 0.0;
}
}
}
@ -2077,7 +2079,7 @@ public Action Timer_Draw(Handle Timer, any data)
{
origin[2] -= gF_Height;
TE_SetupBeamPoints(vPlayerOrigin, origin, gI_BeamSprite, gI_HaloSprite, 0, 0, 0.1, 1.0, 1.0, 0, 0.0, {255, 255, 255, 230}, 0);
TE_SetupBeamPoints(vPlayerOrigin, origin, gI_BeamSprite, gI_HaloSprite, 0, 0, 0.1, 1.0, 1.0, 0, 0.0, {255, 255, 255, 75}, 0);
TE_SendToAll(0.0);
// visualize grid snap
@ -2092,7 +2094,7 @@ public Action Timer_Draw(Handle Timer, any data)
snap2 = origin;
snap2[i] += (gI_GridSnap[client] / 2);
TE_SetupBeamPoints(snap1, snap2, gI_BeamSprite, gI_HaloSprite, 0, 0, 0.1, 1.0, 1.0, 0, 0.0, {255, 255, 255, 230}, 0);
TE_SetupBeamPoints(snap1, snap2, gI_BeamSprite, gI_HaloSprite, 0, 0, 0.1, 1.0, 1.0, 0, 0.0, {255, 255, 255, 75}, 0);
TE_SendToAll(0.0);
}
}
@ -2143,9 +2145,21 @@ void DrawZone(float points[8][3], int color[4], float life, float width, bool fl
}
}
// by blacky
// original by blacky
// creates 3d box from 2 points
void CreateZonePoints(float point[8][3], float offset = 0.0)
{
// calculate all zone edges
for(int i = 1; i < 7; i++)
{
for(int j = 0; j < 3; j++)
{
point[i][j] = point[((i >> (2 - j)) & 1) * 7][j];
}
}
// apply beam offset
if(offset != 0.0)
{
float center[2];
center[0] = ((point[0][0] + point[7][0]) / 2);
@ -2153,21 +2167,14 @@ void CreateZonePoints(float point[8][3], float offset = 0.0)
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 3; j++)
{
if(i > 0 && i < 7)
{
point[i][j] = point[((i >> (2 - j)) & 1) * 7][j];
}
if(offset != 0.0 && j < 2)
for(int j = 0; j < 2; j++)
{
if(point[i][j] < center[j])
{
point[i][j] += offset;
}
else
else if(point[i][j] > center[j])
{
point[i][j] -= offset;
}
@ -2340,9 +2347,9 @@ public void Shavit_OnRestart(int client, int track)
{
if(gB_TeleportToStart)
{
if(!EmptyVector(gF_CustomSpawn[track]))
if(!EmptyVector(gF_CustomSpawns[track][Zone_Start]))
{
TeleportEntity(client, gF_CustomSpawn[track], NULL_VECTOR, view_as<float>({0.0, 0.0, 0.0}));
TeleportEntity(client, gF_CustomSpawns[track][Zone_Start], NULL_VECTOR, view_as<float>({0.0, 0.0, 0.0}));
}
else if(Shavit_IsKZMap() && !EmptyVector(gF_ClimbButtonCache[client][track][0]) && !EmptyVector(gF_ClimbButtonCache[client][track][1]))
@ -2377,6 +2384,13 @@ public void Shavit_OnEnd(int client, int track)
{
if(gB_TeleportToEnd)
{
if(!EmptyVector(gF_CustomSpawns[track][Zone_End]))
{
TeleportEntity(client, gF_CustomSpawns[track][Zone_End], NULL_VECTOR, view_as<float>({0.0, 0.0, 0.0}));
return;
}
int index = GetZoneIndex(Zone_End, track);
if(index == -1)

View File

@ -105,11 +105,6 @@
"#format" "{1:s},{2:s}"
"en" "Timer has been {1}paused{2}."
}
"PausePractice"
{
"#format" "{1:s},{2:s}"
"en" "You {1}are not{2} allowed to pause while in practice mode."
}
// ---------- Zones ---------- //
"StartZoneUndefined"
{