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