Skip to main content

manabrew_engine/ability/effects/
endure_effect.rs

1//! Endure — creature endures: either put +1/+1 counters on it, or create
2//! a Spirit token with power/toughness equal to the endure amount.
3//! Ported from Java's EndureEffect.
4
5use forge_foundation::ZoneType;
6
7use super::token_effect_base::{TokenEffectBase, TOKEN_EFFECT_BASE};
8use super::EffectContext;
9use crate::card::card_zone_table::CardZoneTable;
10use crate::ids::CardId;
11
12/// Struct form of this effect so it can participate in the
13/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
14/// `EndureEffect` class extending `SpellAbilityEffect`.
15#[manabrew_engine_macros::spell_effect(EndureEffect)]
16fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
17    let amount = super::resolve_numeric_svar(ctx.game, sa, "Num", 1).max(0);
18    if amount < 1 {
19        return; // CR 701.63b
20    }
21
22    let targets: Vec<CardId> = if let Some(target) = sa.target_chosen.target_card {
23        vec![target]
24    } else if let Some(source) = sa.source {
25        ctx.game.card(source).remembered_cards.clone()
26    } else {
27        return;
28    };
29
30    let mut token_table = super::token_effect_base::TokenCreateTable::default();
31    for card_id in targets {
32        if ctx.game.card(card_id).zone != ZoneType::Battlefield {
33            continue;
34        }
35
36        let counter_type = super::parse_counter_type("P1P1");
37        if crate::card::card_predicates::can_receive_counters(ctx.game, card_id, &counter_type) {
38            // Rust agents do not expose Java's Endure confirm prompt yet; preserve
39            // the current auto-counter behavior when the target can receive counters.
40            ctx.game
41                .card_mut(card_id)
42                .add_counter(&counter_type, amount);
43        } else {
44            let controller = ctx.game.card(card_id).controller;
45            let mut token =
46                TOKEN_EFFECT_BASE.require_token_template(ctx.token_templates, "w_x_x_spirit");
47            token.set_base_power(Some(amount));
48            token.set_base_toughness(Some(amount));
49            token_table.put(controller, token, 1);
50        }
51    }
52
53    if !token_table.is_empty() {
54        let mut trigger_list = CardZoneTable::default();
55        let result =
56            TOKEN_EFFECT_BASE.make_token_table(ctx, token_table, false, &mut trigger_list, sa);
57        if !result.created.is_empty() {
58            trigger_list.trigger_changes_zone_all(ctx.trigger_handler, ctx.game, Some(sa));
59        }
60    }
61}