M7.4: Pause menu + save-from-pause, slot rows show wall-clock time
PauseMenuScreen — CanvasLayer overlay on PlayScreen, Layer=50 with ProcessMode=WhenPaused so it stays responsive while the tree is paused. _Ready sets GetTree().Paused=true; Resume/Close/QuitToTitle unpause first. Two sub-states share one VBoxContainer-and-status-label panel: main menu (Resume / ★ Level Up / Save Game / Quicksave / Quit to Title) and slot picker. Save Game flips to the picker, click a slot to write, back returns to main. Esc backs out of picker to main on first press, closes the overlay on a second. CodexTheme applied at the panel root since overlays mount outside PlayScreen's Control tree and theme cascade doesn't cross CanvasLayer boundaries. Level-up button surfaces only when LevelUpFlow.CanLevelUp(pc) returns true (matches MonoGame), and is rendered disabled with a "ships with M8" tooltip — fresh L1 characters won't see it in M7 play-tests. Quit to Title autosaves first (matches MonoGame). A failed autosave doesn't block the quit; better to let the user leave than trap them. Save-from-pause writes to an internal status label inside the panel rather than PlayScreen's save-flash toast — the toast lives on the paused tree branch and would freeze mid-fade. PlayScreen Esc now AddChild(new PauseMenuScreen(this)) instead of BackToTitle. Added paused-guard + Echo filter in _Input. New public PlayerCharacter() accessor lets the pause panel call CanLevelUp. HUD hint updated to "F5 quicksaves · Esc opens pause". SaveSlotFormat — shared helper between SaveLoadScreen (load picker) and PauseMenuScreen (save picker) so both surfaces render rows with the same prefix + in-game time + wall-clock time. Parses SavedAtUtc, converts to local time, renders relative (today/yesterday), short (MMM d, HH:mm within year), or full (yyyy-MM-dd HH:mm), with "<unknown>" fallback for empty headers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -269,6 +269,12 @@ public partial class PlayScreen : Control
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
if (@event is not InputEventKey { Pressed: true } key) return;
|
||||
if (key.Echo) return;
|
||||
// Skip key events while the game is paused — the pause overlay
|
||||
// owns input handling for itself; PlayScreen shouldn't see Esc/F5
|
||||
// again until the overlay closes.
|
||||
if (GetTree().Paused) return;
|
||||
|
||||
switch (key.Keycode)
|
||||
{
|
||||
case Key.F5:
|
||||
@@ -277,11 +283,17 @@ public partial class PlayScreen : Control
|
||||
break;
|
||||
case Key.Escape:
|
||||
GetViewport().SetInputAsHandled();
|
||||
BackToTitle();
|
||||
AddChild(new PauseMenuScreen(this));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Read-only accessor for the live player Character — used
|
||||
/// by <see cref="PauseMenuScreen"/> to surface the level-up affordance
|
||||
/// when eligible.</summary>
|
||||
public Theriapolis.Core.Rules.Character.Character? PlayerCharacter()
|
||||
=> _actors?.Player?.Character;
|
||||
|
||||
private Vector2 ScreenToWorld(Vector2 screenPos)
|
||||
=> _render.Camera.GetCanvasTransform().AffineInverse() * screenPos;
|
||||
|
||||
@@ -594,7 +606,7 @@ public partial class PlayScreen : Control
|
||||
$"{viewBlock}\n" +
|
||||
$"Time: Day {_clock.Day}, {_clock.Hour:D2}:{_clock.Minute:D2}\n" +
|
||||
$"{status}\n" +
|
||||
"F5 quicksaves · Esc → title (pause menu lands M7.4)";
|
||||
"F5 quicksaves · Esc opens pause";
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user