Skip to content
2 changes: 1 addition & 1 deletion src/ST-Commands/PlayerCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void PlayerGoToStage(CCSPlayerController? player, CommandInfo command)
Server.NextFrame(() => player.PlayerPawn.Value!.Teleport(CurrentMap.StageStartZone[stage], CurrentMap.StageStartZoneAngles[stage], new Vector(0,0,0)));

playerList[player.UserId ?? 0].Timer.Reset();
playerList[player.UserId ?? 0].Timer.StageMode = true;
playerList[player.UserId ?? 0].Timer.IsStageMode = true;

// To-do: If you run this while you're in the start zone, endtouch for the start zone runs after you've teleported
// causing the timer to start. This needs to be fixed.
Expand Down
30 changes: 24 additions & 6 deletions src/ST-Player/PlayerHUD.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,29 @@ private string FormatHUDElementHTML(string title, string body, string color, str
}
}

public string FormatTime(int ticks) // https://github.com/DEAFPS/SharpTimer/blob/e4ef24fff29a33c36722d23961355742d507441f/Utils.cs#L38
/// <summary>
/// Formats the given time in ticks into a readable time string.
/// Unless specified differently, the default formatting will be `Verbose`.
/// Check <see cref="PlayerTimer.TimeFormatStyle"/> for all formatting types.
/// </summary>
public string FormatTime(int ticks, PlayerTimer.TimeFormatStyle style = PlayerTimer.TimeFormatStyle.Verbose)
{
TimeSpan time = TimeSpan.FromSeconds(ticks / 64.0);
int millis = (int)(ticks % 64 * (1000.0 / 64.0));
return $"{time.Minutes:D2}:{time.Seconds:D2}.{millis:D3}";

switch (style)
{
case PlayerTimer.TimeFormatStyle.Compact:
return time.TotalMinutes < 1
? $"{time.Seconds:D1}.{millis:D3}"
: $"{time.Minutes:D1}:{time.Seconds:D1}.{millis:D3}";
case PlayerTimer.TimeFormatStyle.Full:
return $"{time.Hours:D2}:{time.Minutes:D2}:{time.Seconds:D2}.{millis:D3}";
case PlayerTimer.TimeFormatStyle.Verbose:
return $"{time.Hours}h {time.Minutes}m {time.Seconds}s {millis}ms";
default:
throw new ArgumentException("Invalid time format style");
}
}

public void Display()
Expand All @@ -43,22 +61,22 @@ public void Display()
string timerColor = "#79d1ed";
if (_player.Timer.IsRunning)
{
if (_player.Timer.PracticeMode)
if (_player.Timer.IsPracticeMode)
timerColor = "#F2C94C";
else
timerColor = "#2E9F65";
}
string timerModule = FormatHUDElementHTML("", FormatTime(_player.Timer.Ticks), timerColor);

// Velocity Module - To-do: Make velocity module configurable (XY or XYZ velocity)
float velocity = (float)Math.Sqrt(_player.Controller.PlayerPawn.Value!.AbsVelocity.X * _player.Controller.PlayerPawn.Value!.AbsVelocity.X
+ _player.Controller.PlayerPawn.Value!.AbsVelocity.Y * _player.Controller.PlayerPawn.Value!.AbsVelocity.Y
float velocity = (float)Math.Sqrt(_player.Controller.PlayerPawn.Value!.AbsVelocity.X * _player.Controller.PlayerPawn.Value!.AbsVelocity.X
+ _player.Controller.PlayerPawn.Value!.AbsVelocity.Y * _player.Controller.PlayerPawn.Value!.AbsVelocity.Y
+ _player.Controller.PlayerPawn.Value!.AbsVelocity.Z * _player.Controller.PlayerPawn.Value!.AbsVelocity.Z);
string velocityModule = FormatHUDElementHTML("Speed", velocity.ToString("000"), "#79d1ed") + " u/s";
// Rank Module
string rankModule = FormatHUDElementHTML("Rank", "N/A", "#7882dd"); // IMPLEMENT IN PlayerStats
// PB & WR Modules
string pbModule = FormatHUDElementHTML("PB", _player.Stats.PB[0,0] > 0 ? FormatTime(_player.Stats.PB[0,0]) : "N/A", "#7882dd"); // IMPLEMENT IN PlayerStats
string pbModule = FormatHUDElementHTML("PB", _player.Stats.PB[0, 0] > 0 ? FormatTime(_player.Stats.PB[0, 0]) : "N/A", "#7882dd"); // IMPLEMENT IN PlayerStats
string wrModule = FormatHUDElementHTML("WR", "N/A", "#7882dd"); // IMPLEMENT IN PlayerStats

// Build HUD
Expand Down
36 changes: 22 additions & 14 deletions src/ST-Player/PlayerTimer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,49 @@ namespace SurfTimer;
internal class PlayerTimer
{
// Status
public bool Enabled {get; set;} = true; // Enable toggle for entire timer
public bool Paused {get; set;} = false; // Pause toggle for timer
public bool IsRunning {get; set;} = false; // Is the timer currently running?
public bool IsEnabled { get; set; } = true; // Enable toggle for entire timer
public bool IsPaused { get; set; } = false; // Pause toggle for timer
public bool IsRunning { get; set; } = false; // Is the timer currently running?

// Modes
public bool PracticeMode {get; set;} = false; // Practice mode toggle
public bool StageMode {get; set;} = false; // Stage mode toggle
public bool IsPracticeMode { get; set; } = false; // Practice mode toggle
public bool IsStageMode { get; set; } = false; // Stage mode toggle

// Tracking
public int Stage {get; set;} = 0; // Current stage tracker
public int Bonus {get; set;} = 0; // Current bonus tracker - To-do: bonus implementation
public int Stage { get; set; } = 0; // Current stage tracker
public int Bonus { get; set; } = 0; // Current bonus tracker - To-do: bonus implementation
// public int Style = 0; // To-do: style implementation

// Timing
public int Ticks {get; set;} = 0; // To-do: sub-tick counting? This currently goes on OnTick, which is not sub-tick I believe? Needs investigating
public int Ticks { get; set; } = 0; // To-do: sub-tick counting? This currently goes on OnTick, which is not sub-tick I believe? Needs investigating

// Time Formatting
public enum TimeFormatStyle
{
Compact,
Full,
Verbose
}

// Methods
public void Reset()
{
this.Stop();
this.Ticks = 0;
this.Stage = 0;
this.Paused = false;
this.PracticeMode = false;
this.IsPaused = false;
this.IsPracticeMode = false;
}

public void Pause()
{
this.Paused = true;
this.IsPaused = true;
}

public void Start()
{
// Timer Start method - notes: OnStartTimerPress
if (this.Enabled)
if (this.IsEnabled)
this.IsRunning = true;
}

Expand All @@ -51,9 +59,9 @@ public void Tick()
{
// Tick the timer - this checks for any restrictions, so can be conveniently called from anywhere
// without worry for any timing restrictions (eg: Paused, Enabled, etc)
if (this.Paused || !this.Enabled || !this.IsRunning)
if (this.IsPaused || !this.IsEnabled || !this.IsRunning)
return;

this.Ticks++;
}
}