Skip to main content

manabrew_engine/ability/effects/
time_travel_effect.rs

1use forge_foundation::ZoneType;
2
3use super::resolve_numeric_svar;
4use super::EffectContext;
5use crate::agent::BinaryChoiceKind;
6use crate::card::CounterType;
7use crate::ids::CardId;
8use crate::parsing::keys;
9
10/// `SP$ TimeTravel` — for chosen cards, add or remove a time counter.
11///
12/// Mirrors Java `TimeTravelEffect.java` binary choice semantics.
13/// Struct form of this effect so it can participate in the
14/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
15/// `TimeTravelEffect` class extending `SpellAbilityEffect`.
16#[manabrew_engine_macros::spell_effect(TimeTravelEffect)]
17fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
18    let controller = sa.activating_player;
19    let Some(source_id) = sa.source else { return };
20    let source_name = ctx.game.card(source_id).card_name.clone();
21
22    let amount = resolve_numeric_svar(ctx.game, sa, keys::AMOUNT, 1);
23    if amount <= 0 {
24        return;
25    }
26
27    for _ in 0..amount {
28        let mut valid: Vec<CardId> = Vec::new();
29        for &cid in ctx.game.cards_in_zone(ZoneType::Exile, controller) {
30            if ctx.game.card(cid).get_suspend_cost().is_some() {
31                valid.push(cid);
32            }
33        }
34        for &cid in ctx.game.cards_in_zone(ZoneType::Battlefield, controller) {
35            if ctx.game.card(cid).counter_count(&CounterType::Time) > 0 {
36                valid.push(cid);
37            }
38        }
39        if valid.is_empty() {
40            break;
41        }
42
43        let chosen = ctx.agents[controller.index()].choose_cards_for_effect(
44            controller,
45            &valid,
46            0,
47            valid.len(),
48        );
49        for cid in chosen {
50            let prompt = format!(
51                "Add or remove time counter on {}?",
52                ctx.game.card(cid).card_name
53            );
54            let add = ctx.agents[controller.index()].choose_binary(
55                controller,
56                &prompt,
57                BinaryChoiceKind::AddOrRemove,
58                None,
59                Some(source_id),
60                sa.api,
61            );
62            if add {
63                ctx.game.card_mut(cid).add_counter(&CounterType::Time, 1);
64                ctx.trigger_handler.run_trigger(
65                    crate::trigger::TriggerType::CounterAdded,
66                    crate::event::RunParams {
67                        card: Some(cid),
68                        counter_type: Some("Time".to_string()),
69                        counter_amount: Some(1),
70                        cause_player: Some(controller),
71                        ..Default::default()
72                    },
73                    false,
74                );
75            } else {
76                ctx.game.card_mut(cid).remove_counter(&CounterType::Time, 1);
77                ctx.trigger_handler.run_trigger(
78                    crate::trigger::TriggerType::CounterRemoved,
79                    crate::event::RunParams {
80                        card: Some(cid),
81                        counter_type: Some("Time".to_string()),
82                        counter_amount: Some(1),
83                        cause_player: Some(controller),
84                        ..Default::default()
85                    },
86                    false,
87                );
88            }
89        }
90    }
91}