screeps/constants/
look.rs

1//! Constants for use with [`Room::look_for_at`] and related functions.
2//!
3//! *Note:* Types in this module have purposefully ambiguous names, and are
4//! intended to be used as, for example, `look::CREEPS`, not `CREEPS`.
5//!
6//! You can do this my importing the module itself, rather than any individual
7//! constant, and then just referring to the constants relative to the module.
8//!
9//! [`Room::look_for_at`]: crate::objects::Room::look_for_at
10use enum_iterator::Sequence;
11use serde::{Deserialize, Serialize};
12use wasm_bindgen::prelude::*;
13
14use crate::{constants::Terrain, enums::StructureObject, objects::*};
15
16/// Translates `LOOK_*` constants for interal API calls
17///
18/// Unless you're storing the type of look constant to be used for a call, you
19/// likely want the constants which implement the `LookConstant` trait to make
20/// calls to look methods.
21///
22/// This is hidden from the documentation to avoid confusion due to its
23/// narrow use case, but wasm_bindgen requires it remain public.
24#[doc(hidden)]
25#[wasm_bindgen]
26#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Sequence)]
27pub enum Look {
28    Creeps = "creep",
29    Energy = "energy",
30    Resources = "resource",
31    Sources = "source",
32    Minerals = "mineral",
33    Structures = "structure",
34    Flags = "flag",
35    ConstructionSites = "constructionSite",
36    Nukes = "nuke",
37    Terrain = "terrain",
38    Tombstones = "tombstone",
39    PowerCreeps = "powerCreep",
40    Deposits = "deposit",
41    Ruins = "ruin",
42    // todo these seem to not work when conditionally compiled out - they're not hurting to leave
43    // in but need to figure that out
44    //#[cfg(feature = "seasonal-season-1")]
45    ScoreContainers = "scoreContainer",
46    //#[cfg(feature = "seasonal-season-1")]
47    ScoreCollectors = "scoreCollector",
48    //#[cfg(feature = "seasonal-season-2")]
49    SymbolContainers = "symbolContainer",
50    //#[cfg(feature = "seasonal-season-2")]
51    SymbolDecoders = "symbolDecoder",
52    //#[cfg(feature = "seasonal-season-5")]
53    Reactors = "reactor",
54}
55
56//TODO: wiarchbe: Add back in calculated doc.
57macro_rules! typesafe_look_constants {
58    (
59        $(
60            $vis:vis struct $constant_name:ident = ($value:expr, $result:path, $conversion_method:expr);
61        )*
62    ) => (
63        $(
64            #[allow(bad_style)]
65            $vis struct $constant_name;
66            impl LookConstant for $constant_name {
67                type Item = $result;
68
69                fn convert_and_check_item(reference: JsValue) -> Self::Item {
70                    $conversion_method(reference)
71                }
72
73                #[inline]
74                fn look_code() -> Look {
75                    $value
76                }
77            }
78        )*
79    );
80}
81
82pub trait LookConstant {
83    type Item;
84
85    fn convert_and_check_item(reference: JsValue) -> Self::Item;
86
87    fn look_code() -> Look;
88}
89
90typesafe_look_constants! {
91    pub struct CREEPS = (Look::Creeps, Creep, Into::into);
92    pub struct ENERGY = (Look::Energy, Resource, Into::into);
93    pub struct RESOURCES = (Look::Resources, Resource, Into::into);
94    pub struct SOURCES = (Look::Sources, Source, Into::into);
95    pub struct MINERALS = (Look::Minerals, Mineral, Into::into);
96    pub struct DEPOSITS = (Look::Deposits, Deposit, Into::into);
97    pub struct STRUCTURES = (Look::Structures, StructureObject, Into::into);
98    pub struct FLAGS = (Look::Flags, Flag, Into::into);
99    pub struct CONSTRUCTION_SITES = (Look::ConstructionSites, ConstructionSite,
100        Into::into);
101    pub struct NUKES = (Look::Nukes, Nuke, Into::into);
102    pub struct TERRAIN = (Look::Terrain, Terrain, Terrain::from_look_constant_jsvalue);
103    pub struct TOMBSTONES = (Look::Tombstones, Tombstone, Into::into);
104    pub struct POWER_CREEPS = (Look::PowerCreeps, PowerCreep, Into::into);
105    pub struct RUINS = (Look::Ruins, Ruin, Into::into);
106}
107
108#[cfg(feature = "seasonal-season-1")]
109typesafe_look_constants! {
110    pub struct SCORE_CONTAINERS = (Look::ScoreContainers, ScoreContainer, Into::into);
111    pub struct SCORE_COLLECTORS = (Look::ScoreCollectors, ScoreCollector, Into::into);
112}
113
114#[cfg(feature = "seasonal-season-2")]
115typesafe_look_constants! {
116    pub struct SYMBOL_CONTAINERS = (Look::SymbolContainers, SymbolContainer, Into::into);
117    pub struct SYMBOL_DECODERS = (Look::SymbolDecoders, SymbolDecoder, Into::into);
118}
119
120#[cfg(feature = "seasonal-season-5")]
121typesafe_look_constants! {
122    pub struct REACTORS = (Look::Reactors, Reactor, Into::into);
123}
124
125#[derive(Debug)]
126pub enum LookResult {
127    Creep(Creep),
128    Energy(Resource),
129    Resource(Resource),
130    Source(Source),
131    Mineral(Mineral),
132    Deposit(Deposit),
133    Structure(Structure),
134    Flag(Flag),
135    ConstructionSite(ConstructionSite),
136    Nuke(Nuke),
137    Terrain(Terrain),
138    Tombstone(Tombstone),
139    PowerCreep(PowerCreep),
140    Ruin(Ruin),
141    #[cfg(feature = "seasonal-season-1")]
142    ScoreContainer(ScoreContainer),
143    #[cfg(feature = "seasonal-season-1")]
144    ScoreCollector(ScoreCollector),
145    #[cfg(feature = "seasonal-season-2")]
146    SymbolContainer(SymbolContainer),
147    #[cfg(feature = "seasonal-season-2")]
148    SymbolDecoder(SymbolDecoder),
149    #[cfg(feature = "seasonal-season-5")]
150    Reactor(Reactor),
151}
152
153impl LookResult {
154    pub(crate) fn from_result_with_type(result: JsLookResult, t: Look) -> Self {
155        match t {
156            Look::Creeps => Self::Creep(result.creep()),
157            Look::Energy => Self::Energy(result.energy()),
158            Look::Resources => Self::Resource(result.resource()),
159            Look::Sources => Self::Source(result.source()),
160            Look::Minerals => Self::Mineral(result.mineral()),
161            Look::Deposits => Self::Deposit(result.deposit()),
162            Look::Structures => Self::Structure(result.structure()),
163            Look::Flags => Self::Flag(result.flag()),
164            Look::ConstructionSites => Self::ConstructionSite(result.construction_site()),
165            Look::Nukes => Self::Nuke(result.nuke()),
166            Look::Terrain => Self::Terrain(Terrain::from_look_constant_str(&result.terrain())),
167            Look::Tombstones => Self::Tombstone(result.tombstone()),
168            Look::PowerCreeps => Self::PowerCreep(result.power_creep()),
169            Look::Ruins => Self::Ruin(result.ruin()),
170            #[cfg(feature = "seasonal-season-1")]
171            Look::ScoreContainers => Self::ScoreContainer(result.score_container()),
172            #[cfg(feature = "seasonal-season-1")]
173            Look::ScoreCollectors => Self::ScoreCollector(result.score_collector()),
174            #[cfg(feature = "seasonal-season-2")]
175            Look::SymbolContainers => Self::SymbolContainer(result.symbol_container()),
176            #[cfg(feature = "seasonal-season-2")]
177            Look::SymbolDecoders => Self::SymbolDecoder(result.symbol_decoder()),
178            #[cfg(feature = "seasonal-season-5")]
179            Look::Reactors => Self::Reactor(result.reactor()),
180            _ => panic!("look result type not matched, object type feature may be disabled?"),
181        }
182    }
183
184    pub(crate) fn from_jsvalue_unknown_type(v: JsValue) -> Self {
185        let result: JsLookResult = v.unchecked_into();
186        let rt = result.result_type();
187        Self::from_result_with_type(result, rt)
188    }
189}
190
191#[derive(Debug)]
192pub struct PositionedLookResult {
193    pub x: u8,
194    pub y: u8,
195    pub look_result: LookResult,
196}
197
198impl PositionedLookResult {
199    pub(crate) fn from_jsvalue_with_type(v: JsValue, t: Look) -> Self {
200        let result: JsLookResult = v.unchecked_into();
201        let x = result.x();
202        let y = result.y();
203        let look_result = LookResult::from_result_with_type(result, t);
204        Self { x, y, look_result }
205    }
206
207    pub(crate) fn from_jsvalue_unknown_type(v: JsValue) -> Self {
208        let result: JsLookResult = v.unchecked_into();
209        let rt = result.result_type();
210        let x = result.x();
211        let y = result.y();
212        let look_result = LookResult::from_result_with_type(result, rt);
213        Self { x, y, look_result }
214    }
215}
216
217// internal accessors for results for look functions, any of which may be
218// undefined in different kinds of look return calls
219#[wasm_bindgen]
220extern "C" {
221    #[wasm_bindgen]
222    pub(crate) type JsLookResult;
223    #[wasm_bindgen(method, getter = type)]
224    fn result_type(this: &JsLookResult) -> Look;
225    #[wasm_bindgen(method, getter)]
226    fn x(this: &JsLookResult) -> u8;
227    #[wasm_bindgen(method, getter)]
228    fn y(this: &JsLookResult) -> u8;
229    #[wasm_bindgen(method, getter)]
230    fn creep(this: &JsLookResult) -> Creep;
231    #[wasm_bindgen(method, getter)]
232    fn energy(this: &JsLookResult) -> Resource;
233    #[wasm_bindgen(method, getter)]
234    fn resource(this: &JsLookResult) -> Resource;
235    #[wasm_bindgen(method, getter)]
236    fn source(this: &JsLookResult) -> Source;
237    #[wasm_bindgen(method, getter)]
238    fn mineral(this: &JsLookResult) -> Mineral;
239    #[wasm_bindgen(method, getter)]
240    fn deposit(this: &JsLookResult) -> Deposit;
241    #[wasm_bindgen(method, getter)]
242    fn structure(this: &JsLookResult) -> Structure;
243    #[wasm_bindgen(method, getter)]
244    fn flag(this: &JsLookResult) -> Flag;
245    #[wasm_bindgen(method, getter = constructionSite)]
246    fn construction_site(this: &JsLookResult) -> ConstructionSite;
247    #[wasm_bindgen(method, getter)]
248    fn nuke(this: &JsLookResult) -> Nuke;
249    // note that this one is a string representing a terrain constant, and must be
250    // converted
251    #[wasm_bindgen(method, getter)]
252    fn terrain(this: &JsLookResult) -> String;
253    #[wasm_bindgen(method, getter)]
254    fn tombstone(this: &JsLookResult) -> Tombstone;
255    #[wasm_bindgen(method, getter = powerCreep)]
256    fn power_creep(this: &JsLookResult) -> PowerCreep;
257    #[wasm_bindgen(method, getter)]
258    fn ruin(this: &JsLookResult) -> Ruin;
259    #[cfg(feature = "seasonal-season-1")]
260    #[wasm_bindgen(method, getter = scoreContainer)]
261    fn score_container(this: &JsLookResult) -> ScoreContainer;
262    #[cfg(feature = "seasonal-season-1")]
263    #[wasm_bindgen(method, getter = scoreCollector)]
264    fn score_collector(this: &JsLookResult) -> ScoreCollector;
265    #[cfg(feature = "seasonal-season-2")]
266    #[wasm_bindgen(method, getter = symbolContainer)]
267    fn symbol_container(this: &JsLookResult) -> SymbolContainer;
268    #[cfg(feature = "seasonal-season-2")]
269    #[wasm_bindgen(method, getter = symbolDecoder)]
270    fn symbol_decoder(this: &JsLookResult) -> SymbolDecoder;
271    #[cfg(feature = "seasonal-season-5")]
272    #[wasm_bindgen(method, getter = reactor)]
273    fn reactor(this: &JsLookResult) -> Reactor;
274}