1use enum_iterator::Sequence;
11use serde::{Deserialize, Serialize};
12use wasm_bindgen::prelude::*;
13
14use crate::{constants::Terrain, enums::StructureObject, objects::*};
15
16#[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 ScoreContainers = "scoreContainer",
46 ScoreCollectors = "scoreCollector",
48 SymbolContainers = "symbolContainer",
50 SymbolDecoders = "symbolDecoder",
52 Reactors = "reactor",
54}
55
56macro_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#[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 #[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}