ArmorDisplay.cs
using Sandbox;
using Sandbox.UI;
using Sandbox.UI.Construct;
using SWB.Player;
using System;
// The armour bar. Sits directly above SWB's health box and is built to the
// same look, so the two read as a pair: health on the bottom, the vest
// protecting it on top.
//
// A plain Panel rather than a PanelComponent, because it lives inside
// SWB's RootDisplay the same way HealthDisplay does. RootDisplay already
// handles only existing on the local player's screen and hiding while
// scoped, so this gets both for free.
//
// Hidden entirely when there's no vest. An empty bar would just be a
// permanent reminder of something you didn't buy.
public class ArmorDisplay : Panel
{
readonly PlayerBase _player;
Label _valueLabel;
Panel _fill;
public ArmorDisplay( PlayerBase player )
{
_player = player;
StyleSheet.Load( "/ArmorDisplay.cs.scss" );
Add.Label( "armor", "name" );
_valueLabel = Add.Label( "", "value" );
var bar = Add.Panel( "bar" );
_fill = bar.Add.Panel( "fill" );
}
public override void Tick()
{
// Looked up each tick rather than cached: it's one component
// lookup, and caching it would mean handling the loadout not
// existing yet on the first few frames.
var loadout = _player?.Components.Get<PlayerLoadout>();
var show = loadout is not null && _player.IsAlive && loadout.HasArmor;
SetClass( "hide", !show );
if ( !show )
return;
var max = MathF.Max( loadout.MaxArmorHealth, 1f );
var fraction = MathX.Clamp( loadout.ArmorHealth / max, 0f, 1f );
// Rounded UP for display. The vest still works at 0.3, and showing
// "0" while it's still cutting your damage would be a lie.
_valueLabel.Text = MathF.Ceiling( loadout.ArmorHealth ).ToString();
_fill.Style.Width = Length.Fraction( fraction );
// Goes amber in its last quarter, as a heads-up that the next few
// hits are the last ones it'll take.
SetClass( "low", fraction <= 0.25f );
}
}