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.game.card_mut(target).add_counter(&counter_type, amount);
89
90 let has_type = ctx
92 .game
93 .card(target)
94 .type_line
95 .subtypes
96 .iter()
97 .any(|s| s.eq_ignore_ascii_case(amass_type));
98
99 if !has_type {
100 add_type_effect(ctx, sa, controller, target, amass_type);
101 }
102}
103
104fn create_army_token(
106 ctx: &mut EffectContext,
107 _sa: &SpellAbility,
108 controller: crate::ids::PlayerId,
109 amass_type: &str,
110) {
111 let army_script = format!("b_0_0_{}_army", amass_type.to_lowercase());
112 let mut token = TOKEN_EFFECT_BASE.require_token_template(ctx.token_templates, &army_script);
113 token.set_owner(controller);
114 token.set_controller(controller);
115 token.set_is_token(true);
116 token.set_s_var("TokenScript", army_script);
117 token.set_s_var("TokenSpawningAbility", _sa.ability_text.clone());
118 token.card_name = format!("{} Army Token", amass_type);
119 token.type_line = CardTypeLine::parse(&format!("Creature - {} Army", amass_type));
120
121 let token_table = TOKEN_EFFECT_BASE.make_token_table_internal(controller, token, 1);
122 let mut trigger_list = CardZoneTable::default();
123 let result =
124 TOKEN_EFFECT_BASE.make_token_table(ctx, token_table, false, &mut trigger_list, _sa);
125 if !result.created.is_empty() {
126 trigger_list.trigger_changes_zone_all(ctx.trigger_handler, ctx.game, Some(_sa));
127 }
128}
129
130fn add_type_effect(
133 ctx: &mut EffectContext,
134 sa: &SpellAbility,
135 controller: crate::ids::PlayerId,
136 target: CardId,
137 amass_type: &str,
138) {
139 let mut effect = Card::new(
140 CardId(0),
141 "Amass Effect".to_string(),
142 controller,
143 CardTypeLine::parse("Effect"),
144 ManaCost::parse("0"),
145 ColorSet::COLORLESS,
146 None,
147 None,
148 vec![],
149 vec![],
150 );
151 effect.set_controller(controller);
152 effect.set_effect_source(sa.source);
153 effect.add_remembered_card(target);
154 effect.set_temp_effect_host(Some(target)); let static_text = format!(
157 "Mode$ Continuous | Affected$ Card.IsRemembered | EffectZone$ Command | AddType$ {}",
158 amass_type
159 );
160 if let Some(parsed) = parse_static_ability(&format!("S$ {}", static_text)) {
161 effect.add_static_ability(parsed);
162 }
163
164 let effect_id = ctx.game.create_card(effect);
165 ctx.move_card(effect_id, ZoneType::Command, controller);
166}