A Razor UI panel (InfoPanel) for the game HUD that displays player XP, dash charges, and HP bars and related numeric data. It computes percents and progress, renders progress overlays and small data readouts, and implements BuildHash to provide a UI change hash based on player stats.
@using Sandbox;
@using Sandbox.UI;
@namespace SS1
@inherits Panel
@attribute [StyleSheet("InfoPanel.razor.scss")]
<root>
@{
var xp_percent = Player.ExperienceCurrent / (float)Player.ExperienceRequired;
var hp_percent = Math.Clamp(Math.Max(Player.Health, 0f) / Player.Stats[PlayerStat.MaxHp], 0f, 1f);
// var hp_regen = Player.Stats[PlayerStat.HealthRegen] + (Player.IsMoving ? 0f : Player.Stats[PlayerStat.HealthRegenStill]) + Player.Stats[PlayerStat.HealthDrain];
var hp_regen = Player.Stats[PlayerStat.HealthRegen] + (Player.IsMoving ? 0f : Player.Stats[PlayerStat.HealthRegenStill]);
}
<div class="info_bar">
<div class="info_bar_overlay" style="width:@(xp_percent * 100f)%; background-color: #8888ff33; transition: all 0.2s ease-in-out;"></div>
<div class="info_bar_label">XP</div>
<div class="data_container">
<div class="data" style="opacity: 0.3;">@($"LVL {Player.Level}")</div>
</div>
@*<div class="data" style="opacity: 0.1;">@($"{Player.ExperienceCurrent}/{Player.ExperienceRequired}")</div>*@
</div>
@{
var numDashes = (int)MathF.Round(Player.Stats[PlayerStat.NumDashes]);
}
<div class="info_dash_container">
@for(int i = 0; i < numDashes; i++)
{
var progress = i == Player.NumDashesAvailable ? Player.DashRechargeProgress : (i < Player.NumDashesAvailable ? 1f : 0f);
var isRecharging = i >= Player.NumDashesAvailable;
<div class="info_bar">
<div class="info_bar_overlay" style="width:@(progress * 100f)%; background-color: @(isRecharging ? "#00ff4411" : "#00ff0055");"></div>
@*
<div class="info_bar_label">
@("DASH")
</div>
*@
</div>
}
<div class="info_bar_label">
@("DASH")
</div>
</div>
<div class="info_bar">
<div class="info_bar_overlay" style="width:@(hp_percent * 100f)%; background-color: #ffffffff; transition: all 0.4s ease-in-out;"></div>
<div class="info_bar_overlay" style="width:@(hp_percent * 100f)%; background-color: #ff0000ff; transition: all 0.2s ease-in-out;"></div>
<div class="info_bar_label">HP</div>
<div class="data_container">
<div class="data">@($"{(int)Player.Stats[PlayerStat.MaxHp]}")</div>
<div class="data">/</div>
<div class="data">@($"{(Math.Max(Player.Health, 0f) > 0f && Math.Max(Player.Health, 0f) < 1f ? (int)Math.Ceiling(Math.Max(Player.Health, 0f)) : (int)Math.Floor(Math.Max(Player.Health, 0f)))}")</div>
@if(Math.Abs(hp_regen) > 0f)
{
<div class="data" style="color:@((hp_regen > 0f ? new Color(0f, 1f, 0f) : new Color(1f, 0f, 0f)).Rgba); letter-spacing: 2px; font-size: 22px; padding-right: 10px;">@($"{(hp_regen > 0f ? "+" : "")}{hp_regen.ToString("0.##")}")</div>
}
</div>
</div>
</root>
@code
{
public Player Player { get; set; }
protected override int BuildHash()
{
var hpHash = HashCode.Combine(
Player.Health,
Player.Stats[PlayerStat.MaxHp],
Player.Stats[PlayerStat.HealthRegen],
Player.Stats[PlayerStat.HealthRegenStill],
Player.IsMoving
);
return HashCode.Combine(
Player.ExperienceCurrent,
Player.ExperienceRequired,
Player.DashRechargeProgress,
Player.NumDashesAvailable,
Player.Stats[PlayerStat.NumDashes],
hpHash
);
}
}