UI/TrickScore.razor
@using Skateboard.Player
@using Skateboard.Tricks
@inherits PanelComponent

<root>
	<div class="@GetMultiplierClass()">@_multiplierText</div>
	<div class="@GetTrickClass()">@_trickText</div>
</root>

@code
{
	private float _displayTime;
	private const float MaxDisplayTime = 5f;
	private bool _lastFinished;
	private int _pulseTick;

	private string _multiplierText = "";
	private string _trickText = "";
	private bool _done;
	private bool _failed;
	private bool _fadeout;
	private bool _visuallyEmpty;

	protected override void OnStart()
	{
		TrickScoreHolder.OnLocalTrickScoreUpdate += OnTrickScoreUpdate;
	}

	protected override void OnDestroy()
	{
		TrickScoreHolder.OnLocalTrickScoreUpdate -= OnTrickScoreUpdate;
	}

	private void OnTrickScoreUpdate()
	{
		_displayTime = 0f;
		_pulseTick++;
		StateHasChanged();
	}

	protected override void OnUpdate()
	{
		var holder = SkatePawn.Local?.TrickScores;
		if ( holder is null )
			return;

		if ( _displayTime < MaxDisplayTime && holder.Finished )
			_displayTime += Time.Delta;

		if ( _lastFinished != holder.Finished )
		{
			_lastFinished = holder.Finished;
			_displayTime = 0f;
		}

		var visuallyEmpty = holder.VisuallyEmpty;
		var multiplierText = visuallyEmpty ? "" : $"{holder.Score} x {holder.Multiplier}";
		var trickText = visuallyEmpty ? "" : holder.String;
		var done = holder.Finished;
		var failed = holder.Failed;
		var fadeout = _displayTime >= MaxDisplayTime;

		if ( _visuallyEmpty == visuallyEmpty &&
			 _multiplierText == multiplierText &&
			 _trickText == trickText &&
			 _done == done &&
			 _failed == failed &&
			 _fadeout == fadeout )
			return;

		_visuallyEmpty = visuallyEmpty;
		_multiplierText = multiplierText;
		_trickText = trickText;
		_done = done;
		_failed = failed;
		_fadeout = fadeout;

		StateHasChanged();
	}

	private string GetMultiplierClass()
	{
		return BuildClass( $"multiplier skate-trick-text {GetPulseClass()}" );
	}

	private string GetTrickClass()
	{
		return BuildClass( $"tricks skate-trick-text {GetPulseClass()}" );
	}

	private string BuildClass( string baseClass )
	{
		if ( _visuallyEmpty )
			return $"{baseClass} hidden";

		if ( _fadeout )
			baseClass += " fadeout";

		if ( _failed )
			baseClass += " failed";
		else if ( _done )
			baseClass += " done";

		return baseClass;
	}

	private string GetPulseClass()
	{
		return _pulseTick % 2 == 0 ? "pulse pulse-a" : "pulse pulse-b";
	}
}