OverdriveHud.razor
@using Sandbox
@using Sandbox.UI
@using PaintballBaddies
@inherits PanelComponent
@namespace PaintballBaddies
<root>
@if(Visible)
{
<div class="overdrive-status">
<label class="mode">SAUSAGE SURVIVAL</label>
<label class="objective">@Objective</label>
<div class="health @(LowHealth ? "low" : "")"><div class="fill" style=@($"width: {Actor?.OverdriveHealth ?? 0}%;")></div></div>
<label class="detail">@($"{Actor?.OverdriveHealth ?? 0} HEALTH · {Session.TeamScore} PTS · {Actor?.SausageKills ?? 0} KILLS")</label>
<label class="detail">@WeaponStatus</label>
<label class="detail">@($"HEADSHOTS {Actor?.SausageHeadshots%5 ?? 0}/5 · NEXT: {Actor?.NextSpecialName}")</label>
@if(Actor?.GrenadeCharges>0){<div class="grenade-ready @(Actor.FreezeGrenadeReady ? "freeze-ready" : "")"><img src="@(Actor.FreezeGrenadeReady ? "ui/freeze.svg" : "ui/grenade.svg")"/><div><label class="grenade-title">@($"GRENADE ×{Actor.GrenadeCharges}")</label><label class="grenade-key">@($"{GrenadeKey} — THROW · 2s FUSE")</label></div></div>}
@if(Actor?.HotShotSeconds>0){<label class="powerup-ready">@($"HOT SHOT · {(int)System.MathF.Ceiling(Actor.HotShotSeconds)}s")</label>}
</div>
@if(Session.OverdriveWipe>0){<div class="danger">@($"SQUAD DOWN · RECOVER NOW · {(int)System.MathF.Ceiling(12-Session.OverdriveWipe)}s")</div>}
@if(!string.IsNullOrEmpty(GrenadeNotice)){<div class="grenade-notice">@GrenadeNotice</div>}
@if(RestSeconds>0){<div class="gun-rest">LET IT COOL<label>@($"{RestSeconds:0.0}s · TAP FOR CONTROLLED SHOTS")</label></div>}
@if(PlateLocked){<div class="plate-lock">PLATE · FIRE</div>}
@if(KillStreak.Visible){<div class="streak">@KillStreak.Callout</div>}
@if(SwapVisible){<div class="weapon-swap">@(Actor?.HasCrossbow==true ? "CROSSBOW!" : "DUAL PISTOLS!")<label>@(Actor?.HasCrossbow==true ? "EXPLOSIVE BOLTS · 2 SECOND FUSE" : "LEFT, RIGHT, LEFT · BLAST SAUSAGES")</label></div>}
@if(rewardSeconds>0)
{<div class="reward-wrap"><div class="reward-ticket"><label class="reward-kicker">FIVE HEADSHOTS · ORDER UP!</label><label class="reward-title">@Actor.LastPowerup</label><label class="reward-detail">@(Actor.LastPowerup=="FLASH FREEZE READY" ? $"{GrenadeKey} — THROW QUEUED SPECIAL · FREEZE, THEN SHOOT TO SHATTER" : $"{GrenadeKey} — THROW QUEUED SPECIAL · CLEARS NEARBY SAUSAGES")</label></div></div>}
}
</root>
@code {
MultiplayerSession Session=>MultiplayerSession.Find(Scene);
PlayerController Player=>MultiplayerSession.LocalPlayer(Scene);
PaintballCombatant Actor=>Player?.Components.Get<PaintballCombatant>();
bool LowHealth=>Actor is not null && Actor.OverdriveHealth>0 && Actor.OverdriveHealth<=30;
bool SwapVisible=>Actor?.Components.Get<OverdriveLoadout>()?.SwapSeconds>0;
string WeaponStatus=>Actor is null ? "" : $"{(Actor.HasCrossbow ? "CROSSBOW" : "DUAL PISTOLS")} · {PaintballControls.Display(Scene,"slot1")} / {PaintballControls.Display(Scene,"slot2")} OR WHEEL";
string GrenadeNotice=>Scene.GetAllComponents<PaintballControls>().FirstOrDefault()?.GrenadeNotice;
string GrenadeKey=>PaintballControls.Display(Scene,"grenade");
float RestSeconds=>Actor?.Components.Get<PaintballMarker>()?.GunRestRemaining ?? 0;
bool PlateLocked=>Scene.GetAllComponents<PaintballControls>().FirstOrDefault()?.PlateAssist.Locked==true;
bool Visible=>Session?.IsOverdrive==true && Session.InRound && Player.IsValid() && Components.Get<TrainingHud>()?.LoadingArena!=true && Scene.GetAllComponents<PaintballControls>().FirstOrDefault()?.Open!=true;
string Objective=>!OverdriveAssets.Ready ? "DOWNLOADING PROTOTYPE ASSETS…" : Session.OverdrivePhase switch
{
"READY"=>$"SAUSAGES INBOUND · {(int)System.MathF.Ceiling(Session.OverdrivePhaseSeconds)}",
"BREATHER"=>$"WAVE CLEAR · NEXT WAVE IN {(int)System.MathF.Ceiling(Session.OverdrivePhaseSeconds)}",
_=>$"WAVE {Session.OverdriveWave}/3 · {Session.OverdriveRemaining} ENEMIES"
};
private int previousReward=-1,previousRound=-1;
private float rewardSeconds;
protected override void OnUpdate()
{
var session=Session;var actor=Actor;if(session is null || actor is null)return;
rewardSeconds=System.MathF.Max(0,rewardSeconds-Time.Delta);
if(previousRound!=session.RoundId){previousRound=session.RoundId;previousReward=actor.PowerupSerial;rewardSeconds=0;return;}
if(previousReward>=0 && previousReward!=actor.PowerupSerial && session.InRound)
{rewardSeconds=5;KitchenCombatAudio.Play("swap",Player.WorldPosition);}
previousReward=actor.PowerupSerial;
}
protected override int BuildHash()=>!Visible ? 0 : System.HashCode.Combine(
System.HashCode.Combine(Objective,Actor?.OverdriveHealth,Session.TeamScore,Actor?.SausageHeadshots,Actor?.GrenadeCharges,(int)(Actor?.HotShotSeconds ?? 0),PlateLocked),
WeaponStatus+GrenadeKey+GrenadeNotice+Actor?.SpecialQueue,SwapVisible,Actor?.SausageKills,KillStreak.Visible ? KillStreak.Serial : -1,rewardSeconds>0,Actor?.LastPowerup,(int)(RestSeconds*10));
}