UI/GameMenu/PlayerList/PlayerListEntry.razor
@using Sandbox;
@using Sandbox.UI;
@using System;
@attribute [StyleSheet]

@namespace GuessIt

<root class="player @(Player.HasGuessed ? "correct" : "") @(Player.IsDrawing ? "drawing" : "")">
    <div class="avatar @(Player.Network.Owner.IsHost ? "host" : "")" style="background-color: @(Player.Color.Hex);">
        <Image Texture=@(Player.CameraTexture) class="pic" />
        @if (Player.Network.Owner.IsHost)
        {
            <img src="ui/host_frame.png" class="pic" />
        }
        @if (Player.IsDrawing)
        {
            <label class="drawing">✏️</label>
        }
    </div>
    <div class="info">
        <div class="player-name">
            @if (true)
            {
                var name = Player.Network.Owner.DisplayName;
                for (int i = 0; i < name.Length; i++)
                {
                    <label style=@GetCharacterStyle(i)>@name[i]</label>
                }
            }
        </div>
        <div class="player-score">@Player.Score.ToString()</div>
    </div>
    <div class="rank">##@(Rank)</div>
</root>

@code
{
    public Player Player { get; set; }
    public int Rank { get; set; } = 1;

    float VoiceIntensity = 0f;
    float VoiceTimer = 0f;

    public override void Tick()
    {
        base.Tick();

        VoiceIntensity = VoiceIntensity.LerpTo(Player.Voice.Amplitude, Time.Delta * 20f);
        if (VoiceIntensity < 0.01f)
            VoiceIntensity = 0f;

        VoiceTimer += MathF.Max(Time.Delta, Time.Delta * VoiceIntensity);
    }

    string GetCharacterStyle(int index)
    {
        if (VoiceIntensity < 0.05f)
        {
            return "position: relative; top: 0px; color: black;";
        }
        var pixels = MathF.Sin(20f * VoiceTimer + index * 1.2f) * 4f * VoiceIntensity;
        var color = Color.Lerp(Color.Black, new ColorHsv(180f * VoiceTimer + index * 45f, 1f, 1f).ToColor(), VoiceIntensity / 1f);
        return $"position: relative; top: {pixels}px; color: {color.Hex};";
    }

    protected override int BuildHash()
    {
        return HashCode.Combine(Rank, Player?.Score, Player?.ColorHue, Player?.HasGuessed, VoiceIntensity, Player?.IsDrawing);
    }
}