manabrew_engine/ability/effects/
change_targets_effect.rs1use forge_foundation::ZoneType;
10
11use super::EffectContext;
12use crate::ability::ability_ir::DefinedRef;
13use crate::ids::CardId;
14use crate::parsing::keys;
15use crate::spellability::SpellAbility;
16
17pub fn build_spell_ability(sa: &mut SpellAbility) {
21 if sa.uses_targeting() {
22 if let Some(ref mut tr) = sa.target_restrictions {
23 tr.tgt_zone = vec![ZoneType::Stack];
24 }
25 }
26}
27
28#[manabrew_engine_macros::spell_effect(ChangeTargetsEffect)]
32fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
33 let controller = sa.activating_player;
34
35 let target_spell_card = match sa.target_chosen.target_card {
37 Some(card_id) => card_id,
38 None => return,
39 };
40
41 if ctx.game.card(target_spell_card).zone != ZoneType::Stack {
43 return;
44 }
45
46 if sa.param_is_true(keys::RANDOM_TARGET) {
48 let candidates: Vec<CardId> = ctx
50 .game
51 .cards
52 .iter()
53 .filter(|c| c.zone == ZoneType::Battlefield)
54 .map(|c| c.id)
55 .collect();
56
57 if candidates.is_empty() {
58 return;
59 }
60
61 let idx = ctx.rng.next_int(candidates.len() as i32) as usize % candidates.len();
63 let new_target = candidates[idx];
64
65 ctx.game
68 .card_mut(target_spell_card)
69 .set_s_var("RedirectedTarget", format!("{}", new_target.0));
70 return;
71 }
72
73 if let Some(magnet_def) = sa.ir.defined_magnet_text.as_deref() {
75 let magnet_ref = DefinedRef::parse(magnet_def);
76 let new_target = if matches!(magnet_ref, DefinedRef::SelfCard) {
77 sa.source
78 } else if matches!(magnet_ref, DefinedRef::ParentTarget) {
79 sa.target_chosen.target_card
80 } else {
81 sa.source
82 .and_then(|sid| ctx.game.card(sid).remembered_cards.first().copied())
83 };
84
85 if let Some(new_tgt) = new_target {
86 ctx.game
87 .card_mut(target_spell_card)
88 .set_s_var("RedirectedTarget", format!("{}", new_tgt.0));
89 }
90 return;
91 }
92
93 let candidates: Vec<CardId> = ctx
97 .game
98 .cards
99 .iter()
100 .filter(|c| c.zone == ZoneType::Battlefield && c.controller != controller)
101 .map(|c| c.id)
102 .collect();
103
104 if candidates.is_empty() {
105 return;
106 }
107
108 ctx.agents[controller.index()].snapshot_state(ctx.game, ctx.mana_pools);
110 if let Some(chosen) = ctx.agents[controller.index()].choose_single_card_for_zone_change(
111 ctx.game,
112 controller,
113 &candidates,
114 "Choose new target",
115 false,
116 ) {
117 ctx.game
118 .card_mut(target_spell_card)
119 .set_s_var("RedirectedTarget", format!("{}", chosen.0));
120 }
121}