manabrew_engine/replacement/
replace_produce_mana.rs1use crate::card::Card;
6use crate::game::GameState;
7use crate::ids::CardId;
8
9use super::replacement_effect::ReplacementEffect;
10use super::replacement_handler::ReplacementEvent;
11use super::replacement_result::ReplacementResult;
12use super::replacement_type::ReplacementType;
13use crate::card_trait_base::CardTrait;
14
15pub fn can_replace(
17 effect: &ReplacementEffect,
18 event: &ReplacementEvent,
19 game: &GameState,
20 source_card: &Card,
21) -> bool {
22 if effect.event != ReplacementType::ProduceMana {
23 return false;
24 }
25 let (source_id, activator) = match event {
26 ReplacementEvent::ProduceMana {
27 source, activator, ..
28 } => (*source, *activator),
29 _ => return false,
30 };
31 let producing_card = &game.cards[source_id.index()];
32 if let Some(valid) = effect.ir.valid_card_selector.as_ref() {
33 if !valid.is_any_of(["Permanent", "Card"])
34 && !effect.matches_compiled_valid_card(valid, producing_card, source_card)
35 {
36 return false;
37 }
38 }
39 if let Some(valid_player) = effect.ir.valid_activator_text.as_deref() {
40 if !effect.matches_valid_player(valid_player, activator, source_card) {
41 return false;
42 }
43 } else if let Some(valid_player) = effect.ir.valid_player_selector.as_ref() {
44 if !effect.matches_compiled_valid_player(valid_player, activator, source_card) {
45 return false;
46 }
47 }
48 true
49}
50
51pub fn execute(
53 effect: &ReplacementEffect,
54 event: &mut ReplacementEvent,
55 game: &GameState,
56 source_card_id: CardId,
57) -> ReplacementResult {
58 let mana = match event {
59 ReplacementEvent::ProduceMana { mana, .. } => mana,
60 _ => return ReplacementResult::NotReplaced,
61 };
62
63 fn color_word_to_short(s: &str) -> String {
64 match s.to_lowercase().as_str() {
65 "white" | "w" => "W".into(),
66 "blue" | "u" => "U".into(),
67 "black" | "b" => "B".into(),
68 "red" | "r" => "R".into(),
69 "green" | "g" => "G".into(),
70 "colorless" | "c" => "C".into(),
71 _ => s.to_uppercase(),
72 }
73 }
74
75 if let Some(replace_mana) = effect.ir.replace_mana_text.as_deref() {
76 let replacement = if replace_mana == "Any" {
77 "W".to_string()
78 } else {
79 color_word_to_short(replace_mana)
80 };
81 *mana = replacement;
82 return ReplacementResult::Updated;
83 } else if let Some(replace_type) = effect.ir.replace_type_text.as_deref() {
84 let color = if replace_type == "Any" {
85 "W".to_string()
86 } else {
87 color_word_to_short(replace_type)
88 };
89 let replaced: Vec<&str> = mana.split_whitespace().collect();
90 let new_parts: Vec<String> = replaced.iter().map(|_| color.clone()).collect();
91 *mana = new_parts.join(" ");
92 return ReplacementResult::Updated;
93 } else if let Some(replace_color) = effect.ir.replace_color_text.as_deref() {
94 let color = if replace_color == "Chosen" {
95 let host_card = &game.cards[source_card_id.index()];
96 host_card
97 .chosen_colors
98 .first()
99 .map(|c| color_word_to_short(c))
100 .unwrap_or_else(|| "W".into())
101 } else {
102 color_word_to_short(replace_color)
103 };
104 let replace_only = effect
105 .ir
106 .replace_only_text
107 .as_deref()
108 .map(color_word_to_short);
109 let colored = ["W", "U", "B", "R", "G"];
110 let replaced: Vec<String> = mana
111 .split_whitespace()
112 .map(|tok| {
113 if let Some(ref only) = replace_only {
114 if tok == only {
115 color.clone()
116 } else {
117 tok.to_string()
118 }
119 } else if colored.contains(&tok) {
120 color.clone()
121 } else {
122 tok.to_string()
123 }
124 })
125 .collect();
126 *mana = replaced.join(" ");
127 return ReplacementResult::Updated;
128 } else if let Some(replace_with) = effect.replace_with() {
129 let multiplier = if replace_with.contains("Triple") || replace_with.contains("Thrice") {
130 3usize
131 } else if replace_with.contains("Twice") || replace_with.contains("Double") {
132 2usize
133 } else {
134 effect
135 .ir
136 .replace_amount_text
137 .as_deref()
138 .and_then(|s| s.parse::<usize>().ok())
139 .unwrap_or(2)
140 };
141 if multiplier > 1 {
142 let parts: Vec<&str> = mana.split_whitespace().collect();
143 let mut repeated = Vec::new();
144 for _ in 0..multiplier {
145 repeated.extend_from_slice(&parts);
146 }
147 *mana = repeated.join(" ");
148 return ReplacementResult::Updated;
149 }
150 } else if let Some(amount) = effect.ir.replace_amount_text.as_deref() {
151 if let Ok(multiplier) = amount.parse::<usize>() {
152 if multiplier > 1 {
153 let parts: Vec<&str> = mana.split_whitespace().collect();
154 let mut repeated = Vec::new();
155 for _ in 0..multiplier {
156 repeated.extend_from_slice(&parts);
157 }
158 *mana = repeated.join(" ");
159 return ReplacementResult::Updated;
160 }
161 }
162 }
163 ReplacementResult::Replaced
164}