Skip to main content

manabrew_engine/ability/effects/
internal_radiation_effect.rs

1//! InternalRadiation effect — process radiation counter damage.
2//!
3//! Ported from Java's `InternalRadiationEffect.java`.
4//! Mills cards equal to radiation counters, then the player loses life
5//! equal to the number of non-land cards milled, and removes that many
6//! rad counters.
7
8use forge_foundation::ZoneType;
9
10use super::EffectContext;
11use crate::event::RunParams;
12use crate::trigger::TriggerType;
13
14/// Struct form of this effect so it can participate in the
15/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
16/// `InternalRadiationEffect` class extending `SpellAbilityEffect`.
17#[manabrew_engine_macros::spell_effect(InternalRadiationEffect)]
18fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
19    let controller = sa.activating_player;
20    let num_rad = ctx.game.player(controller).radiation_counters;
21
22    if num_rad <= 0 {
23        return;
24    }
25
26    // Mill cards equal to radiation counter count
27    let mut non_land_count = 0;
28    for _ in 0..num_rad {
29        let lib = ctx.game.zone(ZoneType::Library, controller);
30        if lib.cards.is_empty() {
31            break;
32        }
33        let top_card = lib.cards[0];
34
35        // Check if the card is non-land before moving
36        let is_land = ctx.game.card(top_card).type_line.is_land();
37
38        // Mill: move from library to graveyard
39        ctx.game
40            .move_card(top_card, ZoneType::Graveyard, controller);
41        super::emit_zone_trigger(
42            ctx.trigger_handler,
43            top_card,
44            ZoneType::Library,
45            ZoneType::Graveyard,
46        );
47
48        if !is_land {
49            non_land_count += 1;
50        }
51    }
52
53    // Lose life equal to number of non-land cards milled
54    if non_land_count > 0 {
55        ctx.game.player_lose_life(controller, non_land_count);
56
57        // Fire LifeLost trigger
58        ctx.trigger_handler.run_trigger(
59            TriggerType::LifeLost,
60            RunParams {
61                player: Some(controller),
62                life_amount: Some(non_land_count),
63                ..Default::default()
64            },
65            false,
66        );
67    }
68
69    // Remove rad counters equal to non-land cards milled
70    let current_rad = ctx.game.player(controller).radiation_counters;
71    ctx.game
72        .player_set_radiation(controller, (current_rad - non_land_count).max(0));
73}