veloren_world/site/plot/
dwarven_mine.rs

1use super::*;
2use crate::{Land, util::within_distance};
3use gen::render_prefab;
4use rand::prelude::*;
5use vek::*;
6
7const TILE_SIZE: i32 = 13;
8
9/// Represents house data generated by the `generate()` method
10pub struct DwarvenMine {
11    name: String,
12    /// Axis aligned bounding region for the house
13    bounds: Aabr<i32>,
14    /// Approximate altitude of the door tile
15    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        // TODO: i18n for the word "mine"
35
36        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        // Entrance
65        let entrance_path = "site_structures.dwarves.entrance";
66        let entrance_pos: Vec3<i32> = (center.x, center.y, self.alt - 37).into(); //+2
67        render_prefab(entrance_path, entrance_pos, painter);
68        // Hallway 0
69        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        // Hallway 1
73        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        // Mining
77        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        // After Mining
81        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        // Hallway 2
89        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        // Excavation Site
93        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        // Forgemaster Boss
97        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        // Cleansing Room
101        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        // Smelting Room
105        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        // Forgemaster Room
109        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        // Spawn random NPCs/Rotated Sprites
114        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        //Entities
125        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            // Entrance
140            (
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            // Hallway0
149            (
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            // Hallway1
162            (
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            // Mining
171            (
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            // After Mining
208            // Hallway 2
209            (
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            // Excavation Site
222            (
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            // lavathrower on wood railing
235            (
236                excavation_site_pos.map(|x| x as f32) + Vec3::new(0.0, -25.0, 18.0),
237                lavathrower,
238            ),
239            // lavathrower, turret & miner on corner platforms
240            (
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            // lavathrower and turret on ridge (forgemaster side)
253            (
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            // Lavaroom Exit
262            (
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            // Iron Golem
271            (
272                excavation_site_pos.map(|x| x as f32) + Vec3::new(-30.0, -12.0, 8.0),
273                irongolem_key,
274            ),
275            // Cleansing Room
276            // Snaretongue
277            (
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            // Smelting Room
286            (
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            // Treasure Room
295            // Iron Golem
296            (
297                forgemaster_pos.map(|x| x as f32) + Vec3::new(0.0, 4.0, 3.0),
298                irongolem,
299            ),
300        ];
301
302        // Entity Groups
303        let entity_group_positions = vec![
304            // Smelting Room
305            (
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            // Staircase Back up
327            (
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}