From f444378184b872f2874520274bd26cc59d9528fa Mon Sep 17 00:00:00 2001 From: funman300 Date: Thu, 28 May 2026 14:24:09 -0700 Subject: [PATCH] fix(engine): toast on challenge exhaustion, block input during auto-complete (#71, #72) - challenge_plugin: replace silent warn+return with InfoToast when all challenges are completed so the player gets clear feedback (#72) - input_plugin: add AutoCompleteState guard to start_drag, touch_start_drag, and handle_double_tap so player input cannot race with the auto-complete move sequence (#71) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- solitaire_engine/src/challenge_plugin.rs | 4 +++- solitaire_engine/src/input_plugin.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/solitaire_engine/src/challenge_plugin.rs b/solitaire_engine/src/challenge_plugin.rs index 0df9782..64f826f 100644 --- a/solitaire_engine/src/challenge_plugin.rs +++ b/solitaire_engine/src/challenge_plugin.rs @@ -93,7 +93,9 @@ fn handle_start_challenge_request( return; } let Some(seed) = challenge_seed_for(progress.0.challenge_index) else { - warn!("challenge seed list is empty"); + info_toast.write(InfoToastEvent( + "You've completed all challenges! More coming soon.".into(), + )); return; }; new_game.write(NewGameRequestEvent { diff --git a/solitaire_engine/src/input_plugin.rs b/solitaire_engine/src/input_plugin.rs index 5293535..d08ef67 100644 --- a/solitaire_engine/src/input_plugin.rs +++ b/solitaire_engine/src/input_plugin.rs @@ -31,6 +31,7 @@ use solitaire_core::game_state::GameState; use solitaire_core::pile::PileType; use solitaire_core::rules::{can_place_on_foundation, can_place_on_tableau}; +use crate::auto_complete_plugin::AutoCompleteState; use crate::card_animation::tuning::AnimationTuning; use crate::card_animation::{CardAnimation, MotionCurve}; use crate::card_plugin::{CardEntity, HintHighlight, HintHighlightTimer, STACK_FAN_FRAC}; @@ -572,6 +573,7 @@ fn start_drag( buttons: Res>, touches: Option>, paused: Option>, + auto_complete: Option>, windows: Query<&Window, With>, cameras: Query<(&Camera, &GlobalTransform)>, layout: Option>, @@ -581,6 +583,9 @@ fn start_drag( if paused.is_some_and(|p| p.0) { return; } + if auto_complete.is_some_and(|ac| ac.active) { + return; + } // Only start a new drag when idle (no touch drag running either). if !buttons.just_pressed(MouseButton::Left) || !drag.is_idle() { return; @@ -858,6 +863,7 @@ fn end_drag( fn touch_start_drag( mut touch_events: MessageReader, paused: Option>, + auto_complete: Option>, cameras: Query<(&Camera, &GlobalTransform)>, layout: Option>, game: Res, @@ -866,6 +872,9 @@ fn touch_start_drag( if paused.is_some_and(|p| p.0) { return; } + if auto_complete.is_some_and(|ac| ac.active) { + return; + } // Only one drag at a time. if !drag.is_idle() { return; @@ -1503,6 +1512,7 @@ fn handle_double_tap( mut touch_events: MessageReader, paused: Option>, radial: Option>, + auto_complete: Option>, drag: Res, game: Res, settings: Option>, @@ -1522,6 +1532,10 @@ fn handle_double_tap( if radial.is_some_and(|r| r.is_active()) { return; } + // Auto-complete owns all moves during its sequence. + if auto_complete.is_some_and(|ac| ac.active) { + return; + } let Some(active_id) = drag.active_touch_id else { return;