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 ctx.game
77 .card_mut(from)
78 .remove_counter(&counter_type, actual);
79 ctx.trigger_handler.run_trigger(
80 TriggerType::CounterRemoved,
81 RunParams {
82 card: Some(from),
83 counter_type: Some(format!("{:?}", counter_type)),
84 counter_amount: Some(actual),
85 ..Default::default()
86 },
87 false,
88 );
89
90 if crate::staticability::static_ability_cant_put_counter::any_cant_put_counter_on_card(
92 &ctx.game.cards,
93 ctx.game.card(to),
94 &counter_type,
95 ) {
96 return;
97 }
98 let add_amount = if let Some(max) =
99 crate::staticability::static_ability_max_counter::max_counter(
100 &ctx.game.cards,
101 ctx.game.card(to),
102 &counter_type,
103 ) {
104 (max - ctx.game.card(to).counter_count(&counter_type)).clamp(0, actual)
105 } else {
106 actual
107 };
108 if add_amount <= 0 {
109 return;
110 }
111 ctx.game.card_mut(to).add_counter(&counter_type, add_amount);
112 ctx.trigger_handler.run_trigger(
113 TriggerType::CounterAdded,
114 RunParams {
115 card: Some(to),
116 counter_type: Some(format!("{:?}", counter_type)),
117 counter_amount: Some(add_amount),
118 ..Default::default()
119 },
120 false,
121 );
122}