feat(engine): add Modes dropdown with Classic/Daily/Zen/Challenge/Time Attack
Continues the UI-first pass. The five game modes were each behind a keyboard shortcut (N/Z/X/T/C) with no visible UI affordance, three of them additionally gated by an unlock level the player has to discover themselves. Add a "Modes ▾" button to the action bar that toggles a popover panel beneath. Each row dispatches the same code path the keyboard accelerator uses by writing a new `Start*RequestEvent` (or `NewGameRequestEvent` for Classic): - Classic → NewGameRequestEvent::default() - Daily Challenge → StartDailyChallengeRequestEvent - Zen → StartZenRequestEvent - Challenge → StartChallengeRequestEvent - Time Attack → StartTimeAttackRequestEvent The existing keyboard handlers in input_plugin (Z), challenge_plugin (X), time_attack_plugin (T), and daily_challenge_plugin (C) now read either their key or the matching request event, so level gates, TimeAttackResource setup, daily seed lookup, and toast feedback for locked modes all stay in their owning plugins — the popover never duplicates that logic. The popover only lists modes available to the player: Classic always shows, Daily Challenge shows when DailyChallengeResource is loaded, and Zen/Challenge/Time Attack show once the player reaches level 5 (the existing CHALLENGE_UNLOCK_LEVEL). Click handler despawns the popover after dispatch; clicking the Modes button again toggles it shut. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,36 @@ pub struct PauseRequestEvent;
|
||||
#[derive(Message, Debug, Clone, Copy, Default)]
|
||||
pub struct HelpRequestEvent;
|
||||
|
||||
/// Request to start a Zen-mode game. Fired by the HUD Modes-popover "Zen"
|
||||
/// row alongside the existing `Z` accelerator. The handler in
|
||||
/// `input_plugin` enforces the level gate (Zen unlocks at level 5) and
|
||||
/// shows an informational toast when locked.
|
||||
#[derive(Message, Debug, Clone, Copy, Default)]
|
||||
pub struct StartZenRequestEvent;
|
||||
|
||||
/// Request to start the next Challenge-mode game. Fired by the HUD
|
||||
/// Modes-popover "Challenge" row alongside the existing `X` accelerator.
|
||||
/// The handler in `challenge_plugin` enforces the level gate, picks the
|
||||
/// next seed from `progress.challenge_index`, and writes the
|
||||
/// corresponding `NewGameRequestEvent`.
|
||||
#[derive(Message, Debug, Clone, Copy, Default)]
|
||||
pub struct StartChallengeRequestEvent;
|
||||
|
||||
/// Request to start a Time Attack session. Fired by the HUD
|
||||
/// Modes-popover "Time Attack" row alongside the existing `T`
|
||||
/// accelerator. The handler in `time_attack_plugin` enforces the level
|
||||
/// gate, initialises `TimeAttackResource`, and writes the corresponding
|
||||
/// `NewGameRequestEvent`.
|
||||
#[derive(Message, Debug, Clone, Copy, Default)]
|
||||
pub struct StartTimeAttackRequestEvent;
|
||||
|
||||
/// Request to start today's Daily Challenge. Fired by the HUD
|
||||
/// Modes-popover "Daily Challenge" row alongside the existing `C`
|
||||
/// accelerator. The handler in `daily_challenge_plugin` reads
|
||||
/// `DailyChallengeResource::seed` and writes a `NewGameRequestEvent`.
|
||||
#[derive(Message, Debug, Clone, Copy, Default)]
|
||||
pub struct StartDailyChallengeRequestEvent;
|
||||
|
||||
/// Fired by `SyncPlugin` after a pull task resolves and the merged result has
|
||||
/// been persisted to disk. `Ok(SyncResponse)` carries the merged payload plus
|
||||
/// any `ConflictReport`s the merge produced. `Err(String)` carries a
|
||||
|
||||
Reference in New Issue
Block a user