DiamondPanel.Restart.cs
using System;
using Sandbox;
namespace Diamonds;
public sealed partial class DiamondPanel
{
const float RestartFrameWidth = 400, RestartFrameHeight = 132, RestartBarWidth = 320, RestartBarHeight = 10;
// Hotload leaves new fields at their defaults, so an idle, unlatched hold must be the default state.
float restartHeld, restartShownProgress, restartOverlay, restartColorPhase;
bool restartHolding, restartLatched;
/// <summary>The restart key is held and counting toward its delay.</summary>
public bool RestartHolding => restartHolding;
/// <summary>Held fraction of the restart delay, from zero to one.</summary>
public float RestartProgress => restartShownProgress;
/// <summary>
/// Count a held restart key toward <paramref name="delay"/> seconds. Releasing it discards the progress. Completing a hold
/// fades out, restarts through <see cref="PlayRequested"/> and fades back in. Returns true when a zero delay asks the
/// caller to restart instantly instead. Presses during the title, an overlay or a fade are latched until release,
/// so a key still held afterwards never restarts by itself.
/// </summary>
public bool UpdateRestartHold( float delta, bool down, float delay )
{
delta = MathF.Max( 0, delta );
restartColorPhase = (restartColorPhase + delta * 2.4f) % Palette.Length;
bool allowed = !TitleScreen && !ModalOpen && !TransitionPending;
bool instant = false;
if ( !down ) restartLatched = false;
restartHolding = false;
if ( down && !restartLatched )
{
if ( !allowed ) restartLatched = true;
else if ( delay <= 0 ) { restartLatched = true; instant = true; }
else
{
restartHeld += delta;
restartShownProgress = Math.Clamp( restartHeld / delay, 0, 1 );
if ( restartHeld >= delay )
{
restartLatched = true;
BeginTransition( true );
}
else restartHolding = true;
}
}
if ( !restartHolding ) restartHeld = 0;
if ( instant || !allowed && !TransitionPending ) restartOverlay = 0;
// Appear quickly, and let a completed hold fade under the black rather than vanish.
else restartOverlay = restartHolding ? MathF.Min( 1, restartOverlay + delta / 0.06f ) : MathF.Max( 0, restartOverlay - delta / 0.12f );
return instant;
}
/// <summary>Drop the hold and its overlay at once, for a restart switch, a new game or a disabled panel.</summary>
public void ClearRestartHold()
{
restartHeld = restartShownProgress = restartOverlay = 0;
restartHolding = false;
}
float RestartOverlayFade => restartOverlay * restartOverlay * (3 - 2 * restartOverlay);
/// <summary>A light screen-wide dimming with the RESTARTING bar above it; gameplay keeps running beneath.</summary>
void DrawRestartHold( Painter p, Matrix screenTransform, Vector2 center, float canvasScale )
{
if ( restartOverlay <= 0 || TitleScreen ) return;
float fade = RestartOverlayFade;
using var scope = p.Scope();
var canvasTransform = p.Transform;
p.Transform = screenTransform;
p.Stroke = Stroke.None;
p.Fill = Color.Black.WithAlpha( 0.3f * fade );
p.Rect( p.Bounds );
p.Transform = canvasTransform;
var frame = new Rect( center - new Vector2( RestartFrameWidth, RestartFrameHeight ) * 0.5f, new Vector2( RestartFrameWidth, RestartFrameHeight ) );
p.Fill = Color.Parse( "#0d151e" ).Value.WithAlpha( 0.96f * fade );
p.Rect( frame );
var color = ScoreColor( restartColorPhase );
DrawScoreNumber( p, "RESTARTING", center + new Vector2( 0, -22 ), 34, Ink.WithAlpha( fade ) );
var track = new Rect( center + new Vector2( -RestartBarWidth * 0.5f, 30 - RestartBarHeight * 0.5f ), new Vector2( RestartBarWidth, RestartBarHeight ) );
p.Stroke = Stroke.None;
p.Fill = Ink.WithAlpha( 0.08f * fade );
p.Rect( track );
float fill = track.Width * restartShownProgress;
if ( fill <= 0 ) return;
p.Fill = color.WithAlpha( 0.14f * fade );
p.Rect( new Rect( track.Left, track.Center.y - 9, fill, 18 ) );
p.Fill = color.WithAlpha( 0.9f * fade );
p.Rect( new Rect( track.Left, track.Top, fill, track.Height ) );
// Keep the leading edge crisp at any canvas scale.
p.Fill = Color.Lerp( color, Color.White, 0.6f ).WithAlpha( fade );
p.Rect( new Rect( track.Left + fill - 2 / canvasScale, track.Top, 2 / canvasScale, track.Height ) );
}
}