manabrew_engine/ability/effects/
move_counter_effect.rs1use forge_foundation::ZoneType;
2
3use super::{resolve_numeric_svar, EffectContext};
4use crate::ability::ability_ir::DefinedRef;
5use crate::card::CounterType;
6use crate::event::RunParams;
7use crate::parsing::keys;
8use crate::trigger::TriggerType;
9
10#[manabrew_engine_macros::spell_effect(MoveCounterEffect)]
27fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
28 let counter_type = sa.ir.counter_type.clone().unwrap_or(CounterType::P1P1);
29 let count = resolve_numeric_svar(ctx.game, sa, keys::COUNTER_NUM, 1);
30 if count <= 0 {
31 return;
32 }
33
34 let from_id = match sa.ir.source_text.as_deref() {
36 Some(source) if matches!(DefinedRef::parse(source), DefinedRef::Targeted) => {
37 sa.target_chosen.target_card
38 }
39 Some(source) if matches!(DefinedRef::parse(source), DefinedRef::ParentTarget) => {
40 ctx.parent_target_card
41 }
42 _ => sa.source, };
44
45 let to_id = sa
47 .target_chosen
48 .target_card
49 .or_else(|| match sa.defined_ref() {
50 Some(DefinedRef::SelfCard) => sa.source,
51 Some(DefinedRef::ParentTarget) => ctx.parent_target_card,
52 _ => None,
53 });
54
55 let from = match from_id {
56 Some(id) if ctx.game.card(id).zone == ZoneType::Battlefield => id,
57 _ => return,
58 };
59 let to = match to_id {
60 Some(id) if ctx.game.card(id).zone == ZoneType::Battlefield => id,
61 _ => return,
62 };
63
64 if from == to {
65 return;
66 }
67
68 let available = ctx.game.card(from).counter_count(&counter_type);
70 let actual = count.min(available);
71 if actual <= 0 {
72 return;
73 }
74
75 if ctx.game.card(to).phased_out
76 || crate::staticability::static_ability_cant_put_counter::any_cant_put_counter_on_card(
77 &ctx.game.cards,
78 ctx.game.card(to),
79 &counter_type,
80 )
81 {
82 return;
83 }
84 ctx.game
85 .card_mut(from)
86 .remove_counter(&counter_type, actual);
87 ctx.trigger_handler.run_trigger(
88 TriggerType::CounterRemoved,
89 RunParams {
90 card: Some(from),
91 counter_type: Some(format!("{:?}", counter_type)),
92 counter_amount: Some(actual),
93 ..Default::default()
94 },
95 false,
96 );
97 ctx.add_counter(to, &counter_type, actual, sa, RunParams::default());
98}