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