Skip to main content

manabrew_engine/ability/effects/
goad_effect.rs

1use forge_foundation::ZoneType;
2
3use super::{matches_valid_cards_selector_opt, EffectContext};
4use crate::ids::CardId;
5
6/// End-of-turn revert for goad. Mirrors the `GameCommand.run()` in Java
7/// `GoadEffect` that removes the goaded-by marker 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_goaded_by(None);
11    }
12}
13
14/// `SP$ Goad` — goad target creature(s). Goaded creatures must attack each
15/// combat if able, and can't attack the player who goaded them.
16///
17/// Mirrors Java's `GoadEffect.java`.
18///
19/// # Card script examples
20/// ```text
21/// A:SP$ Goad | ValidTgts$ Creature.OppCtrl
22/// A:SP$ Goad | ValidCards$ Creature.OppCtrl
23/// ```
24/// Struct form of this effect so it can participate in the
25/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
26/// `GoadEffect` class extending `SpellAbilityEffect`.
27#[manabrew_engine_macros::spell_effect(GoadEffect)]
28fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
29    let controller = sa.activating_player;
30
31    // Targeted mode
32    if let Some(target) = sa.target_chosen.target_card {
33        if ctx.game.card(target).zone == ZoneType::Battlefield {
34            ctx.game.card_mut(target).set_goaded_by(Some(controller));
35        }
36        return;
37    }
38
39    // Mass goad: ValidCards$ filter
40    if let Some(valid_filter) = 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_selector_opt(
47                    Some(valid_filter),
48                    ctx.game.card(cid),
49                    sa.activating_player,
50                ) {
51                    targets.push(cid);
52                }
53            }
54        }
55        for cid in targets {
56            if ctx.game.card(cid).zone == ZoneType::Battlefield {
57                ctx.game.card_mut(cid).set_goaded_by(Some(controller));
58            }
59        }
60        return;
61    }
62
63    // Defined$ Self fallback
64    if let Some(source) = sa.source {
65        if ctx.game.card(source).zone == ZoneType::Battlefield {
66            ctx.game.card_mut(source).set_goaded_by(Some(controller));
67        }
68    }
69}