veloren_world/site/plot/
camp.rs1use super::*;
2use crate::{Land, assets::AssetHandle, site::generation::PrimitiveTransform};
3use common::{
4 generation::EntityInfo,
5 terrain::{Structure as PrefabStructure, StructuresGroup},
6};
7use lazy_static::lazy_static;
8
9use rand::prelude::*;
10use vek::*;
11
12pub struct Camp {
13 bounds: Aabr<i32>,
14 pub(crate) alt: i32,
15 temp: f32,
16}
17
18#[derive(Copy, Clone)]
19enum CampType {
20 Pirate,
21 Snow,
22 Forest,
23}
24
25impl Camp {
26 pub fn generate(
27 land: &Land,
28 _rng: &mut impl Rng,
29 site: &Site,
30 tile_aabr: Aabr<i32>,
31 site_temp: f32,
32 ) -> Self {
33 let bounds = Aabr {
34 min: site.tile_wpos(tile_aabr.min),
35 max: site.tile_wpos(tile_aabr.max),
36 };
37 let temp = site_temp;
38 Self {
39 bounds,
40 alt: land.get_alt_approx(site.tile_center_wpos(tile_aabr.center())) as i32 + 2,
41 temp,
42 }
43 }
44}
45
46impl Structure for Camp {
47 #[cfg(feature = "dyn-lib")]
48 #[unsafe(export_name = "as_dyn_structure_camp")]
49 fn as_dyn_outer(&self) -> Option<(&dyn Structure, &'static str)> {
50 Some((Self::as_dyn_impl(self), "as_dyn_structure_camp"))
51 }
52
53 fn render_inner(&self, _site: &Site, land: &Land, painter: &Painter) {
54 let center = self.bounds.center();
55 let base = land.get_alt_approx(center) as i32;
56 let mut rng = rand::rng();
57 let model_pos = center.with_z(base);
58 let temp = self.temp;
59 let camp_type = if temp >= CONFIG.tropical_temp {
60 CampType::Pirate
61 } else if temp <= (CONFIG.snow_temp) {
62 CampType::Snow
63 } else {
64 CampType::Forest
65 };
66 lazy_static! {
68 pub static ref MODEL_PIRATE: AssetHandle<StructuresGroup> =
69 PrefabStructure::load_group("site_structures.camp.camp_pirate");
70 pub static ref MODEL_SNOW: AssetHandle<StructuresGroup> =
71 PrefabStructure::load_group("site_structures.camp.camp_snow");
72 pub static ref MODEL_FOREST: AssetHandle<StructuresGroup> =
73 PrefabStructure::load_group("site_structures.camp.camp_forest");
74 }
75 let prefab_structure = match camp_type {
76 CampType::Pirate => MODEL_PIRATE.read(),
77 CampType::Snow => MODEL_SNOW.read(),
78 CampType::Forest => MODEL_FOREST.read(),
79 }[0]
80 .clone();
81
82 painter
83 .prim(Primitive::Prefab(Box::new(prefab_structure.clone())))
84 .translate(model_pos)
85 .fill(Fill::Prefab(Box::new(prefab_structure), model_pos, 0));
86
87 let npc_rng = rng.random_range(1..=5);
89 match camp_type {
90 CampType::Pirate => {
91 for p in 0..npc_rng {
92 painter.spawn(
93 EntityInfo::at((center + p).with_z(base + 2).as_()).with_asset_expect(
94 "common.entity.spot.pirate",
95 &mut rng,
96 None,
97 ),
98 )
99 }
100 let pet = if npc_rng < 3 {
101 "common.entity.wild.peaceful.parrot"
102 } else {
103 "common.entity.wild.peaceful.rat"
104 };
105 painter.spawn(
106 EntityInfo::at(center.with_z(base + 2).as_())
107 .with_asset_expect(pet, &mut rng, None),
108 )
109 },
110 _ => {
111 if npc_rng > 2 {
112 painter.spawn(
113 EntityInfo::at((center - 1).with_z(base + 2).as_()).with_asset_expect(
114 "common.entity.village.bowman",
115 &mut rng,
116 None,
117 ),
118 );
119 }
120 if npc_rng < 4 {
121 painter.spawn(
122 EntityInfo::at((center + 1).with_z(base + 2).as_()).with_asset_expect(
123 "common.entity.village.skinner",
124 &mut rng,
125 None,
126 ),
127 )
128 }
129 },
130 };
131 }
132}