feat(engine): MoveRejectedEvent + PausePlugin (Esc)

- New MoveRejectedEvent fires from end_drag when the cursor is over
  a real pile but the placement is illegal. AudioPlugin plays
  card_invalid.wav on it.
- New PausePlugin + PausedResource: Esc toggles a full-window
  overlay and the flag. tick_elapsed_time and advance_time_attack
  skip work while paused. Help cheat sheet updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-04-25 22:56:35 -07:00
parent adacdf533c
commit b720588687
10 changed files with 214 additions and 25 deletions
+8 -2
View File
@@ -35,6 +35,7 @@ impl Plugin for GamePlugin {
.add_event::<UndoRequestEvent>()
.add_event::<NewGameRequestEvent>()
.add_event::<StateChangedEvent>()
.add_event::<crate::events::MoveRejectedEvent>()
.add_event::<GameWonEvent>()
.add_event::<crate::events::CardFlippedEvent>()
.add_event::<crate::events::AchievementUnlockedEvent>()
@@ -72,13 +73,18 @@ pub fn advance_elapsed(
}
/// Increment `GameState.elapsed_seconds` once per real-world second while
/// the game is in progress (not won). Stops counting on win so the final
/// time reflects how long the player took to solve the deal.
/// the game is in progress (not won) and not paused. Stops counting on
/// win so the final time reflects how long the player took to solve the
/// deal; stops while the pause overlay is open.
fn tick_elapsed_time(
time: Res<Time>,
mut game: ResMut<GameStateResource>,
mut accumulator: Local<f32>,
paused: Option<Res<crate::pause_plugin::PausedResource>>,
) {
if paused.is_some_and(|p| p.0) {
return;
}
let is_won = game.0.is_won;
advance_elapsed(
&mut game.0.elapsed_seconds,