manabrew_engine/ability/effects/
flip_coin_effect.rs1use super::EffectContext;
2use crate::agent::BinaryChoiceKind;
3use crate::spellability::SpellAbility;
4
5#[manabrew_engine_macros::spell_effect(FlipCoinEffect)]
21fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
22 let controller = sa.activating_player;
23 let no_call = sa.ir.no_call;
24
25 let is_heads = ctx.rng.next_int(2) == 0;
27
28 let source_id = match sa.source {
29 Some(id) => id,
30 None => return,
31 };
32
33 if no_call {
34 let sub_key = if is_heads {
36 "HeadsSubAbility"
37 } else {
38 "TailsSubAbility"
39 };
40 if let Some(sub_sa) = sa.get_additional_ability(sub_key).cloned() {
41 resolve_sub_chain(ctx, sub_sa);
42 }
43 } else {
44 let card_name = ctx.game.card(source_id).card_name.clone();
46 let called_heads = ctx.agents[controller.index()].choose_binary(
47 controller,
48 "Call the coin flip",
49 BinaryChoiceKind::HeadsOrTails,
50 None,
51 Some(source_id),
52 sa.api,
53 );
54 let won = called_heads == is_heads;
55
56 let sub_key = if won {
57 "WinSubAbility"
58 } else {
59 "LoseSubAbility"
60 };
61 if let Some(sub_sa) = sa.get_additional_ability(sub_key).cloned() {
62 resolve_sub_chain(ctx, sub_sa);
63 }
64 }
65}
66
67pub fn flip_coins(
74 ctx: &mut EffectContext,
75 flipper: crate::ids::PlayerId,
76 sa: &SpellAbility,
77 amount: i32,
78) -> i32 {
79 let flip_until_lose = sa.ir.flip_until_you_lose;
80
81 let multiplier = get_flip_multiplier(ctx, flipper);
84
85 let mut total_wins = 0;
86 let mut won = false;
87
88 loop {
89 for _ in 0..amount {
90 won = flip_single_coin(ctx, flipper, multiplier);
91 if won {
92 total_wins += 1;
93 }
94 }
95 if !flip_until_lose || !won {
97 break;
98 }
99 }
100
101 total_wins
102}
103
104fn flip_single_coin(
106 ctx: &mut EffectContext,
107 _flipper: crate::ids::PlayerId,
108 multiplier: i32,
109) -> bool {
110 let mut any_heads = false;
113 for _ in 0..multiplier {
114 let result = ctx.rng.next_int(2) == 0;
115 if result {
116 any_heads = true;
117 }
118 }
119 any_heads
120}
121
122pub fn get_flip_multiplier(ctx: &EffectContext, flipper: crate::ids::PlayerId) -> i32 {
127 let keyword = "If you would flip a coin, instead flip two coins and ignore one.";
128 let count = ctx
129 .game
130 .cards
131 .iter()
132 .filter(|c| {
133 c.zone == forge_foundation::ZoneType::Battlefield
134 && c.controller == flipper
135 && c.keywords.contains_string_ignore_case(keyword)
136 })
137 .count() as u32;
138 1i32 << count
139}
140
141fn resolve_sub_chain(ctx: &mut EffectContext, initial: SpellAbility) {
142 let mut cur_opt: Option<SpellAbility> = Some(initial);
143 while let Some(cur_sa) = cur_opt {
144 super::resolve_effect(ctx, &cur_sa);
145 cur_opt = cur_sa.sub_ability.map(|b| *b);
146 if ctx.game.game_over {
147 break;
148 }
149 }
150}