UI/TeleportOverlay.razor

Razor UI component for the teleport overlay shown while a player is riding a teleporter. It renders a single panel and each frame sets its background image and opacity every update using values from TeleportOverlayState.

File Access
@using Sandbox;
@using Sandbox.UI;
@using System;
@using NZombies;
@inherits PanelComponent

@*
    TELEPORT OVERLAY — what a rider sees while in transit.

    ⛔ IT PLAYS ELEMENTAL POP'S FRAMES. `ui/nz/cherry/shock_NN.png` is 21 frames of blue
    electrical arcs that already carry alpha. Der Riese's own `codtele.vtf` was the
    alternative and is worse on every axis: 41 DXT1 frames with NO alpha channel, so it
    would need alpha derived from luminance, and it costs 4 MB (75 MB for all four
    upstream styles). Same read, no new assets.

    ⛔ A SEPARATE PANEL FROM CherryShockHud, NOT A REUSE OF IT. Cherry Shock is a fixed
    0.7s one-shot with a decaying shake; a transit is a variable hold with no shake.
    Sharing the panel would mean one of them driving the other's playback. They share
    the FRAMES, which is the expensive part, and nothing else.

    ⚠️ DRAWS INDEPENDENTLY OF THE SURVIVAL HUD'S `Visible`, like the powerup banner and
    Cherry Shock — a teleporter can be ridden in creative, where that HUD is hidden.
*@

<root class="teleport-overlay">
    <div @ref="Frame" class="frame"></div>
</root>

@code
{
    /// <summary>
    /// ⛔ CONSTANT, like CherryShockHud's. Every visible property — the frame image and
    /// the opacity — is written to Style per frame, and a hash tracking the frame index
    /// would rebuild the tree 24 times a second for something a style write handles.
    /// </summary>
    protected override int BuildHash() => 0;

    Panel Frame;

    // ⚠️ NO STATE HERE. The phase, length, frame index and switch all live in
    // TeleportOverlayState, because gameplay code has to reach them and a generated
    // razor class is not reachable from it. This file is only the drawing.

    protected override void OnUpdate()
    {
        if ( Frame is null ) return;

        var index = TeleportOverlayState.Frame;

        if ( index < 0 )
        {
            Frame.Style.Opacity = 0f;
            return;
        }

        Frame.Style.Opacity = TeleportOverlayState.Opacity;
        Frame.Style.SetBackgroundImage( $"ui/nz/cherry/shock_{index:00}.png" );
    }
}