1use super::*;
2use crate::{Land, util::within_distance};
3use gen::render_prefab;
4use rand::prelude::*;
5use vek::*;
6
7const TILE_SIZE: i32 = 13;
8
9pub struct DwarvenMine {
11 name: String,
12 bounds: Aabr<i32>,
14 pub(crate) alt: i32,
16 origin: Vec2<i32>,
17}
18
19impl DwarvenMine {
20 pub fn generate(
21 land: &Land,
22 rng: &mut impl Rng,
23 site: &Site,
24 wpos: Vec2<i32>,
25 tile_aabr: Aabr<i32>,
26 ) -> Self {
27 let bounds = Aabr {
28 min: site.tile_wpos(tile_aabr.min),
29 max: site.tile_wpos(tile_aabr.max),
30 };
31
32 let name = format!("{} Mine", NameGen::location(rng).generate_mine());
33
34 Self {
37 name,
38 bounds,
39 origin: wpos - TILE_SIZE / 2,
40 alt: land.get_alt_approx(site.tile_center_wpos(wpos)) as i32,
41 }
42 }
43
44 pub fn name(&self) -> &str { &self.name }
45
46 pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
47 let near_entrance = within_distance(wpos, self.origin, 64);
48 SpawnRules {
49 trees: !near_entrance,
50 max_warp: (!near_entrance) as i32 as f32,
51 ..SpawnRules::default()
52 }
53 }
54}
55
56impl Structure for DwarvenMine {
57 #[cfg(feature = "use-dyn-lib")]
58 const UPDATE_FN: &'static [u8] = b"render_mine\0";
59
60 #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "render_mine"))]
61
62 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
63 let center = self.bounds.center();
64 let entrance_path = "site_structures.dwarves.entrance";
66 let entrance_pos: Vec3<i32> = (center.x, center.y, self.alt - 37).into(); render_prefab(entrance_path, entrance_pos, painter);
68 let hallway0_path = "site_structures.dwarves.hallway";
70 let hallway0_pos: Vec3<i32> = entrance_pos + Vec3::new(-67, 8, -37);
71 render_prefab(hallway0_path, hallway0_pos + Vec3::new(0, 0, 0), painter);
72 let hallway1_path = "site_structures.dwarves.hallway1";
74 let hallway1_pos: Vec3<i32> = hallway0_pos + Vec3::new(-55, -7, -33);
75 render_prefab(hallway1_path, hallway1_pos, painter);
76 let mining_site_path = "site_structures.dwarves.mining_site";
78 let mining_site_pos: Vec3<i32> = hallway1_pos + Vec3::new(-5, 28, 21);
79 render_prefab(mining_site_path, mining_site_pos, painter);
80 let after_mining_path = "site_structures.dwarves.after_forgemaster";
82 let after_mining_pos: Vec3<i32> = mining_site_pos + Vec3::new(-12, -9, -3);
83 render_prefab(
84 after_mining_path,
85 after_mining_pos + Vec3::new(0, -2, 0),
86 painter,
87 );
88 let hallway2_path = "site_structures.dwarves.hallway2";
90 let hallway2_pos: Vec3<i32> = after_mining_pos + Vec3::new(-3, 35, -18);
91 render_prefab(hallway2_path, hallway2_pos, painter);
92 let excavation_site_path = "site_structures.dwarves.excavation_site";
94 let excavation_site_pos: Vec3<i32> = hallway2_pos + Vec3::new(-35, 83, -10);
95 render_prefab(excavation_site_path, excavation_site_pos, painter);
96 let forgemaster_boss_path = "site_structures.dwarves.forgemaster_boss";
98 let forgemaster_boss_pos: Vec3<i32> = excavation_site_pos + Vec3::new(115, 0, -17);
99 render_prefab(forgemaster_boss_path, forgemaster_boss_pos, painter);
100 let cleansing_room_path = "site_structures.dwarves.cleansing_room";
102 let cleansing_room_pos: Vec3<i32> = excavation_site_pos + Vec3::new(-47, -125, 6);
103 render_prefab(cleansing_room_path, cleansing_room_pos, painter);
104 let smelting_room_path = "site_structures.dwarves.smelting_room";
106 let smelting_room_pos: Vec3<i32> = cleansing_room_pos + Vec3::new(49, -6, 0);
107 render_prefab(smelting_room_path, smelting_room_pos, painter);
108 let forgemaster_path = "site_structures.dwarves.forgemaster_room";
110 let forgemaster_pos: Vec3<i32> = smelting_room_pos + Vec3::new(8, 36, 10);
111 render_prefab(forgemaster_path, forgemaster_pos, painter);
112
113 let random_entities: Vec<(Vec3<i32>, u8)> = vec![
115 (forgemaster_pos + Vec3::new(11, 20, 1), 0),
116 (forgemaster_pos + Vec3::new(0, 20, 1), 0),
117 (forgemaster_pos + Vec3::new(-11, 20, 1), 0),
118 ];
119
120 for (pos, rot) in random_entities {
121 spawn_random_entity(pos, painter, rot);
122 }
123
124 let miner = "common.entity.dungeon.dwarven_quarry.miner";
126 let iron_dwarf = "common.entity.dungeon.dwarven_quarry.iron_dwarf";
127 let turret = "common.entity.dungeon.dwarven_quarry.turret";
128 let lavathrower = "common.entity.dungeon.dwarven_quarry.lavathrower";
129 let mine_guard = "common.entity.dungeon.dwarven_quarry.mine_guard";
130 let flamekeeper = "common.entity.dungeon.dwarven_quarry.flamekeeper";
131 let forgemaster = "common.entity.dungeon.dwarven_quarry.forgemaster";
132 let irongolem = "common.entity.dungeon.dwarven_quarry.irongolem";
133 let irongolem_key = "common.entity.dungeon.dwarven_quarry.irongolem_key";
134 let snaretongue_forge_key = "common.entity.dungeon.dwarven_quarry.snaretongue_forge_key";
135 let snaretongue_miner_key = "common.entity.dungeon.dwarven_quarry.snaretongue_miner_key";
136
137 let entrance_offset: Vec3<f32> = (20.0, -20.0, 45.0).into();
138 let miner_pos: Vec<(Vec3<f32>, &str)> = vec![
139 (
141 (entrance_pos + Vec3::new(-6, 0, 0)).map(|x| x as f32) + entrance_offset,
142 miner,
143 ),
144 (
145 (entrance_pos + Vec3::new(-2, 0, 0)).map(|x| x as f32) + entrance_offset,
146 miner,
147 ),
148 (
150 hallway0_pos.map(|x| x as f32) + Vec3::new(10.0, -4.0, 16.0),
151 miner,
152 ),
153 (
154 hallway0_pos.map(|x| x as f32) + Vec3::new(-10.0, -4.0, 10.0),
155 miner,
156 ),
157 (
158 hallway0_pos.map(|x| x as f32) + Vec3::new(-10.0, -6.0, 10.0),
159 miner,
160 ),
161 (
163 hallway0_pos.map(|x| x as f32) + Vec3::new(-30.0, -4.0, 0.0),
164 miner,
165 ),
166 (
167 hallway0_pos.map(|x| x as f32) + Vec3::new(-46.0, -4.0, -5.0),
168 miner,
169 ),
170 (
172 mining_site_pos.map(|x| x as f32) + Vec3::new(14.0, 17.0, 10.0),
173 flamekeeper,
174 ),
175 (
176 mining_site_pos.map(|x| x as f32) + Vec3::new(14.0, 27.0, 8.0),
177 mine_guard,
178 ),
179 (
180 mining_site_pos.map(|x| x as f32) + Vec3::new(-4.0, 32.0, 8.0),
181 turret,
182 ),
183 (
184 mining_site_pos.map(|x| x as f32) + Vec3::new(32.0, 32.0, 10.0),
185 turret,
186 ),
187 (
188 mining_site_pos.map(|x| x as f32) + Vec3::new(14.0, 32.0, 10.0),
189 mine_guard,
190 ),
191 (
192 mining_site_pos.map(|x| x as f32) + Vec3::new(-8.0, 0.0, 10.0),
193 miner,
194 ),
195 (
196 mining_site_pos.map(|x| x as f32) + Vec3::new(36.0, 0.0, 10.0),
197 miner,
198 ),
199 (
200 mining_site_pos.map(|x| x as f32) + Vec3::new(-8.0, 15.0, 0.0),
201 iron_dwarf,
202 ),
203 (
204 mining_site_pos.map(|x| x as f32) + Vec3::new(36.0, 15.0, 0.0),
205 iron_dwarf,
206 ),
207 (
210 hallway2_pos.map(|x| x as f32) + Vec3::new(-4.0, -22.0, 20.0),
211 miner,
212 ),
213 (
214 hallway2_pos.map(|x| x as f32) + Vec3::new(-4.0, 7.0, 10.0),
215 miner,
216 ),
217 (
218 hallway2_pos.map(|x| x as f32) + Vec3::new(-5.0, 30.0, 0.0),
219 mine_guard,
220 ),
221 (
223 hallway2_pos.map(|x| x as f32) + Vec3::new(0.0, 44.0, 0.0),
224 iron_dwarf,
225 ),
226 (
227 hallway2_pos.map(|x| x as f32) + Vec3::new(2.0, 44.0, 0.0),
228 lavathrower,
229 ),
230 (
231 forgemaster_boss_pos.map(|x| x as f32) + Vec3::new(23.0, 1.0, 20.0),
232 forgemaster,
233 ),
234 (
236 excavation_site_pos.map(|x| x as f32) + Vec3::new(0.0, -25.0, 18.0),
237 lavathrower,
238 ),
239 (
241 excavation_site_pos.map(|x| x as f32) + Vec3::new(50.0, 42.0, 25.0),
242 mine_guard,
243 ),
244 (
245 excavation_site_pos.map(|x| x as f32) + Vec3::new(48.0, 40.0, 12.0),
246 turret,
247 ),
248 (
249 excavation_site_pos.map(|x| x as f32) + Vec3::new(44.0, 50.0, 15.0),
250 lavathrower,
251 ),
252 (
254 excavation_site_pos.map(|x| x as f32) + Vec3::new(50.0, 18.0, 18.0),
255 turret,
256 ),
257 (
258 excavation_site_pos.map(|x| x as f32) + Vec3::new(50.0, 10.0, 18.0),
259 lavathrower,
260 ),
261 (
263 excavation_site_pos.map(|x| x as f32) + Vec3::new(-1.0, 44.0, 20.0),
264 lavathrower,
265 ),
266 (
267 excavation_site_pos.map(|x| x as f32) + Vec3::new(-1.0, 42.0, 20.0),
268 mine_guard,
269 ),
270 (
272 excavation_site_pos.map(|x| x as f32) + Vec3::new(-30.0, -12.0, 8.0),
273 irongolem_key,
274 ),
275 (
278 cleansing_room_pos.map(|x| x as f32) + Vec3::new(-10.0, -5.0, 10.0),
279 snaretongue_forge_key,
280 ),
281 (
282 cleansing_room_pos.map(|x| x as f32) + Vec3::new(-14.0, 60.0, -10.0),
283 snaretongue_miner_key,
284 ),
285 (
287 smelting_room_pos.map(|x| x as f32) + Vec3::new(-8.0, -2.0, 5.0),
288 lavathrower,
289 ),
290 (
291 smelting_room_pos.map(|x| x as f32) + Vec3::new(20.0, -10.0, 5.0),
292 lavathrower,
293 ),
294 (
297 forgemaster_pos.map(|x| x as f32) + Vec3::new(0.0, 4.0, 3.0),
298 irongolem,
299 ),
300 ];
301
302 let entity_group_positions = vec![
304 (
306 smelting_room_pos.map(|x| x as f32) + Vec3::new(26.0, -10.0, 5.0),
307 vec![iron_dwarf],
308 2,
309 5.0,
310 4.0,
311 ),
312 (
313 smelting_room_pos.map(|x| x as f32) + Vec3::new(6.0, 2.0, 12.0),
314 vec![iron_dwarf],
315 2,
316 5.0,
317 4.0,
318 ),
319 (
320 smelting_room_pos.map(|x| x as f32) + Vec3::new(8.0, -10.0, 18.0),
321 vec![miner, iron_dwarf, mine_guard],
322 4,
323 5.0,
324 4.0,
325 ),
326 (
328 hallway1_pos.map(|x| x as f32) + Vec3::new(-5.0, 2.0, 0.0),
329 vec![miner, iron_dwarf, mine_guard],
330 2,
331 5.0,
332 4.0,
333 ),
334 (
335 hallway1_pos.map(|x| x as f32) + Vec3::new(-20.0, 10.0, 0.0),
336 vec![miner, iron_dwarf, mine_guard],
337 2,
338 5.0,
339 4.0,
340 ),
341 (
342 hallway1_pos.map(|x| x as f32) + Vec3::new(4.0, 15.0, 0.0),
343 vec![miner, iron_dwarf, mine_guard],
344 2,
345 5.0,
346 4.0,
347 ),
348 (
349 hallway1_pos.map(|x| x as f32) + Vec3::new(-5.0, -8.0, 18.0),
350 vec![miner, iron_dwarf, mine_guard],
351 3,
352 5.0,
353 4.0,
354 ),
355 (
356 hallway1_pos.map(|x| x as f32) + Vec3::new(-5.0, -8.0, 30.0),
357 vec![miner, iron_dwarf, mine_guard],
358 3,
359 5.0,
360 4.0,
361 ),
362 (
363 hallway1_pos.map(|x| x as f32) + Vec3::new(-20.0, 18.0, 10.0),
364 vec![miner, iron_dwarf, mine_guard],
365 3,
366 5.0,
367 4.0,
368 ),
369 (
370 hallway1_pos.map(|x| x as f32) + Vec3::new(4.0, 15.0, 12.0),
371 vec![miner, iron_dwarf, mine_guard],
372 3,
373 5.0,
374 4.0,
375 ),
376 ];
377
378 for (position, entity_paths, num_entities, max_distance, entity_distance) in
379 entity_group_positions
380 {
381 spawn_entities(
382 position,
383 painter,
384 &entity_paths,
385 num_entities,
386 max_distance,
387 entity_distance,
388 );
389 }
390
391 for (pos, entity) in miner_pos {
392 spawn_entity(pos, painter, entity);
393 }
394 }
395}
396fn spawn_entity(pos: Vec3<f32>, painter: &Painter, entity_path: &str) {
397 let mut rng = thread_rng();
398 painter.spawn(
399 EntityInfo::at(pos)
400 .with_asset_expect(entity_path, &mut rng, None)
401 .with_no_flee(),
402 );
403}
404
405fn spawn_entities(
406 pos: Vec3<f32>,
407 painter: &Painter,
408 entity_paths: &[&str],
409 num_entities: u32,
410 max_distance: f32,
411 entity_distance: f32,
412) {
413 let mut rng = thread_rng();
414 let num_paths = entity_paths.len();
415
416 let side_length = (num_entities as f32).sqrt().ceil() as u32;
417 let spacing = entity_distance;
418
419 for i in 0..num_entities {
420 let path_index = rng.gen_range(0..num_paths);
421 let entity_path = entity_paths[path_index];
422
423 let row = i / side_length;
424 let col = i % side_length;
425
426 let x_offset = col as f32 * spacing - max_distance;
427 let y_offset = row as f32 * spacing - max_distance;
428
429 let spawn_pos = pos + Vec3::new(x_offset, y_offset, 0.0);
430
431 painter.spawn(EntityInfo::at(spawn_pos).with_asset_expect(entity_path, &mut rng, None));
432 }
433}
434
435fn spawn_random_entity(pos: Vec3<i32>, painter: &Painter, rot: u8) {
436 let mut rng = thread_rng();
437
438 let entities = [
439 "common.entity.dungeon.dwarven_quarry.miner",
440 "common.entity.dungeon.dwarven_quarry.turret",
441 "common.entity.dungeon.dwarven_quarry.iron_dwarf",
442 ];
443
444 let sprites = [
445 SpriteKind::Anvil,
446 SpriteKind::Forge,
447 SpriteKind::RepairBench,
448 SpriteKind::DungeonChest5,
449 ];
450
451 let random_number = rng.gen_range(0..=10);
452
453 if random_number <= 3 {
454 let pos_f32 = pos.map(|coord| coord as f32);
455 let random_entity_index = rng.gen_range(0..entities.len());
456 let random_entity = entities[random_entity_index];
457 spawn_entity(pos_f32, painter, random_entity);
458 } else if random_number <= 9 {
459 let random_sprite_index = rng.gen_range(0..sprites.len());
460 let random_sprite = sprites[random_sprite_index];
461 painter.rotated_sprite(pos, random_sprite, rot);
462 } else {
463 return;
464 }
465}