veloren_world/site/plot/
house.rs

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
35/// Represents house data generated by the `generate()` method
36pub struct House {
37    /// Tile position of the door tile
38    pub door_tile: Vec2<i32>,
39    /// Axis aligned bounding region of tiles
40    tile_aabr: Aabr<i32>,
41    /// Axis aligned bounding region for the house
42    bounds: Aabr<i32>,
43    /// Approximate altitude of the door tile
44    pub(crate) alt: i32,
45    /// Number of floors
46    levels: u32,
47    /// Difference between a level and the floor above
48    overhang: i32,
49    /// Color of the roof
50    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            // Don't use wood for some houses, even in woody areas
87            .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            // Nothing else can support stone
109            Style::Stone => Style::Stone,
110            Style::Brick => Style::Brick,
111            // Stone may appear below anything else
112            _ 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                // Overhangs of 3 at this building height are ill-advised.
131                // Failure to comply with Veloren building code will result
132                // in a fine and a revoked building permit.
133                *[-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                // Single story buildings require no overhangs
138                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            // Style::Brick => Fill::Block(Block::new(BlockKind::Rock, Rgb::new(40, 44, 45))),
187            _ => Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
188        };
189
190        // Roof
191        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), /* self.bounds.min - roof_lip).with_z(alt +
221                                                      * roof), */
222                            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), /* self.bounds.min - roof_lip).with_z(alt +
257                                                      * roof), */
258                            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        // Walls
585        // For each storey...
586        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            // Walls
593            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            // Wall Pillars
702            // Only upper non-stone floors have wooden beams in the walls
703            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                            //2 => site.tile_wpos(Vec2::new(x, self.tile_aabr.min.y)),
712                            _ => Vec2::zero(),
713                        };
714                        // NOTE: Orientation 2 doesn't work for some reason. I believe it is
715                        // something to do with AABBs with min and max not smaller in the right
716                        // order. The same thing is true for orientation 3.
717                        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                            //2 => {
732                            //    painter.line(
733                            //    Vec2::new(temp.x, self.bounds.min.y - storey_increase -
734                            // 6).with_z(alt + previous_height + 30),
735                            //    Vec2::new(temp.x + 1, self.bounds.min.y - storey_increase
736                            // - 3).with_z(alt + previous_height - 3), 1.0)
737                            //},
738                            _ => 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            // Windows x axis
922            {
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                // Wall lamps
951                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            // Windows y axis
986            {
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                // Wall lamps
1015                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            // Shed roof on negative overhangs
1051            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                // Dormers
1329                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            // Floor
1548            // No extra floor needed for the ground floor
1549            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            // interior furniture sprites
1633            let base = alt + (storey * (i as i32 - 1)).max(0);
1634            if i % 2 == 0 {
1635                // bedroom on even-leveled floors
1636                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                // drawer next to bed
1649                painter.sprite(nightstand_pos.with_z(base), SpriteKind::DrawerWoodWoodlandS);
1650                // collectible on top of drawer
1651                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                // wardrobe along wall in corner of the room
1665                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                // living room with table + chairs + random
1687                for dir in DIRS {
1688                    // random accent pieces and loot
1689                    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                    // room is smaller, so use small table
1710                    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                    // room is bigger, so use large table + chair positions
1724                    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                // drawer along a wall
1739                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            // Stairs
1753            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 = /*match self.front */{
1768                        //0 => {
1769                            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                        /*},
1778                        1 => {
1779                            painter.prim(Primitive::Ramp {
1780                                aabb: Aabb {
1781                                    min: Vec2::new(stair_origin.x, stair_origin.y + 3).with_z(alt + previous_floor_height),
1782                                    max: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 10).with_z(alt + previous_height + 1),
1783                                },
1784                                inset: storey,
1785                                dir: 0,
1786                            })
1787                        },
1788                        2 => {
1789                            painter.prim(Primitive::Ramp {
1790                                aabb: Aabb {
1791                                    min: Vec2::new(stair_origin.x + 3, stair_origin.y).with_z(alt + previous_floor_height),
1792                                    max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
1793                                },
1794                                inset: storey,
1795                                dir: 0,
1796                            })
1797                        },
1798                        _ => {
1799                            painter.prim(Primitive::Ramp {
1800                                aabb: Aabb {
1801                                    min: Vec2::new(stair_origin.x, stair_origin.y + 3).with_z(alt + previous_floor_height),
1802                                    max: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 10).with_z(alt + previous_height + 1),
1803                                },
1804                                inset: storey,
1805                                dir: 0,
1806                            })
1807                        }*/
1808                    };
1809                    let support = {
1810                        //match self.front {
1811                        //0 => {
1812                        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                        //},
1819                        //1 => {
1820                        //    painter.prim(Primitive::Aabb(Aabb {
1821                        //        min: Vec2::new(stair_origin.x, stair_origin.y
1822                        // + 10).with_z(alt + previous_floor_height), max:
1823                        //   Vec2::new(stair_origin.x + stair_width,
1824                        // stair_origin.y + 12).with_z(alt + previous_height +
1825                        // 1),    }))
1826                        //},
1827                        //2 => {
1828                        //    painter.prim(Primitive::Aabb(Aabb {
1829                        //        min: Vec2::new(stair_origin.x + 10,
1830                        // stair_origin.y).with_z(alt + previous_floor_height),
1831                        //        max: Vec2::new(stair_origin.x + 12,
1832                        // stair_origin.y + stair_width).with_z(alt +
1833                        // previous_height + 1),    }))
1834                        //},
1835                        //_ => {
1836                        //    painter.prim(Primitive::Aabb(Aabb {
1837                        //        min: Vec2::new(stair_origin.x, stair_origin.y
1838                        // + 10).with_z(alt + previous_floor_height), max:
1839                        //   Vec2::new(stair_origin.x + stair_width,
1840                        // stair_origin.y + 12).with_z(alt + previous_height +
1841                        // 1),    }))
1842                        //},
1843                    };
1844                    painter.prim(Primitive::union(ramp, support))
1845                } else {
1846                    let ramp = /*match self.front */{
1847                        //0 => {
1848                            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                        /*},
1857                        1 => {
1858                            painter.prim(Primitive::Ramp {
1859                                aabb: Aabb {
1860                                    min: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 1).with_z(alt + previous_floor_height),
1861                                    max: Vec2::new(stair_origin.x + 2 * stair_width, stair_origin.y + 8).with_z(alt + previous_height + 1),
1862                                },
1863                                inset: storey,
1864                                dir: 1,
1865                            })
1866                        },
1867                        2 => {
1868                            painter.prim(Primitive::Ramp {
1869                                aabb: Aabb {
1870                                    min: Vec2::new(stair_origin.x + 1, stair_origin.y + stair_width).with_z(alt + previous_floor_height),
1871                                    max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
1872                                },
1873                                inset: storey,
1874                                dir: 1,
1875                            })
1876                        },
1877                        _ => {
1878                            painter.prim(Primitive::Ramp {
1879                                aabb: Aabb {
1880                                    min: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 1).with_z(alt + previous_floor_height),
1881                                    max: Vec2::new(stair_origin.x + 2 * stair_width, stair_origin.y + 8).with_z(alt + previous_height + 1),
1882                                },
1883                                inset: storey,
1884                                dir: 1,
1885                            })
1886                        },
1887                        */
1888                    };
1889                    let support = {
1890                        //match self.front {
1891                        //0 => {
1892                        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                        //},
1899                        //1 => {
1900                        //    painter.prim(Primitive::Aabb(Aabb {
1901                        //        min: Vec2::new(stair_origin.x + stair_width,
1902                        // stair_origin.y).with_z(alt + previous_floor_height),
1903                        //        max: Vec2::new(stair_origin.x + 2 *
1904                        // stair_width, stair_origin.y + 2).with_z(alt +
1905                        // previous_height + 1),    }))
1906                        //},
1907                        //2 => {
1908                        //    painter.prim(Primitive::Aabb(Aabb {
1909                        //        min: Vec2::new(stair_origin.x, stair_origin.y
1910                        // + stair_width).with_z(alt + previous_floor_height),
1911                        //   max: Vec2::new(stair_origin.x + 2,
1912                        // stair_origin.y + 2 * stair_width).with_z(alt +
1913                        // previous_height + 1),    }))
1914                        //},
1915                        //_ => {
1916                        //    painter.prim(Primitive::Aabb(Aabb {
1917                        //        min: Vec2::new(stair_origin.x + stair_width,
1918                        // stair_origin.y).with_z(alt + previous_floor_height),
1919                        //        max: Vec2::new(stair_origin.x + 2 *
1920                        // stair_width, stair_origin.y + 2).with_z(alt +
1921                        // previous_height + 1),    }))
1922                        //},
1923                    };
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                    //match self.front {
1936                    //    0 => {
1937                    //        painter.prim(Primitive::Aabb(Aabb {
1938                    //                min: Vec2::new(stair_origin.x,
1939                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1940                    //                max: Vec2::new(stair_origin.x + 9,
1941                    // stair_origin.y + stair_width).with_z(alt +
1942                    // previous_height + 1),        }))
1943                    //    },
1944                    //    1 => {
1945                    //        painter.prim(Primitive::Aabb(Aabb {
1946                    //                min: Vec2::new(stair_origin.x,
1947                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1948                    //                max: Vec2::new(stair_origin.x +
1949                    // stair_width, stair_origin.y + 9).with_z(alt +
1950                    // previous_height + 1),        }))
1951                    //    },
1952                    //    2 => {
1953                    //        painter.prim(Primitive::Aabb(Aabb {
1954                    //                min: Vec2::new(stair_origin.x,
1955                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1956                    //                max: Vec2::new(stair_origin.x + 9,
1957                    // stair_origin.y + stair_width).with_z(alt +
1958                    // previous_height + 1),        }))
1959                    //    },
1960                    //    _ => {
1961                    //        painter.prim(Primitive::Aabb(Aabb {
1962                    //                min: Vec2::new(stair_origin.x,
1963                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1964                    //                max: Vec2::new(stair_origin.x +
1965                    // stair_width, stair_origin.y + 9).with_z(alt +
1966                    // previous_height + 1),        }))
1967                    //    },
1968                    //}
1969                } 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                    //match self.front {
1977                    //    0 => {
1978                    //        painter.prim(Primitive::Aabb(Aabb {
1979                    //                min: Vec2::new(stair_origin.x + 2,
1980                    // stair_origin.y + stair_width).with_z(alt +
1981                    // previous_floor_height + 1),
1982                    //                max: Vec2::new(stair_origin.x + 11,
1983                    // stair_origin.y + 2 * stair_width).with_z(alt +
1984                    // previous_height + 1),        }))
1985                    //    },
1986                    //    1 => {
1987                    //        painter.prim(Primitive::Aabb(Aabb {
1988                    //                min: Vec2::new(stair_origin.x +
1989                    // stair_width, stair_origin.y + 2).with_z(alt +
1990                    // previous_floor_height + 1),
1991                    //                max: Vec2::new(stair_origin.x + 2 *
1992                    // stair_width, stair_origin.y + 11).with_z(alt +
1993                    // previous_height + 1),        }))
1994                    //    },
1995                    //    2 => {
1996                    //        painter.prim(Primitive::Aabb(Aabb {
1997                    //                min: Vec2::new(stair_origin.x + 2,
1998                    // stair_origin.y + stair_width).with_z(alt +
1999                    // previous_floor_height + 1),
2000                    //                max: Vec2::new(stair_origin.x + 11,
2001                    // stair_origin.y + 2 * stair_width).with_z(alt +
2002                    // previous_height + 1),        }))
2003                    //    },
2004                    //    _ => {
2005                    //        painter.prim(Primitive::Aabb(Aabb {
2006                    //                min: Vec2::new(stair_origin.x +
2007                    // stair_width, stair_origin.y + 2).with_z(alt +
2008                    // previous_floor_height + 1),
2009                    //                max: Vec2::new(stair_origin.x + 2 *
2010                    // stair_width, stair_origin.y + 11).with_z(alt +
2011                    // previous_height + 1),        }))
2012                    //    },
2013                    //}
2014                };
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        // Foundation
2025        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        // Fireplace and chimney
2034        let fireplace_origin = /*if self.levels > 1 {
2035            match self.front {
2036                0 => {
2037                    Vec2::new(self.bounds.min.x + 12, self.bounds.min.y + 1)
2038                },
2039                1 => {
2040                    Vec2::new(self.bounds.min.x + 1, self.bounds.max.y - 12)
2041                },
2042                2 => {
2043                    Vec2::new(self.bounds.max.x - 12, self.bounds.max.y - 1)
2044                },
2045                _ => {
2046                    Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 12)
2047                },
2048            }
2049        } else */{
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        // bedroom on first level corners in case there is no 2nd level
2162        if self.levels == 1 {
2163            // different positions for smaller houses
2164            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        // Door
2234        // Fill around the door with wall
2235        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        // Carve out the doorway with air
2256        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        // Fill in the right and left side doors
2280        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            // we need to randomize position to see both variants
2360            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}