Skip to main content

manabrew_engine/ability/effects/
activate_ability_effect.rs

1use super::{resolve_defined_players, EffectContext};
2
3/// Mirrors Java's `ActivateAbilityEffect` for the common `ManaAbility$ True`
4/// case used by cards like Pygmy Hippo.
5/// Struct form of this effect so it can participate in the
6/// `SpellAbilityEffect` trait hierarchy — mirrors Java's
7/// `ActivateAbilityEffect` class extending `SpellAbilityEffect`.
8#[manabrew_engine_macros::spell_effect(ActivateAbilityEffect)]
9fn resolve(ctx: &mut EffectContext, sa: &crate::spellability::SpellAbility) {
10    let controller = sa.activating_player;
11    let defined = sa.defined().unwrap_or("You");
12    let only_mana = sa.ir.mana_ability;
13    let type_filter = sa.ir.type_filter.as_deref().unwrap_or("Card");
14
15    let players = resolve_defined_players(defined, controller, ctx.game);
16    for pid in players {
17        if !ctx.game.player(pid).is_alive() {
18            continue;
19        }
20        let battlefield = ctx
21            .game
22            .cards_in_zone(forge_foundation::ZoneType::Battlefield, pid);
23        let card_ids: Vec<crate::ids::CardId> = battlefield.to_vec();
24        for cid in card_ids {
25            let (is_land, is_tapped, chosen_colors, produced_ir, has_tap_cost) = {
26                let card = ctx.game.card(cid);
27                if type_filter.eq_ignore_ascii_case("Land") && !card.is_land() {
28                    continue;
29                }
30                if !type_filter.eq_ignore_ascii_case("Land")
31                    && !type_filter.eq_ignore_ascii_case("Card")
32                {
33                    continue;
34                }
35                if card.tapped {
36                    continue;
37                }
38
39                // Java lets controller choose one ability per card. For parity with
40                // current engine scope, resolve the first legal mana ability.
41                let maybe_mana_ab = card.activated_abilities.iter().find(|ab| {
42                    (!only_mana || ab.is_mana_ability) && ab.ability_kind.as_str() == "Mana"
43                });
44                let Some(mana_ab) = maybe_mana_ab else {
45                    continue;
46                };
47
48                (
49                    card.is_land(),
50                    card.tapped,
51                    card.chosen_colors.clone(),
52                    mana_ab.produced_ir.clone(),
53                    mana_ab.cost.has_tap,
54                )
55            };
56
57            if type_filter.eq_ignore_ascii_case("Land") && !is_land {
58                continue;
59            }
60            if is_tapped {
61                continue;
62            }
63            if has_tap_cost {
64                ctx.game.tap(cid);
65            }
66
67            if let Some(produced_ir) = produced_ir.as_ref() {
68                let atoms = produced_ir.to_atoms(&chosen_colors);
69                if let Some(atom) = atoms.first().copied() {
70                    ctx.mana_pools[pid.index()].add(atom, 1);
71                }
72            }
73        }
74    }
75}