FpsUI/Models/ScoreboardModel.cs

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;
    }
}