Skip to main content

manabrew_engine/ability/effects/
prevent_damage_effect.rs

1use forge_foundation::ZoneType;
2
3use super::EffectContext;
4use crate::ability::ability_ir::DefinedRef;
5
6/// `SP$ PreventDamage` — prevent the next N damage that would be dealt to
7/// a target creature or player this turn.
8///
9/// Mirrors Java's `PreventDamageEffect.java`.
10/// - `Amount$` — number of damage to prevent (default 1).
11/// - `Defined$` — who gets the shield (Self, Targeted, ParentTarget, You).
12///
13/// # Card script examples
14/// ```text
15/// A:SP$ PreventDamage | Defined$ Self | Amount$ 3
16/// A:SP$ PreventDamage | Defined$ Targeted | Amount$ X
17/// ```
18/// Struct form of this effect so it can participate in the
19/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
20/// `PreventDamageEffect` class extending `SpellAbilityEffect`.
21#[manabrew_engine_macros::spell_effect(PreventDamageEffect)]
22fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
23    let amount = sa
24        .ir
25        .amount
26        .as_deref()
27        .map(|raw| super::resolve_numeric_value(ctx.game, sa, raw, 1))
28        .unwrap_or(1);
29    if amount <= 0 {
30        return;
31    }
32
33    // Try targeted creature first
34    if let Some(target) = sa.target_chosen.target_card {
35        if ctx.game.card(target).zone == ZoneType::Battlefield {
36            ctx.game.card_mut(target).damage_prevention += amount;
37        }
38        return;
39    }
40
41    // Try targeted player
42    if let Some(pid) = sa.target_chosen.target_player {
43        ctx.game.player_add_damage_prevention(pid, amount);
44        return;
45    }
46
47    // Defined$ resolution
48    match sa
49        .ir
50        .defined
51        .as_ref()
52        .and_then(|defined| defined.refs.first())
53    {
54        Some(DefinedRef::SelfCard) => {
55            if let Some(source) = sa.source {
56                if ctx.game.card(source).zone == ZoneType::Battlefield {
57                    ctx.game.card_mut(source).damage_prevention += amount;
58                }
59            }
60        }
61        Some(DefinedRef::ParentTarget) => {
62            if let Some(parent_target) = ctx.parent_target_card {
63                if ctx.game.card(parent_target).zone == ZoneType::Battlefield {
64                    ctx.game.card_mut(parent_target).damage_prevention += amount;
65                }
66            }
67        }
68        Some(DefinedRef::You) => {
69            let controller = sa.activating_player;
70            ctx.game.player_add_damage_prevention(controller, amount);
71        }
72        Some(DefinedRef::Opponent) => {
73            let opp = ctx.game.opponent_of(sa.activating_player);
74            ctx.game.player_add_damage_prevention(opp, amount);
75        }
76        _ => {
77            // Default: prevent damage to self (source card)
78            if let Some(source) = sa.source {
79                if ctx.game.card(source).zone == ZoneType::Battlefield {
80                    ctx.game.card_mut(source).damage_prevention += amount;
81                }
82            }
83        }
84    }
85}