manabrew_engine/ability/effects/
branch_effect.rs1use super::EffectContext;
2use crate::parsing::compare::compare_expr;
3use crate::parsing::keys;
4use crate::spellability::SpellAbility;
5
6#[manabrew_engine_macros::spell_effect(BranchEffect)]
12fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
13 let take_true_branch = evaluate_branch_condition(ctx, sa);
14 let key = if take_true_branch {
15 keys::TRUE_SUB_ABILITY
16 } else {
17 keys::FALSE_SUB_ABILITY
18 };
19
20 let sub_svar_name = match key {
21 keys::TRUE_SUB_ABILITY => sa.ir.true_sub_ability.as_deref(),
22 keys::FALSE_SUB_ABILITY => sa.ir.false_sub_ability.as_deref(),
23 _ => None,
24 };
25 let Some(sub_svar_name) = sub_svar_name else {
26 return;
27 };
28 let Some(source_id) = sa.source else {
29 return;
30 };
31 let Some(sub_text) = ctx
32 .game
33 .card(source_id)
34 .get_s_var(sub_svar_name)
35 .map(str::to_string)
36 else {
37 return;
38 };
39
40 let mut sub_sa = crate::spellability::build_spell_ability(
41 ctx.game,
42 source_id,
43 &sub_text,
44 sa.activating_player,
45 );
46 sub_sa.target_chosen = sa.target_chosen.clone();
47 sub_sa.trigger_source = sa.trigger_source;
48 sub_sa.trigger_index = sa.trigger_index;
49 sub_sa.trigger_remembered_amount = sa.trigger_remembered_amount;
50 sub_sa.x_mana_cost_paid = sa.x_mana_cost_paid;
51 sub_sa.kicked = sa.kicked;
52 sub_sa.kick_count = sa.kick_count;
53 sub_sa.buyback_paid = sa.buyback_paid;
54 sub_sa.overloaded = sa.overloaded;
55 sub_sa.replicate_count = sa.replicate_count;
56 sub_sa.is_copy = sa.is_copy;
57
58 let mut cur_opt: Option<SpellAbility> = Some(sub_sa);
62 while let Some(cur_sa) = cur_opt {
63 super::resolve_effect(ctx, &cur_sa);
64 cur_opt = cur_sa.sub_ability.map(|b| *b);
65 if ctx.game.game_over {
66 break;
67 }
68 }
69}
70
71fn evaluate_branch_condition(ctx: &EffectContext, sa: &SpellAbility) -> bool {
72 let Some(condition_svar) = sa.ir.branch_condition_svar.as_deref() else {
73 return true;
74 };
75 let Some(source_id) = sa.source else {
76 return false;
77 };
78 let Some(expr) = ctx.game.card(source_id).get_s_var(condition_svar) else {
79 return false;
80 };
81
82 if let Some(valid_filter) = expr.strip_prefix("Remembered$Valid ") {
83 let remembered = ctx.game.card(source_id).remembered_cards.clone();
84 if remembered.is_empty() {
85 return false;
86 }
87 if valid_filter.eq_ignore_ascii_case("Card.ChosenType") {
88 let Some(chosen_type) = ctx.game.card(source_id).chosen_type.clone() else {
89 return false;
90 };
91 return remembered
92 .iter()
93 .copied()
94 .any(|cid| ctx.game.card(cid).type_line.has_subtype(&chosen_type));
95 }
96 return remembered.iter().copied().any(|cid| {
97 super::matches_valid_cards_for_sa(ctx.game, sa, ctx.game.card(cid), None, valid_filter)
98 });
99 }
100
101 let branch_compare = sa
102 .ir
103 .branch_condition_svar_compare
104 .as_deref()
105 .unwrap_or("GE1");
106 let (operator, operand) = branch_compare.split_at(branch_compare.len().min(2));
107 let svar_value = super::resolve_numeric_value(ctx.game, sa, condition_svar, 0);
108 let operand_value = super::resolve_numeric_value(ctx.game, sa, operand, 0);
109
110 compare_expr(svar_value, &format!("{operator}{operand_value}"))
111}