1use super::*;
2use crate::{
3 Land,
4 site2::{gen::wall_staircase, util::sprites::PainterSpriteExt},
5 util::{CARDINALS, NEIGHBORS, RandomField, Sampler},
6};
7use common::terrain::{BlockKind, SpriteKind};
8use rand::prelude::*;
9use std::sync::Arc;
10use strum::IntoEnumIterator;
11use vek::*;
12
13pub struct CoastalHouse {
15 pub door_tile: Vec2<i32>,
17 bounds: Aabr<i32>,
19 pub(crate) alt: i32,
21}
22
23impl CoastalHouse {
24 pub fn generate(
25 land: &Land,
26 _rng: &mut impl Rng,
27 site: &Site,
28 door_tile: Vec2<i32>,
29 door_dir: Vec2<i32>,
30 tile_aabr: Aabr<i32>,
31 alt: Option<i32>,
32 ) -> Self {
33 let door_tile_pos = site.tile_center_wpos(door_tile);
34 let bounds = Aabr {
35 min: site.tile_wpos(tile_aabr.min),
36 max: site.tile_wpos(tile_aabr.max),
37 };
38 Self {
39 door_tile: door_tile_pos,
40 bounds,
41 alt: alt.unwrap_or_else(|| {
42 land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32
43 }) + 2,
44 }
45 }
46}
47
48impl Structure for CoastalHouse {
49 #[cfg(feature = "use-dyn-lib")]
50 const UPDATE_FN: &'static [u8] = b"render_coastalhouse\0";
51
52 #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "render_coastalhouse"))]
53 fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) {
54 let base = self.alt + 1;
55 let center = self.bounds.center();
56 let white = Fill::Sampling(Arc::new(|center| {
57 Some(match (RandomField::new(0).get(center)) % 37 {
58 0..=8 => Block::new(BlockKind::Rock, Rgb::new(251, 251, 227)),
59 9..=17 => Block::new(BlockKind::Rock, Rgb::new(245, 245, 229)),
60 18..=26 => Block::new(BlockKind::Rock, Rgb::new(250, 243, 221)),
61 27..=35 => Block::new(BlockKind::Rock, Rgb::new(240, 240, 230)),
62 _ => Block::new(BlockKind::Rock, Rgb::new(255, 244, 193)),
63 })
64 }));
65 let blue_broken = Fill::Sampling(Arc::new(|center| {
66 Some(match (RandomField::new(0).get(center)) % 20 {
67 0 => Block::new(BlockKind::Rock, Rgb::new(30, 187, 235)),
68 _ => Block::new(BlockKind::Rock, Rgb::new(11, 146, 187)),
69 })
70 }));
71 let length = (14 + RandomField::new(0).get(center.with_z(base)) % 3) as i32;
72 let width = (12 + RandomField::new(0).get((center - 1).with_z(base)) % 3) as i32;
73 let height = (12 + RandomField::new(0).get((center + 1).with_z(base)) % 4) as i32;
74 let storeys = (1 + RandomField::new(0).get(center.with_z(base)) % 2) as i32;
75
76 painter
78 .aabb(Aabb {
79 min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - 2),
80 max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 1),
81 })
82 .fill(blue_broken.clone());
83
84 for dir in CARDINALS {
85 let frame_pos = Vec2::new(
86 center.x + dir.x * (length + 5),
87 center.y + dir.y * (width + 5),
88 );
89 painter
90 .line(center.with_z(base - 1), frame_pos.with_z(base - 1), 3.0)
91 .fill(blue_broken.clone());
92 }
93 painter
95 .aabb(Aabb {
96 min: Vec2::new(center.x - length - 6, center.y - width - 6).with_z(base - height),
97 max: Vec2::new(center.x + length + 7, center.y + width + 7).with_z(base - 2),
98 })
99 .fill(white.clone());
100 for f in 0..8 {
101 painter
102 .aabb(Aabb {
103 min: Vec2::new(center.x - length - 7 - f, center.y - width - 7 - f)
104 .with_z(base - 3 - f),
105 max: Vec2::new(center.x + length + 8 + f, center.y + width + 8 + f)
106 .with_z(base - 2 - f),
107 })
108 .fill(white.clone());
109 }
110 painter
112 .aabb(Aabb {
113 min: Vec2::new(center.x - length - 5, center.y - width - 5).with_z(base - 2),
114 max: Vec2::new(center.x + length + 6, center.y + width + 6).with_z(base + height),
115 })
116 .clear();
117 for dir in CARDINALS {
119 let clear_pos = Vec2::new(
120 center.x + dir.x * (length + 7),
121 center.y + dir.y * (width + 7),
122 );
123 painter
124 .line(center.with_z(base - 1), clear_pos.with_z(base - 1), 2.0)
125 .clear();
126 }
127 for s in 0..storeys {
128 painter
130 .aabb(Aabb {
131 min: Vec2::new(
132 center.x - length - 3 + (2 * s),
133 center.y - width - 3 + (2 * s),
134 )
135 .with_z(base - 3 + height + (s * height)),
136 max: Vec2::new(
137 center.x + length + 2 - (2 * s),
138 center.y + width + 2 - (2 * s),
139 )
140 .with_z(base - 2 + height + (s * height)),
141 })
142 .fill(white.clone());
143 painter
144 .aabb(Aabb {
145 min: Vec2::new(
146 center.x - length - 3 + (2 * s),
147 center.y - width - 3 + (2 * s),
148 )
149 .with_z(base - 2 + height + (s * height)),
150 max: Vec2::new(
151 center.x + length + 2 - (2 * s),
152 center.y + width + 2 - (2 * s),
153 )
154 .with_z(base - 1 + height + (s * height)),
155 })
156 .fill(blue_broken.clone());
157 painter
158 .aabb(Aabb {
159 min: Vec2::new(
160 center.x - length - 2 + (2 * s),
161 center.y - width - 2 + (2 * s),
162 )
163 .with_z(base - 2 + height + (s * height)),
164 max: Vec2::new(
165 center.x + length + 1 - (2 * s),
166 center.y + width + 1 - (2 * s),
167 )
168 .with_z(base - 1 + height + (s * height)),
169 })
170 .clear();
171 painter
173 .aabb(Aabb {
174 min: Vec2::new(center.x - length + (2 * s), center.y - width + (2 * s))
175 .with_z(base - 2 + (s * height)),
176 max: Vec2::new(center.x + length - (2 * s), center.y + width - (2 * s))
177 .with_z(base - 1 + (s * height)),
178 })
179 .fill(blue_broken.clone());
180 painter
181 .aabb(Aabb {
182 min: Vec2::new(
183 center.x - length + 1 + (2 * s),
184 center.y - width + 1 + (2 * s),
185 )
186 .with_z(base - 2 + (s * height)),
187 max: Vec2::new(
188 center.x + length - 1 - (2 * s),
189 center.y + width - 1 - (2 * s),
190 )
191 .with_z(base - 1 + height - 1 + (s * height)),
192 })
193 .fill(white.clone());
194
195 painter
197 .line(
198 Vec2::new(center.x, center.y + 1 - width + (2 * s))
199 .with_z(base - 1 + (s * height)),
200 Vec2::new(center.x, center.y - 2 + width - (2 * s))
201 .with_z(base - 1 + (s * height)),
202 3.0,
203 )
204 .fill(blue_broken.clone());
205 painter
206 .line(
207 Vec2::new(center.x, center.y - width + (2 * s)).with_z(base - 1 + (s * height)),
208 Vec2::new(center.x, center.y + width - (2 * s)).with_z(base - 1 + (s * height)),
209 2.0,
210 )
211 .clear();
212 painter
213 .line(
214 Vec2::new(center.x + 1 - length + (2 * s), center.y)
215 .with_z(base - 1 + (s * height)),
216 Vec2::new(center.x - 2 + length - (2 * s), center.y)
217 .with_z(base - 1 + (s * height)),
218 3.0,
219 )
220 .fill(blue_broken.clone());
221 painter
222 .line(
223 Vec2::new(center.x - length + (2 * s), center.y)
224 .with_z(base - 1 + (s * height)),
225 Vec2::new(center.x + length - (2 * s), center.y)
226 .with_z(base - 1 + (s * height)),
227 2.0,
228 )
229 .clear();
230 painter
232 .line(
233 Vec2::new(center.x - (length / 3), center.y + 1 - width + (2 * s))
234 .with_z(base - 1 + (s * height) + (height / 2)),
235 Vec2::new(center.x - (length / 3), center.y - 2 + width - (2 * s))
236 .with_z(base - 1 + (s * height) + (height / 2)),
237 3.0,
238 )
239 .fill(blue_broken.clone());
240 painter
241 .line(
242 Vec2::new(center.x - (length / 3), center.y - width - 2 + (2 * s))
243 .with_z(base - 1 + (s * height) + (height / 2)),
244 Vec2::new(center.x - (length / 3), center.y + width + 2 - (2 * s))
245 .with_z(base - 1 + (s * height) + (height / 2)),
246 2.0,
247 )
248 .clear();
249
250 painter
251 .line(
252 Vec2::new(center.x + (length / 3), center.y + 1 - width + (2 * s))
253 .with_z(base - 1 + (s * height) + (height / 2)),
254 Vec2::new(center.x + (length / 3), center.y - 2 + width - (2 * s))
255 .with_z(base - 1 + (s * height) + (height / 2)),
256 3.0,
257 )
258 .fill(blue_broken.clone());
259 painter
260 .line(
261 Vec2::new(center.x + (length / 3), center.y - width - 2 + (2 * s))
262 .with_z(base - 1 + (s * height) + (height / 2)),
263 Vec2::new(center.x + (length / 3), center.y + width + 2 - (2 * s))
264 .with_z(base - 1 + (s * height) + (height / 2)),
265 2.0,
266 )
267 .clear();
268
269 painter
271 .line(
272 Vec2::new(center.x + 1 - length + (2 * s), center.y)
273 .with_z(base - 1 + (s * height) + (height / 2)),
274 Vec2::new(center.x - 2 + length - (2 * s), center.y)
275 .with_z(base - 1 + (s * height) + (height / 2)),
276 3.0,
277 )
278 .fill(blue_broken.clone());
279 painter
280 .line(
281 Vec2::new(center.x - length - 2 + (2 * s), center.y)
282 .with_z(base - 1 + (s * height) + (height / 2)),
283 Vec2::new(center.x + length + 2 - (2 * s), center.y)
284 .with_z(base - 1 + (s * height) + (height / 2)),
285 2.0,
286 )
287 .clear();
288
289 painter
291 .aabb(Aabb {
292 min: Vec2::new(
293 center.x - length + 2 + (2 * s),
294 center.y - width + 2 + (2 * s),
295 )
296 .with_z(base - 2 + (s * height)),
297 max: Vec2::new(
298 center.x + length - 2 - (2 * s),
299 center.y + width - 2 - (2 * s),
300 )
301 .with_z(base - 2 + height - 1 + (s * height)),
302 })
303 .clear();
304
305 painter
307 .aabb(Aabb {
308 min: Vec2::new(
309 center.x - length + 5 + (2 * s),
310 center.y - width + 5 + (2 * s),
311 )
312 .with_z(base - 3 + (s * height)),
313 max: Vec2::new(
314 center.x + length - 5 - (2 * s),
315 center.y + width - 5 - (2 * s),
316 )
317 .with_z(base - 2 + (s * height)),
318 })
319 .fill(blue_broken.clone());
320 painter
321 .aabb(Aabb {
322 min: Vec2::new(
323 center.x - length + 6 + (2 * s),
324 center.y - width + 6 + (2 * s),
325 )
326 .with_z(base - 3 + (s * height)),
327 max: Vec2::new(
328 center.x + length - 6 - (2 * s),
329 center.y + width - 6 - (2 * s),
330 )
331 .with_z(base - 2 + (s * height)),
332 })
333 .fill(white.clone());
334 let mut sprites = vec![
336 SpriteKind::Bowl,
337 SpriteKind::VialEmpty,
338 SpriteKind::FountainArabic,
339 SpriteKind::Crate,
340 SpriteKind::Lantern,
341 ];
342 'outer: for dir in NEIGHBORS {
343 let furniture_pos = Vec2::new(
344 center.x + dir.x * ((length / 2) + 1),
345 center.y + dir.y * ((width / 2) + 1),
346 );
347 if sprites.is_empty() {
348 break 'outer;
349 }
350 let sprite = sprites.swap_remove(
351 RandomField::new(0).get(furniture_pos.with_z(base)) as usize % sprites.len(),
352 );
353 painter.owned_resource_sprite(
354 furniture_pos.with_z(base - 2 + (s * height)),
355 sprite,
356 0,
357 );
358 }
359
360 if storeys > 1 {
362 painter
363 .cylinder(Aabb {
364 min: (center - 6).with_z(base - 2 + (s * height)),
365 max: (center + 6).with_z(base + (s * height)),
366 })
367 .clear();
368 };
369
370 let random_index_1 = (RandomField::new(0).get(center.with_z(base + s)) % 4) as usize;
372 let random_index_2 = 3 - random_index_1;
373 for (d, dir) in Dir::iter().enumerate() {
375 let diagonal = dir.diagonal();
376 let bed_pos = center + diagonal * ((length / 2) - 2);
377 let table_pos = Vec2::new(
378 center.x + diagonal.x * ((length / 2) - 1),
379 center.y + diagonal.y * ((width / 2) - 2),
380 );
381 let alt = base - 2 + (s * height);
382 if d == random_index_1 {
383 painter.bed_coastal(bed_pos.with_z(alt), dir);
384 } else if d == random_index_2 {
385 painter.rotated_sprite(table_pos.with_z(alt), SpriteKind::TableCoastalLarge, 2);
386 painter.sprite(table_pos.with_z(alt + 1), SpriteKind::JugAndCupsCoastal);
387
388 for dir in Dir::iter() {
389 let vec = dir.to_vec2();
390 let bench_pos = Vec2::new(table_pos.x + vec.x * 2, table_pos.y + vec.y);
391 painter.rotated_sprite(
392 bench_pos.with_z(alt),
393 SpriteKind::BenchCoastal,
394 dir.opposite().sprite_ori(),
395 );
396 }
397 }
398 }
399
400 for d in 0..2 {
402 let door_lamp_pos = Vec2::new(
403 center.x - length + 2 + (2 * s) + (d * ((2 * (length - (2 * s))) - 5)),
404 center.y,
405 )
406 .with_z(base + 1 + (s * height));
407 painter.rotated_sprite(
408 door_lamp_pos,
409 SpriteKind::WallLampSmall,
410 2 + ((d * 4) as u8),
411 );
412
413 let lamp_pos = Vec2::new(
414 center.x,
415 center.y - width + 2 + (2 * s) + (d * ((2 * (width - (2 * s))) - 5)),
416 )
417 .with_z(base + 1 + (s * height));
418 painter.rotated_sprite(lamp_pos, SpriteKind::WallLampSmall, 4 - ((d * 4) as u8));
419 }
420 for d in 0..2 {
421 let door_lamp_pos = Vec2::new(
422 center.x - length - 1 + (2 * s) + (d * ((2 * (length - (2 * s))) + 1)),
423 center.y,
424 )
425 .with_z(base + 1 + (s * height));
426 painter.rotated_sprite(
427 door_lamp_pos,
428 SpriteKind::WallLampSmall,
429 6 + ((d * 4) as u8),
430 );
431
432 let lamp_pos = Vec2::new(
433 center.x,
434 center.y - width - 1 + (2 * s) + (d * ((2 * (width - (2 * s))) + 1)),
435 )
436 .with_z(base + 1 + (s * height));
437 painter.rotated_sprite(lamp_pos, SpriteKind::WallLampSmall, 8 - ((d * 4) as u8));
438 }
439 }
440 let top_limit = painter.aabb(Aabb {
441 min: Vec2::new(center.x - length, center.y - width)
442 .with_z(base + (storeys * height) - 2),
443 max: Vec2::new(center.x + length, center.y + width)
444 .with_z(base - 2 + (storeys * height) + (height / 2)),
445 });
446 painter
447 .superquadric(
448 Aabb {
449 min: Vec2::new(center.x - length - 1, center.y - width - 1)
450 .with_z(base + (storeys * height) - (height / 2)),
451 max: Vec2::new(center.x + length, center.y + width)
452 .with_z(base - 2 + (storeys * height) + (height / 2)),
453 },
454 1.5,
455 )
456 .intersect(top_limit)
457 .fill(white.clone());
458 if storeys > 1 {
459 let stair_radius1 = 3.0;
461 let stairs_clear1 = painter.cylinder(Aabb {
462 min: (center - 1 - stair_radius1 as i32).with_z(base - 2),
463 max: (center + 2 + stair_radius1 as i32)
464 .with_z(base + ((storeys - 1) * height) - 2),
465 });
466 let stairs_clear2 = painter.cylinder(Aabb {
467 min: (center - 2 - stair_radius1 as i32).with_z(base - 2),
468 max: (center + 3 + stair_radius1 as i32)
469 .with_z(base + ((storeys - 1) * height) - 2),
470 });
471 stairs_clear1.clear();
472 painter
473 .cylinder(Aabb {
474 min: (center - 1).with_z(base - 2),
475 max: (center + 2).with_z(base + ((storeys - 1) * height) - 2),
476 })
477 .fill(white.clone());
478
479 stairs_clear2
480 .sample(wall_staircase(
481 center.with_z(base + ((storeys - 1) * height) - 2),
482 stair_radius1,
483 (height / 2) as f32,
484 ))
485 .fill(white);
486 }
487 }
488}