Model for the scoreboard UI. Holds gamemode enum, round clock, TDM/Domination scores, domination point ownership and labels, and simple FFA player stats; provides clock formatting and a Tick method to decrement time.
using System;
namespace Goo.FpsUI;
// Which gamemode header to render.
public enum ScoreboardMode { Tdm, Domination, Ffa }
// Ownership of a Domination capture point.
public enum CapOwner { Neutral, Friendly, Enemy }
// Gamemode scoreboard logic: timer plus the per-mode score state. Engine-free, mutate the public
// fields from your game (eg hud.Scoreboard.FriendlyScore = 42) and the header updates next frame.
public sealed class ScoreboardModel
{
public ScoreboardMode Mode = ScoreboardMode.Tdm; // which header variant renders
public float TimeRemaining = 600f; // round clock in seconds (counts down)
public int ScoreLimit = 100; // shown as the target score
// ---- TDM / Domination ----
public int FriendlyScore;
public int EnemyScore;
// ---- Domination capture points ----
public CapOwner[] Points = { CapOwner.Friendly, CapOwner.Neutral, CapOwner.Enemy };
public string[] PointLabels = { "A", "B", "C" };
// ---- FFA ----
public int PlayerScore;
public int PlayerRank = 1; // 1-based placement
public int PlayerCount = 8; // total players
public int LeaderScore;
// Round clock formatted MM:SS. Uses U+2236 RATIO, NOT ':', because the engine label renderer
// drops a mid-string ASCII colon ("05:28" would render "0528").
public string Clock => FormatClock( TimeRemaining );
public static string FormatClock( float seconds )
{
if ( seconds < 0f ) seconds = 0f;
int total = (int)seconds;
return $"{total / 60:D2}∶{total % 60:D2}";
}
public bool Tick( float dt ) // count the clock down, always "moving" so the header keeps repainting
{
if ( TimeRemaining > 0f ) TimeRemaining = MathF.Max( 0f, TimeRemaining - dt );
return true;
}
}