manabrew_engine/ability/effects/
counters_proliferate_effect.rs1use forge_foundation::ZoneType;
2
3use super::EffectContext;
4use crate::agent::GameEntity;
5use crate::card::CounterType;
6use crate::event::RunParams;
7use crate::ids::CardId;
8use crate::replacement::replacement_handler::{apply_replacements_with_agents, ReplacementEvent};
9use crate::trigger::TriggerType;
10
11#[manabrew_engine_macros::spell_effect(CountersProliferateEffect)]
24fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
25 let controller = sa.activating_player;
26
27 let mut prolif_event = ReplacementEvent::Proliferate {
29 player: controller,
30 count: 1,
31 };
32 let prolif_result =
33 apply_replacements_with_agents(&mut *ctx.game, ctx.agents, &mut prolif_event);
34 if prolif_result == crate::replacement::ReplacementResult::Skipped
35 || prolif_result == crate::replacement::ReplacementResult::Replaced
36 {
37 return;
38 }
39
40 let player_ids = ctx.game.player_order.clone();
44 let mut candidates: Vec<GameEntity> = Vec::new();
45
46 for &pid in &player_ids {
48 let p = ctx.game.player(pid);
49 if p.poison_counters > 0 || p.energy_counters > 0 {
50 candidates.push(GameEntity::Player(pid));
51 }
52 }
53
54 for &pid in &player_ids {
56 let zone_cards = ctx.game.cards_in_zone(ZoneType::Battlefield, pid).to_vec();
57 for cid in zone_cards {
58 if !ctx.game.card(cid).counters.is_empty()
59 && ctx.game.card(cid).counters.values().any(|&v| v > 0)
60 {
61 candidates.push(GameEntity::Card(cid));
62 }
63 }
64 }
65
66 if candidates.is_empty() {
67 return;
68 }
69
70 let chosen = ctx.agents[controller.index()].choose_entities_for_effect(
72 controller,
73 &candidates,
74 0,
75 candidates.len(),
76 );
77
78 for entity in chosen {
80 match entity {
81 GameEntity::Player(pid) => {
82 proliferate_player(ctx, pid);
83 }
84 GameEntity::Card(cid) => {
85 proliferate_card(ctx, cid);
86 }
87 }
88 }
89}
90
91fn proliferate_player(ctx: &mut EffectContext, pid: crate::ids::PlayerId) {
93 let p = ctx.game.player(pid);
94 if p.poison_counters > 0 {
95 ctx.game.player_add_poison(pid, 1);
96 }
97 let p = ctx.game.player(pid);
98 if p.energy_counters > 0 {
99 ctx.game.player_add_energy(pid, 1);
100 }
101}
102
103fn proliferate_card(ctx: &mut EffectContext, cid: CardId) {
105 if ctx.game.card(cid).zone != ZoneType::Battlefield {
106 return;
107 }
108 let counter_types: Vec<CounterType> = ctx
110 .game
111 .card(cid)
112 .counters
113 .iter()
114 .filter(|(_, &count)| count > 0)
115 .map(|(ct, _)| ct.clone())
116 .collect();
117
118 for ct in &counter_types {
119 if crate::staticability::static_ability_cant_put_counter::any_cant_put_counter_on_card(
120 &ctx.game.cards,
121 ctx.game.card(cid),
122 ct,
123 ) {
124 continue;
125 }
126 if let Some(max) = crate::staticability::static_ability_max_counter::max_counter(
127 &ctx.game.cards,
128 ctx.game.card(cid),
129 ct,
130 ) {
131 if ctx.game.card(cid).counter_count(ct) >= max {
132 continue;
133 }
134 }
135 let mut add_event = ReplacementEvent::AddCounter {
137 target: cid,
138 counter_type: ct.clone(),
139 count: 1,
140 is_effect: true,
141 };
142 apply_replacements_with_agents(&mut *ctx.game, ctx.agents, &mut add_event);
143 let final_count = if let ReplacementEvent::AddCounter { count, .. } = add_event {
144 count
145 } else {
146 1
147 };
148 ctx.game.card_mut(cid).add_counter(ct, final_count);
149 ctx.trigger_handler.run_trigger(
150 TriggerType::CounterAdded,
151 RunParams {
152 card: Some(cid),
153 counter_type: Some(format!("{:?}", ct)),
154 counter_amount: Some(1),
155 ..Default::default()
156 },
157 false,
158 );
159 }
160}