manabrew_engine/ability/effects/
repeat_each_effect.rs1use forge_foundation::ZoneType;
2
3use super::{matches_valid_cards_for_sa, resolve_defined_players, EffectContext};
4use crate::spellability::{build_spell_ability, SpellAbility};
5
6#[manabrew_engine_macros::spell_effect(RepeatEachEffect)]
19fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
20 let source_id = match sa.source {
21 Some(id) => id,
22 None => return,
23 };
24
25 let controller = sa.activating_player;
26 let use_damage_map = sa.ir.damage_map;
27 let use_change_zone_table = sa.ir.change_zone_table;
28
29 if use_damage_map {
30 ctx.game.ensure_pending_damage_maps();
31 }
32 if use_change_zone_table {
33 ctx.game.ensure_pending_change_zone_table();
34 }
35
36 let sub_svar_name = match sa.ir.repeat_sub_ability.as_deref() {
38 Some(name) => name,
39 None => return,
40 };
41
42 let sub_text = match ctx
44 .game
45 .card(source_id)
46 .get_s_var(sub_svar_name)
47 .map(str::to_string)
48 {
49 Some(text) => text,
50 None => return,
51 };
52
53 if let Some(repeat_cards_filter) = sa.ir.repeat_cards_text.as_deref() {
55 let repeat_cards_selector = sa.ir.repeat_cards_selector.as_ref();
56 let zone = sa.ir.zone.unwrap_or(ZoneType::Battlefield);
58
59 let matching: Vec<crate::ids::CardId> = {
61 let mut result = Vec::new();
62 for &pid in &ctx.game.player_order.clone() {
63 let zone_cards = ctx.game.cards_in_zone(zone, pid).to_vec();
64 for cid in zone_cards {
65 if matches_valid_cards_for_sa(
66 ctx.game,
67 sa,
68 ctx.game.card(cid),
69 repeat_cards_selector,
70 repeat_cards_filter,
71 ) {
72 result.push(cid);
73 }
74 }
75 }
76 result
77 };
78
79 for card_id in matching {
81 ctx.game.card_mut(source_id).clear_remembered();
82 ctx.game.card_mut(source_id).add_remembered_card(card_id);
83
84 let sub_sa = build_spell_ability(ctx.game, source_id, &sub_text, controller);
86 resolve_sub_chain(ctx, sub_sa);
87
88 if ctx.game.game_over {
89 break;
90 }
91 }
92
93 ctx.game.card_mut(source_id).clear_remembered();
95 } else if let Some(repeat_players) = sa.ir.repeat_players.as_deref() {
96 let players = resolve_defined_players(repeat_players, controller, ctx.game);
98
99 for pid in players {
100 ctx.game.card_mut(source_id).clear_remembered();
101 ctx.game.card_mut(source_id).add_remembered_player(pid);
102
103 let sub_sa = build_spell_ability(ctx.game, source_id, &sub_text, controller);
106 resolve_sub_chain(ctx, sub_sa);
107
108 if ctx.game.game_over {
109 break;
110 }
111 }
112
113 ctx.game.card_mut(source_id).clear_remembered();
114 }
115
116 if use_damage_map {
117 let mut flush_sa = sa.clone();
119 flush_sa.damage_map = ctx.game.pending_damage_map.clone();
120 flush_sa.prevent_map = ctx.game.pending_prevent_map.clone();
121 super::damage_resolve_effect::DamageResolveEffect::resolve(ctx, &flush_sa);
122 ctx.game.clear_pending_damage_maps();
123 }
124 if use_change_zone_table {
125 if let Some(table) = ctx.game.pending_change_zone_table.clone() {
126 table.trigger_changes_zone_all(ctx.trigger_handler, ctx.game, Some(sa));
127 ctx.game.clear_pending_change_zone_table();
128 }
129 }
130}
131
132fn resolve_sub_chain(ctx: &mut EffectContext, initial: SpellAbility) {
134 let mut cur_opt: Option<SpellAbility> = Some(initial);
135 while let Some(cur_sa) = cur_opt {
136 super::resolve_effect(ctx, &cur_sa);
137 cur_opt = cur_sa.sub_ability.map(|b| *b);
138 if ctx.game.game_over {
139 break;
140 }
141 }
142}