screeps/objects/impls/
structure_spawn.rs

1use js_sys::{Array, JsString, Object};
2use wasm_bindgen::prelude::*;
3
4use crate::{
5    constants::{Direction, Part},
6    enums::action_error_codes::{spawning::*, structure_spawn::*},
7    objects::{Creep, OwnedStructure, RoomObject, Store, Structure},
8    prelude::*,
9};
10
11#[wasm_bindgen]
12extern "C" {
13    /// An object representing a [`StructureSpawn`], which creates your creeps.
14    ///
15    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn)
16    #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)]
17    #[derive(Clone, Debug)]
18    pub type StructureSpawn;
19
20    /// A shortcut to `Memory.spawns[spawn.name]`.
21    ///
22    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.memory)
23    #[wasm_bindgen(method, getter)]
24    pub fn memory(this: &StructureSpawn) -> JsValue;
25
26    /// Sets a new value to `Memory.spawns[spawn.name]`.
27    ///
28    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.memory)
29    #[wasm_bindgen(method, setter)]
30    pub fn set_memory(this: &StructureSpawn, val: &JsValue);
31
32    /// The spawn's name as a [`String`].
33    ///
34    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.name)
35    #[wasm_bindgen(method, getter)]
36    pub fn name(this: &StructureSpawn) -> String;
37
38    /// The spawn's name as a [`JsString`].
39    ///
40    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.name)
41    #[wasm_bindgen(method, getter = name)]
42    pub fn name_jsstring(this: &StructureSpawn) -> JsString;
43
44    /// Information about the spawning creep, if one is currently being spawned.
45    ///
46    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.spawning)
47    #[wasm_bindgen(method, getter)]
48    pub fn spawning(this: &StructureSpawn) -> Option<Spawning>;
49
50    /// The [`Store`] of the spawn, which contains information about what
51    /// resources it is it holding.
52    ///
53    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.store)
54    #[wasm_bindgen(method, getter)]
55    pub fn store(this: &StructureSpawn) -> Store;
56
57    #[wasm_bindgen(method, js_name = spawnCreep)]
58    fn spawn_creep_internal(
59        this: &StructureSpawn,
60        body: &Array,
61        name: &str,
62        options: Option<&Object>,
63    ) -> i8;
64
65    #[wasm_bindgen(method, js_name = recycleCreep)]
66    fn recycle_creep_internal(this: &StructureSpawn, creep: &Creep) -> i8;
67
68    #[wasm_bindgen(method, js_name = renewCreep)]
69    fn renew_creep_internal(this: &StructureSpawn, creep: &Creep) -> i8;
70}
71
72impl StructureSpawn {
73    /// Create a new creep with the specified body part [`Array`], name
74    /// [`JsString`], and optional spawning options. Note that successfully
75    /// spawning will store data in `Memory.creeps[creep_name]` _regardless
76    /// of whether any memory data was passed in the options object_ and enable
77    /// the default serialization behavior of the `Memory` object, which may
78    /// hamper attempts to directly use `RawMemory`. todo, add note+docs
79    /// about how to replace Memory and/or delete RawMemory._parsed
80    ///
81    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.spawnCreep)
82    pub fn spawn_creep(&self, body: &[Part], name: &str) -> Result<(), SpawnCreepErrorCode> {
83        let body = body.iter().cloned().map(JsValue::from).collect();
84
85        SpawnCreepErrorCode::result_from_i8(Self::spawn_creep_internal(self, &body, name, None))
86    }
87
88    /// Create a new creep with the specified body part [`Array`], name
89    /// [`JsString`], and optional spawning options. Note that successfully
90    /// spawning will store data in `Memory.creeps[creep_name]` _regardless
91    /// of whether any memory data was passed in the options object_ and enable
92    /// the default serialization behavior of the `Memory` object, which may
93    /// hamper attempts to directly use `RawMemory`. todo, add note+docs
94    /// about how to replace Memory and/or delete RawMemory._parsed
95    ///
96    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.spawnCreep)
97    pub fn spawn_creep_with_options(
98        &self,
99        body: &[Part],
100        name: &str,
101        opts: &SpawnOptions,
102    ) -> Result<(), SpawnCreepErrorCode> {
103        let body = body.iter().cloned().map(JsValue::from).collect();
104
105        let js_opts = ObjectExt::unchecked_from_js(JsValue::from(Object::new()));
106
107        if let Some(mem) = &opts.memory {
108            ObjectExt::set(&js_opts, "memory", mem);
109        }
110
111        if let Some(array) = &opts.energy_structures {
112            ObjectExt::set(&js_opts, "energyStructures", array);
113        }
114
115        if opts.dry_run {
116            ObjectExt::set(&js_opts, "dryRun", &true.into());
117        }
118
119        if let Some(array) = &opts.directions {
120            ObjectExt::set(&js_opts, "directions", array);
121        }
122
123        SpawnCreepErrorCode::result_from_i8(Self::spawn_creep_internal(
124            self,
125            &body,
126            name,
127            Some(&js_opts),
128        ))
129    }
130
131    /// Kill a [`Creep`] in melee range, returning 100% of its TTL-adjusted
132    /// resources (5x more than if the creep is killed another way). Can be used
133    /// while spawning.
134    ///
135    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.recycleCreep)
136    pub fn recycle_creep(&self, creep: &Creep) -> Result<(), RecycleCreepErrorCode> {
137        RecycleCreepErrorCode::result_from_i8(self.recycle_creep_internal(creep))
138    }
139
140    /// Renew a [`Creep`] in melee range, removing all boosts adding to its TTL.
141    /// Cannot be used while spawning.
142    ///
143    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.renewCreep)
144    pub fn renew_creep(&self, creep: &Creep) -> Result<(), RenewCreepErrorCode> {
145        RenewCreepErrorCode::result_from_i8(self.renew_creep_internal(creep))
146    }
147}
148
149impl JsCollectionFromValue for StructureSpawn {
150    fn from_value(val: JsValue) -> Self {
151        val.unchecked_into()
152    }
153}
154
155impl HasStore for StructureSpawn {
156    fn store(&self) -> Store {
157        Self::store(self)
158    }
159}
160
161impl Attackable for StructureSpawn {}
162impl Dismantleable for StructureSpawn {}
163impl Repairable for StructureSpawn {}
164impl Transferable for StructureSpawn {}
165impl Withdrawable for StructureSpawn {}
166
167#[derive(Default)]
168pub struct SpawnOptions {
169    memory: Option<JsValue>,
170    energy_structures: Option<Array>,
171    dry_run: bool,
172    directions: Option<Array>,
173}
174
175impl SpawnOptions {
176    pub fn new() -> Self {
177        Self::default()
178    }
179
180    pub fn memory(mut self, mem: JsValue) -> Self {
181        self.memory = Some(mem);
182        self
183    }
184
185    /// Structures other than [`StructureSpawn`] and [`StructureExtension`] will
186    /// be ignored.
187    ///
188    /// [`StructureExtension`]: crate::objects::StructureExtension
189    pub fn energy_structures<T: IntoIterator<Item = V>, V: AsRef<Structure>>(
190        mut self,
191        structures: T,
192    ) -> Self {
193        self.energy_structures = Some(
194            structures
195                .into_iter()
196                .map(|structure| JsValue::from(structure.as_ref()))
197                .collect(),
198        );
199        self
200    }
201
202    pub fn dry_run(mut self, dry_run: bool) -> Self {
203        self.dry_run = dry_run;
204        self
205    }
206
207    pub fn directions(mut self, directions: &[Direction]) -> Self {
208        self.directions = Some(
209            directions
210                .iter()
211                .map(|&d| JsValue::from(d as u32))
212                .collect(),
213        );
214        self
215    }
216}
217
218#[wasm_bindgen]
219extern "C" {
220    /// Object with info on what a [`StructureSpawn`] or
221    /// [`StructureInvaderCore`] is currently spawning.
222    ///
223    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn-Spawning)
224    ///
225    /// [`StructureInvaderCore`]: crate::objects::StructureInvaderCore
226    #[wasm_bindgen(js_namespace = StructureSpawn)]
227    pub type Spawning;
228
229    /// Allowed directions for the creep to exit the spawn; can be changed with
230    /// [`Spawning::set_directions`].
231    ///
232    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.Spawning.directions)
233    #[wasm_bindgen(method, getter)]
234    pub fn directions(this: &Spawning) -> Array;
235
236    /// The name of the spawning creep.
237    ///
238    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.Spawning.name)
239    #[wasm_bindgen(method, getter)]
240    pub fn name(this: &Spawning) -> JsString;
241
242    /// Total time needed to spawn this creep.
243    ///
244    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.Spawning.needTime)
245    #[wasm_bindgen(method, getter = needTime)]
246    pub fn need_time(this: &Spawning) -> u32;
247
248    /// Total time remaining to spawn this creep.
249    ///
250    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.Spawning.remainingTime)
251    #[wasm_bindgen(method, getter = remainingTime)]
252    pub fn remaining_time(this: &Spawning) -> u32;
253
254    /// Get a reference to the [`Structure`] spawning the creep, either a
255    /// [`StructureSpawn`] or a [`StructureInvaderCore`].
256    ///
257    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.Spawning.spawn)
258    ///
259    /// [`StructureInvaderCore`]: crate::objects::StructureInvaderCore
260    #[wasm_bindgen(method, getter)]
261    pub fn spawn(this: &Spawning) -> Structure;
262
263    #[wasm_bindgen(method, js_name = cancel)]
264    fn cancel_internal(this: &Spawning) -> i8;
265
266    #[wasm_bindgen(method, js_name = setDirections)]
267    fn set_directions_internal(this: &Spawning, directions: &Array) -> i8;
268}
269
270impl Spawning {
271    /// Cancel spawning this creep, without refunding any energy.
272    ///
273    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.Spawning.cancel)
274    pub fn cancel(&self) -> Result<(), CancelErrorCode> {
275        CancelErrorCode::result_from_i8(self.cancel_internal())
276    }
277
278    /// Change allowed directions for the creep to leave the spawn once it's
279    /// ready.
280    ///
281    /// [Screeps documentation](https://docs.screeps.com/api/#StructureSpawn.Spawning.setDirections)
282    pub fn set_directions(&self, directions: &Array) -> Result<(), SetDirectionsErrorCode> {
283        SetDirectionsErrorCode::result_from_i8(self.set_directions_internal(directions))
284    }
285}