Skip to main content

manabrew_engine/card/
counter_type.rs

1use serde::{Deserialize, Serialize};
2use strum_macros::{Display, EnumString};
3
4/// Counter types commonly used in MTG.
5/// Note: `Copy` is intentionally absent because the `Named(String)` variant
6/// holds heap-allocated data. Use `.clone()` when an owned copy is needed.
7#[derive(
8    Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, EnumString, Display,
9)]
10pub enum CounterType {
11    P1P1,
12    M1M1,
13    Poison,
14    Loyalty,
15    Charge,
16    Quest,
17    Study,
18    Age,
19    Fade,
20    Time,
21    Depletion,
22    Storage,
23    Mining,
24    Brick,
25    Level,
26    Lore,
27    Page,
28    Dream,
29    /// Catch-all for counter types not in the enum (e.g. SUPPLY, VERSE, LUCK).
30    /// Stored as uppercase name for consistent comparison.
31    Named(String),
32}
33
34/// Parse a counter type string to CounterType enum (case-insensitive).
35/// Unknown types produce `CounterType::Named(UPPER)` instead of silently
36/// falling back to P1P1, so cards like Stocking the Pantry get the correct
37/// SUPPLY counters.
38pub fn parse_counter_type(s: &str) -> CounterType {
39    match s.to_uppercase().as_str() {
40        "P1P1" | "+1/+1" => CounterType::P1P1,
41        "M1M1" | "-1/-1" => CounterType::M1M1,
42        "POISON" => CounterType::Poison,
43        "LOYALTY" => CounterType::Loyalty,
44        "CHARGE" => CounterType::Charge,
45        "QUEST" => CounterType::Quest,
46        "STUDY" => CounterType::Study,
47        "AGE" => CounterType::Age,
48        "FADE" => CounterType::Fade,
49        "TIME" => CounterType::Time,
50        "DEPLETION" => CounterType::Depletion,
51        "STORAGE" => CounterType::Storage,
52        "MINING" => CounterType::Mining,
53        "BRICK" => CounterType::Brick,
54        "LEVEL" => CounterType::Level,
55        "LORE" => CounterType::Lore,
56        "PAGE" => CounterType::Page,
57        "DREAM" => CounterType::Dream,
58        other => CounterType::Named(other.to_string()),
59    }
60}
61
62impl CounterType {
63    /// Java parity helper for interface-style checks.
64    pub fn is(&self, other: &CounterType) -> bool {
65        self == other
66    }
67
68    /// Java parity helper for "keyword counter" classification.
69    pub fn is_keyword_counter(&self) -> bool {
70        matches!(self, CounterType::Named(_))
71    }
72}