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> {}