screeps/traits.rs
1//! Traits associated with how specific [game objects] can be used.
2//!
3//! [game objects]: crate::objects
4use std::str::FromStr;
5
6use enum_dispatch::enum_dispatch;
7use js_sys::{Array, JsString};
8use wasm_bindgen::prelude::*;
9
10use crate::{
11 constants::*,
12 enums::{
13 action_error_codes::{
14 DestroyErrorCode, DropErrorCode, NotifyWhenAttackedErrorCode, PickupErrorCode,
15 SayErrorCode, StructureNotifyWhenAttackedErrorCode, SuicideErrorCode,
16 TransferErrorCode, WithdrawErrorCode,
17 },
18 *,
19 },
20 local::{ObjectId, Position, RawObjectId, RoomXY},
21 objects::*,
22 prelude::*,
23};
24
25pub trait FromReturnCode {
26 type Error;
27
28 fn result_from_i8(val: i8) -> Result<(), Self::Error>;
29
30 fn try_result_from_i8(val: i8) -> Option<Result<(), Self::Error>>;
31
32 fn try_result_from_jsvalue(val: &JsValue) -> Option<Result<(), Self::Error>> {
33 val.as_f64().and_then(|f| Self::try_result_from_i8(f as i8))
34 }
35}
36
37#[enum_dispatch]
38pub trait HasHits {
39 /// Retrieve the current hits of this object.
40 fn hits(&self) -> u32;
41
42 /// Retrieve the maximum hits of this object.
43 fn hits_max(&self) -> u32;
44}
45
46#[enum_dispatch]
47pub trait CanDecay {
48 /// The number of ticks until the object will decay, losing hits.
49 fn ticks_to_decay(&self) -> u32;
50}
51
52#[enum_dispatch]
53pub trait HasCooldown {
54 /// The number of ticks until the object can be used again.
55 fn cooldown(&self) -> u32;
56}
57
58/// Trait for all game objects which have an associated unique identifier.
59pub trait HasId: MaybeHasId {
60 /// Object ID of the object stored in Rust memory, which can be used to
61 /// efficiently fetch a fresh reference to the object on subsequent
62 /// ticks.
63 fn id(&self) -> ObjectId<Self>
64 where
65 Self: Sized,
66 {
67 self.raw_id().into()
68 }
69
70 /// Object ID of the object stored in Rust memory, without its associated
71 /// type information.
72 fn raw_id(&self) -> RawObjectId {
73 let id: String = self.js_raw_id().into();
74
75 RawObjectId::from_str(&id).expect("expected object ID to be parseable")
76 }
77
78 /// Object ID of the object stored in JavaScript memory, which can be used
79 /// to efficiently fetch a fresh reference to the object on subsequent
80 /// ticks.
81 fn js_id(&self) -> JsObjectId<Self>
82 where
83 Self: Sized,
84 {
85 self.js_raw_id().into()
86 }
87
88 /// Object ID of the object stored in JavaScript memory, without its
89 /// associated type information.
90 fn js_raw_id(&self) -> JsString;
91}
92
93/// Trait for all game objects which may (or may not) have an associated unique
94/// identifier.
95pub trait MaybeHasId {
96 /// Object ID of the object, which can be used to efficiently fetch a
97 /// fresh reference to the object on subsequent ticks, or `None` if the
98 /// object doesn't currently have an ID.
99 fn try_id(&self) -> Option<ObjectId<Self>>
100 where
101 Self: Sized,
102 {
103 self.try_raw_id().map(Into::into)
104 }
105
106 /// Object ID of the object, without its associated type information, or
107 /// `None` if the object doesn't currently have an ID.
108 fn try_raw_id(&self) -> Option<RawObjectId> {
109 self.try_js_raw_id()
110 .map(String::from)
111 .map(|id| RawObjectId::from_str(&id).expect("expected object ID to be parseable"))
112 }
113
114 /// Object ID of the object stored in JavaScript memory, which can be used
115 /// to efficiently fetch a fresh reference to the object on subsequent
116 /// ticks, or `None` if the object doesn't currently have an ID.
117 fn try_js_id(&self) -> Option<JsObjectId<Self>>
118 where
119 Self: Sized,
120 {
121 self.try_js_raw_id().map(Into::into)
122 }
123
124 /// Object ID of the object stored in JavaScript memory, without its
125 /// associated type information, or `None` if the object doesn't currently
126 /// have an ID.
127 fn try_js_raw_id(&self) -> Option<JsString>;
128}
129
130impl<T> MaybeHasId for T
131where
132 T: HasId,
133{
134 fn try_js_raw_id(&self) -> Option<JsString> {
135 Some(self.js_raw_id())
136 }
137}
138
139#[enum_dispatch]
140pub trait HasPosition {
141 /// Position of the object.
142 fn pos(&self) -> Position;
143}
144
145#[enum_dispatch]
146pub trait MaybeHasPosition {
147 /// Position of the object, or `None` if the object is a power creep not
148 /// spawned on the current shard.
149 fn try_pos(&self) -> Option<Position>;
150}
151
152pub trait CostMatrixSet {
153 fn set_xy(&mut self, xy: RoomXY, cost: u8);
154}
155
156pub trait CostMatrixGet {
157 fn get_xy(&mut self, xy: RoomXY) -> u8;
158}
159
160#[enum_dispatch]
161pub trait HasStore {
162 /// The store of the object, containing information about the resources it
163 /// is holding.
164 fn store(&self) -> Store;
165}
166
167#[enum_dispatch]
168pub trait OwnedStructureProperties {
169 /// Whether this structure is owned by the player.
170 ///
171 /// [Screeps documentation](https://docs.screeps.com/api/#OwnedStructure.my)
172 fn my(&self) -> bool;
173
174 /// The [`Owner`] of this structure that contains the owner's username, or
175 /// `None` if it's an ownable structure currently not under a player's
176 /// control.
177 ///
178 /// [Screeps documentation](https://docs.screeps.com/api/#OwnedStructure.owner)
179 fn owner(&self) -> Option<Owner>;
180}
181
182#[enum_dispatch]
183pub trait RoomObjectProperties {
184 /// Effects applied to the object.
185 ///
186 /// [Screeps documentation](https://docs.screeps.com/api/#RoomObject.effects)
187 fn effects(&self) -> Vec<Effect>;
188
189 /// Effects applied to the object.
190 ///
191 /// [Screeps documentation](https://docs.screeps.com/api/#RoomObject.effects)
192 fn effects_raw(&self) -> Option<Array>;
193
194 /// A link to the room that the object is currently in, or `None` if the
195 /// object is a power creep not spawned on the current shard, or a flag or
196 /// construction site not in a visible room.
197 ///
198 /// [Screeps documentation](https://docs.screeps.com/api/#RoomObject.room)
199 fn room(&self) -> Option<Room>;
200}
201
202#[enum_dispatch]
203pub trait SharedCreepProperties {
204 /// A shortcut to the part of the `Memory` tree used for this creep by
205 /// default
206 fn memory(&self) -> JsValue;
207
208 /// Sets a new value to the memory object shortcut for this creep.
209 fn set_memory(&self, val: &JsValue);
210
211 /// Whether this creep is owned by the player.
212 fn my(&self) -> bool;
213
214 /// The creep's name as a [`String`].
215 ///
216 /// [Screeps documentation](https://docs.screeps.com/api/#Creep.name)
217 fn name(&self) -> String;
218
219 /// The creep's name as a [`JsString`].
220 ///
221 /// [Screeps documentation](https://docs.screeps.com/api/#Creep.name)
222 fn name_jsstring(&self) -> JsString;
223
224 /// The [`Owner`] of this creep that contains the owner's username.
225 fn owner(&self) -> Owner;
226
227 /// What the creep said last tick.
228 fn saying(&self) -> Option<JsString>;
229
230 /// The number of ticks the creep has left to live.
231 fn ticks_to_live(&self) -> Option<u32>;
232
233 /// Drop a resource on the ground from the creep's [`Store`].
234 fn drop(&self, ty: ResourceType, amount: Option<u32>) -> Result<(), DropErrorCode>;
235
236 /// Whether to send an email notification when this creep is attacked.
237 fn notify_when_attacked(&self, enabled: bool) -> Result<(), NotifyWhenAttackedErrorCode>;
238
239 /// Pick up a [`Resource`] in melee range (or at the same position as the
240 /// creep).
241 fn pickup(&self, target: &Resource) -> Result<(), PickupErrorCode>;
242
243 /// Display a string in a bubble above the creep next tick. 10 character
244 /// limit.
245 fn say(&self, message: &str, public: bool) -> Result<(), SayErrorCode>;
246
247 /// Immediately kill the creep.
248 fn suicide(&self) -> Result<(), SuicideErrorCode>;
249
250 /// Transfer a resource from the creep's store to [`Structure`],
251 /// [`PowerCreep`], or another [`Creep`].
252 fn transfer<T>(
253 &self,
254 target: &T,
255 ty: ResourceType,
256 amount: Option<u32>,
257 ) -> Result<(), TransferErrorCode>
258 where
259 T: Transferable + ?Sized;
260
261 /// Withdraw a resource from a [`Structure`], [`Tombstone`], or [`Ruin`].
262 fn withdraw<T>(
263 &self,
264 target: &T,
265 ty: ResourceType,
266 amount: Option<u32>,
267 ) -> Result<(), WithdrawErrorCode>
268 where
269 T: Withdrawable + ?Sized;
270}
271
272#[enum_dispatch]
273pub trait StructureProperties {
274 fn structure_type(&self) -> StructureType;
275
276 fn destroy(&self) -> Result<(), DestroyErrorCode>;
277
278 fn is_active(&self) -> bool;
279
280 fn notify_when_attacked(&self, val: bool) -> Result<(), StructureNotifyWhenAttackedErrorCode>;
281}
282
283/// Trait for all wrappers over Screeps JavaScript objects which can be the
284/// target of `Creep.transfer`.
285///
286/// # Contracts
287///
288/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
289/// target for `Creep.transfer`.
290#[enum_dispatch]
291pub trait Transferable: AsRef<RoomObject> {}
292
293/// Trait for all wrappers over Screeps JavaScript objects which can be the
294/// target of `Creep.withdraw`.
295///
296/// # Contracts
297///
298/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
299/// target for `Creep.withdraw`.
300pub trait Withdrawable: AsRef<RoomObject> {}
301
302/// Trait for all wrappers over Screeps JavaScript objects which can be the
303/// target of `Creep.harvest`.
304///
305/// # Contracts
306///
307/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
308/// target for `Creep.harvest`.
309pub trait Harvestable: AsRef<RoomObject> {}
310
311/// Trait for all wrappers over Screeps JavaScript objects which can be the
312/// target of `Creep.attack`.
313///
314/// # Contracts
315///
316/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
317/// target for `Creep.attack`.
318pub trait Attackable: HasHits + AsRef<RoomObject> {}
319
320/// Trait for all wrappers over Screeps JavaScript objects which can be the
321/// target of `Creep.dismantle`.
322///
323/// # Contracts
324///
325/// The reference returned from `AsRef<Structure>::as_ref` must be a valid
326/// target for `Creep.dismantle`.
327pub trait Dismantleable: HasHits + AsRef<Structure> {}
328
329/// Trait for all wrappers over Screeps JavaScript objects which can be the
330/// target of `Creep.repair` or `StructureTower.repair`.
331///
332/// # Contracts
333///
334/// The reference returned from `AsRef<Structure>::as_ref` must be a valid
335/// target for repair.
336pub trait Repairable: HasHits + AsRef<Structure> {}
337
338/// Trait for all wrappers over Screeps JavaScript objects which can be the
339/// target of `Creep.heal`.
340///
341/// # Contracts
342///
343/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
344/// target for `Creep.heal`.
345pub trait Healable: AsRef<RoomObject> {}