Skip to main content

manabrew_engine/ability/effects/
tap_or_untap_effect.rs

1use forge_foundation::ZoneType;
2
3use super::EffectContext;
4use crate::ability::ability_ir::DefinedRef;
5use crate::agent::BinaryChoiceKind;
6use crate::ids::CardId;
7
8/// `SP$ TapOrUntap` — choose tap or untap for the targeted/defined permanent.
9///
10/// Mirrors Java `TapOrUntapEffect.java` binary prompt behavior.
11/// Struct form of this effect so it can participate in the
12/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
13/// `TapOrUntapEffect` class extending `SpellAbilityEffect`.
14#[manabrew_engine_macros::spell_effect(TapOrUntapEffect)]
15fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
16    let controller = sa.activating_player;
17    let _source_name = sa
18        .source
19        .map(|cid| ctx.game.card(cid).card_name.clone())
20        .unwrap_or_else(|| "Ability".to_string());
21
22    let mut candidates: Vec<CardId> = Vec::new();
23    if let Some(target) = sa.target_chosen.target_card {
24        candidates.push(target);
25    } else if let Some(source) = sa.source {
26        if matches!(sa.defined_ref(), Some(DefinedRef::SelfCard)) {
27            candidates.push(source);
28        }
29    }
30
31    for card_id in candidates {
32        if ctx.game.card(card_id).zone != ZoneType::Battlefield {
33            continue;
34        }
35        let should_tap = if sa.ir.toggle {
36            !ctx.game.card(card_id).tapped
37        } else {
38            let prompt = format!("Tap or untap {}?", ctx.game.card(card_id).card_name);
39            ctx.agents[controller.index()].choose_binary(
40                controller,
41                &prompt,
42                BinaryChoiceKind::TapOrUntap,
43                None,
44                sa.source,
45                sa.api,
46            )
47        };
48
49        if should_tap {
50            if ctx.game.tap(card_id) {
51                ctx.trigger_handler.run_trigger(
52                    crate::trigger::TriggerType::Taps,
53                    crate::event::RunParams {
54                        card: Some(card_id),
55                        player: Some(controller),
56                        ..Default::default()
57                    },
58                    false,
59                );
60            }
61        } else if ctx.game.untap(card_id) {
62            ctx.trigger_handler.run_trigger(
63                crate::trigger::TriggerType::Untaps,
64                crate::event::RunParams {
65                    card: Some(card_id),
66                    player: Some(controller),
67                    ..Default::default()
68                },
69                false,
70            );
71        }
72    }
73}