A UI Razor component that renders the player's perk icons. It selects either the currently selected player or the local player, chooses display height, and shows either proxy (synced) perks with PerkIconStatic or local PerkIcon entries with a small random rotation per icon. It also overrides BuildHash to provide a render invalidation hash based on player, perk count, perk hash, and game over state.
@namespace Sandbox
@using Sandbox;
@using Sandbox.UI;
@using System;
@inherits Panel
@attribute [StyleSheet("PlayerPerks.razor.scss")]
@{
var player = Manager.Instance.SelectedPlayer.IsValid()
? Manager.Instance.SelectedPlayer
: Manager.Instance.LocalPlayer;
if (!player.IsValid())
return;
var height = Manager.Instance.Players.Count > 1 ? 880f : 950f;
}
<root style="height: @(height)px; max-height: @(height)px;">
@if( player.IsProxy )
{
if (player.SyncPerks.Count == 0)
return;
int index = 0;
<div class="itemlist" style="opacity:@(1f);">
@foreach (var pair in player.SyncPerks)
{
var rot = Utils.Map((player.PerkRandomRotationSeed + index * 3f) % 10, 0, 9, -5f, 5f);
<PerkIconStatic style="width: 50px; height: 50px; transform: rotate(@(rot)deg);" PerkType=@(PerkManager.IdentityToType(pair.Key)) Level=@(pair.Value) ProgressLevel=@(pair.Value) Banished=@false />
index++;
}
</div>
}
else
{
if (player.Perks.Count == 0)
return;
int index = 0;
<div class="itemlist @(Manager.Instance.IsGameOver ? "" : "itemlist_hover")">
@foreach (var (_, perk) in player.Perks)
{
var rot = Utils.Map((player.PerkRandomRotationSeed + index * 3f) % 10, 0, 9, -5f, 5f);
<PerkIcon style="width: 50px; height: 50px;" Perk=@perk Angle=@rot Banished=@false />
index++;
}
</div>
}
</root>
@code
{
protected override int BuildHash()
{
var player = Manager.Instance.SelectedPlayer.IsValid()
? Manager.Instance.SelectedPlayer
: Manager.Instance.LocalPlayer;
var perkHash = player.IsValid()
? player.PerkHash
: 0;
var perkCount = player.IsValid()
? player.SyncPerks.Count
: 0;
return HashCode.Combine(
player,
// player.Id // todo: this instead?
perkCount,
perkHash,
Manager.Instance.IsGameOver
// Time.Now
);
}
}