fix(engine): drop duplicate "You Win" toast — WinSummary modal owns the celebration

The post-win UI was firing TWO celebration surfaces on every
GameWonEvent:

  - animation_plugin::handle_win_cascade spawned a 4-second toast:
    "You Win!  Score: {score}  Time: {m}:{ss}"
  - win_summary_plugin spawned the proper "You Won!" modal with
    score breakdown, time bonus, achievements unlocked, XP earned,
    and a Play Again button

Both rendered on top of each other — in screenshots the toast
banner was partially clipped behind the modal card, peeking out
on either side. The toast predates the WinSummary modal; the
modal carries strictly more information so the toast is dead
weight.

handle_win_cascade keeps the cards-fly-off animation
(MotionCurve::Expressive cascade with per-card rotation drift) —
that's the visual celebration, distinct from the textual
celebration the modal owns. The system still gates on the same
GameWonEvent message reader; it just doesn't write a toast
afterward. WIN_TOAST_SECS const removed (no remaining callers).

Workspace: 1172 passing tests / 0 failing. cargo clippy
--workspace --all-targets -- -D warnings clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-05-06 19:35:04 -07:00
parent 21ec03b157
commit 55c235b55f
+8 -8
View File
@@ -61,7 +61,6 @@ fn anim_speed_to_secs(speed: &AnimSpeed) -> f32 {
scaled_duration(MOTION_SLIDE_SECS, *speed)
}
const WIN_TOAST_SECS: f32 = 4.0;
const ACHIEVEMENT_TOAST_SECS: f32 = 3.0;
const LEVELUP_TOAST_SECS: f32 = 3.0;
const DAILY_TOAST_SECS: f32 = 3.0;
@@ -266,9 +265,15 @@ fn handle_win_cascade(
layout: Option<Res<LayoutResource>>,
settings: Option<Res<SettingsResource>>,
) {
let Some(ev) = events.read().next() else {
// Drain the event reader; the cascade visual is the only thing
// this system contributes — the post-win "You Won!" modal
// (`win_summary_plugin`) consumes the same `GameWonEvent` and
// carries score / time / achievements / XP itself, so a duplicate
// toast saying "You Win! Score X Time Y" rendered behind the modal
// in earlier builds. Removed.
if events.read().next().is_none() {
return;
};
}
let margin = layout.as_ref().map_or(800.0, |l| l.0.card_size.x * 8.0);
@@ -284,11 +289,6 @@ fn handle_win_cascade(
Vec3::new(-margin, 0.0, 300.0),
];
let m = ev.time_seconds / 60;
let s = ev.time_seconds % 60;
let win_msg = format!("You Win! Score: {} Time: {m}:{s:02}", ev.score);
spawn_toast(&mut commands, win_msg, WIN_TOAST_SECS);
let step = settings
.as_ref()
.map_or(CASCADE_STAGGER_NORMAL, |s| cascade_step_secs(s.0.animation_speed));