1use super::*;
2use crate::{
3 Land,
4 all::ForestKind,
5 site::util::{Dir, sprites::PainterSpriteExt},
6 util::{DIRS, RandomField, Sampler},
7};
8use common::{
9 calendar::{Calendar, CalendarEvent},
10 terrain::{Block, BlockKind, SpriteKind},
11};
12use rand::prelude::*;
13use strum::IntoEnumIterator;
14use vek::*;
15
16#[derive(Copy, Clone)]
17enum Style {
18 Wooden(Rgb<u8>),
19 Stone,
20 Brick,
21 Daub,
22}
23
24impl Style {
25 fn get_fill(self) -> Fill {
26 match self {
27 Self::Wooden(color) => Fill::PlankWall(BlockKind::Wood, color, 64),
28 Self::Stone => Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 50),
29 Self::Daub => Fill::Brick(BlockKind::Wood, Rgb::new(200, 180, 150), 24),
30 Self::Brick => Fill::Brick(BlockKind::Rock, Rgb::new(100, 32, 20), 48),
31 }
32 }
33}
34
35pub struct House {
37 pub door_tile: Vec2<i32>,
39 tile_aabr: Aabr<i32>,
41 bounds: Aabr<i32>,
43 pub(crate) alt: i32,
45 levels: u32,
47 overhang: i32,
49 roof_color: Rgb<u8>,
51 front: Dir,
52 christmas_decorations: bool,
53 lower_style: Style,
54 upper_style: Style,
55 gable_style: Style,
56}
57
58impl House {
59 pub fn generate(
60 land: &Land,
61 rng: &mut impl Rng,
62 site: &Site,
63 door_tile: Vec2<i32>,
64 door_dir: Vec2<i32>,
65 tile_aabr: Aabr<i32>,
66 calendar: Option<&Calendar>,
67 alt: Option<i32>,
68 ) -> Self {
69 let levels = rng.gen_range(1..2 + (tile_aabr.max - tile_aabr.min).product() / 6) as u32;
70 let bounds = Aabr {
71 min: site.tile_wpos(tile_aabr.min),
72 max: site.tile_wpos(tile_aabr.max),
73 };
74
75 let front = match door_dir {
76 dir if dir.y < 0 => Dir::NegY,
77 dir if dir.x < 0 => Dir::NegX,
78 dir if dir.y > 0 => Dir::Y,
79 _ => Dir::X,
80 };
81
82 let christmas_decorations = calendar.is_some_and(|c| c.is_event(CalendarEvent::Christmas));
83
84 let door_wpos = site.tile_center_wpos(door_tile);
85 let upper_style = match land.make_forest_lottery(door_wpos).choose_seeded(rng.gen())
86 .filter(|_| rng.gen_bool(0.75))
88 {
89 Some(
90 ForestKind::Cedar
91 | ForestKind::AutumnTree
92 | ForestKind::Frostpine
93 | ForestKind::Mangrove,
94 ) => Style::Wooden(Rgb::new(63, 28, 12)),
95 Some(ForestKind::Oak | ForestKind::Swamp | ForestKind::Baobab) => {
96 Style::Wooden(Rgb::new(102, 87, 63))
97 },
98 Some(ForestKind::Acacia | ForestKind::Birch | ForestKind::Palm) => {
99 Style::Wooden(Rgb::new(130, 104, 102))
100 },
101 Some(
102 ForestKind::Mapletree | ForestKind::Redwood | ForestKind::Pine | ForestKind::Cherry,
103 ) => Style::Wooden(Rgb::new(117, 95, 46)),
104 _ if rng.gen_bool(0.5) => Style::Brick,
105 _ => Style::Daub,
106 };
107 let lower_style = match upper_style {
108 Style::Stone => Style::Stone,
110 Style::Brick => Style::Brick,
111 _ if rng.gen_bool(0.3) => Style::Brick,
113 _ if rng.gen_bool(0.5) => Style::Stone,
114 _ => upper_style,
115 };
116 let gable_style = match upper_style {
117 Style::Wooden(_) | Style::Daub => upper_style,
118 Style::Stone | Style::Brick => Style::Daub,
119 };
120
121 Self {
122 door_tile,
123 tile_aabr,
124 bounds,
125 alt: alt.unwrap_or_else(|| {
126 land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32
127 }),
128 levels,
129 overhang: if levels > 3 {
130 *[-5, 1, 2].choose(rng).unwrap_or(&-5)
134 } else if levels > 1 {
135 *[-5, 1, 2, 3].choose(rng).unwrap_or(&2)
136 } else {
137 0
139 },
140 roof_color: {
141 let colors = [
142 Rgb::new(21, 43, 48),
143 Rgb::new(11, 23, 38),
144 Rgb::new(45, 28, 21),
145 Rgb::new(10, 55, 40),
146 Rgb::new(5, 35, 15),
147 Rgb::new(40, 5, 11),
148 Rgb::new(55, 45, 11),
149 ];
150 *colors.choose(rng).unwrap_or(&Rgb::new(21, 43, 48))
151 },
152 front,
153 christmas_decorations,
154 lower_style,
155 upper_style,
156 gable_style,
157 }
158 }
159
160 pub fn z_range(&self) -> Range<i32> { self.alt..self.alt + self.levels as i32 * STOREY }
161
162 pub fn roof_color(&self) -> Rgb<u8> { self.roof_color }
163}
164
165const STOREY: i32 = 5;
166
167impl Structure for House {
168 #[cfg(feature = "use-dyn-lib")]
169 const UPDATE_FN: &'static [u8] = b"render_house\0";
170
171 #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "render_house"))]
172 fn render_inner(&self, site: &Site, _land: &Land, painter: &Painter) {
173 let storey = STOREY;
174 let roof = storey * self.levels as i32 - 1;
175 let foundations = 20;
176 let alt = self.alt + 1;
177 let door_tile_wpos = site.tile_center_wpos(self.door_tile);
178
179 let wall_fill_upper = self.upper_style.get_fill();
180 let wall_fill_lower = self.lower_style.get_fill();
181 let wall_fill_gable = self.gable_style.get_fill();
182
183 let pillar_fill = match self.upper_style {
184 Style::Wooden(color) => Fill::Block(Block::new(BlockKind::Wood, color / 2)),
185 Style::Brick => Fill::Block(Block::new(BlockKind::Rock, Rgb::new(85, 35, 8))),
186 _ => Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
188 };
189
190 let roof_lip = 1;
192 let roof_height = (self.bounds.min - self.bounds.max)
193 .map(|e| e.abs())
194 .reduce_min()
195 / 2
196 + roof_lip
197 + 1;
198
199 let (roof_primitive, roof_empty) = match self.front {
200 Dir::Y => {
201 (
202 painter.prim(Primitive::Gable {
203 aabb: Aabb {
204 min: (self.bounds.min - roof_lip).with_z(alt + roof),
205 max: (Vec2::new(
206 self.bounds.max.x + 1 + roof_lip,
207 self.bounds.max.y
208 + 1
209 + roof_lip
210 + (self.levels as i32 - 1) * self.overhang,
211 ))
212 .with_z(alt + roof + roof_height),
213 },
214 inset: roof_height,
215 dir: Dir::Y,
216 }),
217 painter.prim(Primitive::Gable {
218 aabb: Aabb {
219 min: (Vec2::new(self.bounds.min.x, self.bounds.min.y - 1))
220 .with_z(alt + roof), max: (Vec2::new(
223 self.bounds.max.x + 1,
224 self.bounds.max.y
225 + 1
226 + (self.levels as i32 - 1) * self.overhang
227 + 1,
228 ))
229 .with_z(alt + roof + roof_height - 1),
230 },
231 inset: roof_height - 1,
232 dir: Dir::Y,
233 }),
234 )
235 },
236 Dir::X => {
237 (
238 painter.prim(Primitive::Gable {
239 aabb: Aabb {
240 min: (self.bounds.min - roof_lip).with_z(alt + roof),
241 max: Vec2::new(
242 self.bounds.max.x
243 + 1
244 + roof_lip
245 + (self.levels as i32 - 1) * self.overhang,
246 self.bounds.max.y + 1 + roof_lip,
247 )
248 .with_z(alt + roof + roof_height),
249 },
250 inset: roof_height,
251 dir: Dir::X,
252 }),
253 painter.prim(Primitive::Gable {
254 aabb: Aabb {
255 min: (Vec2::new(self.bounds.min.x - 1, self.bounds.min.y))
256 .with_z(alt + roof), max: Vec2::new(
259 self.bounds.max.x
260 + 1
261 + (self.levels as i32 - 1) * self.overhang
262 + 1,
263 self.bounds.max.y + 1,
264 )
265 .with_z(alt + roof + roof_height - 1),
266 },
267 inset: roof_height - 1,
268 dir: Dir::X,
269 }),
270 )
271 },
272 Dir::NegY => (
273 painter.prim(Primitive::Gable {
274 aabb: Aabb {
275 min: Vec2::new(
276 self.bounds.min.x - roof_lip,
277 self.bounds.min.y - roof_lip - (self.levels as i32 - 1) * self.overhang,
278 )
279 .with_z(alt + roof),
280 max: Vec2::new(
281 self.bounds.max.x + 1 + roof_lip,
282 self.bounds.max.y + roof_lip + 1,
283 )
284 .with_z(alt + roof + roof_height),
285 },
286 inset: roof_height,
287 dir: Dir::Y,
288 }),
289 painter.prim(Primitive::Gable {
290 aabb: Aabb {
291 min: Vec2::new(
292 self.bounds.min.x,
293 self.bounds.min.y - 1 - (self.levels as i32 - 1) * self.overhang - 1,
294 )
295 .with_z(alt + roof),
296 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + roof_lip + 1)
297 .with_z(alt + roof + roof_height - 1),
298 },
299 inset: roof_height - 1,
300 dir: Dir::Y,
301 }),
302 ),
303 _ => (
304 painter.prim(Primitive::Gable {
305 aabb: Aabb {
306 min: Vec2::new(
307 self.bounds.min.x - roof_lip - (self.levels as i32 - 1) * self.overhang,
308 self.bounds.min.y - roof_lip,
309 )
310 .with_z(alt + roof),
311 max: Vec2::new(
312 self.bounds.max.x + 1 + roof_lip,
313 self.bounds.max.y + 1 + roof_lip,
314 )
315 .with_z(alt + roof + roof_height),
316 },
317 inset: roof_height,
318 dir: Dir::X,
319 }),
320 painter.prim(Primitive::Gable {
321 aabb: Aabb {
322 min: Vec2::new(
323 self.bounds.min.x
324 - roof_lip
325 - 1
326 - (self.levels as i32 - 1) * self.overhang,
327 self.bounds.min.y,
328 )
329 .with_z(alt + roof),
330 max: Vec2::new(self.bounds.max.x + 1 + roof_lip, self.bounds.max.y + 1)
331 .with_z(alt + roof + roof_height - 1),
332 },
333 inset: roof_height - 1,
334 dir: Dir::X,
335 }),
336 ),
337 };
338
339 let (roof_front_wall, roof_rear_wall) = match self.front {
340 Dir::Y => (
341 painter.prim(Primitive::Aabb(Aabb {
342 min: (Vec2::new(
343 self.bounds.min.x,
344 self.bounds.max.y + (self.levels as i32 - 1) * self.overhang,
345 ))
346 .with_z(alt + roof),
347 max: (Vec2::new(
348 self.bounds.max.x + 1,
349 self.bounds.max.y + (self.levels as i32 - 1) * self.overhang + 1,
350 ))
351 .with_z(alt + roof + roof_height),
352 })),
353 painter.prim(Primitive::Aabb(Aabb {
354 min: (Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof)),
355 max: (Vec2::new(self.bounds.max.x + 1, self.bounds.min.y + 1)
356 .with_z(alt + roof + roof_height)),
357 })),
358 ),
359 Dir::X => (
360 painter.prim(Primitive::Aabb(Aabb {
361 min: Vec2::new(
362 self.bounds.max.x + (self.levels as i32 - 1) * self.overhang,
363 self.bounds.min.y,
364 )
365 .with_z(alt + roof),
366 max: Vec2::new(
367 self.bounds.max.x + (self.levels as i32 - 1) * self.overhang + 1,
368 self.bounds.max.y + 1,
369 )
370 .with_z(alt + roof + roof_height),
371 })),
372 painter.prim(Primitive::Aabb(Aabb {
373 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
374 max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1)
375 .with_z(alt + roof + roof_height),
376 })),
377 ),
378 Dir::NegY => (
379 painter.prim(Primitive::Aabb(Aabb {
380 min: Vec2::new(
381 self.bounds.min.x,
382 self.bounds.min.y - (self.levels as i32 - 1) * self.overhang,
383 )
384 .with_z(alt + roof),
385 max: Vec2::new(
386 self.bounds.max.x + 1,
387 self.bounds.min.y - (self.levels as i32 - 1) * self.overhang + 1,
388 )
389 .with_z(alt + roof + roof_height),
390 })),
391 painter.prim(Primitive::Aabb(Aabb {
392 min: Vec2::new(self.bounds.min.x, self.bounds.max.y).with_z(alt + roof),
393 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
394 .with_z(alt + roof + roof_height),
395 })),
396 ),
397 _ => (
398 painter.prim(Primitive::Aabb(Aabb {
399 min: Vec2::new(
400 self.bounds.min.x - (self.levels as i32 - 1) * self.overhang,
401 self.bounds.min.y,
402 )
403 .with_z(alt + roof),
404 max: Vec2::new(
405 self.bounds.min.x - (self.levels as i32 - 1) * self.overhang + 1,
406 self.bounds.max.y + 1,
407 )
408 .with_z(alt + roof + roof_height),
409 })),
410 painter.prim(Primitive::Aabb(Aabb {
411 min: Vec2::new(self.bounds.max.x, self.bounds.min.y).with_z(alt + roof),
412 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
413 .with_z(alt + roof + roof_height),
414 })),
415 ),
416 };
417 let roof_front = painter.prim(Primitive::intersect(roof_empty, roof_front_wall));
418 let roof_rear = painter.prim(Primitive::intersect(roof_empty, roof_rear_wall));
419 painter.fill(
420 roof_primitive,
421 Fill::Brick(BlockKind::Wood, self.roof_color, 24),
422 );
423 painter.fill(roof_empty, Fill::Block(Block::empty()));
424 let roof_walls = painter.prim(Primitive::union(roof_front, roof_rear));
425 painter.fill(roof_walls, wall_fill_gable.clone());
426 let max_overhang = (self.levels as i32 - 1) * self.overhang;
427 let (roof_beam, roof_beam_right, roof_beam_left) = match self.front {
428 Dir::Y => (
429 painter.prim(Primitive::Aabb(Aabb {
430 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
431 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1 + max_overhang)
432 .with_z(alt + roof + 1),
433 })),
434 painter.prim(Primitive::Aabb(Aabb {
435 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
436 max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1 + max_overhang)
437 .with_z(alt + roof + 1),
438 })),
439 painter.prim(Primitive::Aabb(Aabb {
440 min: Vec2::new(self.bounds.max.x, self.bounds.min.y).with_z(alt + roof),
441 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1 + max_overhang)
442 .with_z(alt + roof + 1),
443 })),
444 ),
445 Dir::X => (
446 painter.prim(Primitive::Aabb(Aabb {
447 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
448 max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.max.y + 1)
449 .with_z(alt + roof + 1),
450 })),
451 painter.prim(Primitive::Aabb(Aabb {
452 min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
453 max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.min.y + 1)
454 .with_z(alt + roof + 1),
455 })),
456 painter.prim(Primitive::Aabb(Aabb {
457 min: Vec2::new(self.bounds.min.x, self.bounds.max.y).with_z(alt + roof),
458 max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.max.y + 1)
459 .with_z(alt + roof + 1),
460 })),
461 ),
462 Dir::NegY => (
463 painter.prim(Primitive::Aabb(Aabb {
464 min: Vec2::new(self.bounds.min.x, self.bounds.min.y - max_overhang)
465 .with_z(alt + roof),
466 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
467 .with_z(alt + roof + 1),
468 })),
469 painter.prim(Primitive::Aabb(Aabb {
470 min: Vec2::new(self.bounds.max.x, self.bounds.min.y - max_overhang)
471 .with_z(alt + roof),
472 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
473 .with_z(alt + roof + 1),
474 })),
475 painter.prim(Primitive::Aabb(Aabb {
476 min: Vec2::new(self.bounds.min.x, self.bounds.min.y - max_overhang)
477 .with_z(alt + roof),
478 max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1)
479 .with_z(alt + roof + 1),
480 })),
481 ),
482 _ => (
483 painter.prim(Primitive::Aabb(Aabb {
484 min: Vec2::new(self.bounds.min.x - max_overhang - 1, self.bounds.min.y)
485 .with_z(alt + roof),
486 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
487 .with_z(alt + roof + 1),
488 })),
489 painter.prim(Primitive::Aabb(Aabb {
490 min: Vec2::new(self.bounds.min.x - max_overhang, self.bounds.min.y)
491 .with_z(alt + roof),
492 max: Vec2::new(self.bounds.max.x + 1, self.bounds.min.y + 1)
493 .with_z(alt + roof + 1),
494 })),
495 painter.prim(Primitive::Aabb(Aabb {
496 min: Vec2::new(self.bounds.min.x - max_overhang, self.bounds.max.y)
497 .with_z(alt + roof),
498 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
499 .with_z(alt + roof + 1),
500 })),
501 ),
502 };
503 let quarter_x = self.bounds.min.x + (self.bounds.max.x - self.bounds.min.x) / 4;
504 let quarter_y = self.bounds.min.y + (self.bounds.max.y - self.bounds.min.y) / 4;
505 let half_x = self.bounds.min.x + (self.bounds.max.x - self.bounds.min.x) / 2;
506 let half_y = self.bounds.min.y + (self.bounds.max.y - self.bounds.min.y) / 2;
507 let three_quarter_x = self.bounds.min.x + 3 * (self.bounds.max.x - self.bounds.min.x) / 4;
508 let three_quarter_y = self.bounds.min.y + 3 * (self.bounds.max.y - self.bounds.min.y) / 4;
509 let top_rafter = if self.front.is_y() {
510 painter.prim(Primitive::Aabb(Aabb {
511 min: (Vec2::new(half_x, self.bounds.min.y - 2 - max_overhang.abs())
512 .with_z(alt + roof)),
513 max: (Vec2::new(half_x + 1, self.bounds.max.y + 2 + max_overhang.abs()))
514 .with_z(alt + roof + roof_height),
515 }))
516 } else {
517 painter.prim(Primitive::Aabb(Aabb {
518 min: (Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y)
519 .with_z(alt + roof)),
520 max: (Vec2::new(self.bounds.max.x + 1 + max_overhang.abs(), half_y + 1))
521 .with_z(alt + roof + roof_height),
522 }))
523 };
524 let left_rafter = if self.front.is_y() {
525 painter.prim(Primitive::Plane(
526 Aabr {
527 min: Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()),
528 max: Vec2::new(
529 three_quarter_x + 1,
530 self.bounds.max.y + 1 + max_overhang.abs(),
531 ),
532 },
533 Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()).with_z(alt + roof),
534 Vec2::new(1.0, 0.0),
535 ))
536 } else {
537 painter.prim(Primitive::Plane(
538 Aabr {
539 min: Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y),
540 max: Vec2::new(
541 self.bounds.max.x + 1 + max_overhang.abs(),
542 three_quarter_y + 1,
543 ),
544 },
545 Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y).with_z(alt + roof),
546 Vec2::new(0.0, 1.0),
547 ))
548 };
549 let right_rafter = if self.front.is_y() {
550 painter.prim(Primitive::Plane(
551 Aabr {
552 min: Vec2::new(quarter_x, self.bounds.min.y - 1 - max_overhang.abs()),
553 max: Vec2::new(half_x + 1, self.bounds.max.y + 1 + max_overhang.abs()),
554 },
555 Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()).with_z(alt + roof),
556 Vec2::new(1.0, 0.0),
557 ))
558 } else {
559 painter.prim(Primitive::Plane(
560 Aabr {
561 min: Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), quarter_y),
562 max: Vec2::new(self.bounds.max.x + 1 + max_overhang.abs(), half_y + 1),
563 },
564 Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y).with_z(alt + roof),
565 Vec2::new(0.0, 1.0),
566 ))
567 };
568 let rafters1 = painter.prim(Primitive::union(left_rafter, right_rafter));
569 let rafters2 = painter.prim(Primitive::union(rafters1, top_rafter));
570
571 painter.fill(
572 painter.prim(Primitive::intersect(roof_beam, roof_walls)),
573 pillar_fill.clone(),
574 );
575 painter.fill(
576 painter.prim(Primitive::union(roof_beam_left, roof_beam_right)),
577 pillar_fill.clone(),
578 );
579 painter.fill(
580 painter.prim(Primitive::intersect(rafters2, roof_walls)),
581 pillar_fill.clone(),
582 );
583
584 for i in 1..self.levels + 1 {
587 let previous_height = (storey * (i as i32 - 1) - 1).max(-1);
588 let height = storey * i as i32 - 1;
589 let window_height = storey - 3;
590 let storey_increase = (i as i32 - 1) * self.overhang;
591
592 let inner_level = if self.overhang < -4 && i > 1 {
594 match self.front {
595 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
596 min: (self.bounds.min + 1).with_z(alt + previous_height),
597 max: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase + 1)
598 .with_z(alt + height),
599 })),
600 Dir::X => painter.prim(Primitive::Aabb(Aabb {
601 min: (self.bounds.min + 1).with_z(alt + previous_height),
602 max: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.max.y)
603 .with_z(alt + height),
604 })),
605 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
606 min: Vec2::new(
607 self.bounds.min.x + 1,
608 self.bounds.min.y - storey_increase + 1,
609 )
610 .with_z(alt + previous_height),
611 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
612 })),
613 _ => painter.prim(Primitive::Aabb(Aabb {
614 min: Vec2::new(
615 self.bounds.min.x - storey_increase + 1,
616 self.bounds.min.y + 1,
617 )
618 .with_z(alt + previous_height),
619 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
620 })),
621 }
622 } else {
623 match self.front {
624 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
625 min: (self.bounds.min + 1).with_z(alt + previous_height),
626 max: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase)
627 .with_z(alt + height),
628 })),
629 Dir::X => painter.prim(Primitive::Aabb(Aabb {
630 min: (self.bounds.min + 1).with_z(alt + previous_height),
631 max: (Vec2::new(self.bounds.max.x + storey_increase, self.bounds.max.y))
632 .with_z(alt + height),
633 })),
634 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
635 min: Vec2::new(
636 self.bounds.min.x + 1,
637 self.bounds.min.y - storey_increase + 1,
638 )
639 .with_z(alt + previous_height),
640 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
641 })),
642 _ => painter.prim(Primitive::Aabb(Aabb {
643 min: Vec2::new(
644 self.bounds.min.x - storey_increase + 1,
645 self.bounds.min.y + 1,
646 )
647 .with_z(alt + previous_height),
648 max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
649 })),
650 }
651 };
652 let outer_level = match self.front {
653 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
654 min: self.bounds.min.with_z(alt + previous_height),
655 max: (Vec2::new(
656 self.bounds.max.x + 1,
657 self.bounds.max.y + storey_increase + 1,
658 ))
659 .with_z(alt + height),
660 })),
661 Dir::X => painter.prim(Primitive::Aabb(Aabb {
662 min: self.bounds.min.with_z(alt + previous_height),
663 max: Vec2::new(
664 self.bounds.max.x + storey_increase + 1,
665 self.bounds.max.y + 1,
666 )
667 .with_z(alt + height),
668 })),
669 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
670 min: Vec2::new(self.bounds.min.x, self.bounds.min.y - storey_increase)
671 .with_z(alt + previous_height),
672 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
673 .with_z(alt + height),
674 })),
675 _ => painter.prim(Primitive::Aabb(Aabb {
676 min: Vec2::new(self.bounds.min.x - storey_increase, self.bounds.min.y)
677 .with_z(alt + previous_height),
678 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
679 .with_z(alt + height),
680 })),
681 };
682
683 let is_lower = i <= 1;
684 let style = if is_lower {
685 self.lower_style
686 } else {
687 self.upper_style
688 };
689 let wall_block_fill = if is_lower {
690 wall_fill_lower.clone()
691 } else {
692 wall_fill_upper.clone()
693 };
694 painter.fill(outer_level, wall_block_fill);
695 painter.fill(inner_level, Fill::Block(Block::empty()));
696
697 let walls = outer_level
698 .union(inner_level)
699 .without(outer_level.intersect(inner_level));
700
701 if !matches!(style, Style::Stone) {
704 let mut pillars_y = painter.prim(Primitive::Empty);
705 let mut overhang_supports = painter.prim(Primitive::Empty);
706
707 for x in self.tile_aabr.min.x - 2..self.tile_aabr.max.x + 2 {
708 if self.overhang >= 2 && self.front.is_y() {
709 let temp = match self.front {
710 Dir::Y => site.tile_wpos(Vec2::new(x, self.tile_aabr.max.y)),
711 _ => Vec2::zero(),
713 };
714 let support = match self.front {
718 Dir::Y => painter.line(
719 Vec2::new(
720 temp.x,
721 self.bounds.max.y + storey_increase - self.overhang + 1,
722 )
723 .with_z(alt + previous_height - 3),
724 Vec2::new(
725 temp.x,
726 self.bounds.max.y + storey_increase - self.overhang + 2,
727 )
728 .with_z(alt + previous_height),
729 0.75,
730 ),
731 _ => painter.prim(Primitive::Empty),
739 };
740 if temp.x <= self.bounds.max.x && temp.x >= self.bounds.min.x {
741 overhang_supports =
742 painter.prim(Primitive::union(overhang_supports, support));
743 }
744 }
745 let pillar = painter.prim(Primitive::Aabb(Aabb {
746 min: site
747 .tile_wpos(Vec2::new(x, self.tile_aabr.min.y - 4))
748 .with_z(alt + previous_height),
749 max: (site.tile_wpos(Vec2::new(x, self.tile_aabr.max.y + 4))
750 + Vec2::unit_x())
751 .with_z(alt + height),
752 }));
753 pillars_y = painter.prim(Primitive::union(pillars_y, pillar));
754 }
755 let mut pillars_x = painter.prim(Primitive::Empty);
756 for y in self.tile_aabr.min.y - 2..self.tile_aabr.max.y + 2 {
757 if self.overhang >= 2 && !self.front.is_y() {
758 let temp = match self.front {
759 Dir::Y => Vec2::zero(),
760 Dir::X => site.tile_wpos(Vec2::new(self.tile_aabr.max.x, y)),
761 Dir::NegY => Vec2::zero(),
762 _ => site.tile_wpos(Vec2::new(self.tile_aabr.min.x, y)),
763 };
764 let support = match self.front {
765 Dir::Y => painter.prim(Primitive::Empty),
766 Dir::X => painter.line(
767 Vec2::new(
768 self.bounds.max.x + storey_increase - self.overhang + 1,
769 temp.y,
770 )
771 .with_z(alt + previous_height - 3),
772 Vec2::new(
773 self.bounds.max.x + storey_increase - self.overhang + 2,
774 temp.y,
775 )
776 .with_z(alt + previous_height),
777 0.75,
778 ),
779 Dir::NegY => painter.prim(Primitive::Empty),
780 _ => painter.line(
781 Vec2::new(
782 self.bounds.min.x - storey_increase + self.overhang - 1,
783 temp.y,
784 )
785 .with_z(alt + previous_height - 3),
786 Vec2::new(
787 self.bounds.min.x - storey_increase + self.overhang - 2,
788 temp.y,
789 )
790 .with_z(alt + previous_height),
791 0.75,
792 ),
793 };
794 if temp.y <= self.bounds.max.y && temp.y >= self.bounds.min.y {
795 overhang_supports =
796 painter.prim(Primitive::union(overhang_supports, support));
797 }
798 }
799 let pillar = painter.prim(Primitive::Aabb(Aabb {
800 min: site
801 .tile_wpos(Vec2::new(self.tile_aabr.min.x - 4, y))
802 .with_z(alt + previous_height),
803 max: (site.tile_wpos(Vec2::new(self.tile_aabr.max.x + 4, y))
804 + Vec2::unit_y())
805 .with_z(alt + height),
806 }));
807 pillars_x = painter.prim(Primitive::union(pillars_x, pillar));
808 }
809 let front_wall = if self.overhang < -4 && i > 1 {
810 painter.prim(Primitive::Empty)
811 } else {
812 match self.front {
813 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
814 min: Vec2::new(
815 self.bounds.min.x - 1,
816 self.bounds.max.y + storey_increase,
817 )
818 .with_z(alt + previous_height),
819 max: Vec2::new(
820 self.bounds.max.x + 1,
821 self.bounds.max.y + storey_increase + 1,
822 )
823 .with_z(alt + height),
824 })),
825 Dir::X => painter.prim(Primitive::Aabb(Aabb {
826 min: Vec2::new(
827 self.bounds.max.x + storey_increase,
828 self.bounds.min.y - 1,
829 )
830 .with_z(alt + previous_height),
831 max: Vec2::new(
832 self.bounds.max.x + storey_increase + 1,
833 self.bounds.max.y + 1,
834 )
835 .with_z(alt + height),
836 })),
837 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
838 min: Vec2::new(
839 self.bounds.min.x - 1,
840 self.bounds.min.y - storey_increase,
841 )
842 .with_z(alt + previous_height),
843 max: Vec2::new(
844 self.bounds.max.x + 1,
845 self.bounds.min.y - storey_increase + 1,
846 )
847 .with_z(alt + height),
848 })),
849 _ => painter.prim(Primitive::Aabb(Aabb {
850 min: Vec2::new(
851 self.bounds.min.x - storey_increase,
852 self.bounds.min.y - 1,
853 )
854 .with_z(alt + previous_height),
855 max: Vec2::new(
856 self.bounds.min.x - storey_increase + 1,
857 self.bounds.max.y + 1,
858 )
859 .with_z(alt + height),
860 })),
861 }
862 };
863 let pillars1 = if self.front.is_y() {
864 painter.prim(Primitive::intersect(pillars_y, front_wall))
865 } else {
866 painter.prim(Primitive::intersect(pillars_x, front_wall))
867 };
868 let pillars2 = painter.prim(Primitive::intersect(pillars_x, pillars_y));
869 let pillars3 = painter.prim(Primitive::union(pillars1, pillars2));
870 let pillars4 = match self.front {
871 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
872 min: Vec2::new(self.bounds.min.x - 1, self.bounds.min.y - 1)
873 .with_z(alt + previous_height),
874 max: Vec2::new(
875 self.bounds.max.x + 1,
876 self.bounds.max.y + storey_increase + 1,
877 )
878 .with_z(alt + previous_height + 1),
879 })),
880 Dir::X => painter.prim(Primitive::Aabb(Aabb {
881 min: Vec2::new(self.bounds.min.x - 1, self.bounds.min.y - 1)
882 .with_z(alt + previous_height),
883 max: Vec2::new(
884 self.bounds.max.x + storey_increase + 1,
885 self.bounds.max.y + 1,
886 )
887 .with_z(alt + previous_height + 1),
888 })),
889 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
890 min: Vec2::new(
891 self.bounds.min.x - 1,
892 self.bounds.min.y - storey_increase - 1,
893 )
894 .with_z(alt + previous_height),
895 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
896 .with_z(alt + previous_height + 1),
897 })),
898 _ => painter.prim(Primitive::Aabb(Aabb {
899 min: Vec2::new(
900 self.bounds.min.x - storey_increase - 1,
901 self.bounds.min.y - 1,
902 )
903 .with_z(alt + previous_height),
904 max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
905 .with_z(alt + previous_height + 1),
906 })),
907 };
908 let pillars = if matches!(style, Style::Brick) {
909 pillars4
910 } else {
911 painter.prim(Primitive::union(pillars3, pillars4))
912 };
913 painter.fill(
914 painter.prim(Primitive::intersect(walls, pillars)),
915 pillar_fill.clone(),
916 );
917
918 painter.fill(overhang_supports, pillar_fill.clone());
919 }
920
921 {
923 let mut windows = painter.prim(Primitive::Empty);
924 for y in self.tile_aabr.min.y - 2..self.tile_aabr.max.y + 2 {
925 let min = (site.tile_wpos(Vec2::new(self.tile_aabr.min.x - 4, y))
926 + Vec2::unit_y() * 2)
927 .with_z(alt + previous_height + 2);
928 let max = (site.tile_wpos(Vec2::new(self.tile_aabr.max.x + 4, y + 1))
929 + Vec2::new(1, -1))
930 .with_z(alt + previous_height + 2 + window_height);
931 let window = painter.prim(Primitive::Aabb(Aabb { min, max }));
932 let add_windows = match self.front {
933 Dir::Y => {
934 max.y < self.bounds.max.y + storey_increase && min.y > self.bounds.min.y
935 },
936 Dir::X => max.y < self.bounds.max.y && min.y > self.bounds.min.y,
937 Dir::NegY => {
938 max.y < self.bounds.max.y && min.y > self.bounds.min.y - storey_increase
939 },
940 _ => max.y < self.bounds.max.y && min.y > self.bounds.min.y,
941 };
942 if add_windows {
943 windows = painter.prim(Primitive::union(windows, window));
944 }
945 }
946 painter.fill(
947 painter.prim(Primitive::intersect(walls, windows)),
948 Fill::Block(Block::air(SpriteKind::Window1).with_ori(2).unwrap()),
949 );
950 if i == 1 {
952 let mut torches_min = painter.prim(Primitive::Empty);
953 let mut torches_max = painter.prim(Primitive::Empty);
954 for y in self.tile_aabr.min.y..self.tile_aabr.max.y {
955 let pos = site
956 .tile_wpos(Vec2::new(self.tile_aabr.min.x, y))
957 .with_z(alt + previous_height + 3)
958 + Vec3::new(-1, 0, 0);
959 let torch = painter.prim(Primitive::Aabb(Aabb {
960 min: pos,
961 max: pos + 1,
962 }));
963 torches_min = painter.prim(Primitive::union(torches_min, torch));
964
965 let pos = site
966 .tile_wpos(Vec2::new(self.tile_aabr.max.x, y + 1))
967 .with_z(alt + previous_height + 3)
968 + Vec3::new(1, 0, 0);
969 let torch = painter.prim(Primitive::Aabb(Aabb {
970 min: pos,
971 max: pos + 1,
972 }));
973 torches_max = painter.prim(Primitive::union(torches_max, torch));
974 }
975 painter.fill(
976 torches_min,
977 Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(6).unwrap()),
978 );
979 painter.fill(
980 torches_max,
981 Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(2).unwrap()),
982 );
983 }
984 }
985 {
987 let mut windows = painter.prim(Primitive::Empty);
988 for x in self.tile_aabr.min.x - 2..self.tile_aabr.max.x + 2 {
989 let min = (site.tile_wpos(Vec2::new(x, self.tile_aabr.min.y - 4))
990 + Vec2::unit_x() * 2)
991 .with_z(alt + previous_height + 2);
992 let max = (site.tile_wpos(Vec2::new(x + 1, self.tile_aabr.max.y + 4))
993 + Vec2::new(-1, 1))
994 .with_z(alt + previous_height + 2 + window_height);
995 let window = painter.prim(Primitive::Aabb(Aabb { min, max }));
996 let add_windows = match self.front {
997 Dir::Y => max.x < self.bounds.max.x && min.x > self.bounds.min.x,
998 Dir::X => {
999 max.x < self.bounds.max.x + storey_increase && min.x > self.bounds.min.x
1000 },
1001 Dir::NegY => max.x < self.bounds.max.x && min.x > self.bounds.min.x,
1002 _ => {
1003 max.x < self.bounds.max.x && min.x > self.bounds.min.x - storey_increase
1004 },
1005 };
1006 if add_windows {
1007 windows = painter.prim(Primitive::union(windows, window));
1008 };
1009 }
1010 painter.fill(
1011 painter.prim(Primitive::intersect(walls, windows)),
1012 Fill::Block(Block::air(SpriteKind::Window1).with_ori(0).unwrap()),
1013 );
1014 if i == 1 {
1016 let mut torches_min = painter.prim(Primitive::Empty);
1017 let mut torches_max = painter.prim(Primitive::Empty);
1018 for x in self.tile_aabr.min.x..self.tile_aabr.max.x {
1019 let pos = site
1020 .tile_wpos(Vec2::new(x + 1, self.tile_aabr.min.y))
1021 .with_z(alt + previous_height + 3)
1022 + Vec3::new(0, -1, 0);
1023 let torch = painter.prim(Primitive::Aabb(Aabb {
1024 min: pos,
1025 max: pos + 1,
1026 }));
1027 torches_min = painter.prim(Primitive::union(torches_min, torch));
1028
1029 let pos = site
1030 .tile_wpos(Vec2::new(x, self.tile_aabr.max.y))
1031 .with_z(alt + previous_height + 3)
1032 + Vec3::new(0, 1, 0);
1033 let torch = painter.prim(Primitive::Aabb(Aabb {
1034 min: pos,
1035 max: pos + 1,
1036 }));
1037 torches_max = painter.prim(Primitive::union(torches_max, torch));
1038 }
1039 painter.fill(
1040 torches_min,
1041 Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(0).unwrap()),
1042 );
1043 painter.fill(
1044 torches_max,
1045 Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap()),
1046 );
1047 }
1048 }
1049
1050 if self.overhang < -4 && i > 1 {
1052 let shed = match self.front {
1053 Dir::Y => painter.prim(Primitive::Ramp {
1054 aabb: Aabb {
1055 min: Vec2::new(
1056 self.bounds.min.x - 1,
1057 self.bounds.max.y + storey_increase + 1,
1058 )
1059 .with_z(alt + previous_height),
1060 max: Vec2::new(
1061 self.bounds.max.x + 1,
1062 self.bounds.max.y + storey_increase + self.overhang.abs() + 1,
1063 )
1064 .with_z(alt + height),
1065 },
1066 inset: storey,
1067 dir: Dir::NegY,
1068 }),
1069 Dir::X => painter.prim(Primitive::Ramp {
1070 aabb: Aabb {
1071 min: Vec2::new(
1072 self.bounds.max.x + storey_increase + 1,
1073 self.bounds.min.y - 1,
1074 )
1075 .with_z(alt + previous_height),
1076 max: Vec2::new(
1077 self.bounds.max.x + storey_increase + self.overhang.abs() + 1,
1078 self.bounds.max.y + 1,
1079 )
1080 .with_z(alt + height),
1081 },
1082 inset: storey,
1083 dir: Dir::NegX,
1084 }),
1085 Dir::NegY => painter.prim(Primitive::Ramp {
1086 aabb: Aabb {
1087 min: Vec2::new(
1088 self.bounds.min.x - 1,
1089 self.bounds.min.y - storey_increase - self.overhang.abs(),
1090 )
1091 .with_z(alt + previous_height),
1092 max: Vec2::new(
1093 self.bounds.max.x + 2,
1094 self.bounds.min.y - storey_increase,
1095 )
1096 .with_z(alt + height),
1097 },
1098 inset: storey,
1099 dir: Dir::Y,
1100 }),
1101 _ => painter.prim(Primitive::Ramp {
1102 aabb: Aabb {
1103 min: Vec2::new(
1104 self.bounds.min.x - storey_increase - self.overhang.abs(),
1105 self.bounds.min.y - 1,
1106 )
1107 .with_z(alt + previous_height),
1108 max: Vec2::new(
1109 self.bounds.min.x - storey_increase + 1,
1110 self.bounds.max.y + 2,
1111 )
1112 .with_z(alt + height),
1113 },
1114 inset: storey,
1115 dir: Dir::X,
1116 }),
1117 };
1118 let shed_empty = match self.front {
1119 Dir::Y => painter.prim(Primitive::Ramp {
1120 aabb: Aabb {
1121 min: Vec2::new(
1122 self.bounds.min.x - 1,
1123 self.bounds.max.y + storey_increase + 1,
1124 )
1125 .with_z(alt + previous_height),
1126 max: Vec2::new(
1127 self.bounds.max.x + 1,
1128 self.bounds.max.y + storey_increase + self.overhang.abs(),
1129 )
1130 .with_z(alt + height - 1),
1131 },
1132 inset: storey - 1,
1133 dir: Dir::NegY,
1134 }),
1135 Dir::X => painter.prim(Primitive::Ramp {
1136 aabb: Aabb {
1137 min: Vec2::new(
1138 self.bounds.max.x + storey_increase + 1,
1139 self.bounds.min.y - 1,
1140 )
1141 .with_z(alt + previous_height),
1142 max: Vec2::new(
1143 self.bounds.max.x + storey_increase + self.overhang.abs(),
1144 self.bounds.max.y + 1,
1145 )
1146 .with_z(alt + height - 1),
1147 },
1148 inset: storey - 1,
1149 dir: Dir::NegX,
1150 }),
1151 Dir::NegY => painter.prim(Primitive::Ramp {
1152 aabb: Aabb {
1153 min: Vec2::new(
1154 self.bounds.min.x - 1,
1155 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1156 )
1157 .with_z(alt + previous_height),
1158 max: Vec2::new(
1159 self.bounds.max.x + 2,
1160 self.bounds.min.y - storey_increase + 1,
1161 )
1162 .with_z(alt + height),
1163 },
1164 inset: storey - 1,
1165 dir: Dir::Y,
1166 }),
1167 _ => painter.prim(Primitive::Ramp {
1168 aabb: Aabb {
1169 min: Vec2::new(
1170 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1171 self.bounds.min.y - 1,
1172 )
1173 .with_z(alt + previous_height),
1174 max: Vec2::new(
1175 self.bounds.min.x - storey_increase + 1,
1176 self.bounds.max.y + 2,
1177 )
1178 .with_z(alt + height),
1179 },
1180 inset: storey - 1,
1181 dir: Dir::X,
1182 }),
1183 };
1184 painter.fill(shed, Fill::Brick(BlockKind::Wood, self.roof_color, 24));
1185 painter.fill(shed_empty, Fill::Block(Block::empty()));
1186 let shed_left_wall = match self.front {
1187 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
1188 min: Vec2::new(self.bounds.min.x, self.bounds.max.y + storey_increase + 1)
1189 .with_z(alt + previous_height),
1190 max: Vec2::new(
1191 self.bounds.min.x + 1,
1192 self.bounds.max.y + storey_increase + self.overhang.abs(),
1193 )
1194 .with_z(alt + height - 1),
1195 })),
1196 Dir::X => painter.prim(Primitive::Aabb(Aabb {
1197 min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.min.y)
1198 .with_z(alt + previous_height),
1199 max: Vec2::new(
1200 self.bounds.max.x + storey_increase + self.overhang.abs(),
1201 self.bounds.min.y + 1,
1202 )
1203 .with_z(alt + height - 1),
1204 })),
1205 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
1206 min: Vec2::new(
1207 self.bounds.max.x,
1208 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1209 )
1210 .with_z(alt + previous_height),
1211 max: Vec2::new(
1212 self.bounds.max.x + 1,
1213 self.bounds.min.y - storey_increase + 1,
1214 )
1215 .with_z(alt + height),
1216 })),
1217 _ => painter.prim(Primitive::Aabb(Aabb {
1218 min: Vec2::new(
1219 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1220 self.bounds.max.y,
1221 )
1222 .with_z(alt + previous_height),
1223 max: Vec2::new(
1224 self.bounds.min.x - storey_increase + 1,
1225 self.bounds.max.y + 1,
1226 )
1227 .with_z(alt + height),
1228 })),
1229 };
1230 let shed_right_wall = match self.front {
1231 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
1232 min: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase + 1)
1233 .with_z(alt + previous_height),
1234 max: Vec2::new(
1235 self.bounds.max.x + 1,
1236 self.bounds.max.y + storey_increase + self.overhang.abs(),
1237 )
1238 .with_z(alt + height - 1),
1239 })),
1240 Dir::X => painter.prim(Primitive::Aabb(Aabb {
1241 min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.max.y)
1242 .with_z(alt + previous_height),
1243 max: Vec2::new(
1244 self.bounds.max.x + storey_increase + self.overhang.abs(),
1245 self.bounds.max.y + 1,
1246 )
1247 .with_z(alt + height - 1),
1248 })),
1249 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
1250 min: Vec2::new(
1251 self.bounds.min.x,
1252 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1253 )
1254 .with_z(alt + previous_height),
1255 max: Vec2::new(
1256 self.bounds.min.x + 1,
1257 self.bounds.min.y - storey_increase + 1,
1258 )
1259 .with_z(alt + height),
1260 })),
1261 _ => painter.prim(Primitive::Aabb(Aabb {
1262 min: Vec2::new(
1263 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1264 self.bounds.min.y,
1265 )
1266 .with_z(alt + previous_height),
1267 max: Vec2::new(
1268 self.bounds.min.x - storey_increase + 1,
1269 self.bounds.min.y + 1,
1270 )
1271 .with_z(alt + height),
1272 })),
1273 };
1274 let shed_wall_beams = match self.front {
1275 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
1276 min: Vec2::new(self.bounds.min.x, self.bounds.max.y + storey_increase + 1)
1277 .with_z(alt + previous_height),
1278 max: Vec2::new(
1279 self.bounds.max.x + 1,
1280 self.bounds.max.y + storey_increase + self.overhang.abs(),
1281 )
1282 .with_z(alt + previous_height + 1),
1283 })),
1284 Dir::X => painter.prim(Primitive::Aabb(Aabb {
1285 min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.min.y)
1286 .with_z(alt + previous_height),
1287 max: Vec2::new(
1288 self.bounds.max.x + storey_increase + self.overhang.abs(),
1289 self.bounds.max.y + 1,
1290 )
1291 .with_z(alt + previous_height + 1),
1292 })),
1293 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
1294 min: Vec2::new(
1295 self.bounds.min.x,
1296 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1297 )
1298 .with_z(alt + previous_height),
1299 max: Vec2::new(
1300 self.bounds.max.x + 1,
1301 self.bounds.min.y - storey_increase + 1,
1302 )
1303 .with_z(alt + previous_height + 1),
1304 })),
1305 _ => painter.prim(Primitive::Aabb(Aabb {
1306 min: Vec2::new(
1307 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1308 self.bounds.min.y,
1309 )
1310 .with_z(alt + previous_height),
1311 max: Vec2::new(
1312 self.bounds.min.x - storey_increase + 1,
1313 self.bounds.max.y + 1,
1314 )
1315 .with_z(alt + previous_height + 1),
1316 })),
1317 };
1318 let shed_walls = painter.prim(Primitive::union(shed_left_wall, shed_right_wall));
1319 painter.fill(
1320 painter.prim(Primitive::intersect(shed_walls, shed_empty)),
1321 wall_fill_upper.clone(),
1322 );
1323 painter.fill(
1324 painter.prim(Primitive::intersect(shed_wall_beams, shed_walls)),
1325 pillar_fill.clone(),
1326 );
1327
1328 let range = if self.front.is_y() {
1330 self.tile_aabr.min.x - 3..self.tile_aabr.max.x + 3
1331 } else {
1332 self.tile_aabr.min.y - 3..self.tile_aabr.max.y + 3
1333 };
1334 for n in range {
1335 let temp = match self.front {
1336 Dir::Y => site.tile_wpos(Vec2::new(n, self.tile_aabr.max.y)) - 4,
1337 Dir::X => site.tile_wpos(Vec2::new(self.tile_aabr.max.x, n)) - 4,
1338 Dir::NegY => site.tile_wpos(Vec2::new(n, self.tile_aabr.min.y)) - 4,
1339 _ => site.tile_wpos(Vec2::new(self.tile_aabr.min.x, n)) - 4,
1340 };
1341 let dormer_box = match self.front {
1342 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
1343 min: Vec2::new(temp.x - 1, self.bounds.max.y + storey_increase + 1)
1344 .with_z(alt + previous_height),
1345 max: Vec2::new(
1346 temp.x + 4,
1347 self.bounds.max.y + storey_increase + self.overhang.abs(),
1348 )
1349 .with_z(alt + height - 1),
1350 })),
1351 Dir::X => painter.prim(Primitive::Aabb(Aabb {
1352 min: Vec2::new(self.bounds.max.x + storey_increase + 1, temp.y - 1)
1353 .with_z(alt + previous_height),
1354 max: Vec2::new(
1355 self.bounds.max.x + storey_increase + self.overhang.abs(),
1356 temp.y + 4,
1357 )
1358 .with_z(alt + height - 1),
1359 })),
1360 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
1361 min: Vec2::new(
1362 temp.x - 1,
1363 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1364 )
1365 .with_z(alt + previous_height),
1366 max: Vec2::new(temp.x + 4, self.bounds.min.y - storey_increase - 1)
1367 .with_z(alt + height - 1),
1368 })),
1369 _ => painter.prim(Primitive::Aabb(Aabb {
1370 min: Vec2::new(
1371 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1372 temp.y - 1,
1373 )
1374 .with_z(alt + previous_height),
1375 max: Vec2::new(self.bounds.min.x - storey_increase - 1, temp.y + 4)
1376 .with_z(alt + height - 1),
1377 })),
1378 };
1379 let dormer_roof = match self.front {
1380 Dir::Y => painter.prim(Primitive::Gable {
1381 aabb: Aabb {
1382 min: Vec2::new(temp.x - 1, self.bounds.max.y + storey_increase + 1)
1383 .with_z(alt + height - 2),
1384 max: Vec2::new(
1385 temp.x + 4,
1386 self.bounds.max.y + storey_increase + self.overhang.abs(),
1387 )
1388 .with_z(alt + height + 1),
1389 },
1390 inset: 3,
1391 dir: Dir::Y,
1392 }),
1393 Dir::X => painter.prim(Primitive::Gable {
1394 aabb: Aabb {
1395 min: Vec2::new(self.bounds.max.x + storey_increase + 1, temp.y - 1)
1396 .with_z(alt + height - 2),
1397 max: Vec2::new(
1398 self.bounds.max.x + storey_increase + self.overhang.abs(),
1399 temp.y + 4,
1400 )
1401 .with_z(alt + height + 1),
1402 },
1403 inset: 3,
1404 dir: Dir::X,
1405 }),
1406 Dir::NegY => painter.prim(Primitive::Gable {
1407 aabb: Aabb {
1408 min: Vec2::new(
1409 temp.x - 1,
1410 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1411 )
1412 .with_z(alt + height - 2),
1413 max: Vec2::new(temp.x + 4, self.bounds.min.y - storey_increase)
1414 .with_z(alt + height + 1),
1415 },
1416 inset: 3,
1417 dir: Dir::Y,
1418 }),
1419 _ => painter.prim(Primitive::Gable {
1420 aabb: Aabb {
1421 min: Vec2::new(
1422 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1423 temp.y - 1,
1424 )
1425 .with_z(alt + height - 2),
1426 max: Vec2::new(self.bounds.min.x - storey_increase, temp.y + 4)
1427 .with_z(alt + height + 1),
1428 },
1429 inset: 3,
1430 dir: Dir::X,
1431 }),
1432 };
1433 let window_min = match self.front {
1434 Dir::Y => Vec2::new(
1435 temp.x,
1436 self.bounds.max.y + storey_increase + self.overhang.abs() - 1,
1437 )
1438 .with_z(alt + previous_height + 2),
1439 Dir::X => Vec2::new(
1440 self.bounds.max.x + storey_increase + self.overhang.abs() - 1,
1441 temp.y,
1442 )
1443 .with_z(alt + previous_height + 2),
1444 Dir::NegY => Vec2::new(
1445 temp.x,
1446 self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1447 )
1448 .with_z(alt + previous_height + 2),
1449 _ => Vec2::new(
1450 self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1451 temp.y,
1452 )
1453 .with_z(alt + previous_height + 2),
1454 };
1455 let window_max = match self.front {
1456 Dir::Y => Vec2::new(
1457 temp.x + 3,
1458 self.bounds.max.y + storey_increase + self.overhang.abs(),
1459 )
1460 .with_z(alt + previous_height + 2 + window_height),
1461 Dir::X => Vec2::new(
1462 self.bounds.max.x + storey_increase + self.overhang.abs(),
1463 temp.y + 3,
1464 )
1465 .with_z(alt + previous_height + 2 + window_height),
1466 Dir::NegY => Vec2::new(
1467 temp.x + 3,
1468 self.bounds.min.y - storey_increase - self.overhang.abs() + 2,
1469 )
1470 .with_z(alt + previous_height + 2 + window_height),
1471 _ => Vec2::new(
1472 self.bounds.min.x - storey_increase - self.overhang.abs() + 2,
1473 temp.y + 3,
1474 )
1475 .with_z(alt + previous_height + 2 + window_height),
1476 };
1477 let window = painter.prim(Primitive::Aabb(Aabb {
1478 min: window_min,
1479 max: window_max,
1480 }));
1481 let window_cavity = match self.front {
1482 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
1483 min: Vec2::new(temp.x, self.bounds.max.y + storey_increase)
1484 .with_z(alt + previous_height),
1485 max: Vec2::new(
1486 temp.x + 3,
1487 self.bounds.max.y + storey_increase + self.overhang.abs() - 1,
1488 )
1489 .with_z(alt + previous_height + 2 + window_height),
1490 })),
1491 Dir::X => painter.prim(Primitive::Aabb(Aabb {
1492 min: Vec2::new(self.bounds.max.x + storey_increase, temp.y)
1493 .with_z(alt + previous_height),
1494 max: Vec2::new(
1495 self.bounds.max.x + storey_increase + self.overhang.abs() - 1,
1496 temp.y + 3,
1497 )
1498 .with_z(alt + previous_height + 2 + window_height),
1499 })),
1500 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
1501 min: Vec2::new(
1502 temp.x,
1503 self.bounds.min.y - storey_increase - self.overhang.abs() + 2,
1504 )
1505 .with_z(alt + previous_height),
1506 max: Vec2::new(temp.x + 3, self.bounds.min.y - storey_increase + 1)
1507 .with_z(alt + previous_height + 2 + window_height),
1508 })),
1509 _ => painter.prim(Primitive::Aabb(Aabb {
1510 min: Vec2::new(
1511 self.bounds.min.x - storey_increase - self.overhang.abs() + 2,
1512 temp.y,
1513 )
1514 .with_z(alt + previous_height),
1515 max: Vec2::new(self.bounds.min.x - storey_increase + 1, temp.y + 3)
1516 .with_z(alt + previous_height + 2 + window_height),
1517 })),
1518 };
1519 let valid_dormer = if self.front.is_y() {
1520 window_min.x > self.bounds.min.x && window_max.x < self.bounds.max.x
1521 } else {
1522 window_min.y > self.bounds.min.y && window_max.y < self.bounds.max.y
1523 };
1524 let window_ori = if self.front.is_y() { 0 } else { 2 };
1525 if valid_dormer {
1526 painter.fill(
1527 painter.prim(Primitive::without(dormer_box, shed)),
1528 wall_fill_upper.clone(),
1529 );
1530 painter.fill(
1531 painter.prim(Primitive::without(dormer_roof, shed)),
1532 Fill::Brick(BlockKind::Wood, self.roof_color, 24),
1533 );
1534 painter.fill(window_cavity, Fill::Block(Block::empty()));
1535 painter.fill(
1536 window,
1537 Fill::Block(
1538 Block::air(SpriteKind::Window1)
1539 .with_ori(window_ori)
1540 .unwrap(),
1541 ),
1542 );
1543 }
1544 }
1545 }
1546
1547 if i > 1 {
1550 let floor = if self.overhang < -1 && i > 1 {
1551 match self.front {
1552 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
1553 min: (self.bounds.min + 1).with_z(alt + previous_height),
1554 max: Vec2::new(
1555 self.bounds.max.x,
1556 self.bounds.max.y + storey_increase + self.overhang.abs(),
1557 )
1558 .with_z(alt + previous_height + 1),
1559 })),
1560 Dir::X => painter.prim(Primitive::Aabb(Aabb {
1561 min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1)
1562 .with_z(alt + previous_height),
1563 max: Vec2::new(
1564 self.bounds.max.x + storey_increase + self.overhang.abs(),
1565 self.bounds.max.y,
1566 )
1567 .with_z(alt + previous_height + 1),
1568 })),
1569 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
1570 min: Vec2::new(
1571 self.bounds.min.x + 1,
1572 self.bounds.min.y + 1 - storey_increase - self.overhang.abs(),
1573 )
1574 .with_z(alt + previous_height),
1575 max: Vec2::new(self.bounds.max.x, self.bounds.max.y)
1576 .with_z(alt + previous_height + 1),
1577 })),
1578 _ => painter.prim(Primitive::Aabb(Aabb {
1579 min: Vec2::new(
1580 self.bounds.min.x + 1 - storey_increase - self.overhang.abs(),
1581 self.bounds.min.y + 1,
1582 )
1583 .with_z(alt + previous_height),
1584 max: Vec2::new(self.bounds.max.x, self.bounds.max.y)
1585 .with_z(alt + previous_height + 1),
1586 })),
1587 }
1588 } else {
1589 match self.front {
1590 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
1591 min: (self.bounds.min + 1).with_z(alt + previous_height),
1592 max: (Vec2::new(
1593 self.bounds.max.x,
1594 self.bounds.max.y + storey_increase,
1595 ))
1596 .with_z(alt + previous_height + 1),
1597 })),
1598 Dir::X => painter.prim(Primitive::Aabb(Aabb {
1599 min: (self.bounds.min + 1).with_z(alt + previous_height),
1600 max: (Vec2::new(
1601 self.bounds.max.x + storey_increase,
1602 self.bounds.max.y,
1603 ))
1604 .with_z(alt + previous_height + 1),
1605 })),
1606 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
1607 min: Vec2::new(
1608 self.bounds.min.x + 1,
1609 self.bounds.min.y + 1 - storey_increase,
1610 )
1611 .with_z(alt + previous_height),
1612 max: (Vec2::new(self.bounds.max.x, self.bounds.max.y))
1613 .with_z(alt + previous_height + 1),
1614 })),
1615 _ => painter.prim(Primitive::Aabb(Aabb {
1616 min: Vec2::new(
1617 self.bounds.min.x + 1 - storey_increase,
1618 self.bounds.min.y + 1,
1619 )
1620 .with_z(alt + previous_height),
1621 max: (Vec2::new(self.bounds.max.x, self.bounds.max.y))
1622 .with_z(alt + previous_height + 1),
1623 })),
1624 }
1625 };
1626 painter.fill(
1627 floor,
1628 Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
1629 );
1630 }
1631
1632 let base = alt + (storey * (i as i32 - 1)).max(0);
1634 if i % 2 == 0 {
1635 let bed_pos = match self.front {
1637 Dir::X => Vec2::new(half_x, quarter_y),
1638 Dir::NegY => Vec2::new(three_quarter_x, half_y),
1639 _ => Vec2::new(half_x, half_y),
1640 };
1641 let bed_dir = self.front;
1642 let bed_aabr = painter.bed_wood_woodland(bed_pos.with_z(base), bed_dir);
1643 let nightstand_pos = bed_dir
1644 .opposite()
1645 .select_aabr_with(bed_aabr, bed_dir.rotated_ccw().select_aabr(bed_aabr))
1646 .with_z(base)
1647 + bed_dir.rotated_ccw().to_vec2();
1648 painter.sprite(nightstand_pos.with_z(base), SpriteKind::DrawerWoodWoodlandS);
1650 let rng0 = RandomField::new(0).get(nightstand_pos.with_z(base + 1));
1652 let rng1 = RandomField::new(1).get(nightstand_pos.with_z(base + 1));
1653 painter.owned_resource_sprite(
1654 nightstand_pos.with_z(base + 1),
1655 match rng0 % 5 {
1656 0 => SpriteKind::Lantern,
1657 1 => SpriteKind::PotionMinor,
1658 2 => SpriteKind::VialEmpty,
1659 3 => SpriteKind::Bowl,
1660 _ => SpriteKind::Empty,
1661 },
1662 (rng1 % 4) as u8 * 2,
1663 );
1664 let wardrobe_dir = self.front.rotated_cw();
1666 let bounds = Aabr {
1667 min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1),
1668 max: Vec2::new(self.bounds.max.x - 2, self.bounds.max.y - 1),
1669 };
1670 let wardrobe_pos = wardrobe_dir
1671 .opposite()
1672 .select_aabr_with(
1673 bounds,
1674 bounds.center()
1675 + wardrobe_dir.vec2(bounds.half_size().w, bounds.half_size().h) / 2,
1676 )
1677 .with_z(base);
1678
1679 let sprite = if RandomField::new(0).chance(wardrobe_pos, 0.5) {
1680 SpriteKind::WardrobedoubleWoodWoodland
1681 } else {
1682 SpriteKind::WardrobedoubleWoodWoodland2
1683 };
1684 painter.mirrored2(wardrobe_pos, wardrobe_dir, sprite);
1685 } else {
1686 for dir in DIRS {
1688 let sprite_pos = self.bounds.center() + dir * 5;
1690 let rng0 = RandomField::new(0).get(sprite_pos.with_z(base));
1691 let rng1 = RandomField::new(1).get(sprite_pos.with_z(base));
1692 painter.owned_resource_sprite(
1693 sprite_pos.with_z(base),
1694 match rng0 % 32 {
1695 0..=2 => SpriteKind::Crate,
1696 3..=4 => SpriteKind::CoatrackWoodWoodland,
1697 5..=7 => SpriteKind::FlowerpotWoodWoodlandS,
1698 8..=9 => SpriteKind::Lantern,
1699 _ => SpriteKind::Empty,
1700 },
1701 (rng1 % 4) as u8 * 2,
1702 );
1703 }
1704
1705 if self.bounds.max.x - self.bounds.min.x < 16
1706 || self.bounds.max.y - self.bounds.min.y < 16
1707 {
1708 let table_pos = Vec2::new(half_x, half_y);
1709 painter.sprite(
1711 table_pos.with_z(base),
1712 SpriteKind::DiningtableWoodWoodlandRound,
1713 );
1714 for dir in Dir::iter() {
1715 let chair_pos = table_pos + dir.to_vec2();
1716 painter.rotated_sprite(
1717 chair_pos.with_z(base),
1718 SpriteKind::ChairWoodWoodland,
1719 dir.opposite().sprite_ori(),
1720 );
1721 }
1722 } else {
1723 let table_pos = match self.front {
1725 Dir::Y => Vec2::new(half_x, three_quarter_y),
1726 Dir::X => Vec2::new(half_x, half_y),
1727 _ => Vec2::new(quarter_x, half_y),
1728 }
1729 .with_z(base);
1730 let table_axis = if RandomField::new(0).chance(table_pos, 0.5) {
1731 Dir::X
1732 } else {
1733 Dir::Y
1734 };
1735 let table_bounds = painter.table_wood_fancy_woodland(table_pos, table_axis);
1736 painter.chairs_around(SpriteKind::ChairWoodWoodland, 1, table_bounds, base);
1737 }
1738 let (drawer_pos, drawer_ori) = match self.front {
1740 Dir::Y => (Vec2::new(self.bounds.max.x - 1, self.bounds.max.y - 2), 6),
1741 Dir::X => (Vec2::new(self.bounds.max.x - 2, self.bounds.max.y - 1), 0),
1742 Dir::NegY => (Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 2), 6),
1743 _ => (Vec2::new(self.bounds.min.x + 2, self.bounds.max.y - 1), 0),
1744 };
1745 painter.rotated_sprite(
1746 drawer_pos.with_z(base),
1747 SpriteKind::DrawerWoodWoodlandL1,
1748 drawer_ori,
1749 );
1750 }
1751
1752 if i > 1 {
1754 let stair_width = 3;
1755 let previous_floor_height = (storey * (i as i32 - 2)).max(0);
1756 let stair_origin = match self.front {
1757 Dir::Y => self.bounds.min + 1,
1758 Dir::X => self.bounds.min + 1,
1759 Dir::NegY => {
1760 Vec2::new(self.bounds.max.x - 12, self.bounds.max.y - stair_width * 2)
1761 },
1762 _ => Vec2::new(self.bounds.max.x - 12, self.bounds.min.y + 1),
1763 };
1764 let staircase = if i < 2 {
1765 painter.prim(Primitive::Empty)
1766 } else if i % 2 == 0 {
1767 let ramp = {
1768 painter.prim(Primitive::Ramp {
1770 aabb: Aabb {
1771 min: Vec2::new(stair_origin.x + 3, stair_origin.y).with_z(alt + previous_floor_height),
1772 max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
1773 },
1774 inset: storey,
1775 dir: Dir::X,
1776 })
1777 };
1809 let support = {
1810 painter.prim(Primitive::Aabb(Aabb {
1813 min: Vec2::new(stair_origin.x + 10, stair_origin.y)
1814 .with_z(alt + previous_floor_height),
1815 max: Vec2::new(stair_origin.x + 12, stair_origin.y + stair_width)
1816 .with_z(alt + previous_height + 1),
1817 }))
1818 };
1844 painter.prim(Primitive::union(ramp, support))
1845 } else {
1846 let ramp = {
1847 painter.prim(Primitive::Ramp {
1849 aabb: Aabb {
1850 min: Vec2::new(stair_origin.x + 1, stair_origin.y + stair_width).with_z(alt + previous_floor_height),
1851 max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
1852 },
1853 inset: storey,
1854 dir: Dir::NegX,
1855 })
1856 };
1889 let support = {
1890 painter.prim(Primitive::Aabb(Aabb {
1893 min: Vec2::new(stair_origin.x, stair_origin.y + stair_width)
1894 .with_z(alt + previous_floor_height),
1895 max: Vec2::new(stair_origin.x + 2, stair_origin.y + 2 * stair_width)
1896 .with_z(alt + previous_height + 1),
1897 }))
1898 };
1924 painter.prim(Primitive::union(ramp, support))
1925 };
1926 let stairwell = if i < 2 {
1927 painter.prim(Primitive::Empty)
1928 } else if i % 2 == 0 {
1929 painter.prim(Primitive::Aabb(Aabb {
1930 min: Vec2::new(stair_origin.x + 2, stair_origin.y)
1931 .with_z(alt + previous_floor_height + 1),
1932 max: Vec2::new(stair_origin.x + 9, stair_origin.y + stair_width)
1933 .with_z(alt + previous_height + 1),
1934 }))
1935 } else {
1970 painter.prim(Primitive::Aabb(Aabb {
1971 min: Vec2::new(stair_origin.x + 2, stair_origin.y + stair_width)
1972 .with_z(alt + previous_floor_height + 1),
1973 max: Vec2::new(stair_origin.x + 11, stair_origin.y + 2 * stair_width)
1974 .with_z(alt + previous_height + 1),
1975 }))
1976 };
2015
2016 painter.fill(stairwell, Fill::Block(Block::empty()));
2017 painter.fill(
2018 staircase,
2019 Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
2020 );
2021 }
2022 }
2023
2024 painter.fill(
2026 painter.prim(Primitive::Aabb(Aabb {
2027 min: (self.bounds.min - 1).with_z(self.alt - foundations),
2028 max: (self.bounds.max + 2).with_z(self.alt + 1),
2029 })),
2030 Fill::Block(Block::new(BlockKind::Rock, Rgb::new(31, 33, 32))),
2031 );
2032
2033 let fireplace_origin = {
2050 match self.front {
2051 Dir::Y => {
2052 Vec2::new(half_x, self.bounds.min.y + 1)
2053 },
2054 Dir::X => {
2055 Vec2::new(self.bounds.min.x + 1, half_y)
2056 },
2057 Dir::NegY => {
2058 Vec2::new(half_x - 4, self.bounds.max.y - 3)
2059 },
2060 _ => {
2061 Vec2::new(self.bounds.max.x - 3, half_y)
2062 },
2063 }
2064 };
2065 let chimney = match self.front {
2066 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
2067 min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2068 max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
2069 .with_z(alt + roof + roof_height + 2),
2070 })),
2071 Dir::X => painter.prim(Primitive::Aabb(Aabb {
2072 min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2073 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
2074 .with_z(alt + roof + roof_height + 2),
2075 })),
2076 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
2077 min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2078 max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
2079 .with_z(alt + roof + roof_height + 2),
2080 })),
2081 _ => painter.prim(Primitive::Aabb(Aabb {
2082 min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2083 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
2084 .with_z(alt + roof + roof_height + 2),
2085 })),
2086 };
2087
2088 let chimney_cavity = match self.front {
2089 Dir::Y => painter.prim(Primitive::Aabb(Aabb {
2090 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2091 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
2092 .with_z(alt + roof + roof_height + 2),
2093 })),
2094 Dir::X => painter.prim(Primitive::Aabb(Aabb {
2095 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2096 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
2097 .with_z(alt + roof + roof_height + 2),
2098 })),
2099 Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
2100 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2101 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
2102 .with_z(alt + roof + roof_height + 2),
2103 })),
2104 _ => painter.prim(Primitive::Aabb(Aabb {
2105 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2106 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
2107 .with_z(alt + roof + roof_height + 2),
2108 })),
2109 };
2110 let fire_embers = match self.front {
2111 Dir::Y => Aabb {
2112 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2113 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 1),
2114 },
2115 Dir::X => Aabb {
2116 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2117 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
2118 },
2119 Dir::NegY => Aabb {
2120 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2121 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 1),
2122 },
2123 _ => Aabb {
2124 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2125 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
2126 },
2127 };
2128 let fireplace_cavity = match self.front {
2129 Dir::Y => Aabb {
2130 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2131 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
2132 },
2133 Dir::X => Aabb {
2134 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2135 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
2136 },
2137 Dir::NegY => Aabb {
2138 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y).with_z(alt),
2139 max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 2),
2140 },
2141 _ => Aabb {
2142 min: Vec2::new(fireplace_origin.x, fireplace_origin.y + 1).with_z(alt),
2143 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 2),
2144 },
2145 };
2146
2147 painter.fill(
2148 chimney,
2149 Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24),
2150 );
2151 painter.fill(chimney_cavity, Fill::Block(Block::empty()));
2152 painter.fill(
2153 painter.prim(Primitive::Aabb(fireplace_cavity)),
2154 Fill::Block(Block::empty()),
2155 );
2156 painter.fill(
2157 painter.prim(Primitive::Aabb(fire_embers)),
2158 Fill::Block(Block::air(SpriteKind::Ember)),
2159 );
2160
2161 if self.levels == 1 {
2163 let bed_pos = if self.bounds.max.x - self.bounds.min.x < 16
2165 || self.bounds.max.y - self.bounds.min.y < 16
2166 {
2167 match self.front {
2168 Dir::Y => Vec2::new(self.bounds.min.x + 4, self.bounds.min.y + 2),
2169 Dir::X => Vec2::new(self.bounds.min.x + 2, self.bounds.min.y + 4),
2170 Dir::NegY => Vec2::new(self.bounds.max.x - 4, self.bounds.max.y - 2),
2171 _ => Vec2::new(self.bounds.max.x - 8, self.bounds.max.y - 2),
2172 }
2173 } else {
2174 match self.front {
2175 Dir::Y => Vec2::new(self.bounds.max.x - 4, self.bounds.min.y + 2),
2176 Dir::X => Vec2::new(self.bounds.min.x + 8, self.bounds.max.y - 2),
2177 Dir::NegY => Vec2::new(self.bounds.max.x - 4, self.bounds.max.y - 2),
2178 _ => Vec2::new(self.bounds.max.x - 8, self.bounds.max.y - 2),
2179 }
2180 };
2181 let bed_dir = self.front.abs();
2182
2183 painter.bed_wood_woodland(bed_pos.with_z(alt), bed_dir);
2184 }
2185
2186 if self.christmas_decorations {
2187 let (wreath_pos, wreath_ori) = match self.front {
2188 Dir::Y => (
2189 Aabb {
2190 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 3)
2191 .with_z(alt + 2),
2192 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 4)
2193 .with_z(alt + 3),
2194 },
2195 4,
2196 ),
2197 Dir::X => (
2198 Aabb {
2199 min: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 1)
2200 .with_z(alt + 2),
2201 max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 2)
2202 .with_z(alt + 3),
2203 },
2204 2,
2205 ),
2206 Dir::NegY => (
2207 Aabb {
2208 min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y - 1)
2209 .with_z(alt + 2),
2210 max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y).with_z(alt + 3),
2211 },
2212 0,
2213 ),
2214 _ => (
2215 Aabb {
2216 min: Vec2::new(fireplace_origin.x - 1, fireplace_origin.y + 1)
2217 .with_z(alt + 2),
2218 max: Vec2::new(fireplace_origin.x, fireplace_origin.y + 2).with_z(alt + 3),
2219 },
2220 6,
2221 ),
2222 };
2223 painter.fill(
2224 painter.prim(Primitive::Aabb(wreath_pos)),
2225 Fill::Block(
2226 Block::air(SpriteKind::ChristmasWreath)
2227 .with_ori(wreath_ori)
2228 .unwrap(),
2229 ),
2230 );
2231 }
2232
2233 let doorway1 = match self.front {
2236 Dir::Y => Aabb {
2237 min: Vec2::new(door_tile_wpos.x - 1, self.bounds.max.y).with_z(alt),
2238 max: Vec2::new(door_tile_wpos.x + 3, self.bounds.max.y + 1).with_z(alt + 4),
2239 },
2240 Dir::X => Aabb {
2241 min: Vec2::new(self.bounds.max.x, door_tile_wpos.y - 1).with_z(alt),
2242 max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 3).with_z(alt + 4),
2243 },
2244 Dir::NegY => Aabb {
2245 min: Vec2::new(door_tile_wpos.x - 1, self.bounds.min.y).with_z(alt),
2246 max: Vec2::new(door_tile_wpos.x + 3, self.bounds.min.y + 1).with_z(alt + 4),
2247 },
2248 _ => Aabb {
2249 min: Vec2::new(self.bounds.min.x, door_tile_wpos.y - 1).with_z(alt),
2250 max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 3).with_z(alt + 4),
2251 },
2252 };
2253 painter.fill(painter.prim(Primitive::Aabb(doorway1)), wall_fill_lower);
2254
2255 let doorway2 = match self.front {
2257 Dir::Y => Aabb {
2258 min: Vec2::new(door_tile_wpos.x, self.bounds.max.y).with_z(alt),
2259 max: Vec2::new(door_tile_wpos.x + 2, self.bounds.max.y + 1).with_z(alt + 3),
2260 },
2261 Dir::X => Aabb {
2262 min: Vec2::new(self.bounds.max.x, door_tile_wpos.y).with_z(alt),
2263 max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 2).with_z(alt + 3),
2264 },
2265 Dir::NegY => Aabb {
2266 min: Vec2::new(door_tile_wpos.x, self.bounds.min.y).with_z(alt),
2267 max: Vec2::new(door_tile_wpos.x + 2, self.bounds.min.y + 1).with_z(alt + 3),
2268 },
2269 _ => Aabb {
2270 min: Vec2::new(self.bounds.min.x, door_tile_wpos.y).with_z(alt),
2271 max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 2).with_z(alt + 3),
2272 },
2273 };
2274 painter.fill(
2275 painter.prim(Primitive::Aabb(doorway2)),
2276 Fill::Block(Block::empty()),
2277 );
2278
2279 let (door_gap, door1, door1_ori, door2, door2_ori) = match self.front {
2281 Dir::Y => (
2282 Aabb {
2283 min: Vec2::new(door_tile_wpos.x - 1, self.bounds.max.y + 1).with_z(alt),
2284 max: Vec2::new(door_tile_wpos.x + 3, self.bounds.max.y + 4).with_z(alt + 3),
2285 },
2286 Aabb {
2287 min: Vec2::new(door_tile_wpos.x, self.bounds.max.y).with_z(alt),
2288 max: Vec2::new(door_tile_wpos.x + 1, self.bounds.max.y + 1).with_z(alt + 1),
2289 },
2290 0,
2291 Aabb {
2292 min: Vec2::new(door_tile_wpos.x + 1, self.bounds.max.y).with_z(alt),
2293 max: Vec2::new(door_tile_wpos.x + 2, self.bounds.max.y + 1).with_z(alt + 1),
2294 },
2295 4,
2296 ),
2297 Dir::X => (
2298 Aabb {
2299 min: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y - 1).with_z(alt),
2300 max: Vec2::new(self.bounds.max.x + 4, door_tile_wpos.y + 3).with_z(alt + 3),
2301 },
2302 Aabb {
2303 min: Vec2::new(self.bounds.max.x, door_tile_wpos.y).with_z(alt),
2304 max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 1).with_z(alt + 1),
2305 },
2306 2,
2307 Aabb {
2308 min: Vec2::new(self.bounds.max.x, door_tile_wpos.y + 1).with_z(alt),
2309 max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 2).with_z(alt + 1),
2310 },
2311 6,
2312 ),
2313 Dir::NegY => (
2314 Aabb {
2315 min: Vec2::new(door_tile_wpos.x - 1, self.bounds.min.y - 4).with_z(alt),
2316 max: Vec2::new(door_tile_wpos.x + 3, self.bounds.min.y).with_z(alt + 3),
2317 },
2318 Aabb {
2319 min: Vec2::new(door_tile_wpos.x, self.bounds.min.y).with_z(alt),
2320 max: Vec2::new(door_tile_wpos.x + 1, self.bounds.min.y + 1).with_z(alt + 1),
2321 },
2322 0,
2323 Aabb {
2324 min: Vec2::new(door_tile_wpos.x + 1, self.bounds.min.y).with_z(alt),
2325 max: Vec2::new(door_tile_wpos.x + 2, self.bounds.min.y + 1).with_z(alt + 1),
2326 },
2327 4,
2328 ),
2329 _ => (
2330 Aabb {
2331 min: Vec2::new(self.bounds.min.x - 4, door_tile_wpos.y - 1).with_z(alt),
2332 max: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 3).with_z(alt + 3),
2333 },
2334 Aabb {
2335 min: Vec2::new(self.bounds.min.x, door_tile_wpos.y).with_z(alt),
2336 max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 1).with_z(alt + 1),
2337 },
2338 2,
2339 Aabb {
2340 min: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 1).with_z(alt),
2341 max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 2).with_z(alt + 1),
2342 },
2343 6,
2344 ),
2345 };
2346 painter.fill(
2347 painter.prim(Primitive::Aabb(door_gap)),
2348 Fill::Block(Block::air(SpriteKind::Empty)),
2349 );
2350 painter.fill(
2351 painter.prim(Primitive::Aabb(door1)),
2352 Fill::Block(Block::air(SpriteKind::Door).with_ori(door1_ori).unwrap()),
2353 );
2354 painter.fill(
2355 painter.prim(Primitive::Aabb(door2)),
2356 Fill::Block(Block::air(SpriteKind::Door).with_ori(door2_ori).unwrap()),
2357 );
2358 if self.christmas_decorations {
2359 let rng = RandomField::new(0).get(door_tile_wpos.with_z(alt + 3));
2361 let right = (rng % 2) as i32;
2362 let (door_light_pos, door_light_ori) = match self.front {
2363 Dir::Y => (
2364 Aabb {
2365 min: Vec2::new(door_tile_wpos.x + right, self.bounds.max.y + 1)
2366 .with_z(alt + 3),
2367 max: Vec2::new(door_tile_wpos.x + 1 + right, self.bounds.max.y + 2)
2368 .with_z(alt + 4),
2369 },
2370 4,
2371 ),
2372 Dir::X => (
2373 Aabb {
2374 min: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + right)
2375 .with_z(alt + 3),
2376 max: Vec2::new(self.bounds.max.x + 2, door_tile_wpos.y + 1 + right)
2377 .with_z(alt + 4),
2378 },
2379 2,
2380 ),
2381 Dir::NegY => (
2382 Aabb {
2383 min: Vec2::new(door_tile_wpos.x + right, self.bounds.min.y - 1)
2384 .with_z(alt + 3),
2385 max: Vec2::new(door_tile_wpos.x + 1 + right, self.bounds.min.y)
2386 .with_z(alt + 4),
2387 },
2388 0,
2389 ),
2390 _ => (
2391 Aabb {
2392 min: Vec2::new(self.bounds.min.x - 1, door_tile_wpos.y + right)
2393 .with_z(alt + 3),
2394 max: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 1 + right)
2395 .with_z(alt + 4),
2396 },
2397 6,
2398 ),
2399 };
2400 painter.fill(
2401 painter.prim(Primitive::Aabb(door_light_pos)),
2402 Fill::Block(
2403 Block::air(SpriteKind::ChristmasOrnament)
2404 .with_ori(door_light_ori)
2405 .unwrap(),
2406 ),
2407 );
2408 }
2409 }
2410}