Skip to main content

manabrew_engine/ability/effects/
earthbend_effect.rs

1//! Earthbend — turn a land into a 0/0 creature with haste and +1/+1 counters.
2//! Ported from Java's EarthbendEffect: adds creature type, haste, and counters
3//! to target land, plus sets up a delayed trigger to return it when it dies.
4
5use forge_foundation::{CoreType, ZoneType};
6
7use super::EffectContext;
8use crate::ids::CardId;
9use crate::parsing::Params;
10use crate::trigger::handler::DelayedTrigger;
11use crate::trigger::{parse_trigger, TriggerType};
12
13/// Configure the spell ability during construction.
14/// Mirrors Java `EarthbendEffect.buildSpellAbility` — sets up targeting to
15/// require "Land.YouCtrl" (a land you control).
16pub fn build_spell_ability(sa: &mut crate::spellability::SpellAbility) {
17    use crate::parsing::Params;
18    use crate::spellability::TargetRestrictions;
19
20    // Build target restrictions for "Land.YouCtrl"
21    let params = Params::from_raw("ValidTgts$ Land.YouCtrl | TgtPrompt$ land you control");
22    if let Some(tr) = TargetRestrictions::new(&params) {
23        sa.target_restrictions = Some(tr);
24    }
25}
26
27/// Struct form of this effect so it can participate in the
28/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
29/// `EarthbendEffect` class extending `SpellAbilityEffect`.
30#[manabrew_engine_macros::spell_effect(EarthbendEffect)]
31fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
32    let num = super::resolve_numeric_svar(ctx.game, sa, "Num", 1).max(0);
33
34    let targets: Vec<CardId> = if let Some(target) = sa.target_chosen.target_card {
35        vec![target]
36    } else {
37        return;
38    };
39
40    for card_id in targets {
41        if ctx.game.card(card_id).zone != ZoneType::Battlefield {
42            continue;
43        }
44
45        ctx.game
46            .card_mut(card_id)
47            .capture_changed_characteristics_baseline_if_needed();
48
49        // Set base P/T to 0/0
50        ctx.game.card_mut(card_id).set_base_pt(Some(0), Some(0));
51
52        // Add Creature core type
53        ctx.game
54            .card_mut(card_id)
55            .add_type(CoreType::Creature.name());
56
57        // Add Haste keyword
58        if !ctx
59            .game
60            .card(card_id)
61            .keywords
62            .contains_string_ignore_case("Haste")
63        {
64            ctx.game.card_mut(card_id).add_intrinsic_keyword("Haste");
65        }
66
67        // Add +1/+1 counters
68        let counter_type = super::parse_counter_type("P1P1");
69        ctx.add_counter(
70            card_id,
71            &counter_type,
72            num,
73            sa,
74            crate::event::RunParams::default(),
75        );
76
77        register_return_trigger(ctx, sa, card_id, ZoneType::Graveyard);
78        register_return_trigger(ctx, sa, card_id, ZoneType::Exile);
79    }
80}
81
82fn register_return_trigger(
83    ctx: &mut EffectContext,
84    sa: &crate::spellability::SpellAbility,
85    card_id: CardId,
86    zone: ZoneType,
87) {
88    let trigger_raw = match zone {
89        ZoneType::Graveyard => {
90            "Mode$ ChangesZone | ValidCard$ Card.IsTriggerRemembered | Origin$ Battlefield | Destination$ Graveyard | TriggerDescription$ When it dies or is exiled, return it to the battlefield tapped."
91        }
92        ZoneType::Exile => {
93            "Mode$ Exiled | Origin$ Battlefield | ValidCard$ Card.IsTriggerRemembered | TriggerZones$ Battlefield | TriggerDescription$ When it dies or is exiled, return it to the battlefield tapped."
94        }
95        _ => return,
96    };
97
98    let mut next_id = 0;
99    let Some(trigger) = parse_trigger(trigger_raw, &mut next_id) else {
100        return;
101    };
102    let source_card = sa.source.unwrap_or(card_id);
103    let origin = match zone {
104        ZoneType::Graveyard => "Graveyard",
105        ZoneType::Exile => "Exile",
106        _ => return,
107    };
108    let execute_svar = format!(
109        "DB$ ChangeZone | Defined$ DelayTriggerRemembered | Origin$ {origin} | Destination$ Battlefield | Tapped$ True | GainControl$ You"
110    );
111
112    ctx.trigger_handler
113        .register_delayed_trigger(DelayedTrigger {
114            mode: match zone {
115                ZoneType::Graveyard => TriggerType::ChangesZone,
116                ZoneType::Exile => TriggerType::Exiled,
117                _ => unreachable!(),
118            },
119            trigger_mode: trigger.mode,
120            params: Params::from_raw(trigger_raw),
121            execute_svar,
122            controller: sa.activating_player,
123            source_card,
124            created_turn: ctx.game.turn.turn_number,
125            created_phase: ctx.game.turn.phase,
126            target_card: Some(card_id),
127            remembered_amount: 0,
128            remembered_cards: vec![card_id],
129            remembered_players: Vec::new(),
130            remembered_lki_cards: Vec::new(),
131            sort_after_active: false,
132            trigger_order: None,
133        });
134}