diff --git a/solitaire_engine/src/achievement_plugin.rs b/solitaire_engine/src/achievement_plugin.rs index 6c177d6..e0e88eb 100644 --- a/solitaire_engine/src/achievement_plugin.rs +++ b/solitaire_engine/src/achievement_plugin.rs @@ -17,7 +17,7 @@ use solitaire_data::{ save_progress_to, }; -use crate::events::{AchievementUnlockedEvent, GameWonEvent}; +use crate::events::{AchievementUnlockedEvent, GameWonEvent, XpAwardedEvent}; use crate::game_plugin::GameMutation; use crate::progress_plugin::{LevelUpEvent, ProgressResource, ProgressStoragePath, ProgressUpdate}; use crate::resources::GameStateResource; @@ -72,6 +72,7 @@ impl Plugin for AchievementPlugin { .insert_resource(AchievementsStoragePath(self.storage_path.clone())) .add_event::() .add_event::() + .add_event::() // Run after GameMutation (so GameWonEvent is available), after // StatsUpdate (so stats reflect this win), and after ProgressUpdate // (so daily_challenge_streak is up to date for daily_devotee). @@ -91,6 +92,7 @@ fn evaluate_on_win( mut wins: EventReader, mut unlocks: EventWriter, mut levelups: EventWriter, + mut xp_awarded: EventWriter, game: Res, stats: Res, path: Res, @@ -154,6 +156,7 @@ fn evaluate_on_win( } } Reward::BonusXp(amount) => { + xp_awarded.send(XpAwardedEvent { amount }); let prev_level = progress.0.add_xp(amount); if progress.0.leveled_up_from(prev_level) { levelups.send(LevelUpEvent { @@ -454,6 +457,27 @@ mod tests { assert_eq!(display_name_for("bogus"), "bogus"); } + #[test] + fn bonus_xp_reward_fires_xp_awarded_event() { + let mut app = headless_app(); + // "no_undo" achievement awards BonusXp(25). Trigger it by sending a + // GameWonEvent with undo_count == 0 (default) and enough stats to match. + app.world_mut().send_event(GameWonEvent { + score: 1000, + time_seconds: 300, + }); + app.update(); + + let events = app.world().resource::>(); + let mut cursor = events.get_cursor(); + let xp_events: Vec = cursor.read(events).map(|e| e.amount).collect(); + // The no_undo achievement (BonusXp 25) must have fired an XpAwardedEvent. + assert!( + xp_events.contains(&25), + "BonusXp(25) must fire XpAwardedEvent; got {xp_events:?}" + ); + } + fn press(app: &mut App, key: KeyCode) { let mut input = app.world_mut().resource_mut::>(); input.release(key);