manabrew_engine/ability/effects/
skip_phase_effect.rs1use super::{resolve_defined_players, EffectContext};
2
3pub fn create_skip_phase_effect(
10 game: &mut crate::game::GameState,
11 player: crate::ids::PlayerId,
12 phase: &str,
13) {
14 match phase {
15 "Draw" => game.player_mut(player).skip_next_draw = true,
16 "Combat" | "BeginCombat" => game.player_mut(player).skip_next_combat = true,
17 "Untap" => game.player_mut(player).skip_next_untap = true,
18 _ => {
19 eprintln!("SkipPhaseEffect: Unknown phase to skip: {:?}", phase);
20 }
21 }
22}
23
24pub fn run(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
29 use crate::ability::spell_ability_effect::SpellAbilityEffect;
30 SkipPhaseEffect::resolve(ctx, sa);
31}
32
33#[manabrew_engine_macros::spell_effect(SkipPhaseEffect)]
49fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
50 let controller = sa.activating_player;
51
52 let phase = sa
53 .ir
54 .phase_text
55 .as_deref()
56 .or(sa.ir.step_text.as_deref())
57 .unwrap_or("");
58
59 let defined = sa.defined().unwrap_or("You");
60
61 let targets = resolve_defined_players(defined, controller, ctx.game);
62 for target in targets {
63 if !ctx.game.player(target).is_alive() {
64 continue;
65 }
66 match phase {
67 "Draw" => ctx.game.player_set_skip_draw(target),
68 "Combat" | "BeginCombat" => ctx.game.player_set_skip_combat(target),
69 "Untap" => ctx.game.player_set_skip_untap(target),
70 _ => {
71 let err = crate::ability::IllegalAbilityException::new(format!(
72 "Unknown phase to skip: {:?}",
73 phase
74 ));
75 eprintln!("{}", err);
76 }
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use std::collections::HashMap;
84
85 use super::SkipPhaseEffect;
86 use crate::ability::effects::EffectContext;
87 use crate::ability::spell_ability_effect::SpellAbilityEffect;
88 use crate::agent::PassAgent;
89 use crate::game::GameState;
90 use crate::ids::PlayerId;
91 use crate::mana::ManaPool;
92 use crate::spellability::SpellAbility;
93 use crate::trigger::handler::TriggerHandler;
94
95 #[test]
96 fn skip_draw_phase() {
97 let mut game = GameState::new(&["Alice", "Bob"], 20);
98 let p0 = PlayerId(0);
99 let p1 = PlayerId(1);
100
101 let sa =
102 SpellAbility::new_simple(None, p0, "SP$ SkipPhase | Defined$ Opponent | Phase$ Draw");
103
104 let mut th = TriggerHandler::new();
105 let mut agents: Vec<Box<dyn crate::agent::PlayerAgent>> =
106 vec![Box::new(PassAgent), Box::new(PassAgent)];
107 let mut mp = vec![ManaPool::default(), ManaPool::default()];
108 let templates = HashMap::new();
109 let templates_variants = HashMap::new();
110 let token_fallback = HashMap::new();
111 let edition_dates: HashMap<String, String> = HashMap::new();
112 let mut rng_adapter = crate::game_rng::ThreadRngAdapter;
113 let mut ctx = EffectContext {
114 game: &mut game,
115 combat: None,
116 agents: &mut agents,
117 trigger_handler: &mut th,
118 token_templates: &templates,
119 token_art_variants: &templates_variants,
120 token_fallback: &token_fallback,
121 edition_dates: &edition_dates,
122 mana_pools: &mut mp,
123 parent_target_card: None,
124 rng: &mut rng_adapter,
125 };
126 super::SkipPhaseEffect::resolve(&mut ctx, &sa);
127
128 assert!(ctx.game.player(p1).skip_next_draw);
129 assert!(!ctx.game.player(p1).skip_next_combat);
130 }
131
132 #[test]
133 fn skip_combat_phase() {
134 let mut game = GameState::new(&["Alice", "Bob"], 20);
135 let p0 = PlayerId(0);
136
137 let sa = SpellAbility::new_simple(None, p0, "SP$ SkipPhase | Defined$ You | Phase$ Combat");
138
139 let mut th = TriggerHandler::new();
140 let mut agents: Vec<Box<dyn crate::agent::PlayerAgent>> =
141 vec![Box::new(PassAgent), Box::new(PassAgent)];
142 let mut mp = vec![ManaPool::default(), ManaPool::default()];
143 let templates = HashMap::new();
144 let templates_variants = HashMap::new();
145 let token_fallback = HashMap::new();
146 let edition_dates: HashMap<String, String> = HashMap::new();
147 let mut rng_adapter = crate::game_rng::ThreadRngAdapter;
148 let mut ctx = EffectContext {
149 game: &mut game,
150 combat: None,
151 agents: &mut agents,
152 trigger_handler: &mut th,
153 token_templates: &templates,
154 token_art_variants: &templates_variants,
155 token_fallback: &token_fallback,
156 edition_dates: &edition_dates,
157 mana_pools: &mut mp,
158 parent_target_card: None,
159 rng: &mut rng_adapter,
160 };
161 super::SkipPhaseEffect::resolve(&mut ctx, &sa);
162
163 assert!(ctx.game.player(p0).skip_next_combat);
164 }
165}