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));

}