fix(engine): resolve input coordination bugs in selection/pause/keyboard
- SelectionPlugin: add clear_selection_on_state_change system so undo/move/reject never leave a stale selection pointing at the wrong card - SelectionPlugin: expose SelectionKeySet system set for cross-plugin ordering - PausePlugin: skip Escape→pause when a card is keyboard-selected; toggle_pause now runs before SelectionKeySet so it reads SelectionState before it is cleared - InputPlugin: guard Space→DrawRequestEvent when SelectionState has an active pile so Space executes a card move instead of also drawing from stock - window: enforce 800×600 minimum via WindowResizeConstraints - game_state: add precondition doc to next_auto_complete_move (waste exclusion) - card_plugin: 12 unit tests for constants, face_colour, label_visibility, label_for - pause_plugin: add paused_resource_default and draw_mode_label exhaustiveness tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,7 @@ use crate::events::StateChangedEvent;
|
||||
use crate::game_plugin::{GameOverScreen, GameStatePath};
|
||||
use crate::progress_plugin::ProgressResource;
|
||||
use crate::resources::{DragState, GameStateResource};
|
||||
use crate::selection_plugin::{SelectionKeySet, SelectionState};
|
||||
use crate::settings_plugin::{SettingsChangedEvent, SettingsResource, SettingsStoragePath};
|
||||
use crate::stats_plugin::StatsResource;
|
||||
|
||||
@@ -58,7 +59,15 @@ impl Plugin for PausePlugin {
|
||||
app.add_message::<SettingsChangedEvent>()
|
||||
.add_message::<StateChangedEvent>()
|
||||
.init_resource::<PausedResource>()
|
||||
.add_systems(Update, (toggle_pause, handle_pause_draw_toggle));
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
// toggle_pause must see SelectionState *before* handle_selection_keys
|
||||
// clears it, so it can skip Escape when a card is selected.
|
||||
toggle_pause.before(SelectionKeySet),
|
||||
handle_pause_draw_toggle,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,10 +85,16 @@ fn toggle_pause(
|
||||
settings: Option<Res<SettingsResource>>,
|
||||
mut drag: Option<ResMut<DragState>>,
|
||||
mut changed: MessageWriter<StateChangedEvent>,
|
||||
selection: Option<Res<SelectionState>>,
|
||||
) {
|
||||
if !keys.just_pressed(KeyCode::Escape) {
|
||||
return;
|
||||
}
|
||||
// If a card is currently selected, let SelectionPlugin handle this Escape
|
||||
// (it will clear the selection). Pause must not also open in the same frame.
|
||||
if selection.is_some_and(|s| s.selected_pile.is_some()) {
|
||||
return;
|
||||
}
|
||||
// If the game-over overlay is visible, let handle_game_over_input consume
|
||||
// the Escape key (to start a new game). Do not open the pause overlay.
|
||||
if !game_over_screens.is_empty() {
|
||||
@@ -415,6 +430,16 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// PausedResource default (pure)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn paused_resource_default_is_unpaused() {
|
||||
let p = PausedResource::default();
|
||||
assert!(!p.0, "game must start unpaused");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// draw_mode_label (pure function) — Task #64
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -429,6 +454,17 @@ mod tests {
|
||||
assert_eq!(draw_mode_label(DrawMode::DrawThree), "Draw 3");
|
||||
}
|
||||
|
||||
/// Both variants are covered so the match is exhaustive — this test would
|
||||
/// fail to compile if a new DrawMode variant were added without updating
|
||||
/// `draw_mode_label`.
|
||||
#[test]
|
||||
fn draw_mode_label_covers_all_variants() {
|
||||
for mode in [DrawMode::DrawOne, DrawMode::DrawThree] {
|
||||
let label = draw_mode_label(mode);
|
||||
assert!(!label.is_empty(), "draw_mode_label must never return an empty string");
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// pause_draw_toggle_flips_draw_mode — Task #64
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user