Skip to main content

manabrew_engine/staticability/
static_ability_continuous.rs

1//! Java parity bridge for `StaticAbilityContinuous.java`.
2//! Canonical CR613 recomputation lives in `layer.rs`.
3
4use crate::card::Card;
5use crate::game::GameState;
6use crate::staticability::{Layer, StaticAbility};
7
8pub fn apply_continuous_ability(
9    st_ab: &StaticAbility,
10    source: &Card,
11    game: &mut GameState,
12    layer: Layer,
13) {
14    if !crate::staticability::layer::classify_static_layers(st_ab).contains(&layer) {
15        return;
16    }
17    if !st_ab.check_conditions(source, game) {
18        return;
19    }
20    crate::staticability::layer::apply_continuous_effects(game);
21}
22
23pub fn resolve(st_ab: &StaticAbility, source: &Card, game: &GameState) {
24    let _ = run(st_ab, source, game);
25}
26
27pub fn can_play(st_ab: &StaticAbility, source: &Card, card: &Card, _game: &GameState) -> bool {
28    if !st_ab.ir.may_play {
29        return false;
30    }
31    // Check AffectedZone$ — the zone where the affected cards must be.
32    // Default is Hand if not specified (normal MayPlay like casting from hand).
33    if !st_ab.ir.affected_zones.is_empty() {
34        if !st_ab.ir.affected_zones.contains(&card.zone) {
35            return false;
36        }
37    } else if card.zone != forge_foundation::ZoneType::Hand {
38        return false;
39    }
40    crate::card::valid_filter::matches_valid_card_selector_opt(
41        st_ab.ir.affected.as_ref(),
42        card,
43        source,
44    )
45}
46
47pub fn can_play_or_granted(
48    st_ab: &StaticAbility,
49    source: &Card,
50    card: &Card,
51    game: &GameState,
52) -> bool {
53    if can_play(st_ab, source, card, game) {
54        return true;
55    }
56    if !st_ab.check_conditions(source, game) {
57        return false;
58    }
59    if !crate::card::valid_filter::matches_valid_card_selector_opt(
60        st_ab.ir.affected.as_ref(),
61        source,
62        source,
63    ) {
64        return false;
65    }
66    let Some(add_static) = st_ab.ir.add_static_ability_text.as_deref() else {
67        return false;
68    };
69    add_static
70        .split(" & ")
71        .map(str::trim)
72        .filter(|s| !s.is_empty())
73        .filter_map(|svar_name| source.svars.get(svar_name))
74        .filter_map(|static_text| crate::staticability::parse_static_ability(static_text))
75        .any(|granted| can_play(&granted, source, card, game))
76}
77
78/// If a `MayPlay$ True` static on `source` grants `card` permission to be
79/// cast and also defines `MayPlayAltManaCost$`, return that alt cost string.
80/// Mirrors Java's `GameActionUtil.canPlayCardMayPlay` reading
81/// `getMayPlayAltManaCost()` for the granting static.
82pub fn may_play_alt_mana_cost(
83    st_ab: &StaticAbility,
84    source: &Card,
85    card: &Card,
86    game: &GameState,
87) -> Option<String> {
88    if !can_play(st_ab, source, card, game) {
89        return None;
90    }
91    st_ab.ir.may_play_alt_mana_cost.clone()
92}
93
94pub fn run(st_ab: &StaticAbility, source: &Card, game: &GameState) -> bool {
95    st_ab.check_conditions(source, game)
96}