manabrew_engine/spellability/ability.rs
1//! Ability -- helper functions for in-play abilities.
2//! Mirrors Java's `Ability.java` (base class for abilities on permanents).
3//! In Rust the subclass is flattened into SpellAbility.
4
5use forge_foundation::ZoneType;
6
7use crate::game::GameState;
8use crate::spellability::SpellAbility;
9
10/// Type alias for SpellAbility when used as an in-play ability.
11/// In Java, `Ability` is a subclass; in Rust it's the same struct with `is_activated = true`.
12pub type Ability = super::SpellAbility;
13
14/// Whether this in-play ability can currently be played.
15/// Mirrors Java's `Ability.canPlay()`.
16///
17/// Checks:
18/// 1. Split second not on stack (unless this is a mana ability).
19/// 2. The source card is on the battlefield (in play).
20/// 3. The source card is not face down (face-down cards can't use abilities
21/// except morph/megamorph turn-face-up).
22pub fn can_play(sa: &SpellAbility, game: &GameState) -> bool {
23 let card_id = match sa.source {
24 Some(id) => id,
25 None => return false,
26 };
27
28 // Split second check: mana abilities bypass split second
29 if !sa.is_mana_ability && super::has_split_second_on_stack(game) {
30 return false;
31 }
32
33 // The card must be on the battlefield to activate in-play abilities
34 if !game.card_is_in_zone(card_id, ZoneType::Battlefield) {
35 return false;
36 }
37
38 let card = game.card(card_id);
39
40 // Face-down cards cannot activate abilities (except morph turn-face-up,
41 // which is handled by AbilityStatic, not Ability)
42 if card.face_down {
43 return false;
44 }
45
46 // Delegate to general restriction check
47 sa.can_play(game)
48}