Commit Graph

15 Commits

Author SHA1 Message Date
funman300 6b793aa2ab modified: solitaire_engine/src/game_plugin.rs 2026-04-24 20:12:10 -07:00
funman300 363ddc9b75 feat(engine): surface daily/weekly completions as toasts + progression panel
Phase 6 part 3 (partial):
- AnimationPlugin now shows a 3-second toast on DailyChallengeCompletedEvent
  and WeeklyGoalCompletedEvent.
- Stats overlay (S key) appends a Progression section with level, total XP,
  daily streak, and a live Weekly Goals list pulling from WEEKLY_GOALS.

Special modes (Time Attack / Challenge / Zen) and unlock UI deferred.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 19:28:13 -07:00
funman300 b730902d76 feat(engine): add weekly goals with ISO-week rollover and +75 XP bonus
Phase 6 part 2b:
- solitaire_data::weekly defines WeeklyGoalKind, WeeklyGoalDef,
  WeeklyGoalContext, current_iso_week_key, and three starter goals
  (5 wins, 3 no-undo wins, 3 fast wins).
- PlayerProgress gains weekly_goal_week_iso, roll_weekly_goals_if_new_week,
  and record_weekly_progress (returns true exactly once per goal completion).
- WeeklyGoalsPlugin evaluates GameWonEvent against WEEKLY_GOALS, rolls the
  week if needed, increments matching counters, awards WEEKLY_GOAL_XP for
  newly-completed goals, persists progress, and fires
  WeeklyGoalCompletedEvent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 19:25:18 -07:00
funman300 622b35a3bf feat(engine): add daily challenge, level-up toast, and daily_devotee achievement
Phase 6 part 2 (partial):
- daily_seed_for(date) and PlayerProgress::record_daily_completion in
  solitaire_data, with streak logic that increments on consecutive days,
  resets on a skipped day, and is idempotent on same-day re-completions.
- DailyChallengePlugin tracks today's seed, awards +100 XP and updates
  the streak when the player wins a game whose seed matches. Pressing C
  starts a new game with the daily seed.
- LevelUpEvent toast in AnimationPlugin announces level changes.
- AchievementContext gains daily_challenge_streak; daily_devotee
  achievement unlocks at streak >= 7. AchievementPlugin reads
  ProgressResource and runs after ProgressUpdate.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 19:17:59 -07:00
funman300 ef043c14d4 feat(engine): add ProgressPlugin awarding XP on wins with level-up events
On GameWonEvent, computes xp_for_win(time, used_undo) from
solitaire_data, calls PlayerProgress::add_xp, and emits LevelUpEvent
when the level changes. Persists atomically through the configurable
storage path; ProgressPlugin::headless() disables I/O for tests.

Introduces ProgressUpdate system set so future systems can run after
progress mutations.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 19:11:22 -07:00
funman300 1f6994a084 feat(engine): add AchievementPlugin with persistent unlock tracking
On GameWonEvent, build an AchievementContext from StatsResource + GameState
+ wall-clock hour, evaluate ALL_ACHIEVEMENTS, flip newly-satisfied records
to unlocked, persist atomically, and emit AchievementUnlockedEvent for
each new unlock. AnimationPlugin's toast resolves the event's ID to the
achievement's display name via achievement_plugin::display_name_for.

Introduces StatsUpdate system set so AchievementPlugin can reliably run
after StatsResource reflects the win. AchievementPlugin::headless() used
in tests to avoid touching ~/.local/share/solitaire_quest/achievements.json.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 12:53:31 -07:00
funman300 2ce11f8f4d feat(engine): add StatsPlugin with persistent stats and toggleable overlay
StatsPlugin loads stats on startup, persists them on every GameWonEvent
and abandoned NewGameRequestEvent (>=1 move, not won), and provides a
full-window overlay toggled with `S` showing games played/won, win rate,
streak, best score, fastest win, and average win time.

The storage path is configurable via StatsPlugin::storage_path: the
default ctor uses dirs::data_dir(); StatsPlugin::headless() disables
I/O entirely so tests don't read or overwrite the user's real
stats.json. record_abandoned runs before GameMutation so it reads
move_count before handle_new_game clobbers it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 12:43:49 -07:00
Solitaire Quest 4d2379c426 feat(engine): add AnimationPlugin with slide, cascade, and toast (Phase 3F)
- CardAnim component lerps cards from old to new position on every move
- card_plugin now adds CardAnim instead of teleporting cards on state change
- Snap-back on invalid drag reuses the same mechanism (StateChangedEvent)
- Win cascade flies all 52 cards off-screen with staggered delay on GameWonEvent
- Achievement toast scaffold wired to AchievementUnlockedEvent (Phase 5 content)
- Fix input_plugin test: click Queen's visible strip, not geometric centre

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 21:32:42 -07:00
Solitaire Quest a8a323c6c3 chore(deps): replace bevy_egui+bevy_kira_audio with bevy_ui+kira, drop AssetServer 2026-04-23 21:02:46 -07:00
funman300 b3646d6cad modified: solitaire_engine/src/card_plugin.rs
modified:   solitaire_engine/src/input_plugin.rs
2026-04-23 20:48:57 -07:00
funman300 900de7f376 feat(engine): add InputPlugin with keyboard and stock-click
Keyboard: U=undo, N=new game, D=draw, Escape=pause placeholder (logged
only until the pause screen lands). Mouse: left-click on the stock pile
fires DrawRequestEvent. Cursor coordinates are converted via the active
Camera2d's viewport_to_world_2d so the hit-test works under arbitrary
camera setups.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 16:26:40 -07:00
funman300 0a87f0f8f2 feat(engine): add CardPlugin with procedural card rendering
Each card is a parent Sprite (white for face-up, blue for face-down) with
a Text2d child showing rank+suit (e.g. "AH", "10C", "KS"). Hearts and
diamonds render red; clubs and spades black. Face-down labels are hidden.
Tableau cards fan downward; other piles stack at the same position with a
small z-offset.

Sync runs in PostStartup for the initial deal and in Update after every
StateChangedEvent. To avoid a one-frame lag, downstream plugins run after
the new GameMutation system set.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 16:22:49 -07:00
funman300 d92b4a8648 feat(engine): add layout, LayoutResource, and TablePlugin
compute_layout is a pure function that maps window size to card size and
the 13 pile positions, with clamping at the 800x600 minimum and seven
tableau columns horizontally aligned with stock/waste (cols 0,1) and the
four foundations (cols 3,4,5,6). TablePlugin spawns a 2D camera, a felt
background sprite, and 13 translucent pile-marker sprites, and
repositions them on WindowResized. Plugin registers WindowResized
explicitly so it works under MinimalPlugins in tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 16:18:24 -07:00
funman300 c393eab17d feat(engine): add resources, events, and GamePlugin event routing
Introduces the plumbing layer for Phase 3: GameStateResource wraps
solitaire_core::GameState, DragState tracks in-progress drags, and
SyncStatusResource holds runtime sync status. GamePlugin routes
Draw/Move/Undo/NewGame request events into GameState and emits
StateChangedEvent and GameWonEvent for downstream systems.

Also adds the Phase 3 implementation plan under docs/superpowers/plans/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 16:15:38 -07:00
Solitaire Quest 684f07746d feat(workspace): initialize all seven crates with stubs and blank Bevy window
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 11:00:42 -07:00