1use forge_foundation::ManaCost;
2
3use crate::game::GameState;
4use crate::ids::{CardId, PlayerId};
5
6use super::{
7 auto_tap_lands_trace, auto_tap_lands_with_chooser, AutoTapChoice, ManaPayCallbackFn,
8 ManaPaymentContext, ManaPool, SacrificeChooser,
9};
10
11pub struct AutoPayResult {
12 pub tapped: Vec<CardId>,
13 pub choices: Vec<AutoTapChoice>,
14 pub life_paid: i32,
15 pub colors_spent: u16,
16 pub paying_mana: Vec<u16>,
17 pub cancelled: bool,
25}
26
27pub fn pay_mana_cost_auto(
34 game: &mut GameState,
35 pool: &mut ManaPool,
36 player: PlayerId,
37 mana_cost: &ManaCost,
38 current_spell: Option<CardId>,
39 commander_tax: i32,
40 payment_ctx: &ManaPaymentContext,
41 any_color_conversion: bool,
42) -> Option<AutoPayResult> {
43 pay_mana_cost_auto_with_chooser(
44 game,
45 pool,
46 player,
47 mana_cost,
48 current_spell,
49 commander_tax,
50 payment_ctx,
51 any_color_conversion,
52 None,
53 )
54}
55
56pub fn pay_mana_cost_auto_with_chooser(
59 game: &mut GameState,
60 pool: &mut ManaPool,
61 player: PlayerId,
62 mana_cost: &ManaCost,
63 current_spell: Option<CardId>,
64 commander_tax: i32,
65 payment_ctx: &ManaPaymentContext,
66 any_color_conversion: bool,
67 sacrifice_chooser: Option<SacrificeChooser<'_>>,
68) -> Option<AutoPayResult> {
69 let tapped = match sacrifice_chooser {
70 Some(chooser) => {
71 let mut tapped =
72 auto_tap_lands_with_chooser(game, pool, player, mana_cost, current_spell, chooser);
73 if commander_tax > 0 {
74 tapped.extend(auto_tap_lands_with_chooser(
75 game,
76 pool,
77 player,
78 &ManaCost::generic(commander_tax),
79 current_spell,
80 chooser,
81 ));
82 }
83 tapped
84 }
85 None => {
86 let mut choices = auto_tap_lands_trace(game, pool, player, mana_cost, current_spell);
87 if commander_tax > 0 {
88 choices.extend(auto_tap_lands_trace(
89 game,
90 pool,
91 player,
92 &ManaCost::generic(commander_tax),
93 current_spell,
94 ));
95 }
96 choices.into_iter().map(|choice| choice.card_id).collect()
97 }
98 };
99 let choices = tapped
100 .iter()
101 .map(|&card_id| AutoTapChoice {
102 card_id,
103 mana_ability_index: None,
104 chosen_atom: 0,
105 needs_express_choice: false,
106 })
107 .collect();
108
109 let payment = pool.try_pay_for_spell_converted_with_phyrexian_life_result(
110 mana_cost,
111 payment_ctx,
112 any_color_conversion,
113 game.player(player).life,
114 )?;
115 if commander_tax > 0 && !pool.try_pay_extra_generic(commander_tax) {
116 return None;
117 }
118 Some(AutoPayResult {
119 tapped,
120 choices,
121 life_paid: payment.life_paid,
122 colors_spent: payment.colors_spent,
123 paying_mana: payment.paying_mana,
124 cancelled: false,
125 })
126}
127
128pub fn pay_mana_cost_auto_with_callback(
131 game: &mut GameState,
132 pool: &mut ManaPool,
133 player: PlayerId,
134 mana_cost: &ManaCost,
135 current_spell: Option<CardId>,
136 commander_tax: i32,
137 payment_ctx: &ManaPaymentContext,
138 any_color_conversion: bool,
139 callback: ManaPayCallbackFn<'_>,
140) -> Option<AutoPayResult> {
141 pay_mana_cost_auto_with_callback_and_reserved_sacrifices(
142 game,
143 pool,
144 player,
145 mana_cost,
146 current_spell,
147 commander_tax,
148 payment_ctx,
149 any_color_conversion,
150 &[],
151 callback,
152 )
153}
154
155#[allow(clippy::too_many_arguments)]
165pub fn pay_mana_cost_auto_with_callback_and_reserved_sacrifices(
166 game: &mut GameState,
167 pool: &mut ManaPool,
168 player: PlayerId,
169 mana_cost: &ManaCost,
170 current_spell: Option<CardId>,
171 commander_tax: i32,
172 payment_ctx: &ManaPaymentContext,
173 any_color_conversion: bool,
174 reserved_sacrifices: &[CardId],
175 callback: ManaPayCallbackFn<'_>,
176) -> Option<AutoPayResult> {
177 let mut trace =
178 super::computer_util_mana::auto_tap_lands_pay_incremental_with_callbacks_reserved_and_ctx(
179 game,
180 pool,
181 player,
182 mana_cost,
183 current_spell,
184 reserved_sacrifices,
185 callback,
186 payment_ctx,
187 any_color_conversion,
188 );
189 if commander_tax > 0 && trace.paid {
190 let tapped_tax =
191 super::computer_util_mana::auto_tap_lands_pay_incremental_with_callbacks_reserved_and_ctx(
192 game,
193 pool,
194 player,
195 &ManaCost::generic(commander_tax),
196 current_spell,
197 reserved_sacrifices,
198 callback,
199 payment_ctx,
200 any_color_conversion,
201 );
202 trace.choices.extend(tapped_tax.choices);
203 trace.payment.colors_spent |= tapped_tax.payment.colors_spent;
204 trace
205 .payment
206 .paying_mana
207 .extend(tapped_tax.payment.paying_mana);
208 trace.paid = trace.paid && tapped_tax.paid;
209 }
210 let choices = trace.choices;
211 let tapped: Vec<CardId> = choices.iter().map(|choice| choice.card_id).collect();
212 let life_paid = trace.payment.life_paid;
213
214 if !trace.paid {
215 return Some(AutoPayResult {
218 tapped,
219 choices,
220 life_paid: 0,
221 colors_spent: 0,
222 paying_mana: Vec::new(),
223 cancelled: true,
224 });
225 }
226 Some(AutoPayResult {
227 tapped,
228 choices,
229 life_paid,
230 colors_spent: trace.payment.colors_spent,
231 paying_mana: trace.payment.paying_mana,
232 cancelled: false,
233 })
234}