A Razor UI panel that displays the on-screen interaction prompt (e.g. "Press E - ..."). It reads the current prompt string from UsePrompt.Text(NZPlayer.Local) and renders a centered, styled prompt box when non-empty. BuildHash is overridden to cause re-renders when the prompt changes.
@using Sandbox;
@using Sandbox.UI;
@using System.Linq;
@using NZombies;
@inherits Panel
@*
"Press E - Clear Debris [Cost: 1,000]"
Position ported from cl_target.lua's own draw call:
draw.SimpleTextOutlined( text, font, scw/2, sch - 280*pscale, ... )
⚠️ CENTRED HORIZONTALLY, NOT VERTICALLY. It sits ~26% UP FROM THE BOTTOM —
below the crosshair, above the HUD row. Putting it in the middle of the
screen would sit it on top of the thing you are looking at, which is the one
place it must not be.
⚠️ THE CLASS ON <root> IS LOAD-BEARING. Every panel in this project styles a
class (.lobby, .hud, .devmenu) rather than a bare `root` selector, and this
one did not — so its `pointer-events: none` never applied, leaving a
full-screen interactive panel parked over the lobby eating every click.
The text itself comes from UsePrompt, so the rules stay testable from the
console rather than living in a razor file.
*@
@if ( !string.IsNullOrEmpty( Prompt ) )
{
<div class="use-prompt">
<div class="prompt @(UsePrompt.IsRefusal( Prompt ) ? "refusal" : "")">
<div class="box">@Prompt</div>
</div>
</div>
}
@code
{
/// <summary>
/// ⚠️ Read fresh on every access, not cached in OnUpdate.
///
/// A Panel has no OnUpdate and no Scene of its own — those are Component
/// members, and the previous version inherited PanelComponent purely to get
/// them. Computing it here means the only state is the string, and BuildHash
/// re-renders exactly when the words change.
/// </summary>
string Prompt => UsePrompt.Text(
NZPlayer.Local );
protected override int BuildHash() => System.HashCode.Combine( Prompt );
}