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