Skip to main content

manabrew_engine/spellability/
spell_ability_variables.rs

1//! Activation/condition variables for spell abilities.
2//!
3//! Mirrors Java's `SpellAbilityVariables.java` — stores conditions like
4//! zone, phase, sorcery speed, and various boolean game-state checks.
5
6use std::collections::HashSet;
7
8use forge_foundation::{PhaseType, ZoneType};
9use serde::{Deserialize, Serialize};
10
11/// Variables controlling when a spell ability can be activated or its conditions are met.
12/// Mirrors Java's `SpellAbilityVariables` (lines 36-100).
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct SpellAbilityVariables {
15    /// Zone the card must be in to activate. Mirrors Java's `zone` field.
16    zone: ZoneType,
17    /// Phases during which the ability can be activated.
18    phases: HashSet<PhaseType>,
19    /// Whether this ability can only be activated at sorcery speed.
20    sorcery_speed: bool,
21    /// Whether this ability can be activated at instant speed.
22    instant_speed: bool,
23    /// Who can activate this ability. Mirrors Java's `activator` field.
24    activator: String,
25    /// Whether this can only be activated on an opponent's turn.
26    opponent_turn: bool,
27    /// Whether this can only be activated on the player's own turn.
28    player_turn: bool,
29    /// Per-turn activation limit expression (e.g. "1" means once per turn).
30    limit_to_check: Option<String>,
31    /// Per-game activation limit expression.
32    game_limit_to_check: Option<String>,
33    /// Number of cards required in hand (-1 = no restriction).
34    cards_in_hand: i32,
35    /// Threshold — seven or more cards in graveyard.
36    threshold: bool,
37    /// Metalcraft — three or more artifacts.
38    metalcraft: bool,
39    /// Delirium — four or more card types in graveyard.
40    delirium: bool,
41    /// Hellbent — no cards in hand.
42    hellbent: bool,
43    /// Revolt — a permanent you controlled left the battlefield this turn.
44    revolt: bool,
45    /// Desert — you control a Desert or have one in your graveyard.
46    desert: bool,
47    /// Blessing — your library has no cards (Blessing from Amonkhet).
48    blessing: bool,
49    /// Solved — this case has been solved (Murders at Karlov Manor).
50    solved: bool,
51    /// A card matching this expression must be present.
52    is_present: Option<String>,
53    /// Comparison operator for presence check (e.g. "GE1").
54    present_compare: Option<String>,
55    /// Zone to check for presence. Defaults to Battlefield.
56    present_zone: ZoneType,
57    /// Defined source for presence check (e.g. "You", "Opponent").
58    present_defined: Option<String>,
59    /// Variable operand 1 for condition/restriction comparisons.
60    var_operand: Option<String>,
61    /// Variable operand 2 for condition/restriction comparisons.
62    var_operand2: Option<String>,
63    /// Variable to check 1.
64    var_to_check: Option<String>,
65    /// Variable to check 2.
66    var_to_check2: Option<String>,
67    /// Comparison operator 1 (e.g. "GE", "EQ", "LT").
68    var_operator: Option<String>,
69    /// Comparison operator 2.
70    var_operator2: Option<String>,
71    /// Required Class level expression operand.
72    class_level: Option<String>,
73    /// Comparison operator for class level requirement.
74    class_level_operator: Option<String>,
75    /// Whether this targets a single target only.
76    targets_single_target: bool,
77}
78
79impl Default for SpellAbilityVariables {
80    fn default() -> Self {
81        Self {
82            zone: ZoneType::Battlefield,
83            phases: HashSet::new(),
84            sorcery_speed: false,
85            instant_speed: false,
86            activator: "You".to_string(),
87            opponent_turn: false,
88            player_turn: false,
89            limit_to_check: None,
90            game_limit_to_check: None,
91            cards_in_hand: -1,
92            threshold: false,
93            metalcraft: false,
94            delirium: false,
95            hellbent: false,
96            revolt: false,
97            desert: false,
98            blessing: false,
99            solved: false,
100            is_present: None,
101            present_compare: None,
102            present_zone: ZoneType::Battlefield,
103            present_defined: None,
104            var_operand: None,
105            var_operand2: None,
106            var_to_check: None,
107            var_to_check2: None,
108            var_operator: None,
109            var_operator2: None,
110            class_level: None,
111            class_level_operator: None,
112            targets_single_target: false,
113        }
114    }
115}
116
117impl SpellAbilityVariables {
118    /// Create a new instance with default values.
119    pub fn new() -> Self {
120        Self::default()
121    }
122
123    // ── Zone ──────────────────────────────────────────────────────────────
124
125    pub fn zone(&self) -> ZoneType {
126        self.zone
127    }
128
129    pub fn set_zone(&mut self, zone: ZoneType) {
130        self.zone = zone;
131    }
132
133    // ── Phases ────────────────────────────────────────────────────────────
134
135    pub fn phases(&self) -> &HashSet<PhaseType> {
136        &self.phases
137    }
138
139    pub fn set_phases(&mut self, phases: HashSet<PhaseType>) {
140        self.phases = phases;
141    }
142
143    pub fn add_phase(&mut self, phase: PhaseType) {
144        self.phases.insert(phase);
145    }
146
147    // ── Speed ─────────────────────────────────────────────────────────────
148
149    pub fn sorcery_speed(&self) -> bool {
150        self.sorcery_speed
151    }
152
153    pub fn set_sorcery_speed(&mut self, val: bool) {
154        self.sorcery_speed = val;
155    }
156
157    pub fn instant_speed(&self) -> bool {
158        self.instant_speed
159    }
160
161    pub fn set_instant_speed(&mut self, val: bool) {
162        self.instant_speed = val;
163    }
164
165    // ── Activator ─────────────────────────────────────────────────────────
166
167    pub fn activator(&self) -> &str {
168        &self.activator
169    }
170
171    pub fn set_activator(&mut self, activator: String) {
172        self.activator = activator;
173    }
174
175    // ── Turn restrictions ─────────────────────────────────────────────────
176
177    pub fn opponent_turn(&self) -> bool {
178        self.opponent_turn
179    }
180
181    pub fn set_opponent_turn(&mut self, val: bool) {
182        self.opponent_turn = val;
183    }
184
185    pub fn player_turn(&self) -> bool {
186        self.player_turn
187    }
188
189    pub fn set_player_turn(&mut self, val: bool) {
190        self.player_turn = val;
191    }
192
193    // ── Limits ────────────────────────────────────────────────────────────
194
195    pub fn limit_to_check(&self) -> Option<&str> {
196        self.limit_to_check.as_deref()
197    }
198
199    pub fn set_limit_to_check(&mut self, limit: Option<String>) {
200        self.limit_to_check = limit;
201    }
202
203    pub fn game_limit_to_check(&self) -> Option<&str> {
204        self.game_limit_to_check.as_deref()
205    }
206
207    pub fn set_game_limit_to_check(&mut self, limit: Option<String>) {
208        self.game_limit_to_check = limit;
209    }
210
211    // ── Cards in hand ─────────────────────────────────────────────────────
212
213    pub fn cards_in_hand(&self) -> i32 {
214        self.cards_in_hand
215    }
216
217    pub fn set_cards_in_hand(&mut self, count: i32) {
218        self.cards_in_hand = count;
219    }
220
221    // ── Boolean conditions ────────────────────────────────────────────────
222
223    pub fn threshold(&self) -> bool {
224        self.threshold
225    }
226
227    pub fn set_threshold(&mut self, val: bool) {
228        self.threshold = val;
229    }
230
231    pub fn metalcraft(&self) -> bool {
232        self.metalcraft
233    }
234
235    pub fn set_metalcraft(&mut self, val: bool) {
236        self.metalcraft = val;
237    }
238
239    pub fn delirium(&self) -> bool {
240        self.delirium
241    }
242
243    pub fn set_delirium(&mut self, val: bool) {
244        self.delirium = val;
245    }
246
247    pub fn hellbent(&self) -> bool {
248        self.hellbent
249    }
250
251    pub fn set_hellbent(&mut self, val: bool) {
252        self.hellbent = val;
253    }
254
255    pub fn revolt(&self) -> bool {
256        self.revolt
257    }
258
259    pub fn set_revolt(&mut self, val: bool) {
260        self.revolt = val;
261    }
262
263    pub fn desert(&self) -> bool {
264        self.desert
265    }
266
267    pub fn set_desert(&mut self, val: bool) {
268        self.desert = val;
269    }
270
271    pub fn blessing(&self) -> bool {
272        self.blessing
273    }
274
275    pub fn set_blessing(&mut self, val: bool) {
276        self.blessing = val;
277    }
278
279    pub fn solved(&self) -> bool {
280        self.solved
281    }
282
283    pub fn set_solved(&mut self, val: bool) {
284        self.solved = val;
285    }
286
287    // ── Presence checks ──────────────────────────────────────────────────
288
289    pub fn is_present(&self) -> Option<&str> {
290        self.is_present.as_deref()
291    }
292
293    pub fn set_is_present(&mut self, val: Option<String>) {
294        self.is_present = val;
295    }
296
297    pub fn present_compare(&self) -> Option<&str> {
298        self.present_compare.as_deref()
299    }
300
301    pub fn set_present_compare(&mut self, val: Option<String>) {
302        self.present_compare = val;
303    }
304
305    pub fn present_zone(&self) -> ZoneType {
306        self.present_zone
307    }
308
309    pub fn set_present_zone(&mut self, zone: ZoneType) {
310        self.present_zone = zone;
311    }
312
313    pub fn present_defined(&self) -> Option<&str> {
314        self.present_defined.as_deref()
315    }
316
317    pub fn set_present_defined(&mut self, val: Option<String>) {
318        self.present_defined = val;
319    }
320
321    // ── Variable operands ─────────────────────────────────────────────────
322
323    /// Get variable operand 1.
324    /// Mirrors Java's `SpellAbilityVariables.getVarOperand()`.
325    pub fn gets_var_operand(&self) -> Option<&str> {
326        self.var_operand.as_deref()
327    }
328
329    /// Get variable operand 2.
330    /// Mirrors Java's `SpellAbilityVariables.getVarOperand2()`.
331    pub fn gets_var_operand2(&self) -> Option<&str> {
332        self.var_operand2.as_deref()
333    }
334
335    /// Set variable operand 1.
336    /// Mirrors Java's `SpellAbilityVariables.setVarOperand(String)`.
337    pub fn sets_var_operand(&mut self, val: &str) {
338        self.var_operand = Some(val.to_string());
339    }
340
341    /// Set variable operand 2.
342    /// Mirrors Java's `SpellAbilityVariables.setVarOperand2(String)`.
343    pub fn sets_var_operand2(&mut self, val: &str) {
344        self.var_operand2 = Some(val.to_string());
345    }
346
347    // ── Variable to check ─────────────────────────────────────────────────
348
349    /// Get variable to check 1.
350    /// Mirrors Java's `SpellAbilityVariables.getVarToCheck()`.
351    pub fn gets_var_to_check(&self) -> Option<&str> {
352        self.var_to_check.as_deref()
353    }
354
355    /// Get variable to check 2.
356    /// Mirrors Java's `SpellAbilityVariables.getVarToCheck2()`.
357    pub fn gets_var_to_check2(&self) -> Option<&str> {
358        self.var_to_check2.as_deref()
359    }
360
361    /// Set variable to check 1.
362    /// Mirrors Java's `SpellAbilityVariables.setVarToCheck(String)`.
363    pub fn sets_var_to_check(&mut self, val: &str) {
364        self.var_to_check = Some(val.to_string());
365    }
366
367    /// Set variable to check 2.
368    /// Mirrors Java's `SpellAbilityVariables.setVarToCheck2(String)`.
369    pub fn sets_var_to_check2(&mut self, val: &str) {
370        self.var_to_check2 = Some(val.to_string());
371    }
372
373    // ── Variable operators ────────────────────────────────────────────────
374
375    /// Get variable operator 1.
376    /// Mirrors Java's `SpellAbilityVariables.getVarOperator()`.
377    pub fn gets_var_operator(&self) -> Option<&str> {
378        self.var_operator.as_deref()
379    }
380
381    /// Get variable operator 2.
382    /// Mirrors Java's `SpellAbilityVariables.getVarOperator2()`.
383    pub fn gets_var_operator2(&self) -> Option<&str> {
384        self.var_operator2.as_deref()
385    }
386
387    /// Set variable operator 1.
388    /// Mirrors Java's `SpellAbilityVariables.setVarOperator(String)`.
389    pub fn sets_var_operator(&mut self, val: &str) {
390        self.var_operator = Some(val.to_string());
391    }
392
393    /// Set variable operator 2.
394    /// Mirrors Java's `SpellAbilityVariables.setVarOperator2(String)`.
395    pub fn sets_var_operator2(&mut self, val: &str) {
396        self.var_operator2 = Some(val.to_string());
397    }
398
399    // ── Class level ───────────────────────────────────────────────────────
400
401    pub fn class_level(&self) -> Option<&str> {
402        self.class_level.as_deref()
403    }
404
405    pub fn set_class_level(&mut self, val: Option<String>) {
406        self.class_level = val;
407    }
408
409    pub fn class_level_operator(&self) -> Option<&str> {
410        self.class_level_operator.as_deref()
411    }
412
413    pub fn set_class_level_operator(&mut self, val: Option<String>) {
414        self.class_level_operator = val;
415    }
416
417    // ── Single target ─────────────────────────────────────────────────────
418
419    /// Whether this targets a single target.
420    /// Mirrors Java's `SpellAbilityVariables.targetsSingleTarget()`.
421    pub fn targets_single_target(&self) -> bool {
422        self.targets_single_target
423    }
424
425    /// Set whether this targets a single target.
426    pub fn set_targets_single_target(&mut self, val: bool) {
427        self.targets_single_target = val;
428    }
429
430    // ── Copy ──────────────────────────────────────────────────────────────
431
432    /// Clone these variables.
433    /// Mirrors Java's `SpellAbilityVariables.copy()`.
434    pub fn copy(&self) -> Self {
435        self.clone()
436    }
437}