Commit Graph

7 Commits

Author SHA1 Message Date
funman300 648cd44387 chore(deps): migrate to Bevy 0.17
- Event/EventReader/EventWriter renamed to Message/MessageReader/MessageWriter
- add_event → add_message for all 67 call sites
- ScrollPosition changed to tuple struct ScrollPosition(Vec2)
- CursorIcon import moved from bevy::winit::cursor to bevy::window
- WindowResolution::from((f32,f32)) removed — use (u32,u32) tuple
- World::send_event → World::write_message in test code

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 13:04:44 -07:00
funman300 c8553dc8c5 chore(deps): migrate to Bevy 0.16, axum 0.8, and other package updates
- Bump bevy 0.15 → 0.16; fixes all breaking API changes:
  ChildBuilder → ChildSpawnerCommands, Parent → ChildOf,
  despawn_descendants → despawn_related::<Children>(),
  despawn_recursive → despawn (now recursive by default),
  EventWriter::send → write, Query::{get_single,get_single_mut}
  → {single,single_mut}, ChildOf::get → parent()
- Bump axum 0.7 → 0.8; remove axum::async_trait from FromRequestParts
- Bump tower_governor 0.4 → 0.8; fix GovernorLayer::new() API
- Bump jsonwebtoken 9 → 10 with rust_crypto feature only
- Bump thiserror 1 → 2, dirs 5 → 6, bcrypt 0.15 → 0.19,
  reqwest 0.12 → 0.13 (rustls feature rename)
- Regenerate .sqlx offline cache for sqlx compile-time query checks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 12:31:12 -07:00
funman300 03227f8c77 feat(engine): playability improvements — rounds 7–9 (#40–#64)
Round 7 — Input & feedback
- H key cycles hints; F1 opens help (conflict resolved)
- N key cancels active Time Attack session
- Hint text distinguishes "draw from stock" vs "recycle waste"
- Forfeit (G) clears AutoCompleteState so chime does not bleed into new deal
- Zen mode timer clears immediately on Z press
- HUD shows recycle count in both draw modes
- Settings scroll position persisted across open/close

Round 8 — Polish & clarity
- Undo unavailable fires "Nothing to undo" toast
- Streak-break toast on forfeit/abandon when streak > 1
- F11 fullscreen toggle with toast; documented in help and home screens
- H-after-win, new-game countdown expiry, Tab-no-cards toasts
- Win cascade duration/stagger scales with animation speed setting
- Draw-Three cycle counter HUD ("Cycle: N/3")
- Forfeit requires G×2 confirmation within 3 s (mirrors N key)

Round 9 — Game feel & information
- Escape dismisses game-over/stuck overlay (PausePlugin skips Escape when overlay visible)
- Shake animation on rejected drag before snap-back
- Forfeit countdown cancels when any other key is pressed (U/H/D/Z/Space)
- Tab wrap-around fires "Back to first card" toast
- HUD selection indicator shows active Tab-selected pile in yellow
- Challenge time-limit HUD turns orange < 60s, red < 30s
- Win summary shows XP breakdown (+50 base, +25 no-undo, +N speed)
- Game-over overlay: "No more moves available" with clear N/Escape/G instructions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 02:35:15 +00:00
root bf150f11f1 test(engine): add boundary tests for format_secs and pause toggle cycle
leaderboard_plugin: format_secs was missing the 60-second crossing
boundary (1:00 vs 60s), the zero case (0s), and leading-zero padding
verification (1:05 not 1:5).

pause_plugin: added third-press test confirming the Esc toggle is
symmetric across multiple pause/resume cycles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 04:06:43 +00:00
root 648c5c18d9 feat(leaderboard): opt-out support — server endpoint, client method, UI button
- Server: DELETE /api/leaderboard/opt-in sets leaderboard_opt_in=0,
  hiding the player without deleting their row (scores preserved for re-opt-in)
- SyncProvider trait: opt_out_leaderboard() default no-op method + blanket impl
- SolitaireServerClient: implements opt_out_leaderboard via DELETE request with JWT refresh
- Leaderboard UI: "Opt Out" button (dark red) alongside existing "Opt In" button
- Server integration test: opt-out hides, opt-in restores (round-trip verified)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 02:01:20 +00:00
root f579b96d76 feat(engine): wire AnimSpeed to animation, new achievements, leaderboard opt-in, daily goal display
- AnimSpeed setting now drives card slide duration (Normal=0.15s, Fast=0.07s, Instant=snap);
  EffectiveSlideDuration resource updated on SettingsChangedEvent; AnimSpeed row added to Settings panel
- GameState.recycle_count tracks waste recycles; perfectionist/comeback/zen_winner achievements added
  with full unit tests
- SyncProvider gains opt_in_leaderboard(); SolitaireServerClient implements POST /api/leaderboard/opt-in;
  Opt In button added to leaderboard panel
- DailyChallengeResource stores goal_description/target_score/max_time_secs from server;
  pressing C shows goal description as toast (DailyGoalAnnouncementEvent)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 01:38:25 +00:00
root d56abcd7a9 feat(engine): leaderboard screen (press L to toggle)
Press L to open a leaderboard overlay. On open, an async fetch is
dispatched against the active SyncProvider. Results cache in
LeaderboardResource; the panel rebuilds live when data arrives.
Closing during a fetch is safe (ClosedThisFrame flag prevents
re-spawning the panel in the same frame as the user's despawn command).
Format: ranked table with player name, best score, and fastest win time.
Non-authenticated / LocalOnly providers return an empty list gracefully.

- solitaire_data: add fetch_leaderboard() to SyncProvider trait
  (default → Ok([])) and implement in SolitaireServerClient
- solitaire_engine: new LeaderboardPlugin with 5 unit tests
- solitaire_app: register LeaderboardPlugin

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 00:38:55 +00:00