UI/EnemyVitals.razor
@using Sandbox
@using Sandbox.UI
@using System
@namespace Prototype
@inherits PanelComponent

<root class="@(Enemy?.Spec.Role == EnemyRole.Boss ? "boss" : "")">
	@if ( Enemy?.Vitality is not null && !Enemy.Vitality.IsDead )
	{
		<div class="enemy-name">@Enemy.Spec.Role.ToString().ToUpperInvariant()</div>
		<div class="bar">
			<div class="lost" style="width:@DisplayedHealthPercent%"></div>
			<div class="fill" style="width:@HealthPercent%"></div>
			<span>@MathF.Ceiling(Enemy.Vitality.Health) / @MathF.Ceiling(Enemy.Vitality.MaxHealth)</span>
		</div>

	}
</root>

@code {
	public EnemyBrain Enemy { get; set; }
	float _displayedHealth = 1f;
	float HealthPercent => Enemy?.Vitality is null ? 0f : Math.Clamp( Enemy.Vitality.Health / MathF.Max( 1f, Enemy.Vitality.MaxHealth ) * 100f, 0f, 100f );
	float DisplayedHealthPercent => Math.Clamp( _displayedHealth * 100f, 0f, 100f );

	protected override void OnStart()
	{
		_displayedHealth = Enemy?.Vitality is null ? 1f : Enemy.Vitality.Health / MathF.Max( 1f, Enemy.Vitality.MaxHealth );
	}

	protected override void OnUpdate()
	{
		if ( Enemy is null || !Enemy.IsValid ) return;
		var target = Enemy.Vitality is null ? 0f : Enemy.Vitality.Health / MathF.Max( 1f, Enemy.Vitality.MaxHealth );
		_displayedHealth = MathX.Lerp( _displayedHealth, target, Time.Delta * 4f );
		StateHasChanged();
	}

	protected override int BuildHash() => HashCode.Combine( Enemy?.Vitality?.Health, (int)(_displayedHealth * 1000f) );
}