summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sourcemod-1.5-dev/scripting/ljstats.sp192
-rw-r--r--sourcemod-1.5-dev/scripting/stats.sp15
-rw-r--r--sourcemod/scripting/css-kztimer.sp957
-rw-r--r--sourcemod/scripting/game_manager.sp37
4 files changed, 1095 insertions, 106 deletions
diff --git a/sourcemod-1.5-dev/scripting/ljstats.sp b/sourcemod-1.5-dev/scripting/ljstats.sp
index f220d39..f755835 100644
--- a/sourcemod-1.5-dev/scripting/ljstats.sp
+++ b/sourcemod-1.5-dev/scripting/ljstats.sp
@@ -34,7 +34,7 @@
#define BJ_HEIGHT_DELTA_MAX 2.0
#define LAJ_HEIGHT_DELTA_MIN -6.0
#define LAJ_HEIGHT_DELTA_MAX 0.0
-#define JB_HEIGHT_DELTA_MIN -1.0
+#define JB_HEIGHT_DELTA_MIN -2.0
#define JB_HEIGHT_DELTA_MAX 1.5
#define HUD_HINT_SIZE 256
#define STRAFE_TRAINER_TICKS 9
@@ -538,7 +538,7 @@ public OnPluginStart()
#if defined LJSERV
RegConsoleCmd("sm_wr", Command_LJTop);
#endif
- RegConsoleCmd("sm_tpmenu", Command_CheckpointPanel);
+ //RegConsoleCmd("sm_tpmenu", Command_CheckpointPanel);
RegAdminCmd("sm_ljtopdelete", Command_LJTopDelete, ADMFLAG_RCON);
RegAdminCmd("sm_kz", Command_KZ, ADMFLAG_RCON);
@@ -2842,8 +2842,7 @@ PlayerJump(client, JUMP_TYPE:JumpType2 = JT_LONGJUMP)
GetEntPropVector(client, Prop_Data, "m_vecVelocity", vVel);
// ducking lowers u by 8.5 units
- if( GetEntProp(client, Prop_Send, "m_bDucking", 1) )
- vOrigin[2] -= 8.5;
+ vOrigin[2] -= 8.5;
}
Array_Copy(vOrigin, g_PlayerStates[client][vJumpOrigin], 3);
@@ -3010,34 +3009,6 @@ CheckValidJump(client)
PrintToChat(client, "teleported %f, %f (%f)", GetVectorDistance(vLastOrig, vOrigin), GetVectorLength(vVel) / (1.0 / GetTickInterval()) + 0.001, GetVectorLength(vLastVel) / (1.0 / GetTickInterval()));
#endif
- if(g_PlayerStates[client][bBlockMode])
- {
- if(g_PlayerStates[client][bFailedBlock])
- {
- #if defined DEBUG
- PrintToChat(client, "failedblock; returning");
- #endif
-
- return;
- }
- else
- {
- #if defined DEBUG
- PrintToChat(client, "failedblocklongjump 3 tp %s %f %f %d",
- g_PlayerStates[client][vLastOrigin][2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP) ? "saved" : "not saved",
- g_PlayerStates[client][vLastOrigin][2], g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP), GetGameTickCount());
- #endif
-
- if(g_PlayerStates[client][vLastOrigin][2] >= g_PlayerStates[client][vJumpOrigin][2] + HEIGHT_DELTA_MIN(JT_LONGJUMP))
- {
- GetJumpDistanceLastTick(client);
- g_PlayerStates[client][bFailedBlock] = true;
-
- return;
- }
- }
- }
-
g_PlayerStates[client][IllegalJumpFlags] |= IJF_TELEPORT;
}
}
@@ -3392,7 +3363,12 @@ _OnPlayerRunCmd(client, buttons, const Float:vOrigin[3], const Float:vAngles[3],
g_PlayerStates[client][nStrafeTicks][g_PlayerStates[client][nStrafes] - 1]++;
g_PlayerStates[client][fTotalAngle] += fAngleDelta;
-
+ new Float:delta = vAngles[1] - v2[1];
+ while(delta < -180.0)
+ delta += 360.0;
+ while(delta > 180.0)
+ delta -= 360.0;
+
new tick = g_PlayerStates[client][nTotalTicks];
if(fVelDelta > 0.0)
{
@@ -3402,11 +3378,7 @@ _OnPlayerRunCmd(client, buttons, const Float:vOrigin[3], const Float:vAngles[3],
g_PlayerStates[client][nStrafeTicksSynced][g_PlayerStates[client][nStrafes] - 1]++;
g_PlayerStates[client][fSyncedAngle] += fAngleDelta;
- new Float:delta = vAngles[1] - v2[1];
- while(delta < -180.0)
- delta += 360.0;
- while(delta > 180.0)
- delta -= 360.0;
+
if( tick < MAX_JUMP_TICKS )
g_PlayerStates[client][nMouseDir][tick] = delta > 0.0 ? -1 : 1;
@@ -3415,8 +3387,12 @@ _OnPlayerRunCmd(client, buttons, const Float:vOrigin[3], const Float:vAngles[3],
{
g_PlayerStates[client][fStrafeLoss][g_PlayerStates[client][nStrafes] - 1] -= fVelDelta;
g_PlayerStates[client][fLoss] -= fVelDelta;
- if( tick < MAX_JUMP_TICKS )
- g_PlayerStates[client][nMouseDir][tick] = 0;
+ if( tick < MAX_JUMP_TICKS ) {
+ if( FloatAbs( delta ) > 0.0 )
+ g_PlayerStates[client][nMouseDir][tick] = delta > 0.0 ? -2 : 2;
+ else
+ g_PlayerStates[client][nMouseDir][tick] = 0;
+ }
}
if( tick < MAX_JUMP_TICKS ) {
@@ -3545,6 +3521,14 @@ public PrintSyncStats(client) {
Append( strMouseLeft, sizeof( strMouseLeft ), " " );
Append( strMouseRight, sizeof( strMouseRight ), "|" );
}
+ else if( g_PlayerStates[client][nMouseDir][i] == -2 ) {
+ Append( strMouseLeft, sizeof( strMouseLeft ), "." );
+ Append( strMouseRight, sizeof( strMouseRight ), " " );
+ }
+ else if( g_PlayerStates[client][nMouseDir][i] == 2 ) {
+ Append( strMouseLeft, sizeof( strMouseLeft ), " " );
+ Append( strMouseRight, sizeof( strMouseRight ), "." );
+ }
else {
Append( strMouseLeft, sizeof( strMouseLeft ), " " );
Append( strMouseRight, sizeof( strMouseRight ), " " );
@@ -3577,68 +3561,77 @@ public PrintSyncStats(client) {
}
PrintToConsole( client, strFull );
+ if( !g_PlayerStates[client][bSyncStats] || g_PlayerStates[client][nTotalTicks] > 65 )
+ return;
- if( g_PlayerStates[client][bSyncStats] ) {
- Format( strLeft, sizeof( strLeft ), "[ " );
- Format( strRight, sizeof( strRight ), "[ " );
- Format( strMouseLeft, sizeof( strMouseLeft ), "[ " );
- Format( strMouseRight, sizeof( strMouseRight ), "[ " );
-
- new String:char1[] = "|";
- new String:char2[] = "_";
- new String:strFull2[1024];
+ Format( strLeft, sizeof( strLeft ), "[ " );
+ Format( strRight, sizeof( strRight ), "[ " );
+ Format( strMouseLeft, sizeof( strMouseLeft ), "[ " );
+ Format( strMouseRight, sizeof( strMouseRight ), "[ " );
- for( new i = 0; i < g_PlayerStates[client][nTotalTicks]; ++i ) {
- if( g_PlayerStates[client][nMouseDir][i] == -1 ) {
- Append( strMouseLeft, sizeof( strMouseLeft ), char1 );
- Append( strMouseRight, sizeof( strMouseRight ), char2 );
- }
- else if( g_PlayerStates[client][nMouseDir][i] == 1 ) {
- Append( strMouseLeft, sizeof( strMouseLeft ), char2 );
- Append( strMouseRight, sizeof( strMouseRight ), char1 );
- }
- else {
- Append( strMouseLeft, sizeof( strMouseLeft ), char2 );
- Append( strMouseRight, sizeof( strMouseRight ), char2 );
- }
+ new String:char1[] = "|";
+ new String:char2[] = "_";
+ new String:char3[] = " ,";
+ new String:strFull2[1024];
- if( g_PlayerStates[client][nMoveDir][i] == -1 ) {
- Append( strLeft, sizeof( strLeft ), char1 );
- Append( strRight, sizeof( strRight ), char2 );
- }
- else if( g_PlayerStates[client][nMoveDir][i] == 1 ) {
- Append( strLeft, sizeof( strLeft ), char2 );
- Append( strRight, sizeof( strRight ), char1 );
- }
- else {
- Append( strLeft, sizeof( strLeft ), char2 );
- Append( strRight, sizeof( strRight ), char2 );
- }
+ for( new i = 0; i < g_PlayerStates[client][nTotalTicks]; ++i ) {
+ if( g_PlayerStates[client][nMouseDir][i] == -1 ) {
+ Append( strMouseLeft, sizeof( strMouseLeft ), char1 );
+ Append( strMouseRight, sizeof( strMouseRight ), char2 );
+ }
+ else if( g_PlayerStates[client][nMouseDir][i] == 1 ) {
+ Append( strMouseLeft, sizeof( strMouseLeft ), char2 );
+ Append( strMouseRight, sizeof( strMouseRight ), char1 );
+ }
+ else if( g_PlayerStates[client][nMouseDir][i] == -2 ) {
+ Append( strMouseLeft, sizeof( strMouseLeft ), char3 );
+ Append( strMouseRight, sizeof( strMouseRight ), char2 );
+ }
+ else if( g_PlayerStates[client][nMouseDir][i] == 2 ) {
+ Append( strMouseLeft, sizeof( strMouseLeft ), char2 );
+ Append( strMouseRight, sizeof( strMouseRight ), char3 );
+ }
+ else {
+ Append( strMouseLeft, sizeof( strMouseLeft ), char2 );
+ Append( strMouseRight, sizeof( strMouseRight ), char2 );
}
- Format( strLeft, sizeof( strLeft ), "%s ]", strLeft );
- Format( strRight, sizeof( strRight ), "%s ]", strRight );
- Format( strMouseLeft, sizeof( strMouseLeft ), "%s ]", strMouseLeft );
- Format( strMouseRight, sizeof( strMouseRight ), "%s ]", strMouseRight );
-
- if( g_PlayerStates[client][JumpDir] == JD_SIDEWAYS ) {
- Format( strFull, sizeof( strFull ), "W: %s\nS: %s\n", strLeft, strRight );
+ if( g_PlayerStates[client][nMoveDir][i] == -1 ) {
+ Append( strLeft, sizeof( strLeft ), char1 );
+ Append( strRight, sizeof( strRight ), char2 );
+ }
+ else if( g_PlayerStates[client][nMoveDir][i] == 1 ) {
+ Append( strLeft, sizeof( strLeft ), char2 );
+ Append( strRight, sizeof( strRight ), char1 );
}
else {
- Format( strFull, sizeof( strFull ), "A: %s\nD: %s\n", strLeft, strRight );
+ Append( strLeft, sizeof( strLeft ), char2 );
+ Append( strRight, sizeof( strRight ), char2 );
}
+ }
+
+ Format( strLeft, sizeof( strLeft ), "%s ]", strLeft );
+ Format( strRight, sizeof( strRight ), "%s ]", strRight );
+ Format( strMouseLeft, sizeof( strMouseLeft ), "%s ]", strMouseLeft );
+ Format( strMouseRight, sizeof( strMouseRight ), "%s ]", strMouseRight );
- Format( strFull2, sizeof( strFull2 ), "L: %s\nR: %s", strMouseLeft, strMouseRight );
+ if( g_PlayerStates[client][JumpDir] == JD_SIDEWAYS ) {
+ Format( strFull, sizeof( strFull ), "W: %s\nS: %s\n", strLeft, strRight );
+ }
+ else {
+ Format( strFull, sizeof( strFull ), "A: %s\nD: %s\n", strLeft, strRight );
+ }
- new Handle:hText = CreateHudSynchronizer();
- if(hText != INVALID_HANDLE)
- {
- SetHudTextParams(-1.0, 0.06, 3.0, 255, 255, 255, 255, 0, 0.0, 0.15, 0.5);
- ShowHudText(client, 2, strFull);
- SetHudTextParams(-1.0, 0.14, 3.0, 180, 180, 255, 255, 0, 0.0, 0.15, 0.5);
- ShowHudText(client, 3, strFull2);
- CloseHandle(hText);
- }
+ Format( strFull2, sizeof( strFull2 ), "L: %s\nR: %s", strMouseLeft, strMouseRight );
+
+ new Handle:hText = CreateHudSynchronizer();
+ if(hText != INVALID_HANDLE)
+ {
+ SetHudTextParams(-1.0, 0.06, 3.0, 255, 255, 255, 255, 0, 0.0, 0.15, 0.5);
+ ShowHudText(client, 2, strFull);
+ SetHudTextParams(-1.0, 0.14, 3.0, 180, 180, 255, 255, 0, 0.0, 0.15, 0.5);
+ ShowHudText(client, 3, strFull2);
+ CloseHandle(hText);
}
}
@@ -3651,8 +3644,12 @@ PlayerLand(client)
if(!g_PlayerStates[client][bLJEnabled] && !g_PlayerStates[client][nSpectators] || !g_PlayerStates[client][bShowBhopStats] && g_PlayerStates[client][nBhops] > 1)
return;
- PrintSyncStats( client );
-
+ if( g_PlayerStates[client][IllegalJumpFlags] & IJF_TELEPORT )
+ return;
+
+ if( g_PlayerStates[client][IllegalJumpFlags] & IJF_NOCLIP )
+ return;
+
// Final CheckValidJump
//CheckValidJump(client);
@@ -3868,16 +3865,17 @@ PlayerLand(client)
g_PlayerStates[client][fMaxSpeed],
g_PlayerStates[client][fMaxSpeed] - g_PlayerStates[client][fPrestrafe]);
- Append(buf, sizeof(buf), "\nHeight diff: %s%.2f; jump height: %.2f; efficiency: %.4f; ticks: %d; degrees synced/degrees turned: %.2f/%.2f",
+ Append(buf, sizeof(buf), "\nHeight diff: %s%.2f; jump height: %.2f; ticks: %d\nEfficiency: %.4f; degrees synced/degrees turned: %.2f/%.2f",
g_PlayerStates[client][fHeightDelta] >= 0.0 ? "+" : "",
g_PlayerStates[client][fHeightDelta],
g_PlayerStates[client][fJumpHeight],
- (g_PlayerStates[client][fJumpDistance] - 32.0) / g_PlayerStates[client][fTrajectory],
g_PlayerStates[client][nTotalTicks],
+ (g_PlayerStates[client][fJumpDistance] - 32.0) / g_PlayerStates[client][fTrajectory],
g_PlayerStates[client][fSyncedAngle], g_PlayerStates[client][fTotalAngle]);
PrintToConsole(client, buf);
-
+ PrintSyncStats( client );
+
new Handle:hBuffer = StartMessageOne("KeyHintText", client);
BfWriteByte(hBuffer, 1);
diff --git a/sourcemod-1.5-dev/scripting/stats.sp b/sourcemod-1.5-dev/scripting/stats.sp
index 94f3598..f006f60 100644
--- a/sourcemod-1.5-dev/scripting/stats.sp
+++ b/sourcemod-1.5-dev/scripting/stats.sp
@@ -143,7 +143,6 @@ new g_LJTopMax[LT_END] = { 0, ... };
new g_statsTOP = 0;
new g_playerStats[MAXPLAYERS+1][PlayerStats];
new g_playerTop[STATSTOP_NUM_ENTRIES][PlayerStats];
-new g_displayedStats[MAXPLAYERS+1] = { false, ... };
public OnPluginStart() {
CreateTimer( 1.0, Timer_PlaytimeTick, _ );
@@ -265,6 +264,7 @@ public ResetPlayerStates() {
public OnClientPutInServer( client ) {
ResetPlayerState( client );
+ CreateTimer( 10.0, Timer_SendMsg4, client, TIMER_FLAG_NO_MAPCHANGE );
LoadLJDB();
LoadStatsDBForUser( client );
}
@@ -590,6 +590,15 @@ public LoadStatsDBCallback( Handle:owner, Handle:hndl, String:error[], any:pack
LogMessage( "Loading db for top %s (%s)", g_playerTop[it][plName], steamid );
++it;
}
+
+ if( !pack )
+ g_statsTOP = it;
+ for( new i = 1; i < MaxClients; ++i ) {
+ if( !IsClientConnected( i ) || IsFakeClient( i ) )
+ continue;
+
+ UpdatePlayerPoints( i );
+ }
}
public CreateStatsDBCallback( Handle:owner, Handle:hndl, String:error[], any:pack ) {
@@ -920,7 +929,7 @@ public Action:Timer_SendMsg2( Handle: timer, any: client ) {
public Action:Timer_SendMsg( Handle: Timer, any: client ) {
new String:chatOutput[1024];
- Format( chatOutput, sizeof(chatOutput), "%s{white}Kills {default}: {green}%d {default}(%dpts)\n", chatOutput, g_playerStats[client][plKills], g_playerStats[client][plKills] / 2 );
+ Format( chatOutput, sizeof(chatOutput), "%s{white}Player kills {default}: {green}%d {default}(%dpts)\n", chatOutput, g_playerStats[client][plKills], g_playerStats[client][plKills] / 2 );
Format( chatOutput, sizeof(chatOutput), "%s{white}Deaths {default}: {green}%d {default}(-%dpts)\n", chatOutput, g_playerStats[client][plDeaths], g_playerStats[client][plDeaths] / 2 );
new Float:kdScore = GetKDScore( client );
@@ -1038,7 +1047,7 @@ public Action:Command_Stats( client, args ) {
GetCmdArg( 1, arg, sizeof(arg) );
new top = StringToInt( arg );
- if( top > 0 && top < g_statsTOP + 1 ) {
+ if( top > 0 ) {
if( top > g_statsTOP ) {
CPrintToChat( client, "{fuchsia}There are only {green}%d {fuchsia}players in the database.", g_statsTOP );
return Plugin_Handled;
diff --git a/sourcemod/scripting/css-kztimer.sp b/sourcemod/scripting/css-kztimer.sp
new file mode 100644
index 0000000..9a978ad
--- /dev/null
+++ b/sourcemod/scripting/css-kztimer.sp
@@ -0,0 +1,957 @@
+#include <morecolors>
+#include <sourcemod>
+#include <smlib>
+#include <sdkhooks>
+#include <clientprefs>
+
+#define MAX_TIMES 8192
+
+public Plugin myinfo = {
+ name = "KZTimer",
+ author = "networkheaven.net",
+ description = "KZTimer",
+ version = "420.69",
+ url = "networkheaven.net"
+};
+
+enum MapZoneType {
+ ZONE_NONE,
+ ZONE_BUTTON,
+ ZONE_TRIGGER,
+};
+
+enum struct PlayerData {
+ bool bIsInRun;
+ bool bIsInZone;
+
+ float fStartTime;
+ float fEndTime;
+ float fPausedTime;
+
+ int nJumps;
+ int nTeleports;
+
+ bool bShowingMenu;
+ bool bHideViewmodel;
+
+ float vStartPoint[3];
+ float vStartAngle[3];
+
+ float vPausedAngle[3];
+ float vLastAngle[3];
+
+ float vSavedPoint[3];
+ float vSavedAngles[3];
+ bool bSavedDuck;
+ bool bSavedPoint;
+ bool bPausedRun;
+
+ int nDuckTicks;
+}
+
+enum struct TimeData {
+ float fFinalTime;
+ int nJumps;
+ int nTeleports;
+ char sName[64];
+ char sSteamid[32];
+ char sMapName[32];
+ int nTimestamp;
+ int nPosition;
+}
+
+public bool g_isKZ;
+public PlayerData g_playerData[MAXPLAYERS + 1];
+public Handle g_DB = INVALID_HANDLE;
+
+public int g_topTime = 0;
+public TimeData g_times[MAX_TIMES];
+public Cookie g_hideWeaponCookie;
+
+public ConVar g_nhWarmup = null;
+
+public void OnPluginStart() {
+ HookEntityOutput( "func_button", "OnPressed", OnButtonUsed );
+
+ RegConsoleCmd( "sm_savepoint", Command_SavePoint, "Save your current position." );
+ RegConsoleCmd( "sm_loadpoint", Command_LoadPoint, "Load your saved position." );
+ RegConsoleCmd( "sm_tpmenu", Command_CheckpointPanel, "Show the checkpoint menu." );
+ RegConsoleCmd( "sm_tp", Command_CheckpointPanel, "Show the checkpoint menu." );
+ RegConsoleCmd( "sm_pause", Command_PauseRun, "Pause/resume your run." );
+ RegConsoleCmd( "sm_restart", Command_Restart, "Restart your run." );
+ RegConsoleCmd( "sm_maptop", Command_Maptop, "Show the top 50 times." );
+ RegConsoleCmd( "sm_m", Command_Maptop, "Show the top 50 times." );
+ RegConsoleCmd( "sm_mrank", Command_MyRank, "Show your rank on the current map." );
+ RegConsoleCmd( "sm_viewmodel", Command_HideViewmodel, "Toggle viewmodel." );
+ RegConsoleCmd( "sm_vm", Command_HideViewmodel, "Toggle viewmodel." );
+ RegConsoleCmd( "sm_hideweapon", Command_HideViewmodel, "Toggle viewmodel." );
+
+ HookEvent( "player_spawn", Event_PlayerSpawn, EventHookMode_Post );
+ HookEvent( "player_jump", Event_PlayerJump, EventHookMode_Post );
+
+ g_hideWeaponCookie = RegClientCookie( "kztimer_hideweapon", "kztimer_hideweapon", CookieAccess_Public );
+}
+
+public void OnPluginEnd() {
+}
+
+public void OnAllPluginsLoaded() {
+
+}
+
+public void ClearPlayerData( int i ) {
+ g_playerData[i].bIsInRun = false;
+ g_playerData[i].bIsInZone = false;
+ g_playerData[i].fStartTime = 0.0;
+ g_playerData[i].fEndTime = 0.0;
+ g_playerData[i].fPausedTime = 0.0;
+ g_playerData[i].nJumps = 0;
+ g_playerData[i].nTeleports = 0;
+ g_playerData[i].bSavedPoint = false;
+ g_playerData[i].bPausedRun = false;
+ g_playerData[i].bShowingMenu = false;
+ g_playerData[i].nDuckTicks = 0;
+}
+
+public void ClearAllPlayers() {
+ for( int i = 0; i < MAXPLAYERS; i++ ) {
+ ClearPlayerData( i );
+ }
+}
+
+public void OnClientPutInServer( int client ) {
+ ClearPlayerData( client );
+
+ SDKHook( client, SDKHook_OnTakeDamage, OnTakeDamage );
+}
+
+public void CreateDatabaseCallback( Handle owner, DBResultSet hndl, const char[] error, any pack ) {
+ if( hndl == INVALID_HANDLE ) {
+ LogError( "Failed to create database: %s", error );
+ return;
+ }
+
+ char mapName[256];
+ GetCurrentMap( mapName, sizeof(mapName) );
+
+ LoadDatabase();
+}
+
+public void CreateDatabase() {
+ if( g_DB != INVALID_HANDLE ) {
+ CloseHandle( g_DB );
+ }
+
+ char error[256];
+ g_DB = SQL_Connect( "kztimer", true, error, sizeof(error) );
+
+ if( g_DB == INVALID_HANDLE ) {
+ LogError( "Failed to connect to database: %s", error );
+ return;
+ }
+
+ SQL_TQuery( g_DB, CreateDatabaseCallback, "CREATE TABLE IF NOT EXISTS times ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, steamid VARCHAR(32) NOT NULL , name VARCHAR(64) NOT NULL , map VARCHAR(32) NOT NULL , time FLOAT NOT NULL , jumps INT NOT NULL , teleports INT NOT NULL , date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP )" );
+}
+
+public void LoadDatabaseCallback( Handle owner, DBResultSet hndl, const char[] error, any pack ) {
+ if( hndl == INVALID_HANDLE ) {
+ LogError( "Failed to load database: %s", error );
+ return;
+ }
+
+ g_topTime = SQL_GetRowCount( hndl );
+ LogMessage( "Loaded %d times", g_topTime );
+ for( int i = 0; i < g_topTime; i++ ) {
+ SQL_FetchRow( hndl );
+ TimeData data;
+
+ data.fFinalTime = SQL_FetchFloatByName( hndl, "time" );
+ data.nJumps = SQL_FetchIntByName( hndl, "jumps" );
+ data.nTeleports = SQL_FetchIntByName( hndl, "teleports" );
+ data.nTimestamp = SQL_FetchIntByName( hndl, "date" );
+ SQL_FetchStringByName( hndl, "name", data.sName, sizeof(data.sName) );
+ SQL_FetchStringByName( hndl, "steamid", data.sSteamid, sizeof(data.sSteamid) );
+ SQL_FetchStringByName( hndl, "map", data.sMapName, sizeof(data.sMapName) );
+
+ data.nPosition = i;
+
+ g_times[i] = data;
+ }
+}
+
+public void LoadDatabase() {
+ char mapName[256];
+ GetCurrentMap( mapName, sizeof(mapName) );
+
+ char query[1024];
+ Format( query, sizeof(query), "SELECT * FROM times WHERE map = '%s' ORDER BY time ASC", mapName );
+ SQL_TQuery( g_DB, LoadDatabaseCallback, query );
+}
+
+public UpdateTimeCallback( Handle owner, DBResultSet hndl, const char[] error, TimeData pack ) {
+ if( hndl == INVALID_HANDLE ) {
+ LogError( "Failed to update time: %s", error );
+ return;
+ }
+
+ SaveTime( pack );
+}
+
+public UpdateTime( TimeData data ) {
+ char query[1024];
+ Format( query, sizeof(query), "DELETE FROM times WHERE steamid = '%s' AND map = '%s'", data.sSteamid, data.sMapName );
+ DBResultSet hndl = SQL_Query( g_DB, query );
+
+ if( hndl == INVALID_HANDLE ) {
+ char err[255];
+ SQL_GetError( g_DB, err, sizeof(err) );
+ LogError( "Failed to update time: %s", err );
+ return;
+ }
+
+ SaveTime( data );
+}
+
+public void SaveTimeCallback( Handle owner, DBResultSet hndl, const char[] error, any pack ) {
+ if( hndl == INVALID_HANDLE ) {
+ LogError( "Failed to save time: %s", error );
+ return;
+ }
+
+ LoadDatabase();
+}
+
+public void SaveTime( TimeData data ) {
+ float time = data.fFinalTime;
+ int jumps = data.nJumps;
+ int teleports = data.nTeleports;
+
+ char query[1024];
+ Format( query, sizeof(query), "INSERT INTO times ( steamid, name, map, time, jumps, teleports ) VALUES ( '%s', '%s', '%s', '%f', '%d', '%d' )", data.sSteamid, data.sName, data.sMapName, time, jumps, teleports );
+ SQL_TQuery( g_DB, SaveTimeCallback, query );
+}
+
+public void ClearRecords() {
+ for( int i = 0; i < MAX_TIMES; i++ ) {
+ g_times[i].fFinalTime = 0.0;
+ g_times[i].nJumps = 0;
+ g_times[i].nTeleports = 0;
+ g_times[i].nTimestamp = 0;
+ g_times[i].nPosition = 0;
+ g_times[i].sName[0] = '\0';
+ g_times[i].sSteamid[0] = '\0';
+ g_times[i].sMapName[0] = '\0';
+ }
+}
+
+public Action CommandTimer( Handle timer, any unused ) {
+ ServerCommand( "bot_kick; bot_quota 0; nh_warmup 0; sv_airaccelerate 12; mp_falldamage 0; sv_enablebunnyhopping 1" );
+ if( !g_nhWarmup )
+ g_nhWarmup = FindConVar( "nh_warmup" );
+ else
+ SetConVarInt( g_nhWarmup, 0 );
+
+ return Plugin_Handled;
+}
+
+public void OnMapStart() {
+ ClearRecords();
+ char mapName[32];
+ GetCurrentMap(mapName, sizeof(mapName));
+
+ if( !strncmp( mapName, "kz_", 3, false )
+ || !strncmp( mapName, "xc_", 3, false )
+ || !strncmp( mapName, "bhop_", 5, false )
+ || !strncmp( mapName, "bkz_", 4, false ) ) {
+ g_isKZ = true;
+ } else {
+ g_isKZ = false;
+ }
+
+ ClearAllPlayers();
+
+ if( g_isKZ ) {
+ CreateTimer( 2.0, CommandTimer, 0, TIMER_FLAG_NO_MAPCHANGE );
+ CreateDatabase();
+ }
+
+ PrecacheSound( "quake/standard/wickedsick.wav" );
+}
+
+public void OnMapEnd() {
+ g_isKZ = false;
+}
+
+public void StartRun( int client ) {
+ EmitSoundToClient( client, "buttons/button17.wav" );
+ CPrintToChat( client, "[{green}kz{default}] {white}run started." );
+ g_playerData[client].bIsInRun = true;
+ g_playerData[client].fStartTime = GetGameTime();
+
+ g_playerData[client].nJumps = 0;
+ g_playerData[client].nTeleports = 0;
+
+ float origin[3];
+ GetClientAbsOrigin( client, origin );
+ Array_Copy( origin, g_playerData[client].vStartPoint, 3 );
+
+ float angles[3];
+ GetClientAbsAngles( client, angles );
+ Array_Copy( angles, g_playerData[client].vStartAngle, 3 );
+
+ g_playerData[client].bSavedPoint = false;
+ g_playerData[client].bPausedRun = false;
+
+ if( g_playerData[client].bShowingMenu ) {
+ ShowCheckpointMenu( client, true );
+ }
+}
+
+public void EndRun( int client ) {
+ if( !g_playerData[client].bIsInRun )
+ return;
+
+ EmitSoundToClient( client, "buttons/button9.wav" );
+ g_playerData[client].bIsInRun = false;
+ g_playerData[client].fEndTime = GetGameTime();
+
+ float time = GetGameTime() - g_playerData[client].fStartTime;
+ int hours = RoundToFloor( time ) / 3600;
+ int minutes = RoundToFloor( time ) / 60;
+ int seconds = RoundToFloor( time ) - hours * 3600 - minutes * 60;
+ int milliseconds = RoundToFloor( (time - RoundToFloor( time )) * 1000 );
+
+ char name[64];
+ GetClientName( client, name, sizeof(name) );
+
+ char color[16];
+ strcopy( color, sizeof(color), g_playerData[client].nTeleports > 0 ? "{unique}" : "{cyan}" );
+
+ char chatStr[256];
+ Format( chatStr, sizeof(chatStr), "[{green}kz{default}] {violet}%s {white}finished the map", name );
+
+ float prevRunTime = -1.0;
+ int runPos = -1;
+ char clientSteamId[32];
+ GetClientAuthId( client, AuthId_Engine, clientSteamId, sizeof(clientSteamId) );
+ for( int i = 0; i < g_topTime; i++ ) {
+ PrintToChatAll( "%d : %s", i, g_times[i].sSteamid );
+ if( prevRunTime < 0 && !strcmp( clientSteamId, g_times[i].sSteamid ) ) {
+ prevRunTime = g_times[i].fFinalTime;
+ }
+
+ if( runPos == -1 && time < g_times[i].fFinalTime ) {
+ runPos = i;
+ }
+
+ if( runPos >= 0 && prevRunTime > 0 )
+ break;
+ }
+
+ if( prevRunTime < 0.0 )
+ Format( chatStr, sizeof(chatStr), "%s for the first time", chatStr );
+ Format( chatStr, sizeof(chatStr), "%s in %s", chatStr, color );
+
+ if( hours > 0 ) {
+ Format( chatStr, sizeof(chatStr), "%s%d:%02d:%02d.%03d", chatStr, hours, minutes, seconds, milliseconds );
+ } else {
+ Format( chatStr, sizeof(chatStr), "%s%d:%02d.%03d", chatStr, minutes, seconds, milliseconds );
+ }
+
+ if( prevRunTime > 0.0 ) {
+ float diff = prevRunTime - time;
+ float absDiff = FloatAbs( diff );
+ int diffHours = RoundToFloor( absDiff / 3600.0 );
+ int diffMinutes = RoundToFloor( absDiff / 60.0 ) ;
+ int diffSeconds = RoundToFloor( absDiff - ( diffMinutes * 60.0 ) ) ;
+ int diffMilliseconds = RoundToFloor( ( absDiff - RoundToFloor( absDiff ) ) * 1000.0 );
+
+ if( diffHours > 0 ) {
+ Format( chatStr, sizeof(chatStr), "%s {white}[%s%s%d:%02d:%02d.%03d{white}]", chatStr, diff < 0 ? "{red}" : "{green}", diff < 0 ? "+" : "-", diffHours, diffMinutes, diffSeconds, diffMilliseconds );
+ } else {
+ Format( chatStr, sizeof(chatStr), "%s {white}[%s%s%d:%02d.%03d{white}]", chatStr, diff < 0 ? "{red}" : "{green}", diff < 0 ? "+" : "-", diffMinutes, diffSeconds, diffMilliseconds );
+ }
+ }
+
+ if( runPos >= 0 ) {
+ Format( chatStr, sizeof(chatStr), "%s {white}(#%d/%d).", chatStr, runPos + 1, g_topTime );
+ } else {
+ Format( chatStr, sizeof(chatStr),
+ "%s {white}(#%d/%d).",
+ chatStr,
+ g_topTime + 1,
+ prevRunTime > 0.0 ? g_topTime : g_topTime + 1
+ );
+ }
+
+ CPrintToChatAll( clientSteamId );
+ CPrintToChatAll( chatStr );
+
+ if( prevRunTime < 0.0 || time < prevRunTime ) {
+ TimeData data;
+ data.fFinalTime = time;
+ data.nJumps = g_playerData[client].nJumps;
+ data.nTeleports = g_playerData[client].nTeleports;
+ data.nTimestamp = 0;
+ data.nPosition = 0;
+ strcopy( data.sName, sizeof(data.sName), name );
+ strcopy( data.sSteamid, sizeof(data.sSteamid), clientSteamId );
+ GetCurrentMap( data.sMapName, sizeof(data.sMapName) );
+
+ UpdateTime( data );
+
+ if( runPos == 0 || g_topTime == 0 ) {
+ CPrintToChatAll( "[{green}kz{default}] {violet}%s {white}set a new map record!", name );
+ EmitSoundToAll( "quake/standard/wickedsick.wav" );
+ }
+ }
+
+ g_playerData[client].fStartTime = 0.0;
+ if( g_playerData[client].bShowingMenu )
+ ShowCheckpointMenu( client, true );
+}
+
+public void OnButtonUsed( const char[] output, int caller, int activator, float delay ) {
+ if( !g_isKZ ) return;
+
+ char entityName[64];
+ GetEntPropString( caller, Prop_Data, "m_iName", entityName, sizeof(entityName) );
+
+ if( activator && !strcmp( entityName, "climb_startbutton" ) ) {
+ StartRun( activator );
+ }
+ else if( activator && !strcmp( entityName, "climb_endbutton" ) ) {
+ EndRun( activator );
+ }
+}
+
+public bool AreAllPlayersOnOneTeam() {
+ int ctCount = 0;
+ int tCount = 0;
+ for( int i = 1; i < MaxClients; ++i ) {
+ if( !IsClientConnected( i ) || !IsClientInGame( i ) )
+ continue;
+
+ int team = GetClientTeam( i );
+ if( team == 2 ) {
+ if( ctCount > 0 )
+ return false;
+ ++tCount;
+ } else if( team == 3 ) {
+ if( tCount > 0 )
+ return false;
+ ++ctCount;
+ }
+ }
+
+ return true;
+}
+
+public bool CanUseTPMenu() {
+ if( g_isKZ )
+ return true;
+
+ if( g_nhWarmup == null )
+ g_nhWarmup = FindConVar( "nh_warmup" );
+
+ if( g_nhWarmup != INVALID_HANDLE && GetConVarInt( g_nhWarmup ) != 0 )
+ return true;
+
+ if( AreAllPlayersOnOneTeam() )
+ return true;
+
+ return false;
+}
+
+public void ShowCheckpointMenu( int client, bool kz ) {
+ Menu menu = CreateMenu( CheckpointMenuHandler, MenuAction_Start );
+ AddMenuItem( menu, "save position", "save checkpoint" );
+ char buf[64];
+ if( g_playerData[client].bIsInRun )
+ Format( buf, sizeof(buf), "load checkpoint (%d)", g_playerData[client].nTeleports );
+ else
+ Format( buf, sizeof(buf), "load checkpoint" );
+
+ AddMenuItem( menu, "load position", buf, g_playerData[client].bSavedPoint ? 0 : ITEMDRAW_DISABLED );
+
+ if( kz ) {
+ if( !g_playerData[client].bPausedRun )
+ AddMenuItem( menu, "pause timer", "pause", g_playerData[client].bIsInRun ? 0 : ITEMDRAW_DISABLED );
+ else
+ AddMenuItem( menu, "resume timer", "resume", g_playerData[client].bIsInRun ? 0 : ITEMDRAW_DISABLED );
+
+ AddMenuItem( menu, "respawn", "restart" );
+ }
+
+ DisplayMenu( menu, client, MENU_TIME_FOREVER );
+ g_playerData[client].bShowingMenu = true;
+}
+
+public int CheckpointMenuHandler( Menu menu, MenuAction ma, int client, int nItem ) {
+ if( client <= 0 || client > MAXPLAYERS ) return 0;
+
+ if( ma == MenuAction_Select ) {
+ switch( nItem ) {
+ case 0: { Command_SavePoint( client, 0 ); }
+ case 1: { Command_LoadPoint( client, 0 ); }
+ case 2: { Command_PauseRun( client, 0 ); }
+ case 3: { Command_Restart( client, 0 ); }
+ }
+
+ ShowCheckpointMenu( client, g_isKZ );
+ return 0;
+ }
+ else if( ma == MenuAction_Cancel && nItem == -3 ) {
+ g_playerData[client].bShowingMenu = false;
+ return 0;
+ }
+ else if( ma == MenuAction_End ) {
+ delete menu;
+ }
+
+ return 0;
+}
+
+public Action Command_SavePoint( int client, int nargs ) {
+ if( !IsPlayerAlive( client ) ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}You must be alive to use this command." );
+ return Plugin_Handled;
+ }
+
+ if( g_nhWarmup == null ) {
+ g_nhWarmup = FindConVar( "nh_warmup" );
+ }
+
+ if( !CanUseTPMenu() ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}This command can only be used on KZ maps or during warmup." );
+ return Plugin_Handled;
+ }
+
+ int flags = GetEntProp( client, Prop_Send, "m_fFlags" );
+ if( !( flags & FL_ONGROUND) ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}Cannot set a checkpoint mid-air." );
+ EmitSoundToClient( client, "buttons/button10.wav" );
+ return Plugin_Handled;
+ }
+
+ float origin[3];
+ GetClientAbsOrigin( client, origin );
+ Array_Copy( origin, g_playerData[client].vSavedPoint, 3 );
+ Array_Copy( g_playerData[client].vLastAngle, g_playerData[client].vSavedAngles, 3 );
+
+ g_playerData[client].bSavedDuck = !!GetEntProp( client, Prop_Send, "m_bDucked" );
+ g_playerData[client].bSavedPoint = true;
+
+ return Plugin_Handled;
+}
+
+public Action Command_LoadPoint( int client, int nargs ) {
+ if( !IsPlayerAlive( client ) ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}You must be alive to use this command." );
+ return Plugin_Handled;
+ }
+
+ if( !g_playerData[client].bSavedPoint ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}You must save your position first." );
+ return Plugin_Handled;
+ }
+
+ if( g_playerData[client].bPausedRun ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}Cannot load position while the run is paused." );
+ EmitSoundToClient( client, "buttons/button10.wav" );
+ return Plugin_Handled;
+ }
+
+ if( !CanUseTPMenu() ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}This command can only be used on KZ maps or during warmup." );
+ return Plugin_Handled;
+ }
+
+ float vDiff[3], dist;
+ if( !g_isKZ ) {
+ for( int i = 1; i < MaxClients; ++i ) {
+ if( i == client )
+ continue;
+ if( !IsClientConnected( i ) || !IsClientInGame( i ) || !IsPlayerAlive( i ) )
+ continue;
+
+ float origin[3];
+ GetClientAbsOrigin( i, origin );
+
+ vDiff[0] = origin[0] - g_playerData[client].vSavedPoint[0];
+ vDiff[1] = origin[1] - g_playerData[client].vSavedPoint[1];
+
+ dist = SquareRoot( vDiff[0] * vDiff[0] + vDiff[1] * vDiff[1] );
+ if( FloatAbs( g_playerData[client].vSavedPoint[2] - origin[2] ) < 64.0 && dist < 64.0 ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}Cannot load your position because another player is standing there." );
+ return Plugin_Handled;
+ }
+ }
+ }
+
+ float origin[3];
+ Array_Copy( g_playerData[client].vSavedPoint, origin, 3 );
+
+ float angles[3];
+ Array_Copy( g_playerData[client].vSavedAngles, angles, 3 );
+
+ float velocity[3];
+ velocity[0] = 0.0;
+ velocity[1] = 0.0;
+ velocity[2] = -1.0;
+
+ TeleportEntity( client, origin, angles, velocity );
+ if( g_playerData[client].bSavedDuck ) {
+ SetEntProp( client, Prop_Send, "m_bDucked", 1 );
+ g_playerData[client].nDuckTicks = 5;
+ } else {
+ SetEntProp( client, Prop_Send, "m_bDucked", 0 );
+ }
+
+ if( g_playerData[client].bIsInRun ) {
+ g_playerData[client].nTeleports++;
+ }
+ return Plugin_Handled;
+}
+
+public Action Command_PauseRun( int client, int nargs ) {
+ if( !g_isKZ ) return Plugin_Handled;
+
+ if( !g_playerData[client].bIsInRun ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}You must be in a run to use this command." );
+ return Plugin_Handled;
+ }
+
+ if( !IsPlayerAlive( client ) ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}You must be alive to use this command." );
+ return Plugin_Handled;
+ }
+
+ int flags = GetEntProp( client, Prop_Send, "m_fFlags" );
+ if( !( flags & FL_ONGROUND) ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}Cannot pause mid-air." );
+ EmitSoundToClient( client, "buttons/button10.wav" );
+
+ return Plugin_Handled;
+ }
+
+ if( !g_playerData[client].bPausedRun ) {
+ float runTime = GetGameTime() - g_playerData[client].fStartTime;
+ g_playerData[client].fPausedTime = runTime;
+
+ Array_Copy( g_playerData[client].vLastAngle, g_playerData[client].vPausedAngle, 3 );
+
+ g_playerData[client].bPausedRun = true;
+ CPrintToChat( client, "[{green}kz{default}] {white}run paused." );
+ } else {
+ g_playerData[client].fStartTime = GetGameTime() - g_playerData[client].fPausedTime;
+ g_playerData[client].bPausedRun = false;
+
+ SetEntityFlags( client, GetEntityFlags( client ) & ~FL_FROZEN );
+
+ CPrintToChat( client, "[{green}kz{default}] {white}run resumed." );
+ }
+
+ return Plugin_Handled;
+}
+
+public Action Command_CheckpointPanel( int client, int nargs ) {
+ if( !IsPlayerAlive( client ) ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}You must be alive to use this command." );
+ return Plugin_Handled;
+ }
+
+
+ if( !CanUseTPMenu() ) {
+ CPrintToChat( client, "[{green}kz{default}] {red}This command can only be used on KZ maps or during warmup." );
+ return Plugin_Handled;
+ }
+
+ ShowCheckpointMenu( client, g_isKZ );
+
+ return Plugin_Handled;
+}
+
+public Action Command_Restart( int client, int args ) {
+ float origin[3];
+ Array_Copy( g_playerData[client].vStartPoint, origin, 3 );
+
+ float angle[3];
+ Array_Copy( g_playerData[client].vStartAngle, angle, 3 );
+
+ float velocity[3];
+ velocity[0] = 0.0;
+ velocity[1] = 0.0;
+ velocity[2] = -1.0;
+
+ TeleportEntity( client, origin, angle, velocity );
+ return Plugin_Handled;
+}
+
+public void GetTimeString( int client, char[] buffer, int size ) {
+ float time = 0.0;
+ if( g_playerData[client].bPausedRun ) {
+ time = g_playerData[client].fPausedTime;
+ } else {
+ time = GetGameTime() - g_playerData[client].fStartTime;
+ }
+
+ int hours = RoundToFloor( time ) / 3600;
+ int minutes = RoundToFloor( time ) / 60;
+ int seconds = RoundToFloor( time ) - hours * 3600 - minutes * 60;
+ int milliseconds = RoundToFloor( (time - RoundToFloor( time )) * 1000 );
+
+ Format( buffer, size, "time: " );
+
+ if( hours > 0 ) {
+ Format( buffer, size, "%s%d:%02d:%02d.%03d", buffer, hours, minutes, seconds, milliseconds );
+ } else {
+ Format( buffer, size, "%s%d:%02d.%03d", buffer, minutes, seconds, milliseconds );
+ }
+
+ Format( buffer, size, "%s\njumps: %d\nteleports: %d", buffer, g_playerData[client].nJumps, g_playerData[client].nTeleports );
+ if( g_playerData[client].bPausedRun ) {
+ Format( buffer, size, "%s\n[PAUSED]", buffer );
+ }
+}
+
+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]) {
+ Array_Copy( angles, g_playerData[client].vLastAngle, 3 );
+ if( !g_isKZ ) return Plugin_Continue;
+
+ if( !IsPlayerAlive( client ) ) {
+ g_playerData[client].bIsInRun = false;
+ return Plugin_Continue;
+ }
+
+ if( g_playerData[client].nDuckTicks > 0 ) {
+ buttons |= IN_DUCK;
+ g_playerData[client].nDuckTicks--;
+ }
+
+ SetEntityRenderMode( client, RENDER_TRANSCOLOR );
+ SetEntityRenderColor( client, 255, 255, 255, 100 );
+
+ if( GetEntityMoveType( client ) == MOVETYPE_NOCLIP ) {
+ g_playerData[client].bIsInRun = false;
+ CPrintToChat( client, "[{green}kz{default}] {red}You cannot use noclip during a run." );
+ EmitSoundToClient( client, "buttons/button10.wav" );
+ return Plugin_Continue;
+ }
+
+ if( g_playerData[client].bIsInRun ) {
+ char timeString[256];
+ GetTimeString( client, timeString, sizeof(timeString) );
+ PrintHintText( client, timeString );
+
+ if( g_playerData[client].bPausedRun ) {
+ SetEntityFlags( client, GetEntityFlags( client ) | FL_FROZEN );
+ TeleportEntity( client, NULL_VECTOR, g_playerData[client].vPausedAngle, NULL_VECTOR );
+ return Plugin_Handled;
+ }
+ }
+
+ return Plugin_Continue;
+}
+
+public Action Event_PlayerJump( Event e, const char[] name, bool dontBroadcast ) {
+ int client = GetClientOfUserId( e.GetInt( "userid" ) );
+ if( !g_isKZ ) return Plugin_Continue;
+ if( !client )
+ return Plugin_Continue;
+
+ if( !g_playerData[client].bIsInRun ) return Plugin_Continue;
+
+ g_playerData[client].nJumps++;
+ return Plugin_Continue;
+}
+
+public Action OnTakeDamage( int client, int& attacker, int& inflictor, float& damage, int& damagetype ) {
+ if( !g_isKZ ) return Plugin_Continue;
+
+ if( damagetype & DMG_FALL )
+ return Plugin_Handled;
+
+ return Plugin_Continue;
+}
+
+public Action Event_PlayerSpawn( Event e, const char[] name, bool dontBroadcast ) {
+ int client = GetClientOfUserId( e.GetInt( "userid" ) );
+ if( !g_isKZ ) return Plugin_Continue;
+
+ if( !client )
+ return Plugin_Continue;
+
+ float origin[3];
+ GetClientAbsOrigin( client, origin );
+
+ float angle[3];
+ GetClientAbsAngles( client, angle );
+
+ Array_Copy( origin, g_playerData[client].vStartPoint, 3 );
+ Array_Copy( angle, g_playerData[client].vStartAngle, 3 );
+
+ if( g_isKZ ) {
+ SetEntProp( client, Prop_Send, "m_CollisionGroup", 2 );
+ ShowCheckpointMenu( client, true );
+
+ char cookie[32];
+ g_hideWeaponCookie.Get( client, cookie, sizeof(cookie) );
+
+ bool hide = !!StringToInt( cookie );
+ g_playerData[client].bHideViewmodel = hide;
+ SetEntProp( client, Prop_Send, "m_bDrawViewmodel", hide );
+ }
+
+ return Plugin_Continue;
+}
+
+public int TopTimesMenuHandler( Menu menu, MenuAction ma, int client, int nItem ) {
+ LogMessage( "TopTimesMenuHandler %d %d %d", client, ma, nItem );
+
+ if( ma == MenuAction_Cancel ) {
+ if( g_playerData[client].bShowingMenu ) {
+ ShowCheckpointMenu( client, g_isKZ );
+ }
+ }
+ else if( ma == MenuAction_End ) {
+ delete menu;
+ }
+
+ return 0;
+}
+
+public void ShowTopNubTimes( int client ) {
+ Menu menu = CreateMenu( TopTimesMenuHandler, MenuAction_Start );
+ int max = g_topTime > 50 ? 50 : g_topTime;
+ for( int i = 0; i < max; i++ ) {
+ float time = g_times[i].fFinalTime;
+ int hours = RoundToFloor( time ) / 3600;
+ int minutes = RoundToFloor( time ) / 60;
+ int seconds = RoundToFloor( time ) - hours * 3600 - minutes * 60;
+ int milliseconds = RoundToFloor( (time - RoundToFloor( time )) * 1000 );
+
+ char buf[256];
+ Format( buf, sizeof(buf), "%d. %s - ", i + 1, g_times[i].sName );
+ if( hours > 0 )
+ Format( buf, sizeof(buf), "%s%d:%02d:%02d.%03d", buf, hours, minutes, seconds, milliseconds );
+ else
+ Format( buf, sizeof(buf), "%s%d:%02d.%03d", buf, minutes, seconds, milliseconds );
+
+ Format( buf, sizeof(buf), "%s (%d TP, %d jumps)", buf, g_times[i].nJumps, g_times[i].nTeleports );
+ menu.AddItem( "button", buf, ITEMDRAW_DISABLED );
+ }
+
+ DisplayMenu( menu, client, MENU_TIME_FOREVER );
+}
+
+public void ShowTopProTimes( int client ) {
+ Menu menu = CreateMenu( TopTimesMenuHandler, MenuAction_Start );
+ int it = 0;
+ int max = g_topTime > 50 ? 50 : g_topTime;
+ for( int i = 0; i < max; i++ ) {
+ if( g_times[i].nTeleports > 0 )
+ continue;
+
+ float time = g_times[i].fFinalTime;
+ int hours = RoundToFloor( time ) / 3600;
+ int minutes = RoundToFloor( time ) / 60;
+ int seconds = RoundToFloor( time ) - hours * 3600 - minutes * 60;
+ int milliseconds = RoundToFloor( (time - RoundToFloor( time )) * 1000 );
+
+ char buf[256];
+ Format( buf, sizeof(buf), "%d. %s - ", it + 1, g_times[i].sName );
+ if( hours > 0 )
+ Format( buf, sizeof(buf), "%s%d:%02d:%02d.%03d", buf, hours, minutes, seconds, milliseconds );
+ else
+ Format( buf, sizeof(buf), "%s%d:%02d.%03d", buf, minutes, seconds, milliseconds );
+ menu.AddItem( "button", buf, ITEMDRAW_DISABLED );
+
+ ++it;
+ }
+
+ DisplayMenu( menu, client, MENU_TIME_FOREVER );
+}
+
+public int MaptopMenuHandler( Menu menu, MenuAction ma, int client, int nItem ) {
+ if( ma == MenuAction_Select ) {
+ switch( nItem ) {
+ case 0: { ShowTopProTimes( client ); }
+ case 1: { ShowTopNubTimes( client ); }
+ }
+ } else if( ma == MenuAction_Cancel ) {
+ if( g_playerData[client].bShowingMenu )
+ ShowCheckpointMenu( client, g_isKZ );
+ }
+ else if( ma == MenuAction_End ) {
+ delete menu;
+ }
+
+ return 0;
+}
+
+public Action Command_Maptop( int client, int args ) {
+ if( !g_isKZ ) return Plugin_Handled;
+
+ Menu menu = CreateMenu( MaptopMenuHandler, MenuAction_Start );
+ AddMenuItem( menu, "button", "top 50 PRO" );
+ AddMenuItem( menu, "button", "top 50 NUB" );
+ DisplayMenu( menu, client, MENU_TIME_FOREVER );
+
+ return Plugin_Handled;
+}
+
+public Action Command_MyRank( int client, int args ) {
+ if( !g_isKZ ) return Plugin_Handled;
+
+ char clientSteamId[32];
+ GetClientAuthId( client, AuthId_Engine, clientSteamId, sizeof(clientSteamId) );
+
+ char name[64];
+ GetClientName( client, name, sizeof(name) );
+
+ int rank = -1;
+ for( int i = 0; i < g_topTime; i++ ) {
+ if( !strcmp( clientSteamId, g_times[i].sSteamid ) ) {
+ rank = i + 1;
+ break;
+ }
+ }
+
+ if( rank == -1 ) {
+ CPrintToChatAll( "[{green}kz{default}] {violet}%s {white}has no time on this map." );
+ return Plugin_Handled;
+ }
+
+ float time = g_times[rank - 1].fFinalTime;
+ int hours = RoundToFloor( time ) / 3600;
+ int minutes = RoundToFloor( time ) / 60;
+ int seconds = RoundToFloor( time ) - hours * 3600 - minutes * 60;
+ int milliseconds = RoundToFloor( (time - RoundToFloor( time )) * 1000 );
+
+ char buf[256];
+ Format( buf, sizeof(buf), "[{green}kz{default}] {violet}%s {white}is ranked {cyan}#%d/%d{white} with a time of ", name, rank, g_topTime );
+ if( hours > 0 )
+ Format( buf, sizeof(buf), "%s%d:%02d:%02d.%03d", buf, hours, minutes, seconds, milliseconds );
+ else
+ Format( buf, sizeof(buf), "%s%d:%02d.%03d", buf, minutes, seconds, milliseconds );
+
+ CPrintToChatAll( buf );
+ return Plugin_Handled;
+}
+
+public Action Command_HideViewmodel( int client, int args ) {
+ if( !g_isKZ ) return Plugin_Handled;
+
+ bool draw = !!GetEntProp( client, Prop_Send, "m_bDrawViewmodel" );
+ SetEntProp( client, Prop_Send, "m_bDrawViewmodel", !draw );
+
+ char cookieStr[32];
+ IntToString( !draw, cookieStr, sizeof(cookieStr) );
+ g_hideWeaponCookie.Set( client, cookieStr );
+
+ g_playerData[client].bHideViewmodel = !draw;
+
+ CPrintToChat( client, "[{green}kz{default}] viewmodel is now %s", !draw ? "shown" : "hidden" );
+ return Plugin_Handled;
+} \ No newline at end of file
diff --git a/sourcemod/scripting/game_manager.sp b/sourcemod/scripting/game_manager.sp
index 73d3a2d..7959880 100644
--- a/sourcemod/scripting/game_manager.sp
+++ b/sourcemod/scripting/game_manager.sp
@@ -40,6 +40,7 @@ new Float:g_voteTime = 20.0;
new bool:g_hasVoted[MAXPLAYERS + 1] = {false, ...};
new g_voteCount[9] = {0, ...};
new bool:g_botVoteDone = false;
+new bool:g_isKZ = false;
/* forwards */
new Handle:g_f_on_ht = INVALID_HANDLE;
@@ -52,15 +53,31 @@ public OnMapStart(){
halftime = false;
g_roundCount = 0;
+ new String:mapName[256];
+ GetCurrentMap( mapName, sizeof(mapName) );
+
+ if( !strncmp( mapName, "kz_", 3, false )
+ || !strncmp( mapName, "xc_", 3, false )
+ || !strncmp( mapName, "bhop_", 5, false )
+ || !strncmp( mapName, "bkz_", 4, false ) ) {
+ g_isKZ = true;
+ } else {
+ g_isKZ = false;
+ }
+
g_mp_startmoney = GetConVarInt( g_h_mp_startmoney );
g_maxrounds = GetConVarInt( g_h_mp_maxrounds );
g_lastDmMode = 0;
- OnDmModeChanged( g_h_nh_warmup, "", "" );
g_botVoteEnd = -1.0;
- SetConVarInt( g_h_nh_warmup, 60 );
- CreateTimer( 20.0, BotVoteCreateTimer, _ );
+ LogMessage( "map name: %s kz: %d", mapName, g_isKZ );
+
+ if( g_isKZ == false ) {
+ OnDmModeChanged( g_h_nh_warmup, "", "" );
+ SetConVarInt( g_h_nh_warmup, 60 );
+ CreateTimer( 20.0, BotVoteCreateTimer, _ );
+ }
}
public OnConfigsExecuted() {
@@ -187,9 +204,11 @@ public OnClientPutInServer( client ) {
if( i != client && IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) )
return;
}
-
- SetConVarInt( g_h_nh_warmup, 60 );
- CreateTimer( 20.0, BotVoteCreateTimer, _ );
+
+ if( !g_isKZ ) {
+ SetConVarInt( g_h_nh_warmup, 60 );
+ CreateTimer( 20.0, BotVoteCreateTimer, _ );
+ }
}
public Hook_PostThinkPost( entity ) {
@@ -314,6 +333,9 @@ public Action:CreateBotVote( client, args ) {
if( GetGameTime() < g_botVoteEnd )
return Plugin_Handled;
+ if( g_isKZ )
+ return Plugin_Handled;
+
g_botVoteDone = true;
g_botVoteEnd = GetGameTime() + g_voteTime;
@@ -368,6 +390,9 @@ public OnClientDisconnect( client ) {
}
public Action:ExecServerCfg( Handle:timer, any:unused ) {
+ if( g_isKZ )
+ return;
+
g_botVoteDone = false;
ServerCommand( "exec server.cfg" );
g_h_execServerCfgTimer = INVALID_HANDLE;