manabrew_engine/ability/effects/
discover_effect.rs1use forge_foundation::ZoneType;
9
10use super::cast_from_effect;
11use super::{emit_zone_trigger, EffectContext};
12use crate::ids::{CardId, PlayerId};
13use crate::parsing::keys;
14use crate::spellability::SpellAbility;
15
16#[manabrew_engine_macros::spell_effect(DiscoverEffect)]
20fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
21 let num = super::resolve_numeric_svar(ctx.game, sa, "Num", 1).max(0);
22 let controller = sa.activating_player;
23
24 let players = if let Some(def) = sa.defined_player() {
25 super::resolve_defined_players(def, controller, ctx.game)
26 } else {
27 vec![controller]
28 };
29
30 for pid in players {
31 discover_for_player(ctx, sa, pid, num);
32 }
33}
34
35fn discover_for_player(ctx: &mut EffectContext, sa: &SpellAbility, player: PlayerId, max_cmc: i32) {
36 let mut exiled_rest: Vec<CardId> = Vec::new();
37 let mut found: Option<CardId> = None;
38
39 loop {
42 let lib = ctx.game.cards_in_zone(ZoneType::Library, player).to_vec();
43 let Some(&top) = lib.last() else { break };
44
45 let card = ctx.game.card(top);
46 let is_land = card
47 .type_line
48 .core_types
49 .iter()
50 .any(|ct| matches!(ct, forge_foundation::CoreType::Land));
51 let cmc = card.mana_cost.cmc();
52
53 let old_zone = ctx.game.card(top).zone;
55 ctx.move_card(top, ZoneType::Exile, player);
56 emit_zone_trigger(ctx.trigger_handler, top, old_zone, ZoneType::Exile);
57
58 if !is_land && cmc <= max_cmc {
59 found = Some(top);
60 if sa.param_is_true(keys::REMEMBER_DISCOVERED) {
61 if let Some(sid) = sa.source {
62 ctx.game.card_mut(sid).add_remembered_card(top);
63 }
64 }
65 break;
66 } else {
67 exiled_rest.push(top);
68 }
69 }
70
71 if let Some(card_id) = found {
73 let has_spells = !cast_from_effect::get_basic_spells(ctx, card_id).is_empty();
74
75 if has_spells {
76 let cast = cast_from_effect::offer_cast_or_alternative(
77 ctx,
78 card_id,
79 player,
80 "Cast without paying its mana cost",
81 "Put into your hand",
82 );
83
84 if cast {
85 let ok =
86 cast_from_effect::cast_card_from_effect(ctx, card_id, player, true, "Discover");
87 if !ok {
88 let old = ctx.game.card(card_id).zone;
90 ctx.move_card(card_id, ZoneType::Hand, player);
91 emit_zone_trigger(ctx.trigger_handler, card_id, old, ZoneType::Hand);
92 }
93 } else {
94 let old = ctx.game.card(card_id).zone;
95 ctx.move_card(card_id, ZoneType::Hand, player);
96 emit_zone_trigger(ctx.trigger_handler, card_id, old, ZoneType::Hand);
97 }
98 } else {
99 let old = ctx.game.card(card_id).zone;
100 ctx.move_card(card_id, ZoneType::Hand, player);
101 emit_zone_trigger(ctx.trigger_handler, card_id, old, ZoneType::Hand);
102 }
103 }
104
105 ctx.rng.shuffle_cards(&mut exiled_rest);
107 for card_id in exiled_rest {
108 let old = ctx.game.card(card_id).zone;
109 ctx.move_card(card_id, ZoneType::Library, player);
110 ctx.game
111 .reorder_card_in_zone(ZoneType::Library, player, card_id, 0);
112 emit_zone_trigger(ctx.trigger_handler, card_id, old, ZoneType::Library);
113 }
114}