veloren_world/site2/plot/
savannah_hut.rs1use super::*;
2use crate::{
3 Land,
4 site2::util::sprites::PainterSpriteExt,
5 util::{CARDINALS, DIAGONALS, RandomField, Sampler},
6};
7use common::terrain::{BlockKind, SpriteKind, sprite::Owned};
8use rand::prelude::*;
9use std::{f32::consts::TAU, sync::Arc};
10use vek::*;
11
12pub struct SavannahHut {
14 pub door_tile: Vec2<i32>,
16 bounds: Aabr<i32>,
18 pub(crate) alt: i32,
20}
21
22impl SavannahHut {
23 pub fn generate(
24 land: &Land,
25 _rng: &mut impl Rng,
26 site: &Site,
27 door_tile: Vec2<i32>,
28 door_dir: Vec2<i32>,
29 tile_aabr: Aabr<i32>,
30 alt: Option<i32>,
31 ) -> Self {
32 let door_tile_pos = site.tile_center_wpos(door_tile);
33 let bounds = Aabr {
34 min: site.tile_wpos(tile_aabr.min),
35 max: site.tile_wpos(tile_aabr.max),
36 };
37 Self {
38 bounds,
39 door_tile: door_tile_pos,
40 alt: alt.unwrap_or_else(|| {
41 land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32
42 }) + 2,
43 }
44 }
45}
46
47impl Structure for SavannahHut {
48 #[cfg(feature = "use-dyn-lib")]
49 const UPDATE_FN: &'static [u8] = b"render_savannahhut\0";
50
51 #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "render_savannahhut"))]
52 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
53 let base = self.alt + 1;
54 let center = self.bounds.center();
55 let sprite_fill = Fill::Sampling(Arc::new(|wpos| {
56 Some(match (RandomField::new(0).get(wpos)) % 25 {
57 0 => Block::air(SpriteKind::Bowl).with_attr(Owned(true)).unwrap(),
58 1 => Block::air(SpriteKind::VialEmpty)
59 .with_attr(Owned(true))
60 .unwrap(),
61 2 => Block::air(SpriteKind::Lantern),
62 3 => Block::air(SpriteKind::JugArabic),
63 4 => Block::air(SpriteKind::Crate)
64 .with_attr(Owned(true))
65 .unwrap(),
66 _ => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
67 })
68 }));
69 let wood_dark = Fill::Brick(BlockKind::Misc, Rgb::new(142, 67, 27), 12);
70 let reed = Fill::Brick(BlockKind::Misc, Rgb::new(72, 55, 46), 22);
71 let clay = Fill::Brick(BlockKind::Misc, Rgb::new(209, 124, 57), 22);
72 let color = Fill::Sampling(Arc::new(|center| {
73 Some(match (RandomField::new(0).get(center)) % 7 {
74 0 => Block::new(BlockKind::GlowingRock, Rgb::new(153, 82, 40)),
75 1 => Block::new(BlockKind::GlowingRock, Rgb::new(172, 104, 57)),
76 2 => Block::new(BlockKind::GlowingRock, Rgb::new(135, 106, 100)),
77 3 => Block::new(BlockKind::GlowingRock, Rgb::new(198, 164, 139)),
78 4 => Block::new(BlockKind::GlowingRock, Rgb::new(168, 163, 157)),
79 5 => Block::new(BlockKind::GlowingRock, Rgb::new(73, 53, 42)),
80 _ => Block::new(BlockKind::GlowingRock, Rgb::new(178, 124, 90)),
81 })
82 }));
83 let length = (10 + RandomField::new(0).get(center.with_z(base)) % 6) as i32;
84 let height = 2 * length / 3;
85 let storeys = (1 + RandomField::new(0).get(center.with_z(base)) % 2) as i32;
86 let radius = length + (length / 3);
87 let reed_var = (1 + RandomField::new(0).get(center.with_z(base)) % 4) as f32;
88 let reed_parts = 36_f32 + reed_var;
89 let phi = TAU / reed_parts;
90 painter
92 .cone(Aabb {
93 min: (center - radius).with_z(base + (storeys * height) - (height / 2) + 1),
94 max: (center + radius)
95 .with_z(base + (storeys * height) + (height / 2) - 1 + reed_var as i32),
96 })
97 .fill(reed.clone());
98 painter
99 .cone(Aabb {
100 min: (center - radius).with_z(base + (storeys * height) - (height / 2)),
101 max: (center + radius)
102 .with_z(base + (storeys * height) + (height / 2) - 2 + reed_var as i32),
103 })
104 .clear();
105 painter
107 .cylinder(Aabb {
108 min: (center - length).with_z(base - 3),
109 max: (center + length + 1).with_z(base - 2),
110 })
111 .fill(clay.clone());
112 painter
113 .cylinder(Aabb {
114 min: (center - length - 1).with_z(base - 4),
115 max: (center + length + 2).with_z(base - 3),
116 })
117 .fill(clay.clone());
118 painter
119 .cylinder(Aabb {
120 min: (center - length - 2).with_z(base - 5),
121 max: (center + length + 3).with_z(base - 4),
122 })
123 .fill(clay.clone());
124 painter
125 .cylinder(Aabb {
126 min: (center - length - 3).with_z(base - height),
127 max: (center + length + 4).with_z(base - 5),
128 })
129 .fill(clay.clone());
130 for s in 0..storeys {
132 let room = painter.cylinder(Aabb {
133 min: (center - length + 2 + s).with_z(base - 2 + (s * height)),
134 max: (center + 1 + length - 2 - s).with_z(base + height + (s * height)),
135 });
136 room.fill(clay.clone());
137 for dir in DIAGONALS {
139 let decor_pos = center + dir * (length - 2 - s);
140 let decor = painter
141 .line(
142 center.with_z(base - 1 + (s * (height + 2))),
143 decor_pos.with_z(base - 1 + (s * (height + 2))),
144 5.0,
145 )
146 .intersect(room);
147 decor.fill(color.clone());
148 painter
149 .line(
150 center.with_z(base - 1 + (s * (height + 2))),
151 decor_pos.with_z(base - 1 + (s * (height + 2))),
152 4.0,
153 )
154 .intersect(decor)
155 .fill(clay.clone());
156 }
157 }
158 painter
160 .cylinder(Aabb {
161 min: (center - length + 4).with_z(base - 2),
162 max: (center + 1 + length - 4).with_z(base + (storeys * height)),
163 })
164 .clear();
165 painter
167 .cylinder(Aabb {
168 min: (center - length + 4).with_z(base - 1),
169 max: (center + 1 + length - 4).with_z(base),
170 })
171 .fill(wood_dark.clone());
172 painter
173 .cylinder(Aabb {
174 min: (center - length + 4).with_z(base),
175 max: (center + 1 + length - 4).with_z(base + 1),
176 })
177 .fill(sprite_fill);
178
179 painter
180 .cylinder(Aabb {
181 min: (center - length + 4).with_z(base + (storeys * height) - 1),
182 max: (center + 1 + length - 4).with_z(base + (storeys * height) + 1),
183 })
184 .fill(wood_dark);
185
186 for s in 0..storeys {
187 for dir in CARDINALS {
189 let frame_pos = center + dir * (length - 2 - s);
190 let clear_pos = center + dir * (length + 2 - s);
191
192 painter
193 .line(
194 center.with_z(base - 1 + (s * (height + 2))),
195 frame_pos.with_z(base - 1 + (s * (height + 2))),
196 3.0,
197 )
198 .fill(color.clone());
199 painter
200 .line(
201 center.with_z(base - 1 + (s * (height + 2))),
202 clear_pos.with_z(base - 1 + (s * (height + 2))),
203 2.0,
204 )
205 .clear();
206 }
207 }
208 painter
210 .cylinder(Aabb {
211 min: (center - length + 5).with_z(base - 2),
212 max: (center + 1 + length - 5).with_z(base + (storeys * height) + 1),
213 })
214 .clear();
215 painter
217 .cylinder(Aabb {
218 min: (center - (length / 2) - 1).with_z(base - 3),
219 max: (center + (length / 2) + 1).with_z(base - 2),
220 })
221 .fill(color);
222 painter
223 .cylinder(Aabb {
224 min: (center - (length / 2) + 1).with_z(base - 3),
225 max: (center + (length / 2) - 1).with_z(base - 2),
226 })
227 .fill(clay);
228
229 let mut sprites = vec![
231 SpriteKind::CushionArabic,
232 SpriteKind::TableArabicSmall,
233 SpriteKind::DecorSetArabic,
234 SpriteKind::Bowl,
235 SpriteKind::VialEmpty,
236 SpriteKind::JugArabic,
237 SpriteKind::JugAndBowlArabic,
238 SpriteKind::SepareArabic,
239 ];
240
241 let rows = if length > 12 { 2 } else { 1 };
242 'outer: for d in 0..rows {
243 for dir in DIAGONALS {
244 if sprites.is_empty() {
245 break 'outer;
246 }
247 let position = center + dir * (length - (9 + (d * 3)));
248 let sprite = sprites.swap_remove(
249 RandomField::new(0).get(position.with_z(base)) as usize % sprites.len(),
250 );
251 painter.owned_resource_sprite(position.with_z(base - 2), sprite, 0);
252 }
253 }
254
255 let random_index = (RandomField::new(0).get(center.with_z(base)) % 4) as usize;
257 let dir = *Dir::ALL.get(random_index).unwrap();
259 let diagonal = dir.diagonal();
260 let bed_pos = center + diagonal * (length - 9);
261 painter.bed_savannah(bed_pos.with_z(base - 2), dir);
262
263 for n in 1..=reed_parts as i32 {
265 let pos = Vec2::new(
266 center.x + ((radius as f32) * ((n as f32 * phi).cos())) as i32,
267 center.y + ((radius as f32) * ((n as f32 * phi).sin())) as i32,
268 );
269 painter
270 .line(
271 pos.with_z(base + (storeys * height) - (height / 2)),
272 center.with_z(base + (storeys * height) + (height / 2) + reed_var as i32),
273 1.0,
274 )
275 .fill(reed.clone());
276 }
277 }
278}