manabrew_engine/ability/effects/
add_turn_effect.rs1use super::{resolve_defined_player, resolve_numeric_svar, EffectContext};
2use crate::parsing::keys;
3use crate::phase::ExtraTurn;
4use crate::spellability::SpellAbility;
5
6#[manabrew_engine_macros::spell_effect(AddTurnEffect)]
23fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
24 let controller = sa.activating_player;
25
26 let num_turns = resolve_numeric_svar(ctx.game, sa, keys::NUM_TURNS, 1);
27 let skip_untap = sa.ir.skip_untap;
28
29 let defined = sa.defined().unwrap_or("You");
30
31 let target = resolve_defined_player(defined, controller, ctx.game).unwrap_or(controller);
32
33 if !ctx.game.player(target).is_alive() {
34 return;
35 }
36
37 for _ in 0..num_turns {
38 let mut et = ExtraTurn::new(target);
39 et.set_skip_untap(skip_untap);
40 ctx.game.extra_turns.push_back(et);
41 }
42}
43
44pub fn create_cant_set_schemes_in_motion_effect(ctx: &mut EffectContext, sa: &SpellAbility) {
52 use forge_foundation::{CardTypeLine, ColorSet, ManaCost, ZoneType};
53
54 let source_id = match sa.source {
55 Some(id) => id,
56 None => return,
57 };
58 let controller = sa.activating_player;
59 let card_name = ctx.game.card(source_id).card_name.clone();
60
61 let effect_card = crate::card::Card::new(
63 crate::ids::CardId(0),
64 format!("{}'s Effect", card_name),
65 controller,
66 CardTypeLine::default(),
67 ManaCost::no_cost(),
68 ColorSet::COLORLESS,
69 None,
70 None,
71 vec![],
72 vec![],
73 );
74 let effect_id = ctx.game.create_card(effect_card);
75
76 ctx.game.card_mut(effect_id).set_s_var(
79 "ReplacementEffect",
80 "Event$ SetInMotion | EffectZone$ Command | Layer$ CantHappen | Description$ Schemes can't be set in Motion".to_string(),
81 );
82
83 ctx.game.move_card(effect_id, ZoneType::Command, controller);
85
86 ctx.game
89 .card_mut(effect_id)
90 .set_s_var("ExileAtEndOfTurn", "True".to_string());
91}
92
93#[cfg(test)]
94mod tests {
95 use crate::ability::spell_ability_effect::SpellAbilityEffect;
96 use std::collections::HashMap;
97
98 use crate::ability::effects::EffectContext;
99 use crate::agent::PassAgent;
100 use crate::game::GameState;
101 use crate::ids::PlayerId;
102 use crate::mana::ManaPool;
103 use crate::spellability::SpellAbility;
104 use crate::trigger::handler::TriggerHandler;
105
106 #[test]
107 fn add_turn_queues_extra_turns() {
108 let mut game = GameState::new(&["Alice", "Bob"], 20);
109 let p0 = PlayerId(0);
110
111 let sa = SpellAbility::new_simple(None, p0, "SP$ AddTurn | Defined$ You | NumTurns$ 2");
112
113 let mut th = TriggerHandler::new();
114 let mut agents: Vec<Box<dyn crate::agent::PlayerAgent>> =
115 vec![Box::new(PassAgent), Box::new(PassAgent)];
116 let mut mp = vec![ManaPool::default(), ManaPool::default()];
117 let templates = HashMap::new();
118 let templates_variants = HashMap::new();
119 let token_fallback = HashMap::new();
120 let edition_dates: HashMap<String, String> = HashMap::new();
121 let mut rng_adapter = crate::game_rng::ThreadRngAdapter;
122 let mut ctx = EffectContext {
123 game: &mut game,
124 combat: None,
125 agents: &mut agents,
126 trigger_handler: &mut th,
127 token_templates: &templates,
128 token_art_variants: &templates_variants,
129 token_fallback: &token_fallback,
130 edition_dates: &edition_dates,
131 mana_pools: &mut mp,
132 parent_target_card: None,
133 rng: &mut rng_adapter,
134 };
135 super::AddTurnEffect::resolve(&mut ctx, &sa);
136
137 assert_eq!(ctx.game.extra_turns.len(), 2);
138 assert_eq!(ctx.game.extra_turns[0].player, p0);
139 assert_eq!(ctx.game.extra_turns[1].player, p0);
140 }
141
142 #[test]
143 fn add_turn_default_one() {
144 let mut game = GameState::new(&["Alice", "Bob"], 20);
145 let p0 = PlayerId(0);
146
147 let sa = SpellAbility::new_simple(None, p0, "SP$ AddTurn | Defined$ You");
148
149 let mut th = TriggerHandler::new();
150 let mut agents: Vec<Box<dyn crate::agent::PlayerAgent>> =
151 vec![Box::new(PassAgent), Box::new(PassAgent)];
152 let mut mp = vec![ManaPool::default(), ManaPool::default()];
153 let templates = HashMap::new();
154 let templates_variants = HashMap::new();
155 let token_fallback = HashMap::new();
156 let edition_dates: HashMap<String, String> = HashMap::new();
157 let mut rng_adapter = crate::game_rng::ThreadRngAdapter;
158 let mut ctx = EffectContext {
159 game: &mut game,
160 combat: None,
161 agents: &mut agents,
162 trigger_handler: &mut th,
163 token_templates: &templates,
164 token_art_variants: &templates_variants,
165 token_fallback: &token_fallback,
166 edition_dates: &edition_dates,
167 mana_pools: &mut mp,
168 parent_target_card: None,
169 rng: &mut rng_adapter,
170 };
171 super::AddTurnEffect::resolve(&mut ctx, &sa);
172
173 assert_eq!(ctx.game.extra_turns.len(), 1);
174 assert_eq!(ctx.game.extra_turns[0].player, p0);
175 assert!(!ctx.game.extra_turns[0].skip_untap);
176 }
177}