Skip to main content

manabrew_engine/spellability/
params.rs

1//! Typed accessor helpers for SpellAbility parameters.
2//!
3//! These methods replace raw parameter lookups with
4//! typed accessors that are discoverable via autocomplete and catch
5//! typos at compile time.
6
7use super::SpellAbility;
8use crate::ability::ability_ir::DefinedRef;
9use crate::ability::ProducedMana;
10use crate::card::CounterType;
11use crate::parsing::{keys, CompiledSelector};
12use forge_foundation::ZoneType;
13
14/// Typed accessors for common SpellAbility parameters.
15/// These mirror the param keys used in Java Forge's ability text format.
16impl SpellAbility {
17    // ── Card/Target filters ────────────────────────────────────────────────
18
19    /// Get the compiled `ValidCard$` filter.
20    pub fn valid_card(&self) -> Option<&CompiledSelector> {
21        self.ir.valid_card_selector.as_ref()
22    }
23
24    /// Get the compiled `ValidPlayer$` filter.
25    pub fn valid_player(&self) -> Option<&CompiledSelector> {
26        self.ir.valid_player_selector.as_ref()
27    }
28
29    /// Get the compiled `ValidTarget$` filter.
30    pub fn valid_target(&self) -> Option<&CompiledSelector> {
31        self.ir.valid_target_selector.as_ref()
32    }
33
34    /// Get the `ChangeType$` filter string (used by zone-change effects).
35    pub fn change_type(&self) -> Option<&str> {
36        self.ir.change_type.as_deref()
37    }
38
39    /// Get the compiled `ChangeType$` filter.
40    pub fn change_type_selector(&self) -> Option<&CompiledSelector> {
41        self.ir.change_type_selector.as_ref()
42    }
43
44    // ── Zone/movement params ───────────────────────────────────────────────
45
46    /// Get the `Defined$` card reference (e.g. "Self", "Remembered", "Targeted").
47    pub fn defined(&self) -> Option<&str> {
48        self.ir.defined_text.as_deref()
49    }
50
51    /// Get the first parsed `Defined$` card reference.
52    pub fn defined_ref(&self) -> Option<&DefinedRef> {
53        self.ir
54            .defined
55            .as_ref()
56            .and_then(|defined| defined.refs.first())
57    }
58
59    /// Get the `DefinedPlayer$` player reference (e.g. "Player", "You", "Opponent").
60    pub fn defined_player(&self) -> Option<&str> {
61        self.ir.defined_player_text.as_deref()
62    }
63
64    /// Get the `Origin$` zone type string.
65    pub fn origin(&self) -> Option<&str> {
66        self.ir.origin_text.as_deref()
67    }
68
69    /// Get the `Origin$` zone type.
70    pub fn origin_zone(&self) -> Option<ZoneType> {
71        self.ir.origin_zone
72    }
73
74    /// Get the `Origin$` zone list.
75    pub fn origin_zones(&self) -> Vec<ZoneType> {
76        self.ir.origin_zones.clone()
77    }
78
79    /// Get the `Destination$` zone type string.
80    pub fn destination(&self) -> Option<&str> {
81        self.ir.destination_text.as_deref()
82    }
83
84    /// Get the `Destination$` zone type.
85    pub fn destination_zone(&self) -> Option<ZoneType> {
86        self.ir.destination_zone
87    }
88
89    /// Get the `LibraryPosition$` string (e.g. "0", "-1", "Bottom").
90    pub fn library_position(&self) -> Option<&str> {
91        self.ir.library_position.as_deref()
92    }
93
94    /// Get the `LibraryPosition2$` string for secondary zone placement.
95    pub fn library_position_2(&self) -> Option<&str> {
96        self.ir.library_position_2.as_deref()
97    }
98
99    /// Get the `LibraryPositionAlternative$` string for `DestinationAlternative$`.
100    pub fn library_position_alternative(&self) -> Option<&str> {
101        self.ir.library_position_alternative.as_deref()
102    }
103
104    // ── Mana/cost params ───────────────────────────────────────────────────
105
106    /// Get the lowered `Produced$` mana expression.
107    pub fn produced_ir(&self) -> Option<&ProducedMana> {
108        self.ir.produced_ir.as_ref()
109    }
110
111    // ── Boolean params ─────────────────────────────────────────────────────
112
113    /// Check if a boolean param is set to "True" (case-insensitive).
114    /// This is a more discoverable alias for the existing `param_is_true`.
115    pub fn is_param_true(&self, key: &str) -> bool {
116        self.param_is_true(key)
117    }
118
119    /// Get `Hidden$` as boolean.
120    pub fn is_hidden(&self) -> bool {
121        self.ir.hidden
122    }
123
124    /// Get `Mandatory$` as boolean.
125    pub fn is_mandatory(&self) -> bool {
126        self.ir.mandatory
127    }
128
129    /// Get `Tapped$` as boolean.
130    pub fn is_tapped(&self) -> bool {
131        self.ir.tapped
132    }
133
134    /// Get `Shuffle$` as boolean.
135    pub fn is_shuffle(&self) -> bool {
136        self.ir.shuffle
137    }
138
139    /// Get `RememberChanged$` as boolean.
140    pub fn is_remember_changed(&self) -> bool {
141        self.ir.remember_changed
142    }
143
144    /// Get `Optional$` as boolean.
145    pub fn is_optional(&self) -> bool {
146        self.ir.optional
147    }
148
149    /// Get `GainControl$` as boolean.
150    pub fn is_gain_control(&self) -> bool {
151        self.ir.gain_control
152    }
153
154    /// Get `ForgetChanged$` as boolean.
155    pub fn is_forget_changed(&self) -> bool {
156        self.ir.forget_changed
157    }
158
159    /// Get `Imprint$` as boolean.
160    pub fn is_imprint(&self) -> bool {
161        self.ir.imprint
162    }
163
164    /// Get `FaceDown$` as boolean.
165    pub fn is_face_down(&self) -> bool {
166        self.ir.face_down
167    }
168
169    /// Get `ExileFaceDown$` as boolean.
170    pub fn is_exile_face_down(&self) -> bool {
171        self.ir.exile_face_down
172    }
173
174    /// Get `Transformed$` as boolean.
175    pub fn is_transformed(&self) -> bool {
176        self.ir.transformed
177    }
178
179    /// Get `AtRandom$` as boolean.
180    pub fn is_at_random(&self) -> bool {
181        self.ir.at_random
182    }
183
184    /// Get `Reveal$` as boolean (default true for searches — NoReveal overrides).
185    pub fn is_reveal(&self) -> bool {
186        self.ir.reveal
187    }
188
189    /// Get `ChangeNum$` as usize, defaulting to 1.
190    pub fn change_num(&self) -> usize {
191        self.ir.change_num
192    }
193
194    /// Get `Chooser$` player reference.
195    pub fn chooser(&self) -> Option<&str> {
196        self.ir.chooser.as_deref()
197    }
198
199    /// Get `AttachedTo$` target definition.
200    pub fn attached_to(&self) -> Option<&str> {
201        self.ir.attached_to.as_deref()
202    }
203
204    /// Get `DestinationAlternative$` zone.
205    pub fn destination_alternative(&self) -> Option<&str> {
206        self.ir.destination_alternative.as_deref()
207    }
208
209    /// Get `SelectPrompt$` custom prompt text.
210    pub fn select_prompt(&self) -> Option<&str> {
211        self.ir.select_prompt.as_deref()
212    }
213
214    // ── Numeric params ─────────────────────────────────────────────────────
215
216    /// Get a numeric param by key, returning None if absent or non-numeric.
217    pub fn param_as_i32(&self, key: &str) -> Option<i32> {
218        match key {
219            keys::WITH_TOTAL_CMC => self.ir.with_total_cmc,
220            keys::WITH_TOTAL_POWER => self.ir.with_total_power,
221            _ => None,
222        }
223    }
224
225    // ── SubAbility chain ───────────────────────────────────────────────────
226
227    /// Get the `SubAbility$` SVar name.
228    pub fn sub_ability_name(&self) -> Option<&str> {
229        self.ir.sub_ability_name.as_deref()
230    }
231
232    // ── Token params ───────────────────────────────────────────────────────
233
234    /// Get the `TokenScript$` name.
235    pub fn token_script(&self) -> Option<&str> {
236        self.ir.token_script.as_deref()
237    }
238
239    /// Get the `TokenOwner$` reference.
240    pub fn token_owner(&self) -> Option<&str> {
241        self.ir.token_owner.as_deref()
242    }
243
244    // ── Counter params ─────────────────────────────────────────────────────
245
246    /// Get the `WithCountersType$` string.
247    pub fn with_counters_type(&self) -> Option<&str> {
248        self.ir.with_counters_type_text.as_deref()
249    }
250
251    /// Get the typed `WithCountersType$`.
252    pub fn with_counters_type_enum(&self) -> Option<&CounterType> {
253        self.ir.with_counters_type.as_ref()
254    }
255}