manabrew_engine/ability/effects/
learn_effect.rs1use forge_foundation::ZoneType;
8
9use super::{emit_zone_trigger, EffectContext};
10use crate::event::RunParams;
11use crate::ids::PlayerId;
12use crate::replacement::replacement_handler::{apply_replacements, ReplacementEvent};
13use crate::replacement::ReplacementResult;
14use crate::spellability::SpellAbility;
15use crate::trigger::TriggerType;
16
17#[manabrew_engine_macros::spell_effect(LearnEffect)]
21fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
22 let controller = sa.activating_player;
23
24 let mut event = ReplacementEvent::Learn { player: controller };
26 let result = apply_replacements(ctx.game, &mut event);
27 if result == ReplacementResult::Skipped || result == ReplacementResult::Replaced {
28 return;
29 }
30
31 let players = if let Some(def) = sa.defined_player() {
32 super::resolve_defined_players(def, controller, ctx.game)
33 } else {
34 vec![controller]
35 };
36
37 for pid in players {
38 learn_lesson(ctx, sa, pid);
39 }
40}
41
42fn learn_lesson(ctx: &mut EffectContext, _sa: &SpellAbility, player: PlayerId) {
44 let sideboard_lessons: Vec<crate::ids::CardId> = ctx
46 .game
47 .cards_in_zone(ZoneType::Sideboard, player)
48 .to_vec()
49 .into_iter()
50 .filter(|&cid| {
51 ctx.game
52 .card(cid)
53 .type_line
54 .subtypes
55 .iter()
56 .any(|s| s.eq_ignore_ascii_case("Lesson"))
57 })
58 .collect();
59
60 let hand_cards: Vec<crate::ids::CardId> =
61 ctx.game.cards_in_zone(ZoneType::Hand, player).to_vec();
62
63 let mut all_options = sideboard_lessons.clone();
65 all_options.extend(&hand_cards);
66
67 if all_options.is_empty() {
68 return;
69 }
70
71 ctx.agents[player.index()].snapshot_state(ctx.game, ctx.mana_pools);
73 let chosen = ctx.agents[player.index()].choose_single_card_for_zone_change(
74 ctx.game,
75 player,
76 &all_options,
77 "Learn: choose a Lesson from sideboard, or a card from hand to discard",
78 true, );
80
81 let Some(card_id) = chosen else { return };
82
83 let card_zone = ctx.game.card(card_id).zone;
84
85 if card_zone == ZoneType::Sideboard {
86 let old_zone = ctx.game.card(card_id).zone;
88 ctx.move_card(card_id, ZoneType::Hand, player);
89 emit_zone_trigger(ctx.trigger_handler, card_id, old_zone, ZoneType::Hand);
90 } else if card_zone == ZoneType::Hand {
91 let old_zone = ctx.game.card(card_id).zone;
93 ctx.game.player_record_discard(player, 1);
94 ctx.game.card_mut(card_id).set_discarded(true);
95 ctx.game
96 .move_card(card_id, ZoneType::Graveyard, ctx.game.card(card_id).owner);
97
98 ctx.trigger_handler.run_trigger(
99 TriggerType::Discarded,
100 RunParams {
101 card: Some(card_id),
102 player: Some(player),
103 origin: Some(old_zone),
104 destination: Some(ZoneType::Graveyard),
105 ..Default::default()
106 },
107 false,
108 );
109 emit_zone_trigger(ctx.trigger_handler, card_id, old_zone, ZoneType::Graveyard);
110
111 let lib = ctx.game.cards_in_zone(ZoneType::Library, player).to_vec();
113 if let Some(&top) = lib.last() {
114 let dz = ctx.game.card(top).zone;
115 ctx.move_card(top, ZoneType::Hand, player);
116 ctx.trigger_handler.run_trigger(
117 TriggerType::Drawn,
118 RunParams {
119 card: Some(top),
120 player: Some(player),
121 ..Default::default()
122 },
123 false,
124 );
125 emit_zone_trigger(ctx.trigger_handler, top, dz, ZoneType::Hand);
126 }
127 }
128}