UI/TownScreen.razor
@using System;
@using Sandbox;
@using Sandbox.UI;
@* The town is a 3D street; the clickable names float over the buildings (StageHotspots in the scene). *@
<root class="screen">
@foreach ( var h in Spots )
{
var spot = h;
var at = At( spot );
<div class="hotspot @(spot.Target == GameScreen.Arena ? "arena" : "")" style="left: @(at.x)px; top: @(at.y)px;" onclick=@(() => Gm.Go( spot.Target ))>@spot.Label</div>
}
<div class="tabs">
<div class="tab" onclick=@(() => Gm.Go( GameScreen.Stats ))>@(P.StatPoints > 0 ? $"stats (+{P.StatPoints})" : "stats")</div>
<div class="tab" onclick=@(() => Gm.QuitToTitle())>@("save & quit")</div>
</div>
<div class="who outlined">@P.Name · Level @P.Level · @(P.Enslaved ? $"slave ({P.DuelWins}/{Catalog.DuelsToFreedom} duels won)" : $"{P.Wins} wins")</div>
<div class="gold-bar"><div class="coin"></div>@P.Gold</div>
</root>
@code
{
class Spot
{
public StageHotspot Source;
public GameScreen Target;
public string Label;
}
GameManager Gm => GameManager.Instance;
Profile P => Profile.Current;
List<Spot> spots;
List<Spot> Spots
{
get
{
if ( spots is not null ) return spots;
var set = World3D.Instance?.CurrentSet;
if ( !set.IsValid() ) return new();
spots = set.Hotspots.Select( h => new Spot { Source = h, Target = h.Target, Label = Label( h ) } ).ToList();
return spots;
}
}
// a slave's way in is the dungeon
string Label( StageHotspot h ) => h.Target == GameScreen.Arena && P.Enslaved ? "Dungeon Duel" : h.Label;
/// <summary>Where a building's label goes on screen (it follows the 3D camera).</summary>
static Vector2 At( Spot s )
{
var w = World3D.Instance;
if ( !w.IsValid() || !s.Source.IsValid() ) return new Vector2( -500, -500 );
var p = w.ToStage( s.Source.WorldPosition );
return new Vector2( MathF.Round( p.x ), MathF.Round( p.y ) );
}
protected override int BuildHash() => HashCode.Combine( P?.Gold, P?.Level, P?.StatPoints, P?.Name, spots is null, World3D.Instance?.CurrentSet, (int)(RealTime.Now * 20) );
}