Ui/ResourcePanel.razor

This Razor component is the resource panel UI. It displays the player's current coins and virtual points, providing different views for spectating or playing a city, and manages UI state changes via match events.

@namespace CitySim
@using CitySim.DesignSystem
@using CitySim.Punchboard
@using CitySim.Match
@inherits MatchPanel

<root class="resources"><PlotterSurface Title=@(City.Multiplayer && City.LocalPlayer==null ? GameText.Get("ui.resource_panel.spectating") : GameText.Get("ui.resource_panel.your_city"))><ChildContent>
@if (City.Multiplayer && City.LocalPlayer==null) { <div class="resource-note">@(GameText.Get("ui.resource_panel.watching_the_city"))</div> }
else { <div class="resource-stats"><PbStat Icon="🪙" [email protected]() Tone=@(PbTone.Accent) Label=@(GameText.Get("ui.resource_panel.coins")) Compact=@true /><PbStat Icon="★" [email protected]() Tone=@(PbTone.Red) Label=@(GameText.Get("ui.resource_panel.vp")) Compact=@true /></div> }
<div class="resource-note">@(City.LocalPlayer is { } player && City.OwnAuction is { } bid ? GameText.Get("ui.resource_panel.coins_available", player.Coins) : GameText.Get("ui.resource_panel.save_coins_for_your_next_build"))</div>
@if (City.LocalPlayer != null) { <EffectTray City=@City /> }
</ChildContent></PlotterSurface></root>

@code {
	int Coins => City?.Feedback?.PresentedCoins ?? City?.OwnAuction?.AvailableCoins ?? City?.LocalPlayer?.Coins ?? 0;
	int Vp => City?.LocalPlayer?.Vp ?? 0;
	float coinRoll;
	int DisplayedCoins => (int)MathF.Round(coinRoll);
	protected override void Subscribe() { coinRoll = Coins; if (BoundMatch != null) { BoundMatch.Events.CoinsChanged += Changed; BoundMatch.Events.VpChanged += Changed; BoundMatch.Events.BidChanged += Bid; BoundMatch.Events.PhaseChanged += Phase; } }
	protected override void Unsubscribe() { if (BoundMatch != null) { BoundMatch.Events.CoinsChanged -= Changed; BoundMatch.Events.VpChanged -= Changed; BoundMatch.Events.BidChanged -= Bid; BoundMatch.Events.PhaseChanged -= Phase; } }
	void Bid(Guid owner) { if (owner == CityGame.Me) Refresh(); }
	void Phase(PhaseChange change) => Refresh();
	void Changed(ResourceChange change) { if (change.Player == CityGame.Me) Refresh(); }
	public override void Tick() { base.Tick(); if (MathF.Abs(coinRoll-Coins) < 0.01f) return; var previous = DisplayedCoins; coinRoll += (Coins-coinRoll)*(1-MathF.Exp(-10*Time.Delta)); if (previous != DisplayedCoins) Refresh(); }
}