Skip to main content

manabrew_engine/ability/effects/
must_block_effect.rs

1use forge_foundation::ZoneType;
2
3use super::{matches_valid_cards_for_sa, EffectContext};
4use crate::ids::CardId;
5
6/// End-of-turn revert for must-block. Mirrors the `GameCommand.run()` in Java
7/// `MustBlockEffect` that clears the must-block flag when the effect expires.
8pub fn run(game: &mut crate::game::GameState, card_id: crate::ids::CardId) {
9    if game.card(card_id).zone == ZoneType::Battlefield {
10        game.card_mut(card_id).set_must_block(false);
11    }
12}
13
14/// `SP$ MustBlock` — target creature must block this turn if able.
15///
16/// Mirrors Java's `MustBlockEffect.java` (simplified — sets flag only;
17/// full "must block specific attacker" support deferred).
18///
19/// # Card script examples
20/// ```text
21/// A:SP$ MustBlock | ValidTgts$ Creature
22/// A:SP$ MustBlock | Defined$ Targeted
23/// A:SP$ MustBlock | ValidCards$ Creature.OppCtrl
24/// ```
25/// Struct form of this effect so it can participate in the
26/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
27/// `MustBlockEffect` class extending `SpellAbilityEffect`.
28#[manabrew_engine_macros::spell_effect(MustBlockEffect)]
29fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
30    // Targeted mode
31    if let Some(target) = sa.target_chosen.target_card {
32        if ctx.game.card(target).zone == ZoneType::Battlefield {
33            ctx.game.card_mut(target).set_must_block(true);
34        }
35        return;
36    }
37
38    // ValidCards$ mode (mass must-block)
39    if let Some(valid_filter) = sa.ir.valid_cards_text.as_deref() {
40        let valid_selector = sa.ir.valid_cards_selector.as_ref();
41        let player_ids = ctx.game.player_order.clone();
42        let mut targets: Vec<CardId> = Vec::new();
43        for &pid in &player_ids {
44            let zone_cards = ctx.game.cards_in_zone(ZoneType::Battlefield, pid).to_vec();
45            for cid in zone_cards {
46                if matches_valid_cards_for_sa(
47                    ctx.game,
48                    sa,
49                    ctx.game.card(cid),
50                    valid_selector,
51                    valid_filter,
52                ) {
53                    targets.push(cid);
54                }
55            }
56        }
57        for cid in targets {
58            if ctx.game.card(cid).zone == ZoneType::Battlefield {
59                ctx.game.card_mut(cid).set_must_block(true);
60            }
61        }
62        return;
63    }
64
65    // Defined$ Self
66    if let Some(source) = sa.source {
67        if ctx.game.card(source).zone == ZoneType::Battlefield {
68            ctx.game.card_mut(source).set_must_block(true);
69        }
70    }
71}