screeps/constants/
types.rs

1//! `*Type` constants.
2use std::{borrow::Cow, fmt};
3
4use enum_iterator::Sequence;
5use num_derive::FromPrimitive;
6use num_traits::FromPrimitive;
7use serde::{
8    de::{Error as _, Unexpected},
9    Deserialize, Serialize,
10};
11use serde_repr::{Deserialize_repr, Serialize_repr};
12use wasm_bindgen::prelude::*;
13
14use super::{macros::named_enum_serialize_deserialize, InvalidConstantString};
15use crate::{JsCollectionFromValue, JsCollectionIntoValue};
16
17/// Translates `STRUCTURE_*` constants.
18#[wasm_bindgen]
19#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Sequence)]
20pub enum StructureType {
21    Spawn = "spawn",
22    Extension = "extension",
23    Road = "road",
24    Wall = "constructedWall",
25    Rampart = "rampart",
26    KeeperLair = "keeperLair",
27    Portal = "portal",
28    Controller = "controller",
29    Link = "link",
30    Storage = "storage",
31    Tower = "tower",
32    Observer = "observer",
33    PowerBank = "powerBank",
34    PowerSpawn = "powerSpawn",
35    Extractor = "extractor",
36    Lab = "lab",
37    Terminal = "terminal",
38    Container = "container",
39    Nuker = "nuker",
40    Factory = "factory",
41    InvaderCore = "invaderCore",
42}
43
44named_enum_serialize_deserialize!(StructureType);
45
46impl StructureType {
47    /// Translates the `CONSTRUCTION_COST` constant.
48    #[inline]
49    pub const fn construction_cost(self) -> Option<u32> {
50        use self::StructureType::*;
51
52        let cost = match self {
53            Spawn => 15_000,
54            Extension => 3_000,
55            Road => 300,
56            Wall => 1,
57            Rampart => 1,
58            Link => 5_000,
59            Storage => 30_000,
60            Tower => 5_000,
61            Observer => 8_000,
62            PowerSpawn => 100_000,
63            Extractor => 5_000,
64            Lab => 50_000,
65            Terminal => 100_000,
66            Container => 5_000,
67            Nuker => 100_000,
68            Factory => 100_000,
69            _ => return None,
70        };
71        Some(cost)
72    }
73
74    /// Translates the `CONTROLLER_STRUCTURES` constant
75    #[inline]
76    pub const fn controller_structures(self, current_rcl: u32) -> u32 {
77        use self::StructureType::*;
78
79        match self {
80            Spawn => match current_rcl {
81                0 => 0,
82                1..=6 => 1,
83                7 => 2,
84                _ => 3,
85            },
86            Extension => match current_rcl {
87                0 | 1 => 0,
88                2 => 5,
89                3 => 10,
90                4 => 20,
91                5 => 30,
92                6 => 40,
93                7 => 50,
94                _ => 60,
95            },
96            Road => 2500,
97            Wall => match current_rcl {
98                0 | 1 => 0,
99                _ => 2500,
100            },
101            Rampart => match current_rcl {
102                0 | 1 => 0,
103                _ => 2500,
104            },
105            Link => match current_rcl {
106                0..=4 => 0,
107                5 => 2,
108                6 => 3,
109                7 => 4,
110                _ => 6,
111            },
112            Storage => match current_rcl {
113                0..=3 => 0,
114                _ => 1,
115            },
116            Tower => match current_rcl {
117                0..=2 => 0,
118                3 | 4 => 1,
119                5 | 6 => 2,
120                7 => 3,
121                _ => 6,
122            },
123            Observer => match current_rcl {
124                0..=7 => 0,
125                _ => 1,
126            },
127            PowerSpawn => match current_rcl {
128                0..=7 => 0,
129                _ => 1,
130            },
131            Extractor => match current_rcl {
132                0..=5 => 0,
133                _ => 1,
134            },
135            Lab => match current_rcl {
136                0..=5 => 0,
137                6 => 3,
138                7 => 6,
139                _ => 10,
140            },
141            Terminal => match current_rcl {
142                0..=5 => 0,
143                _ => 1,
144            },
145            Container => 5,
146            Nuker => match current_rcl {
147                0..=7 => 0,
148                _ => 1,
149            },
150            Factory => match current_rcl {
151                0..=6 => 0,
152                _ => 1,
153            },
154            _ => 0,
155        }
156    }
157
158    /// Translates the `*_HITS` constants, initial hits for structures
159    #[inline]
160    pub const fn initial_hits(self) -> Option<u32> {
161        use self::StructureType::*;
162        use super::numbers::*;
163
164        let hits = match self {
165            Spawn => SPAWN_HITS,
166            Extension => EXTENSION_HITS,
167            Road => ROAD_HITS,
168            Wall => WALL_HITS,
169            Rampart => RAMPART_HITS,
170            Link => LINK_HITS,
171            Storage => STORAGE_HITS,
172            Tower => TOWER_HITS,
173            Observer => OBSERVER_HITS,
174            PowerBank => POWER_BANK_HITS,
175            PowerSpawn => POWER_SPAWN_HITS,
176            Extractor => EXTRACTOR_HITS,
177            Lab => LAB_HITS,
178            Terminal => TERMINAL_HITS,
179            Container => CONTAINER_HITS,
180            Nuker => NUKER_HITS,
181            Factory => FACTORY_HITS,
182            InvaderCore => INVADER_CORE_HITS,
183            _ => return None,
184        };
185        Some(hits)
186    }
187}
188
189/// Translates `SUBSCRIPTION_TOKEN` and `INTERSHARD_RESOURCES` constants.
190#[wasm_bindgen]
191#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Sequence)]
192pub enum IntershardResourceType {
193    // no longer used, not implemented
194    // SubscriptionToken = "token",
195    CpuUnlock = "cpuUnlock",
196    Pixel = "pixel",
197    AccessKey = "accessKey",
198}
199
200named_enum_serialize_deserialize!(IntershardResourceType);
201
202impl JsCollectionIntoValue for IntershardResourceType {
203    fn into_value(self) -> JsValue {
204        self.into()
205    }
206}
207
208impl JsCollectionFromValue for IntershardResourceType {
209    fn from_value(v: JsValue) -> IntershardResourceType {
210        IntershardResourceType::from_js_value(&v).expect("valid intershard resource type string")
211    }
212}
213
214/// Translates the values of the `RESOURCES_ALL` constant, representing all
215/// possible in-game (non-intershard) resources.
216#[wasm_bindgen]
217#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Sequence)]
218pub enum ResourceType {
219    Energy = "energy",
220    Power = "power",
221    Hydrogen = "H",
222    Oxygen = "O",
223    Utrium = "U",
224    Lemergium = "L",
225    Keanium = "K",
226    Zynthium = "Z",
227    Catalyst = "X",
228    Ghodium = "G",
229    Silicon = "silicon",
230    Metal = "metal",
231    Biomass = "biomass",
232    Mist = "mist",
233    Hydroxide = "OH",
234    ZynthiumKeanite = "ZK",
235    UtriumLemergite = "UL",
236    UtriumHydride = "UH",
237    UtriumOxide = "UO",
238    KeaniumHydride = "KH",
239    KeaniumOxide = "KO",
240    LemergiumHydride = "LH",
241    LemergiumOxide = "LO",
242    ZynthiumHydride = "ZH",
243    ZynthiumOxide = "ZO",
244    GhodiumHydride = "GH",
245    GhodiumOxide = "GO",
246    UtriumAcid = "UH2O",
247    UtriumAlkalide = "UHO2",
248    KeaniumAcid = "KH2O",
249    KeaniumAlkalide = "KHO2",
250    LemergiumAcid = "LH2O",
251    LemergiumAlkalide = "LHO2",
252    ZynthiumAcid = "ZH2O",
253    ZynthiumAlkalide = "ZHO2",
254    GhodiumAcid = "GH2O",
255    GhodiumAlkalide = "GHO2",
256    CatalyzedUtriumAcid = "XUH2O",
257    CatalyzedUtriumAlkalide = "XUHO2",
258    CatalyzedKeaniumAcid = "XKH2O",
259    CatalyzedKeaniumAlkalide = "XKHO2",
260    CatalyzedLemergiumAcid = "XLH2O",
261    CatalyzedLemergiumAlkalide = "XLHO2",
262    CatalyzedZynthiumAcid = "XZH2O",
263    CatalyzedZynthiumAlkalide = "XZHO2",
264    CatalyzedGhodiumAcid = "XGH2O",
265    CatalyzedGhodiumAlkalide = "XGHO2",
266    Ops = "ops",
267    UtriumBar = "utrium_bar",
268    LemergiumBar = "lemergium_bar",
269    ZynthiumBar = "zynthium_bar",
270    KeaniumBar = "keanium_bar",
271    GhodiumMelt = "ghodium_melt",
272    Oxidant = "oxidant",
273    Reductant = "reductant",
274    Purifier = "purifier",
275    Battery = "battery",
276    Composite = "composite",
277    Crystal = "crystal",
278    Liquid = "liquid",
279    Wire = "wire",
280    Switch = "switch",
281    Transistor = "transistor",
282    Microchip = "microchip",
283    Circuit = "circuit",
284    Device = "device",
285    Cell = "cell",
286    Phlegm = "phlegm",
287    Tissue = "tissue",
288    Muscle = "muscle",
289    Organoid = "organoid",
290    Organism = "organism",
291    Alloy = "alloy",
292    Tube = "tube",
293    Fixtures = "fixtures",
294    Frame = "frame",
295    Hydraulics = "hydraulics",
296    Machine = "machine",
297    Condensate = "condensate",
298    Concentrate = "concentrate",
299    Extract = "extract",
300    Spirit = "spirit",
301    Emanation = "emanation",
302    Essence = "essence",
303    #[cfg(feature = "seasonal-season-1")]
304    Score = "score",
305    #[cfg(feature = "seasonal-season-2")]
306    SymbolAleph = "symbol_aleph",
307    #[cfg(feature = "seasonal-season-2")]
308    SymbolBeth = "symbol_beth",
309    #[cfg(feature = "seasonal-season-2")]
310    SymbolGimmel = "symbol_gimmel",
311    #[cfg(feature = "seasonal-season-2")]
312    SymbolDaleth = "symbol_daleth",
313    #[cfg(feature = "seasonal-season-2")]
314    SymbolHe = "symbol_he",
315    #[cfg(feature = "seasonal-season-2")]
316    SymbolWaw = "symbol_waw",
317    #[cfg(feature = "seasonal-season-2")]
318    SymbolZayin = "symbol_zayin",
319    #[cfg(feature = "seasonal-season-2")]
320    SymbolHeth = "symbol_heth",
321    #[cfg(feature = "seasonal-season-2")]
322    SymbolTeth = "symbol_teth",
323    #[cfg(feature = "seasonal-season-2")]
324    SymbolYodh = "symbol_yodh",
325    #[cfg(feature = "seasonal-season-2")]
326    SymbolKaph = "symbol_kaph",
327    #[cfg(feature = "seasonal-season-2")]
328    SymbolLamedh = "symbol_lamedh",
329    #[cfg(feature = "seasonal-season-2")]
330    SymbolMem = "symbol_mem",
331    #[cfg(feature = "seasonal-season-2")]
332    SymbolNun = "symbol_nun",
333    #[cfg(feature = "seasonal-season-2")]
334    SymbolSamekh = "symbol_samekh",
335    #[cfg(feature = "seasonal-season-2")]
336    SymbolAyin = "symbol_ayin",
337    #[cfg(feature = "seasonal-season-2")]
338    SymbolPe = "symbol_pe",
339    #[cfg(feature = "seasonal-season-2")]
340    SymbolTsade = "symbol_tsade",
341    #[cfg(feature = "seasonal-season-2")]
342    SymbolQoph = "symbol_qoph",
343    #[cfg(feature = "seasonal-season-2")]
344    SymbolRes = "symbol_res",
345    // sin/sim mismatch is intended here - see official mod:
346    // https://github.com/screeps/mod-season2/blob/3dfaa8f6214b2610dbe2a700c6287a10e7960ae8/src/resources.js#L23
347    #[cfg(feature = "seasonal-season-2")]
348    SymbolSin = "symbol_sim",
349    #[cfg(feature = "seasonal-season-2")]
350    SymbolTaw = "symbol_taw",
351    #[cfg(feature = "seasonal-season-5")]
352    Thorium = "T",
353}
354
355named_enum_serialize_deserialize!(ResourceType);
356
357impl ResourceType {
358    /// Translates the `BOOSTS` constant.
359    #[inline]
360    pub const fn boost(self) -> Option<Boost> {
361        use ResourceType::*;
362        let boost = match self {
363            // these comments copied directly from JavaScript 'constants.js' file.
364            // UH: {
365            //     attack: 2
366            // },
367            UtriumHydride => Boost::Attack(2),
368            // UH2O: {
369            //     attack: 3
370            // },
371            UtriumAcid => Boost::Attack(3),
372            // XUH2O: {
373            //     attack: 4
374            // }
375            CatalyzedUtriumAcid => Boost::Attack(4),
376            // UO: {
377            //     harvest: 3
378            // },
379            UtriumOxide => Boost::Harvest(3),
380            // UHO2: {
381            //     harvest: 5
382            // },
383            UtriumAlkalide => Boost::Harvest(5),
384            // XUHO2: {
385            //     harvest: 7
386            // },
387            CatalyzedUtriumAlkalide => Boost::Harvest(7),
388            // KH: {
389            //     capacity: 2
390            // },
391            KeaniumHydride => Boost::Carry(2),
392            // KH2O: {
393            //     capacity: 3
394            // },
395            KeaniumAcid => Boost::Carry(3),
396            // XKH2O: {
397            //     capacity: 4
398            // }
399            CatalyzedKeaniumAcid => Boost::Carry(4),
400            // KO: {
401            //     rangedAttack: 2,
402            //     rangedMassAttack: 2
403            // },
404            KeaniumOxide => Boost::RangedAttack(2),
405            // KHO2: {
406            //     rangedAttack: 3,
407            //     rangedMassAttack: 3
408            // },
409            KeaniumAlkalide => Boost::RangedAttack(3),
410            // XKHO2: {
411            //     rangedAttack: 4,
412            //     rangedMassAttack: 4
413            // }
414            CatalyzedKeaniumAlkalide => Boost::RangedAttack(4),
415            // LH: {
416            //     build: 1.5,
417            //     repair: 1.5
418            // },
419            LemergiumHydride => Boost::BuildAndRepair(1.5),
420            // LH2O: {
421            //     build: 1.8,
422            //     repair: 1.8
423            // },
424            LemergiumAcid => Boost::BuildAndRepair(1.8),
425            // XLH2O: {
426            //     build: 2,
427            //     repair: 2
428            // },
429            CatalyzedLemergiumAcid => Boost::BuildAndRepair(2.0),
430            // LO: {
431            //     heal: 2,
432            //     rangedHeal: 2
433            // },
434            LemergiumOxide => Boost::Heal(2),
435            // LHO2: {
436            //     heal: 3,
437            //     rangedHeal: 3
438            // },
439            LemergiumAlkalide => Boost::Heal(3),
440            // XLHO2: {
441            //     heal: 4,
442            //     rangedHeal: 4
443            // }
444            CatalyzedLemergiumAlkalide => Boost::Heal(4),
445            // ZH: {
446            //     dismantle: 2
447            // },
448            ZynthiumHydride => Boost::Dismantle(2),
449            // ZH2O: {
450            //     dismantle: 3
451            // },
452            ZynthiumAcid => Boost::Dismantle(3),
453            // XZH2O: {
454            //     dismantle: 4
455            // },
456            CatalyzedZynthiumAcid => Boost::Dismantle(4),
457            // ZO: {
458            //     fatigue: 2
459            // },
460            ZynthiumOxide => Boost::Move(2),
461            // ZHO2: {
462            //     fatigue: 3
463            // },
464            ZynthiumAlkalide => Boost::Move(3),
465            // XZHO2: {
466            //     fatigue: 4
467            // }
468            CatalyzedZynthiumAlkalide => Boost::Move(4),
469            // GH: {
470            //     upgradeController: 1.5
471            // },
472            GhodiumHydride => Boost::UpgradeController(1.5),
473            // GH2O: {
474            //     upgradeController: 1.8
475            // },
476            GhodiumAcid => Boost::UpgradeController(1.8),
477            // XGH2O: {
478            //     upgradeController: 2
479            // }
480            CatalyzedGhodiumAcid => Boost::UpgradeController(2.0),
481            // GO: {
482            //     damage: .7
483            // },
484            GhodiumOxide => Boost::Tough(0.7),
485            // GHO2: {
486            //     damage: .5
487            // },
488            GhodiumAlkalide => Boost::Tough(0.5),
489            // XGHO2: {
490            //     damage: .3
491            // }
492            CatalyzedGhodiumAlkalide => Boost::Tough(0.3),
493            // non-boost resources
494            _ => return None,
495        };
496        Some(boost)
497    }
498}
499
500/// A collection of all resource types. This is a direct translation of the
501/// `RESOURCES_ALL` constant in game using the rust `ResourceType` enum.
502///
503/// Feature-specific resources are included in this list when the appropriate
504/// feature is enabled.
505pub const RESOURCES_ALL: &[ResourceType] = &[
506    ResourceType::Power,
507    ResourceType::Energy,
508    ResourceType::Hydrogen,
509    ResourceType::Oxygen,
510    ResourceType::Utrium,
511    ResourceType::Lemergium,
512    ResourceType::Keanium,
513    ResourceType::Zynthium,
514    ResourceType::Catalyst,
515    ResourceType::Ghodium,
516    ResourceType::Silicon,
517    ResourceType::Metal,
518    ResourceType::Biomass,
519    ResourceType::Mist,
520    ResourceType::Hydroxide,
521    ResourceType::ZynthiumKeanite,
522    ResourceType::UtriumLemergite,
523    ResourceType::UtriumHydride,
524    ResourceType::UtriumOxide,
525    ResourceType::KeaniumHydride,
526    ResourceType::KeaniumOxide,
527    ResourceType::LemergiumHydride,
528    ResourceType::LemergiumOxide,
529    ResourceType::ZynthiumHydride,
530    ResourceType::ZynthiumOxide,
531    ResourceType::GhodiumHydride,
532    ResourceType::GhodiumOxide,
533    ResourceType::UtriumAcid,
534    ResourceType::UtriumAlkalide,
535    ResourceType::KeaniumAcid,
536    ResourceType::KeaniumAlkalide,
537    ResourceType::LemergiumAcid,
538    ResourceType::LemergiumAlkalide,
539    ResourceType::ZynthiumAcid,
540    ResourceType::ZynthiumAlkalide,
541    ResourceType::GhodiumAcid,
542    ResourceType::GhodiumAlkalide,
543    ResourceType::CatalyzedUtriumAcid,
544    ResourceType::CatalyzedUtriumAlkalide,
545    ResourceType::CatalyzedKeaniumAcid,
546    ResourceType::CatalyzedKeaniumAlkalide,
547    ResourceType::CatalyzedLemergiumAcid,
548    ResourceType::CatalyzedLemergiumAlkalide,
549    ResourceType::CatalyzedZynthiumAcid,
550    ResourceType::CatalyzedZynthiumAlkalide,
551    ResourceType::CatalyzedGhodiumAcid,
552    ResourceType::CatalyzedGhodiumAlkalide,
553    ResourceType::Ops,
554    ResourceType::UtriumBar,
555    ResourceType::LemergiumBar,
556    ResourceType::ZynthiumBar,
557    ResourceType::KeaniumBar,
558    ResourceType::GhodiumMelt,
559    ResourceType::Oxidant,
560    ResourceType::Reductant,
561    ResourceType::Purifier,
562    ResourceType::Battery,
563    ResourceType::Composite,
564    ResourceType::Crystal,
565    ResourceType::Liquid,
566    ResourceType::Wire,
567    ResourceType::Switch,
568    ResourceType::Transistor,
569    ResourceType::Microchip,
570    ResourceType::Circuit,
571    ResourceType::Device,
572    ResourceType::Cell,
573    ResourceType::Phlegm,
574    ResourceType::Tissue,
575    ResourceType::Muscle,
576    ResourceType::Organoid,
577    ResourceType::Organism,
578    ResourceType::Alloy,
579    ResourceType::Tube,
580    ResourceType::Fixtures,
581    ResourceType::Frame,
582    ResourceType::Hydraulics,
583    ResourceType::Machine,
584    ResourceType::Condensate,
585    ResourceType::Concentrate,
586    ResourceType::Extract,
587    ResourceType::Spirit,
588    ResourceType::Emanation,
589    ResourceType::Essence,
590    #[cfg(feature = "seasonal-season-1")]
591    ResourceType::Score,
592    #[cfg(feature = "seasonal-season-2")]
593    ResourceType::SymbolAleph,
594    #[cfg(feature = "seasonal-season-2")]
595    ResourceType::SymbolBeth,
596    #[cfg(feature = "seasonal-season-2")]
597    ResourceType::SymbolGimmel,
598    #[cfg(feature = "seasonal-season-2")]
599    ResourceType::SymbolDaleth,
600    #[cfg(feature = "seasonal-season-2")]
601    ResourceType::SymbolHe,
602    #[cfg(feature = "seasonal-season-2")]
603    ResourceType::SymbolWaw,
604    #[cfg(feature = "seasonal-season-2")]
605    ResourceType::SymbolZayin,
606    #[cfg(feature = "seasonal-season-2")]
607    ResourceType::SymbolHeth,
608    #[cfg(feature = "seasonal-season-2")]
609    ResourceType::SymbolTeth,
610    #[cfg(feature = "seasonal-season-2")]
611    ResourceType::SymbolYodh,
612    #[cfg(feature = "seasonal-season-2")]
613    ResourceType::SymbolKaph,
614    #[cfg(feature = "seasonal-season-2")]
615    ResourceType::SymbolLamedh,
616    #[cfg(feature = "seasonal-season-2")]
617    ResourceType::SymbolMem,
618    #[cfg(feature = "seasonal-season-2")]
619    ResourceType::SymbolNun,
620    #[cfg(feature = "seasonal-season-2")]
621    ResourceType::SymbolSamekh,
622    #[cfg(feature = "seasonal-season-2")]
623    ResourceType::SymbolAyin,
624    #[cfg(feature = "seasonal-season-2")]
625    ResourceType::SymbolPe,
626    #[cfg(feature = "seasonal-season-2")]
627    ResourceType::SymbolTsade,
628    #[cfg(feature = "seasonal-season-2")]
629    ResourceType::SymbolQoph,
630    #[cfg(feature = "seasonal-season-2")]
631    ResourceType::SymbolRes,
632    #[cfg(feature = "seasonal-season-2")]
633    ResourceType::SymbolSin,
634    #[cfg(feature = "seasonal-season-2")]
635    ResourceType::SymbolTaw,
636    #[cfg(feature = "seasonal-season-5")]
637    ResourceType::Thorium,
638];
639
640/// Returned values from [`ResourceType::boost`] representing the effect of
641/// boosting a creep with the given resource.
642#[derive(Copy, Clone, Debug)]
643pub enum Boost {
644    Harvest(u32),
645    BuildAndRepair(f32),
646    Dismantle(u32),
647    UpgradeController(f32),
648    Attack(u32),
649    RangedAttack(u32),
650    Heal(u32),
651    Carry(u32),
652    Move(u32),
653    Tough(f32),
654}
655
656/// Translates all resource types that can be used on the market.
657#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Sequence)]
658#[serde(untagged)]
659pub enum MarketResourceType {
660    Resource(ResourceType),
661    IntershardResource(IntershardResourceType),
662}
663
664impl wasm_bindgen::convert::FromWasmAbi for MarketResourceType {
665    type Abi = <wasm_bindgen::JsValue as wasm_bindgen::convert::FromWasmAbi>::Abi;
666
667    #[inline]
668    unsafe fn from_abi(js: Self::Abi) -> Self {
669        let s = <wasm_bindgen::JsValue as wasm_bindgen::convert::FromWasmAbi>::from_abi(js);
670        // first try deserialize as ResourceType
671        match ResourceType::from_js_value(&s) {
672            Some(r) => Self::Resource(r),
673            None => {
674                // try with IntershardResourceType
675                match IntershardResourceType::from_js_value(&s) {
676                    Some(r) => Self::IntershardResource(r),
677                    None => unreachable!("should have come from IntoWasmAbi"),
678                }
679            }
680        }
681    }
682}
683
684impl wasm_bindgen::convert::IntoWasmAbi for MarketResourceType {
685    type Abi = <wasm_bindgen::JsValue as wasm_bindgen::convert::IntoWasmAbi>::Abi;
686
687    #[inline]
688    fn into_abi(self) -> Self::Abi {
689        match self {
690            MarketResourceType::Resource(r) => {
691                <wasm_bindgen::JsValue as wasm_bindgen::convert::IntoWasmAbi>::into_abi(r.into())
692            }
693            MarketResourceType::IntershardResource(r) => {
694                <wasm_bindgen::JsValue as wasm_bindgen::convert::IntoWasmAbi>::into_abi(r.into())
695            }
696        }
697    }
698}
699
700impl wasm_bindgen::describe::WasmDescribe for MarketResourceType {
701    fn describe() {
702        <wasm_bindgen::JsValue as wasm_bindgen::describe::WasmDescribe>::describe()
703    }
704}
705
706/// Translates the `POWER_CLASS` constants, which are classes of power creeps
707#[wasm_bindgen]
708#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Sequence)]
709pub enum PowerCreepClass {
710    Operator = "operator",
711}
712
713named_enum_serialize_deserialize!(PowerCreepClass);
714
715/// Translates the `PWR_*` constants, which are types of powers used by power
716/// creeps
717#[wasm_bindgen]
718#[derive(
719    Debug,
720    PartialEq,
721    Eq,
722    Clone,
723    Copy,
724    Hash,
725    FromPrimitive,
726    Deserialize_repr,
727    Serialize_repr,
728    Sequence,
729)]
730#[repr(u32)]
731pub enum PowerType {
732    GenerateOps = 1,
733    OperateSpawn = 2,
734    OperateTower = 3,
735    OperateStorage = 4,
736    OperateLab = 5,
737    OperateExtension = 6,
738    OperateObserver = 7,
739    OperateTerminal = 8,
740    DisruptSpawn = 9,
741    DisruptTower = 10,
742    Shield = 12,
743    RegenSource = 13,
744    RegenMineral = 14,
745    DisruptTerminal = 15,
746    OperatePower = 16,
747    Fortify = 17,
748    OperateController = 18,
749    OperateFactory = 19,
750}
751
752impl JsCollectionFromValue for PowerType {
753    fn from_value(val: JsValue) -> Self {
754        let power_type_id = if let Some(val) = val.as_string() {
755            val.parse::<u32>().expect("expected parseable u32 string")
756        } else {
757            val.as_f64().expect("expected number value") as u32
758        };
759
760        Self::from_u32(power_type_id).expect("unknown power type")
761    }
762}
763
764impl JsCollectionIntoValue for PowerType {
765    fn into_value(self) -> JsValue {
766        JsValue::from_f64(self as u32 as f64)
767    }
768}
769
770/// Translates the `EFFECT_*` constants, which are natural effect types
771#[wasm_bindgen]
772#[derive(
773    Copy,
774    Clone,
775    Debug,
776    PartialEq,
777    Eq,
778    Hash,
779    FromPrimitive,
780    Serialize_repr,
781    Deserialize_repr,
782    Sequence,
783)]
784#[repr(u32)]
785pub enum NaturalEffectType {
786    Invulnerability = 1001,
787    CollapseTimer = 1002,
788}
789
790/// Translates effect types on room objects, which can include both `PWR_*` and
791/// `EFFECT_*` constants.
792#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Sequence)]
793pub enum EffectType {
794    PowerEffect(PowerType),
795    NaturalEffect(NaturalEffectType),
796}
797
798impl wasm_bindgen::convert::IntoWasmAbi for EffectType {
799    type Abi = u32;
800
801    #[inline]
802    fn into_abi(self) -> Self::Abi {
803        match self {
804            EffectType::PowerEffect(e) => (e as u32).into_abi(),
805            EffectType::NaturalEffect(e) => (e as u32).into_abi(),
806        }
807    }
808}
809
810impl wasm_bindgen::convert::FromWasmAbi for EffectType {
811    type Abi = u32;
812
813    #[inline]
814    unsafe fn from_abi(js: u32) -> Self {
815        match PowerType::from_u32(js) {
816            Some(pt) => Self::PowerEffect(pt),
817            None => {
818                Self::NaturalEffect(NaturalEffectType::from_u32(js).expect("unknown effect id!"))
819            }
820        }
821    }
822}
823
824impl wasm_bindgen::describe::WasmDescribe for EffectType {
825    fn describe() {
826        wasm_bindgen::describe::inform(wasm_bindgen::describe::U32)
827    }
828}
829
830#[cfg(test)]
831mod test {
832    use super::*;
833
834    #[test]
835    fn resources_rust_to_serde_json_from_serde_json_roundtrip() {
836        for resource in enum_iterator::all::<ResourceType>() {
837            if resource != ResourceType::__Invalid {
838                let serialized = serde_json::to_string(&resource).unwrap();
839                let parsed: ResourceType = serde_json::from_str(&serialized).unwrap();
840                assert_eq!(resource, parsed);
841            }
842        }
843    }
844
845    #[test]
846    fn resources_rust_to_display_from_str_roundtrip() {
847        for resource in enum_iterator::all::<ResourceType>() {
848            if resource != ResourceType::__Invalid {
849                let string = format!("{}", resource);
850                let parsed = ResourceType::from_str(&string).unwrap();
851                assert_eq!(resource, parsed);
852            }
853        }
854    }
855
856    #[test]
857    fn resources_rust_vec_to_serde_json_from_serde_json_roundtrip() {
858        let mut resources = vec![];
859        for resource in enum_iterator::all::<ResourceType>() {
860            if resource != ResourceType::__Invalid {
861                resources.push(resource);
862            }
863        }
864        let serialized = serde_json::to_string(&resources).unwrap();
865        let resources_reparsed: Vec<ResourceType> = serde_json::from_str(&serialized).unwrap();
866        assert_eq!(resources, resources_reparsed);
867    }
868
869    #[test]
870    fn resources_rust_vec_to_serde_json_from_serde_json_roundtrip_via_values() {
871        let mut resources = vec![];
872        for resource in enum_iterator::all::<ResourceType>() {
873            if resource != ResourceType::__Invalid {
874                resources.push(resource);
875            }
876        }
877        let serialized = serde_json::to_string(&resources).unwrap();
878        let resources_reparsed_values: Vec<serde_json::Value> =
879            serde_json::from_str(&serialized).unwrap();
880        let resources_reparsed_native: Vec<ResourceType> = resources_reparsed_values
881            .iter()
882            .map(|v| serde_json::from_value(v.clone()).unwrap())
883            .collect();
884        assert_eq!(resources, resources_reparsed_native);
885    }
886
887    #[test]
888    fn intershard_resources_rust_to_serde_json_from_serde_json_roundtrip() {
889        for resource in enum_iterator::all::<IntershardResourceType>() {
890            if resource != IntershardResourceType::__Invalid {
891                let serialized = serde_json::to_string(&resource).unwrap();
892                let parsed: IntershardResourceType = serde_json::from_str(&serialized).unwrap();
893                assert_eq!(resource, parsed);
894            }
895        }
896    }
897
898    #[test]
899    fn intershard_resources_rust_to_display_from_str_roundtrip() {
900        for resource in enum_iterator::all::<IntershardResourceType>() {
901            if resource != IntershardResourceType::__Invalid {
902                let string = format!("{}", resource);
903                let parsed = IntershardResourceType::from_str(&string).unwrap();
904                assert_eq!(resource, parsed);
905            }
906        }
907    }
908
909    #[test]
910    fn intershard_resources_rust_vec_to_serde_json_from_serde_json_roundtrip() {
911        let mut resources = vec![];
912        for resource in enum_iterator::all::<IntershardResourceType>() {
913            if resource != IntershardResourceType::__Invalid {
914                resources.push(resource);
915            }
916        }
917        let serialized = serde_json::to_string(&resources).unwrap();
918        let resources_reparsed: Vec<IntershardResourceType> =
919            serde_json::from_str(&serialized).unwrap();
920        assert_eq!(resources, resources_reparsed);
921    }
922
923    #[test]
924    fn intershard_resources_rust_vec_to_serde_json_from_serde_json_roundtrip_via_values() {
925        let mut resources = vec![];
926        for resource in enum_iterator::all::<IntershardResourceType>() {
927            if resource != IntershardResourceType::__Invalid {
928                resources.push(resource);
929            }
930        }
931        let serialized = serde_json::to_string(&resources).unwrap();
932        let resources_reparsed_values: Vec<serde_json::Value> =
933            serde_json::from_str(&serialized).unwrap();
934        let resources_reparsed_native: Vec<IntershardResourceType> = resources_reparsed_values
935            .iter()
936            .map(|v| serde_json::from_value(v.clone()).unwrap())
937            .collect();
938        assert_eq!(resources, resources_reparsed_native);
939    }
940
941    #[test]
942    fn market_resources_rust_to_serde_json_from_serde_json_roundtrip() {
943        for resource in enum_iterator::all::<MarketResourceType>() {
944            if resource != MarketResourceType::Resource(ResourceType::__Invalid)
945                && resource
946                    != MarketResourceType::IntershardResource(IntershardResourceType::__Invalid)
947            {
948                let serialized = serde_json::to_string(&resource).unwrap();
949                let parsed: MarketResourceType = serde_json::from_str(&serialized).unwrap();
950                assert_eq!(resource, parsed);
951            }
952        }
953    }
954
955    #[test]
956    fn market_resources_rust_vec_to_serde_json_from_serde_json_roundtrip() {
957        let mut resources = vec![];
958        for resource in enum_iterator::all::<MarketResourceType>() {
959            if resource != MarketResourceType::Resource(ResourceType::__Invalid)
960                && resource
961                    != MarketResourceType::IntershardResource(IntershardResourceType::__Invalid)
962            {
963                resources.push(resource);
964            }
965        }
966        let serialized = serde_json::to_string(&resources).unwrap();
967        let resources_reparsed: Vec<MarketResourceType> =
968            serde_json::from_str(&serialized).unwrap();
969        assert_eq!(resources, resources_reparsed);
970    }
971
972    #[test]
973    fn market_resources_rust_vec_to_serde_json_from_serde_json_roundtrip_via_values() {
974        let mut resources = vec![];
975        for resource in enum_iterator::all::<MarketResourceType>() {
976            if resource != MarketResourceType::Resource(ResourceType::__Invalid)
977                && resource
978                    != MarketResourceType::IntershardResource(IntershardResourceType::__Invalid)
979            {
980                resources.push(resource);
981            }
982        }
983        let serialized = serde_json::to_string(&resources).unwrap();
984        let resources_reparsed_values: Vec<serde_json::Value> =
985            serde_json::from_str(&serialized).unwrap();
986        let resources_reparsed_native: Vec<MarketResourceType> = resources_reparsed_values
987            .iter()
988            .map(|v| serde_json::from_value(v.clone()).unwrap())
989            .collect();
990        assert_eq!(resources, resources_reparsed_native);
991    }
992}