UI/HUD/PlayerHUD.razor
@namespace Sandbox.UI
@using System;
@using System.Linq;
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
<root>
<style>
PlayerHud {
position: absolute;
bottom: 28px;
left: 28px;
width: 360px;
pointer-events: none;
font-family: sans-serif;
}
.player-hud-frame {
flex-direction: row;
align-items: flex-end;
gap: 12px;
background-color: rgba(13, 15, 20, 0.94);
border: 1px solid rgba(229, 169, 60, 0.4);
border-radius: 6px;
padding: 12px 14px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.85);
}
.hud-left-socket .weapon-slot {
width: 68px;
height: 64px;
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 4px;
background-color: rgba(255, 255, 255, 0.05);
flex-direction: column;
justify-content: center;
align-items: center;
gap: 4px;
}
.weapon-name {
font-size: 10px;
font-weight: 800;
color: #e5a93c;
text-transform: uppercase;
text-align: center;
}
.stance-indicator {
font-size: 8px;
font-weight: 700;
color: #94a3b8;
text-transform: uppercase;
}
.hud-gauges {
flex-grow: 1;
flex-direction: column;
}
.hud-diagnostic-warning {
background-color: rgba(245, 158, 11, 0.9);
color: #000000;
font-weight: 800;
font-size: 11px;
padding: 8px;
border-radius: 4px;
}
</style>
@if ( ActiveFighter == null )
{
<div class="hud-diagnostic-warning">
[HUD] Searching for Player Fighter...
</div>
}
else
{
<div class="player-hud-frame">
<div class="hud-left-socket">
<div class="weapon-slot">
<span class="weapon-name">@(Combat?.CurrentWeapon?.GameObject.Name ?? "UNARMED")</span>
<span class="stance-indicator">@(ActiveFighter.IsParrying ? "PARRY" : "GUARD")</span>
</div>
</div>
<div class="hud-gauges">
<StatBar Label="Condition"
Current="@ActiveFighter.CurrentHealth"
Max="@ActiveFighter.MaxHealth"
Ratio="@ActiveFighter.HealthRatio"
BarType="health" />
<StatBar Label="Balance"
Current="@ActiveFighter.CurrentBalance"
Max="@ActiveFighter.MaxBalance"
Ratio="@ActiveFighter.BalanceRatio"
BarType="balance" />
<StatBar Label="Adrenaline"
Current="@ActiveFighter.CurrentAdrenaline"
Max="@ActiveFighter.MaxAdrenaline"
Ratio="@ActiveFighter.AdrenalineRatio"
BarType="adrenaline" />
</div>
</div>
}
</root>
@code {
[Property] public Fighter ManualFighter { get; set; }
private Fighter _cachedFighter;
private FighterCombat _cachedCombat;
private TimeSince _searchThrottle = 1f;
private Fighter ActiveFighter => ManualFighter ?? _cachedFighter;
private FighterCombat Combat => _cachedCombat;
protected override void OnStart()
{
ResolveFighter();
}
protected override void OnUpdate()
{
if ( ActiveFighter == null || !ActiveFighter.IsValid )
{
if ( _searchThrottle >= 0.5f )
{
_searchThrottle = 0f;
ResolveFighter();
}
}
}
private void ResolveFighter()
{
if ( ManualFighter != null && ManualFighter.IsValid )
{
_cachedCombat = ManualFighter.Components.Get<FighterCombat>( FindMode.EverythingInSelfAndDescendants )
?? ManualFighter.Components.Get<FighterCombat>( FindMode.EverythingInSelfAndAncestors );
return;
}
var localFighter = Components.Get<Fighter>( FindMode.EverythingInSelfAndAncestors )
?? Components.Get<Fighter>( FindMode.EverythingInSelfAndDescendants );
if ( localFighter != null )
{
BindTarget( localFighter );
return;
}
var playerCtrl = Scene.GetAllComponents<PlayerController>().FirstOrDefault();
if ( playerCtrl != null )
{
var found = playerCtrl.Components.Get<Fighter>( FindMode.EverythingInSelfAndAncestors )
?? playerCtrl.Components.Get<Fighter>( FindMode.EverythingInSelfAndDescendants );
if ( found != null )
{
BindTarget( found );
return;
}
}
var humanFighter = Scene.GetAllComponents<Fighter>()
.FirstOrDefault( f => f.Components.Get<AiBrain>( FindMode.EverythingInSelfAndAncestors ) == null );
if ( humanFighter != null )
{
BindTarget( humanFighter );
}
}
private void BindTarget( Fighter target )
{
_cachedFighter = target;
_cachedCombat = target.Components.Get<FighterCombat>( FindMode.EverythingInSelfAndDescendants )
?? target.Components.Get<FighterCombat>( FindMode.EverythingInSelfAndAncestors );
}
protected override int BuildHash()
{
if ( ActiveFighter == null ) return 0;
return HashCode.Combine(
(int)ActiveFighter.CurrentHealth,
(int)ActiveFighter.CurrentBalance,
(int)ActiveFighter.CurrentAdrenaline,
ActiveFighter.IsParrying,
Combat?.CurrentWeapon?.GameObject.Id
);
}
}