manabrew_engine/ability/effects/
dig_until_effect.rs1use forge_foundation::ZoneType;
2
3use super::{
4 emit_zone_trigger, matches_change_type, resolve_defined_player, resolve_numeric_svar,
5 EffectContext,
6};
7use crate::card::valid_filter;
8use crate::parsing::keys;
9
10#[manabrew_engine_macros::spell_effect(DigUntilEffect)]
27fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
28 let amount = resolve_numeric_svar(ctx.game, sa, keys::AMOUNT, 1).max(0) as usize;
29
30 let valid_selector = sa.ir.valid_filter_selector.as_ref();
31 let valid_filter = sa.ir.valid_filter_text.as_deref().unwrap_or("Card");
32
33 let found_dest = sa.ir.found_destination_zone.unwrap_or(ZoneType::Hand);
34 let revealed_dest = sa.ir.revealed_destination_zone.unwrap_or(ZoneType::Library);
35
36 let target_player = sa
37 .target_chosen
38 .target_player
39 .or_else(|| {
40 sa.defined()
41 .and_then(|d| resolve_defined_player(d, sa.activating_player, ctx.game))
42 })
43 .unwrap_or(sa.activating_player);
44
45 let lib_len = ctx
46 .game
47 .cards_in_zone(ZoneType::Library, target_player)
48 .len();
49 if lib_len == 0 {
50 return;
51 }
52
53 let mut found = Vec::new();
54 let mut revealed = Vec::new();
55
56 let lib_cards: Vec<_> = ctx
58 .game
59 .cards_in_zone(ZoneType::Library, target_player)
60 .to_vec();
61 for &cid in lib_cards.iter().rev() {
63 if found.len() >= amount {
64 break;
65 }
66 revealed.push(cid);
67 let card = ctx.game.card(cid);
68 let matches = match (valid_selector, sa.source) {
69 (Some(selector), Some(source_id)) => valid_filter::matches_valid_card_selector_in_game(
70 selector,
71 card,
72 ctx.game.card(source_id),
73 ctx.game,
74 ),
75 _ => matches_change_type(card, valid_filter, &[]),
76 };
77 if matches {
78 found.push(cid);
79 if let Some(source_id) = sa.source {
80 if crate::parsing::raw_has_key(&sa.ability_text, keys::FORGET_OTHER_REMEMBERED) {
81 ctx.game.card_mut(source_id).clear_remembered();
82 }
83 if sa.ir.remember_found {
84 ctx.game.card_mut(source_id).add_remembered_card(cid);
85 }
86 if sa.ir.imprint_found {
87 ctx.game.card_mut(source_id).add_imprinted_card(cid);
88 }
89 }
90 }
91 }
92 let rest: Vec<_> = revealed
93 .iter()
94 .copied()
95 .filter(|cid| !found.contains(cid))
96 .collect();
97 if let Some(source_id) = sa.source {
98 if sa.ir.imprint_revealed {
99 ctx.game
100 .card_mut(source_id)
101 .add_imprinted_cards(rest.iter().copied());
102 }
103 if sa.ir.remember_revealed {
104 ctx.game
105 .card_mut(source_id)
106 .add_remembered_cards(rest.iter().copied());
107 }
108 }
109
110 let removed: Vec<_> = revealed.to_vec();
112 for card_id in removed {
113 ctx.game
114 .remove_card_from_zone(ZoneType::Library, target_player, card_id);
115 }
116
117 for &id in &found {
119 let owner = ctx.game.card(id).owner;
120 let dest_owner = if found_dest == ZoneType::Battlefield {
121 sa.activating_player
122 } else {
123 owner
124 };
125 ctx.move_card(id, found_dest, dest_owner);
126 if found_dest == ZoneType::Battlefield {
127 let _ = super::add_to_combat(ctx, sa, id, keys::ATTACKING);
128 }
129 emit_zone_trigger(ctx.trigger_handler, id, ZoneType::Library, found_dest);
130 }
131
132 for &id in &rest {
134 let owner = ctx.game.card(id).owner;
135 if revealed_dest == ZoneType::Library {
136 ctx.game
138 .add_card_to_zone_bottom(ZoneType::Library, owner, id);
139 ctx.game.card_mut(id).set_zone(ZoneType::Library);
140 } else {
141 ctx.move_card(id, revealed_dest, owner);
142 emit_zone_trigger(ctx.trigger_handler, id, ZoneType::Library, revealed_dest);
143 }
144 }
145}