manabrew_engine/ability/effects/
mana_reflected_effect.rs1use forge_foundation::mana::ManaAtom;
2
3use super::EffectContext;
4use crate::card::card_util;
5use crate::mana::{color_name_to_mana_atom, Mana};
6
7pub fn build_spell_ability(sa: &mut crate::spellability::SpellAbility) {
12 let produced = sa
14 .produced_ir()
15 .map(crate::ability::ProducedMana::as_script_text)
16 .unwrap_or("Any".into());
17 let restriction = sa.ir.restrict_valid.as_deref().unwrap_or("").to_string();
18 sa.mana_part = Some(crate::spellability::AbilityManaPart::new(
19 &produced,
20 &restriction,
21 ));
22 sa.is_mana_ability = true;
23}
24
25#[manabrew_engine_macros::spell_effect(ManaReflectedEffect)]
37fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
38 let player = sa.activating_player;
39 let source_id = match sa.source {
40 Some(id) => id,
41 None => return,
42 };
43
44 let amount = super::resolve_numeric_svar(ctx.game, sa, "Amount", 1);
45 if amount <= 0 {
46 return;
47 }
48
49 let mut available_colors =
50 colors_from_names(card_util::get_reflectable_mana_colors(ctx.game, sa));
51 let color_or_type = sa.ir.color_or_type.as_deref().unwrap_or("Color");
52 if color_or_type == "Type" && !available_colors.contains(&ManaAtom::COLORLESS) {
53 available_colors.push(ManaAtom::COLORLESS);
54 }
55
56 if available_colors.is_empty() {
57 return;
58 }
59
60 let restriction = sa.ir.restrict_valid.clone();
62 let source_is_snow = ctx.game.card(source_id).type_line.is_snow();
63
64 let wubrg_order: &[u16] = &[
66 ManaAtom::WHITE,
67 ManaAtom::BLUE,
68 ManaAtom::BLACK,
69 ManaAtom::RED,
70 ManaAtom::GREEN,
71 ManaAtom::COLORLESS,
72 ];
73 let mut sorted_colors: Vec<u16> = Vec::new();
74 for &atom in wubrg_order {
75 if available_colors.contains(&atom) {
76 sorted_colors.push(atom);
77 }
78 }
79 if sorted_colors.is_empty() {
80 sorted_colors = available_colors;
81 }
82
83 let color_names: Vec<String> = sorted_colors
85 .iter()
86 .map(|&atom| match atom {
87 ManaAtom::WHITE => "White".to_string(),
88 ManaAtom::BLUE => "Blue".to_string(),
89 ManaAtom::BLACK => "Black".to_string(),
90 ManaAtom::RED => "Red".to_string(),
91 ManaAtom::GREEN => "Green".to_string(),
92 ManaAtom::COLORLESS => "Colorless".to_string(),
93 _ => "Colorless".to_string(),
94 })
95 .collect();
96
97 let express_choice = sa
98 .express_mana_choice
99 .filter(|atom| sorted_colors.contains(atom))
100 .or_else(|| {
101 sa.mana_part
102 .as_ref()
103 .map(|part| part.last_express_choice())
104 .filter(|choice| !choice.is_empty())
105 .and_then(color_name_to_mana_atom)
106 .filter(|atom| sorted_colors.contains(atom))
107 });
108
109 let best_color = if let Some(atom) = express_choice {
110 atom
111 } else if let Some(chosen_name) = ctx.agents[player.index()].choose_color(player, &color_names)
112 {
113 match chosen_name.as_str() {
114 "White" => ManaAtom::WHITE,
115 "Blue" => ManaAtom::BLUE,
116 "Black" => ManaAtom::BLACK,
117 "Red" => ManaAtom::RED,
118 "Green" => ManaAtom::GREEN,
119 "Colorless" => ManaAtom::COLORLESS,
120 _ => sorted_colors[0],
121 }
122 } else {
123 sorted_colors[0]
124 };
125
126 for _ in 0..amount {
128 let mut m = Mana::simple(best_color);
129 m.source_card = Some(source_id);
130 m.is_snow = source_is_snow;
131 m.restriction = restriction.clone();
132 ctx.mana_pools[player.index()].add_mana(m);
133 }
134}
135
136fn colors_from_names(colors: std::collections::HashSet<String>) -> Vec<u16> {
137 let mut out = Vec::new();
138 for color in colors {
139 let atom = match color.as_str() {
140 "white" | "White" => Some(ManaAtom::WHITE),
141 "blue" | "Blue" => Some(ManaAtom::BLUE),
142 "black" | "Black" => Some(ManaAtom::BLACK),
143 "red" | "Red" => Some(ManaAtom::RED),
144 "green" | "Green" => Some(ManaAtom::GREEN),
145 "colorless" | "Colorless" => Some(ManaAtom::COLORLESS),
146 _ => None,
147 };
148 if let Some(atom) = atom {
149 if !out.contains(&atom) {
150 out.push(atom);
151 }
152 }
153 }
154 out
155}