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}