Tricks/TrickScoreHolder.cs
namespace Skateboard.Tricks;
public sealed class TrickScoreHolder : Component
{
public delegate void TrickScoreDelegate();
/// <summary>How many tricks to show in the UI string.</summary>
[Property] public int MaxTricks { get; set; } = 5;
public TrickScoreDelegate OnComboFinish;
public TrickScoreDelegate OnComboFailed;
/// <summary>Client UI hook (local pawn only).</summary>
public static TrickScoreDelegate OnLocalTrickScoreUpdate;
// Replicated state
[Sync( SyncFlags.FromHost )] private bool FailedInternal { get; set; }
[Sync( SyncFlags.FromHost )] private bool FinishedInternal { get; set; }
[Sync( SyncFlags.FromHost )] public int TotalScore { get; set; }
/// <summary>All trick entries in the current combo.</summary>
[Sync( SyncFlags.FromHost )] public NetList<TrickScoreEntry> Entries { get; set; } = new();
[Sync( SyncFlags.FromHost )] public int Multiplier { get; private set; }
[Sync( SyncFlags.FromHost )] public int Score { get; private set; }
/// <summary>Concise display string of the last few trick names.</summary>
[Sync( SyncFlags.FromHost )] public string String { get; private set; } = "";
public bool Failed
{
get => FailedInternal;
set
{
if ( FinishedInternal )
return;
if ( value )
OnComboFailed?.Invoke();
FinishedInternal = value;
FailedInternal = value;
}
}
public bool Finished
{
get => FinishedInternal;
set
{
if ( value && !FinishedInternal )
{
TotalScore += Score * Multiplier;
if ( !VisuallyEmpty )
OnComboFinish?.Invoke();
}
FinishedInternal = value;
if ( !FinishedInternal )
FailedInternal = false;
}
}
public bool Empty => Entries.Count == 0;
public bool VisuallyEmpty => Empty || string.IsNullOrEmpty( String );
public void Reset()
{
Finished = false;
Entries.Clear();
Refresh();
}
public void Refresh()
{
var display = new List<TrickScoreEntry>( MaxTricks );
for ( int i = Entries.Count - 1; i >= 0 && display.Count < MaxTricks; i-- )
{
var e = Entries[i];
if ( !string.IsNullOrEmpty( e?.Name ) )
display.Insert( 0, e );
}
String = string.Join( " + ", display.ConvertAll( x => x.Name ) );
var score = 0;
var mult = 0;
var entryCount = 0;
foreach ( var e in Entries )
{
if ( e == null ) continue;
score += e.Score;
mult += e.Multiplier;
entryCount++;
}
mult += entryCount;
Score = score;
Multiplier = mult;
}
public void Add( TrickScoreEntry entry )
{
if ( !Networking.IsHost )
return;
if ( FinishedInternal )
Reset();
FinishedInternal = false;
Entries.Add( entry );
Refresh();
}
}