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.game.card_mut(card_id).add_counter(&counter_type, num);
70
71        register_return_trigger(ctx, sa, card_id, ZoneType::Graveyard);
72        register_return_trigger(ctx, sa, card_id, ZoneType::Exile);
73    }
74}
75
76fn register_return_trigger(
77    ctx: &mut EffectContext,
78    sa: &crate::spellability::SpellAbility,
79    card_id: CardId,
80    zone: ZoneType,
81) {
82    let trigger_raw = match zone {
83        ZoneType::Graveyard => {
84            "Mode$ ChangesZone | ValidCard$ Card.IsTriggerRemembered | Origin$ Battlefield | Destination$ Graveyard | TriggerDescription$ When it dies or is exiled, return it to the battlefield tapped."
85        }
86        ZoneType::Exile => {
87            "Mode$ Exiled | Origin$ Battlefield | ValidCard$ Card.IsTriggerRemembered | TriggerZones$ Battlefield | TriggerDescription$ When it dies or is exiled, return it to the battlefield tapped."
88        }
89        _ => return,
90    };
91
92    let mut next_id = 0;
93    let Some(trigger) = parse_trigger(trigger_raw, &mut next_id) else {
94        return;
95    };
96    let source_card = sa.source.unwrap_or(card_id);
97    let origin = match zone {
98        ZoneType::Graveyard => "Graveyard",
99        ZoneType::Exile => "Exile",
100        _ => return,
101    };
102    let execute_svar = format!(
103        "DB$ ChangeZone | Defined$ DelayTriggerRemembered | Origin$ {origin} | Destination$ Battlefield | Tapped$ True | GainControl$ You"
104    );
105
106    ctx.trigger_handler
107        .register_delayed_trigger(DelayedTrigger {
108            mode: match zone {
109                ZoneType::Graveyard => TriggerType::ChangesZone,
110                ZoneType::Exile => TriggerType::Exiled,
111                _ => unreachable!(),
112            },
113            trigger_mode: trigger.mode,
114            params: Params::from_raw(trigger_raw),
115            execute_svar,
116            controller: sa.activating_player,
117            source_card,
118            created_turn: ctx.game.turn.turn_number,
119            created_phase: ctx.game.turn.phase,
120            target_card: Some(card_id),
121            remembered_amount: 0,
122            remembered_cards: vec![card_id],
123            remembered_players: Vec::new(),
124            remembered_lki_cards: Vec::new(),
125            sort_after_active: false,
126            trigger_order: None,
127        });
128}