manabrew_engine/ability/effects/
amass_effect.rs1use crate::parsing::keys;
10use forge_foundation::{CardTypeLine, ColorSet, ManaCost, ZoneType};
11
12use super::token_effect_base::{TokenEffectBase, TOKEN_EFFECT_BASE};
13use super::{parse_counter_type, EffectContext};
14use crate::card::card_zone_table::CardZoneTable;
15use crate::card::Card;
16use crate::ids::CardId;
17use crate::spellability::SpellAbility;
18use crate::staticability::parse_static_ability;
19
20#[manabrew_engine_macros::spell_effect(AmassEffect)]
24fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
25 let controller = sa.activating_player;
26 let amount = super::resolve_numeric_svar(ctx.game, sa, "Num", 1).max(0);
27 let amass_type = sa.ir.type_filter.as_deref().unwrap_or("Zombie");
28
29 let has_army = ctx.game.cards.iter().any(|c| {
31 c.zone == ZoneType::Battlefield
32 && c.controller == controller
33 && c.type_line
34 .subtypes
35 .iter()
36 .any(|s| s.eq_ignore_ascii_case("Army"))
37 });
38
39 if !has_army {
40 create_army_token(ctx, sa, controller, amass_type);
41 }
42
43 let armies: Vec<CardId> = ctx
45 .game
46 .cards
47 .iter()
48 .filter(|c| {
49 c.zone == ZoneType::Battlefield
50 && c.controller == controller
51 && c.type_line
52 .subtypes
53 .iter()
54 .any(|s| s.eq_ignore_ascii_case("Army"))
55 })
56 .map(|c| c.id)
57 .collect();
58
59 if armies.is_empty() {
60 return;
61 }
62
63 let target = if armies.len() == 1 {
65 armies[0]
66 } else {
67 ctx.agents[controller.index()].snapshot_state(ctx.game, ctx.mana_pools);
68 ctx.agents[controller.index()]
69 .choose_single_card_for_zone_change(
70 ctx.game,
71 controller,
72 &armies,
73 "Choose an Army",
74 false,
75 )
76 .unwrap_or(armies[0])
77 };
78
79 if sa.param_is_true(keys::REMEMBER_AMASS) {
81 if let Some(source_id) = sa.source {
82 ctx.game.card_mut(source_id).add_remembered_card(target);
83 }
84 }
85
86 let counter_type = parse_counter_type("P1P1");
88 ctx.add_counter(
89 target,
90 &counter_type,
91 amount,
92 sa,
93 crate::event::RunParams::default(),
94 );
95
96 let has_type = ctx
98 .game
99 .card(target)
100 .type_line
101 .subtypes
102 .iter()
103 .any(|s| s.eq_ignore_ascii_case(amass_type));
104
105 if !has_type {
106 add_type_effect(ctx, sa, controller, target, amass_type);
107 }
108}
109
110fn create_army_token(
112 ctx: &mut EffectContext,
113 _sa: &SpellAbility,
114 controller: crate::ids::PlayerId,
115 amass_type: &str,
116) {
117 let army_script = format!("b_0_0_{}_army", amass_type.to_lowercase());
118 let mut token = TOKEN_EFFECT_BASE.require_token_template(ctx.token_templates, &army_script);
119 token.set_owner(controller);
120 token.set_controller(controller);
121 token.set_is_token(true);
122 token.set_s_var("TokenScript", army_script);
123 token.set_s_var("TokenSpawningAbility", _sa.ability_text.clone());
124 token.card_name = format!("{} Army Token", amass_type);
125 token.type_line = CardTypeLine::parse(&format!("Creature - {} Army", amass_type));
126
127 let token_table = TOKEN_EFFECT_BASE.make_token_table_internal(controller, token, 1);
128 let mut trigger_list = CardZoneTable::default();
129 let result =
130 TOKEN_EFFECT_BASE.make_token_table(ctx, token_table, false, &mut trigger_list, _sa);
131 if !result.created.is_empty() {
132 trigger_list.trigger_changes_zone_all(ctx.trigger_handler, ctx.game, Some(_sa));
133 }
134}
135
136fn add_type_effect(
139 ctx: &mut EffectContext,
140 sa: &SpellAbility,
141 controller: crate::ids::PlayerId,
142 target: CardId,
143 amass_type: &str,
144) {
145 let mut effect = Card::new(
146 CardId(0),
147 "Amass Effect".to_string(),
148 controller,
149 CardTypeLine::parse("Effect"),
150 ManaCost::parse("0"),
151 ColorSet::COLORLESS,
152 None,
153 None,
154 vec![],
155 vec![],
156 );
157 effect.set_controller(controller);
158 effect.set_effect_source(sa.source);
159 effect.add_remembered_card(target);
160 effect.set_temp_effect_host(Some(target)); let static_text = format!(
163 "Mode$ Continuous | Affected$ Card.IsRemembered | EffectZone$ Command | AddType$ {}",
164 amass_type
165 );
166 if let Some(parsed) = parse_static_ability(&format!("S$ {}", static_text)) {
167 effect.add_static_ability(parsed);
168 }
169
170 let effect_id = ctx.game.create_card(effect);
171 ctx.move_card(effect_id, ZoneType::Command, controller);
172}