Skip to main content

veloren_world/site/plot/
house.rs

1use super::*;
2use crate::{
3    Land,
4    all::ForestKind,
5    site::util::sprites::PainterSpriteExt,
6    util::{DIRS, RandomField, Sampler},
7};
8use common::{
9    calendar::{Calendar, CalendarEvent},
10    terrain::{Block, BlockKind, SpriteKind},
11};
12use rand::{prelude::*, seq::IndexedRandom};
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: Dir2,
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.random_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 => Dir2::NegY,
77            dir if dir.x < 0 => Dir2::NegX,
78            dir if dir.y > 0 => Dir2::Y,
79            _ => Dir2::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.random())
86            // Don't use wood for some houses, even in woody areas
87            .filter(|_| rng.random_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.random_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.random_bool(0.3) => Style::Brick,
113            _ if rng.random_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 = "dyn-lib")]
169    #[unsafe(export_name = "as_dyn_structure_house")]
170    fn as_dyn_outer(&self) -> Option<(&dyn Structure, &'static str)> {
171        Some((Self::as_dyn_impl(self), "as_dyn_structure_house"))
172    }
173
174    fn spawn_rules_inner(
175        &self,
176        spawn_rules: &mut SpawnRules,
177        _land: &Land,
178        _wpos: Vec2<i32>,
179        weight: f32,
180    ) {
181        spawn_rules.prefer_alt(self.alt as f32, weight + weight.powi(8) * 25.0);
182    }
183
184    fn door_tile(&self) -> Option<Vec2<i32>> { Some(self.door_tile) }
185
186    fn render_inner(&self, site: &Site, _land: &Land, painter: &Painter) {
187        let storey = STOREY;
188        let roof = storey * self.levels as i32 - 1;
189        let foundations = 20;
190        let alt = self.alt + 1;
191        let door_tile_wpos = site.tile_center_wpos(self.door_tile);
192
193        let wall_fill_upper = self.upper_style.get_fill();
194        let wall_fill_lower = self.lower_style.get_fill();
195        let wall_fill_gable = self.gable_style.get_fill();
196
197        let pillar_fill = match self.upper_style {
198            Style::Wooden(color) => Fill::Block(Block::new(BlockKind::Wood, color / 2)),
199            Style::Brick => Fill::Block(Block::new(BlockKind::Rock, Rgb::new(85, 35, 8))),
200            // Style::Brick => Fill::Block(Block::new(BlockKind::Rock, Rgb::new(40, 44, 45))),
201            _ => Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
202        };
203
204        // Roof
205        let roof_lip = 1;
206        let roof_height = (self.bounds.min - self.bounds.max)
207            .map(|e| e.abs())
208            .reduce_min()
209            / 2
210            + roof_lip
211            + 1;
212
213        let (roof_primitive, roof_empty) = match self.front {
214            Dir2::Y => {
215                (
216                    painter.prim(Primitive::Gable {
217                        aabb: Aabb {
218                            min: (self.bounds.min - roof_lip).with_z(alt + roof),
219                            max: (Vec2::new(
220                                self.bounds.max.x + 1 + roof_lip,
221                                self.bounds.max.y
222                                    + 1
223                                    + roof_lip
224                                    + (self.levels as i32 - 1) * self.overhang,
225                            ))
226                            .with_z(alt + roof + roof_height),
227                        },
228                        inset: roof_height,
229                        dir: Dir2::Y,
230                    }),
231                    painter.prim(Primitive::Gable {
232                        aabb: Aabb {
233                            min: (Vec2::new(self.bounds.min.x, self.bounds.min.y - 1))
234                                .with_z(alt + roof), /* self.bounds.min - roof_lip).with_z(alt +
235                                                      * roof), */
236                            max: (Vec2::new(
237                                self.bounds.max.x + 1,
238                                self.bounds.max.y
239                                    + 1
240                                    + (self.levels as i32 - 1) * self.overhang
241                                    + 1,
242                            ))
243                            .with_z(alt + roof + roof_height - 1),
244                        },
245                        inset: roof_height - 1,
246                        dir: Dir2::Y,
247                    }),
248                )
249            },
250            Dir2::X => {
251                (
252                    painter.prim(Primitive::Gable {
253                        aabb: Aabb {
254                            min: (self.bounds.min - roof_lip).with_z(alt + roof),
255                            max: Vec2::new(
256                                self.bounds.max.x
257                                    + 1
258                                    + roof_lip
259                                    + (self.levels as i32 - 1) * self.overhang,
260                                self.bounds.max.y + 1 + roof_lip,
261                            )
262                            .with_z(alt + roof + roof_height),
263                        },
264                        inset: roof_height,
265                        dir: Dir2::X,
266                    }),
267                    painter.prim(Primitive::Gable {
268                        aabb: Aabb {
269                            min: (Vec2::new(self.bounds.min.x - 1, self.bounds.min.y))
270                                .with_z(alt + roof), /* self.bounds.min - roof_lip).with_z(alt +
271                                                      * roof), */
272                            max: Vec2::new(
273                                self.bounds.max.x
274                                    + 1
275                                    + (self.levels as i32 - 1) * self.overhang
276                                    + 1,
277                                self.bounds.max.y + 1,
278                            )
279                            .with_z(alt + roof + roof_height - 1),
280                        },
281                        inset: roof_height - 1,
282                        dir: Dir2::X,
283                    }),
284                )
285            },
286            Dir2::NegY => (
287                painter.prim(Primitive::Gable {
288                    aabb: Aabb {
289                        min: Vec2::new(
290                            self.bounds.min.x - roof_lip,
291                            self.bounds.min.y - roof_lip - (self.levels as i32 - 1) * self.overhang,
292                        )
293                        .with_z(alt + roof),
294                        max: Vec2::new(
295                            self.bounds.max.x + 1 + roof_lip,
296                            self.bounds.max.y + roof_lip + 1,
297                        )
298                        .with_z(alt + roof + roof_height),
299                    },
300                    inset: roof_height,
301                    dir: Dir2::Y,
302                }),
303                painter.prim(Primitive::Gable {
304                    aabb: Aabb {
305                        min: Vec2::new(
306                            self.bounds.min.x,
307                            self.bounds.min.y - 1 - (self.levels as i32 - 1) * self.overhang - 1,
308                        )
309                        .with_z(alt + roof),
310                        max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + roof_lip + 1)
311                            .with_z(alt + roof + roof_height - 1),
312                    },
313                    inset: roof_height - 1,
314                    dir: Dir2::Y,
315                }),
316            ),
317            _ => (
318                painter.prim(Primitive::Gable {
319                    aabb: Aabb {
320                        min: Vec2::new(
321                            self.bounds.min.x - roof_lip - (self.levels as i32 - 1) * self.overhang,
322                            self.bounds.min.y - roof_lip,
323                        )
324                        .with_z(alt + roof),
325                        max: Vec2::new(
326                            self.bounds.max.x + 1 + roof_lip,
327                            self.bounds.max.y + 1 + roof_lip,
328                        )
329                        .with_z(alt + roof + roof_height),
330                    },
331                    inset: roof_height,
332                    dir: Dir2::X,
333                }),
334                painter.prim(Primitive::Gable {
335                    aabb: Aabb {
336                        min: Vec2::new(
337                            self.bounds.min.x
338                                - roof_lip
339                                - 1
340                                - (self.levels as i32 - 1) * self.overhang,
341                            self.bounds.min.y,
342                        )
343                        .with_z(alt + roof),
344                        max: Vec2::new(self.bounds.max.x + 1 + roof_lip, self.bounds.max.y + 1)
345                            .with_z(alt + roof + roof_height - 1),
346                    },
347                    inset: roof_height - 1,
348                    dir: Dir2::X,
349                }),
350            ),
351        };
352
353        let (roof_front_wall, roof_rear_wall) = match self.front {
354            Dir2::Y => (
355                painter.prim(Primitive::Aabb(Aabb {
356                    min: (Vec2::new(
357                        self.bounds.min.x,
358                        self.bounds.max.y + (self.levels as i32 - 1) * self.overhang,
359                    ))
360                    .with_z(alt + roof),
361                    max: (Vec2::new(
362                        self.bounds.max.x + 1,
363                        self.bounds.max.y + (self.levels as i32 - 1) * self.overhang + 1,
364                    ))
365                    .with_z(alt + roof + roof_height),
366                })),
367                painter.prim(Primitive::Aabb(Aabb {
368                    min: (Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof)),
369                    max: (Vec2::new(self.bounds.max.x + 1, self.bounds.min.y + 1)
370                        .with_z(alt + roof + roof_height)),
371                })),
372            ),
373            Dir2::X => (
374                painter.prim(Primitive::Aabb(Aabb {
375                    min: Vec2::new(
376                        self.bounds.max.x + (self.levels as i32 - 1) * self.overhang,
377                        self.bounds.min.y,
378                    )
379                    .with_z(alt + roof),
380                    max: Vec2::new(
381                        self.bounds.max.x + (self.levels as i32 - 1) * self.overhang + 1,
382                        self.bounds.max.y + 1,
383                    )
384                    .with_z(alt + roof + roof_height),
385                })),
386                painter.prim(Primitive::Aabb(Aabb {
387                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
388                    max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1)
389                        .with_z(alt + roof + roof_height),
390                })),
391            ),
392            Dir2::NegY => (
393                painter.prim(Primitive::Aabb(Aabb {
394                    min: Vec2::new(
395                        self.bounds.min.x,
396                        self.bounds.min.y - (self.levels as i32 - 1) * self.overhang,
397                    )
398                    .with_z(alt + roof),
399                    max: Vec2::new(
400                        self.bounds.max.x + 1,
401                        self.bounds.min.y - (self.levels as i32 - 1) * self.overhang + 1,
402                    )
403                    .with_z(alt + roof + roof_height),
404                })),
405                painter.prim(Primitive::Aabb(Aabb {
406                    min: Vec2::new(self.bounds.min.x, self.bounds.max.y).with_z(alt + roof),
407                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
408                        .with_z(alt + roof + roof_height),
409                })),
410            ),
411            _ => (
412                painter.prim(Primitive::Aabb(Aabb {
413                    min: Vec2::new(
414                        self.bounds.min.x - (self.levels as i32 - 1) * self.overhang,
415                        self.bounds.min.y,
416                    )
417                    .with_z(alt + roof),
418                    max: Vec2::new(
419                        self.bounds.min.x - (self.levels as i32 - 1) * self.overhang + 1,
420                        self.bounds.max.y + 1,
421                    )
422                    .with_z(alt + roof + roof_height),
423                })),
424                painter.prim(Primitive::Aabb(Aabb {
425                    min: Vec2::new(self.bounds.max.x, self.bounds.min.y).with_z(alt + roof),
426                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
427                        .with_z(alt + roof + roof_height),
428                })),
429            ),
430        };
431        let roof_front = painter.prim(Primitive::intersect(roof_empty, roof_front_wall));
432        let roof_rear = painter.prim(Primitive::intersect(roof_empty, roof_rear_wall));
433        painter.fill(
434            roof_primitive,
435            Fill::Brick(BlockKind::Wood, self.roof_color, 24),
436        );
437        painter.fill(roof_empty, Fill::Block(Block::empty()));
438        let roof_walls = painter.prim(Primitive::union(roof_front, roof_rear));
439        painter.fill(roof_walls, wall_fill_gable.clone());
440        let max_overhang = (self.levels as i32 - 1) * self.overhang;
441        let (roof_beam, roof_beam_right, roof_beam_left) = match self.front {
442            Dir2::Y => (
443                painter.prim(Primitive::Aabb(Aabb {
444                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
445                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1 + max_overhang)
446                        .with_z(alt + roof + 1),
447                })),
448                painter.prim(Primitive::Aabb(Aabb {
449                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
450                    max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1 + max_overhang)
451                        .with_z(alt + roof + 1),
452                })),
453                painter.prim(Primitive::Aabb(Aabb {
454                    min: Vec2::new(self.bounds.max.x, self.bounds.min.y).with_z(alt + roof),
455                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1 + max_overhang)
456                        .with_z(alt + roof + 1),
457                })),
458            ),
459            Dir2::X => (
460                painter.prim(Primitive::Aabb(Aabb {
461                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
462                    max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.max.y + 1)
463                        .with_z(alt + roof + 1),
464                })),
465                painter.prim(Primitive::Aabb(Aabb {
466                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
467                    max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.min.y + 1)
468                        .with_z(alt + roof + 1),
469                })),
470                painter.prim(Primitive::Aabb(Aabb {
471                    min: Vec2::new(self.bounds.min.x, self.bounds.max.y).with_z(alt + roof),
472                    max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.max.y + 1)
473                        .with_z(alt + roof + 1),
474                })),
475            ),
476            Dir2::NegY => (
477                painter.prim(Primitive::Aabb(Aabb {
478                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y - max_overhang)
479                        .with_z(alt + roof),
480                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
481                        .with_z(alt + roof + 1),
482                })),
483                painter.prim(Primitive::Aabb(Aabb {
484                    min: Vec2::new(self.bounds.max.x, self.bounds.min.y - max_overhang)
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, self.bounds.min.y - max_overhang)
491                        .with_z(alt + roof),
492                    max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1)
493                        .with_z(alt + roof + 1),
494                })),
495            ),
496            _ => (
497                painter.prim(Primitive::Aabb(Aabb {
498                    min: Vec2::new(self.bounds.min.x - max_overhang - 1, self.bounds.min.y)
499                        .with_z(alt + roof),
500                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
501                        .with_z(alt + roof + 1),
502                })),
503                painter.prim(Primitive::Aabb(Aabb {
504                    min: Vec2::new(self.bounds.min.x - max_overhang, self.bounds.min.y)
505                        .with_z(alt + roof),
506                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.min.y + 1)
507                        .with_z(alt + roof + 1),
508                })),
509                painter.prim(Primitive::Aabb(Aabb {
510                    min: Vec2::new(self.bounds.min.x - max_overhang, self.bounds.max.y)
511                        .with_z(alt + roof),
512                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
513                        .with_z(alt + roof + 1),
514                })),
515            ),
516        };
517        let quarter_x = self.bounds.min.x + (self.bounds.max.x - self.bounds.min.x) / 4;
518        let quarter_y = self.bounds.min.y + (self.bounds.max.y - self.bounds.min.y) / 4;
519        let half_x = self.bounds.min.x + (self.bounds.max.x - self.bounds.min.x) / 2;
520        let half_y = self.bounds.min.y + (self.bounds.max.y - self.bounds.min.y) / 2;
521        let three_quarter_x = self.bounds.min.x + 3 * (self.bounds.max.x - self.bounds.min.x) / 4;
522        let three_quarter_y = self.bounds.min.y + 3 * (self.bounds.max.y - self.bounds.min.y) / 4;
523        let top_rafter = if self.front.is_y() {
524            painter.prim(Primitive::Aabb(Aabb {
525                min: (Vec2::new(half_x, self.bounds.min.y - 2 - max_overhang.abs())
526                    .with_z(alt + roof)),
527                max: (Vec2::new(half_x + 1, self.bounds.max.y + 2 + max_overhang.abs()))
528                    .with_z(alt + roof + roof_height),
529            }))
530        } else {
531            painter.prim(Primitive::Aabb(Aabb {
532                min: (Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y)
533                    .with_z(alt + roof)),
534                max: (Vec2::new(self.bounds.max.x + 1 + max_overhang.abs(), half_y + 1))
535                    .with_z(alt + roof + roof_height),
536            }))
537        };
538        let left_rafter = if self.front.is_y() {
539            painter.prim(Primitive::Plane(
540                Aabr {
541                    min: Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()),
542                    max: Vec2::new(
543                        three_quarter_x + 1,
544                        self.bounds.max.y + 1 + max_overhang.abs(),
545                    ),
546                },
547                Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()).with_z(alt + roof),
548                Vec2::new(1.0, 0.0),
549            ))
550        } else {
551            painter.prim(Primitive::Plane(
552                Aabr {
553                    min: Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y),
554                    max: Vec2::new(
555                        self.bounds.max.x + 1 + max_overhang.abs(),
556                        three_quarter_y + 1,
557                    ),
558                },
559                Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y).with_z(alt + roof),
560                Vec2::new(0.0, 1.0),
561            ))
562        };
563        let right_rafter = if self.front.is_y() {
564            painter.prim(Primitive::Plane(
565                Aabr {
566                    min: Vec2::new(quarter_x, self.bounds.min.y - 1 - max_overhang.abs()),
567                    max: Vec2::new(half_x + 1, self.bounds.max.y + 1 + max_overhang.abs()),
568                },
569                Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()).with_z(alt + roof),
570                Vec2::new(1.0, 0.0),
571            ))
572        } else {
573            painter.prim(Primitive::Plane(
574                Aabr {
575                    min: Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), quarter_y),
576                    max: Vec2::new(self.bounds.max.x + 1 + max_overhang.abs(), half_y + 1),
577                },
578                Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y).with_z(alt + roof),
579                Vec2::new(0.0, 1.0),
580            ))
581        };
582        let rafters1 = painter.prim(Primitive::union(left_rafter, right_rafter));
583        let rafters2 = painter.prim(Primitive::union(rafters1, top_rafter));
584
585        painter.fill(
586            painter.prim(Primitive::intersect(roof_beam, roof_walls)),
587            pillar_fill.clone(),
588        );
589        painter.fill(
590            painter.prim(Primitive::union(roof_beam_left, roof_beam_right)),
591            pillar_fill.clone(),
592        );
593        painter.fill(
594            painter.prim(Primitive::intersect(rafters2, roof_walls)),
595            pillar_fill.clone(),
596        );
597
598        // Walls
599        // For each storey...
600        for i in 1..self.levels + 1 {
601            let previous_height = (storey * (i as i32 - 1) - 1).max(-1);
602            let height = storey * i as i32 - 1;
603            let window_height = storey - 3;
604            let storey_increase = (i as i32 - 1) * self.overhang;
605
606            // Walls
607            let inner_level = if self.overhang < -4 && i > 1 {
608                match self.front {
609                    Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
610                        min: (self.bounds.min + 1).with_z(alt + previous_height),
611                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase + 1)
612                            .with_z(alt + height),
613                    })),
614                    Dir2::X => painter.prim(Primitive::Aabb(Aabb {
615                        min: (self.bounds.min + 1).with_z(alt + previous_height),
616                        max: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.max.y)
617                            .with_z(alt + height),
618                    })),
619                    Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
620                        min: Vec2::new(
621                            self.bounds.min.x + 1,
622                            self.bounds.min.y - storey_increase + 1,
623                        )
624                        .with_z(alt + previous_height),
625                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
626                    })),
627                    _ => painter.prim(Primitive::Aabb(Aabb {
628                        min: Vec2::new(
629                            self.bounds.min.x - storey_increase + 1,
630                            self.bounds.min.y + 1,
631                        )
632                        .with_z(alt + previous_height),
633                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
634                    })),
635                }
636            } else {
637                match self.front {
638                    Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
639                        min: (self.bounds.min + 1).with_z(alt + previous_height),
640                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase)
641                            .with_z(alt + height),
642                    })),
643                    Dir2::X => painter.prim(Primitive::Aabb(Aabb {
644                        min: (self.bounds.min + 1).with_z(alt + previous_height),
645                        max: (Vec2::new(self.bounds.max.x + storey_increase, self.bounds.max.y))
646                            .with_z(alt + height),
647                    })),
648                    Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
649                        min: Vec2::new(
650                            self.bounds.min.x + 1,
651                            self.bounds.min.y - storey_increase + 1,
652                        )
653                        .with_z(alt + previous_height),
654                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
655                    })),
656                    _ => painter.prim(Primitive::Aabb(Aabb {
657                        min: Vec2::new(
658                            self.bounds.min.x - storey_increase + 1,
659                            self.bounds.min.y + 1,
660                        )
661                        .with_z(alt + previous_height),
662                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
663                    })),
664                }
665            };
666            let outer_level = match self.front {
667                Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
668                    min: self.bounds.min.with_z(alt + previous_height),
669                    max: (Vec2::new(
670                        self.bounds.max.x + 1,
671                        self.bounds.max.y + storey_increase + 1,
672                    ))
673                    .with_z(alt + height),
674                })),
675                Dir2::X => painter.prim(Primitive::Aabb(Aabb {
676                    min: self.bounds.min.with_z(alt + previous_height),
677                    max: Vec2::new(
678                        self.bounds.max.x + storey_increase + 1,
679                        self.bounds.max.y + 1,
680                    )
681                    .with_z(alt + height),
682                })),
683                Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
684                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y - storey_increase)
685                        .with_z(alt + previous_height),
686                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
687                        .with_z(alt + height),
688                })),
689                _ => painter.prim(Primitive::Aabb(Aabb {
690                    min: Vec2::new(self.bounds.min.x - storey_increase, self.bounds.min.y)
691                        .with_z(alt + previous_height),
692                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
693                        .with_z(alt + height),
694                })),
695            };
696
697            let is_lower = i <= 1;
698            let style = if is_lower {
699                self.lower_style
700            } else {
701                self.upper_style
702            };
703            let wall_block_fill = if is_lower {
704                wall_fill_lower.clone()
705            } else {
706                wall_fill_upper.clone()
707            };
708            painter.fill(outer_level, wall_block_fill);
709            painter.fill(inner_level, Fill::Block(Block::empty()));
710
711            let walls = outer_level
712                .union(inner_level)
713                .without(outer_level.intersect(inner_level));
714
715            // Wall Pillars
716            // Only upper non-stone floors have wooden beams in the walls
717            if !matches!(style, Style::Stone) {
718                let mut pillars_y = painter.prim(Primitive::Empty);
719                let mut overhang_supports = painter.prim(Primitive::Empty);
720
721                for x in self.tile_aabr.min.x - 2..self.tile_aabr.max.x + 2 {
722                    if self.overhang >= 2 && self.front.is_y() {
723                        let temp = match self.front {
724                            Dir2::Y => site.tile_wpos(Vec2::new(x, self.tile_aabr.max.y)),
725                            //2 => site.tile_wpos(Vec2::new(x, self.tile_aabr.min.y)),
726                            _ => Vec2::zero(),
727                        };
728                        // NOTE: Orientation 2 doesn't work for some reason. I believe it is
729                        // something to do with AABBs with min and max not smaller in the right
730                        // order. The same thing is true for orientation 3.
731                        let support = match self.front {
732                            Dir2::Y => painter.line(
733                                Vec2::new(
734                                    temp.x,
735                                    self.bounds.max.y + storey_increase - self.overhang + 1,
736                                )
737                                .with_z(alt + previous_height - 3),
738                                Vec2::new(
739                                    temp.x,
740                                    self.bounds.max.y + storey_increase - self.overhang + 2,
741                                )
742                                .with_z(alt + previous_height),
743                                0.75,
744                            ),
745                            //2 => {
746                            //    painter.line(
747                            //    Vec2::new(temp.x, self.bounds.min.y - storey_increase -
748                            // 6).with_z(alt + previous_height + 30),
749                            //    Vec2::new(temp.x + 1, self.bounds.min.y - storey_increase
750                            // - 3).with_z(alt + previous_height - 3), 1.0)
751                            //},
752                            _ => painter.prim(Primitive::Empty),
753                        };
754                        if temp.x <= self.bounds.max.x && temp.x >= self.bounds.min.x {
755                            overhang_supports =
756                                painter.prim(Primitive::union(overhang_supports, support));
757                        }
758                    }
759                    let pillar = painter.prim(Primitive::Aabb(Aabb {
760                        min: site
761                            .tile_wpos(Vec2::new(x, self.tile_aabr.min.y - 4))
762                            .with_z(alt + previous_height),
763                        max: (site.tile_wpos(Vec2::new(x, self.tile_aabr.max.y + 4))
764                            + Vec2::unit_x())
765                        .with_z(alt + height),
766                    }));
767                    pillars_y = painter.prim(Primitive::union(pillars_y, pillar));
768                }
769                let mut pillars_x = painter.prim(Primitive::Empty);
770                for y in self.tile_aabr.min.y - 2..self.tile_aabr.max.y + 2 {
771                    if self.overhang >= 2 && !self.front.is_y() {
772                        let temp = match self.front {
773                            Dir2::Y => Vec2::zero(),
774                            Dir2::X => site.tile_wpos(Vec2::new(self.tile_aabr.max.x, y)),
775                            Dir2::NegY => Vec2::zero(),
776                            _ => site.tile_wpos(Vec2::new(self.tile_aabr.min.x, y)),
777                        };
778                        let support = match self.front {
779                            Dir2::Y => painter.prim(Primitive::Empty),
780                            Dir2::X => painter.line(
781                                Vec2::new(
782                                    self.bounds.max.x + storey_increase - self.overhang + 1,
783                                    temp.y,
784                                )
785                                .with_z(alt + previous_height - 3),
786                                Vec2::new(
787                                    self.bounds.max.x + storey_increase - self.overhang + 2,
788                                    temp.y,
789                                )
790                                .with_z(alt + previous_height),
791                                0.75,
792                            ),
793                            Dir2::NegY => painter.prim(Primitive::Empty),
794                            _ => painter.line(
795                                Vec2::new(
796                                    self.bounds.min.x - storey_increase + self.overhang - 1,
797                                    temp.y,
798                                )
799                                .with_z(alt + previous_height - 3),
800                                Vec2::new(
801                                    self.bounds.min.x - storey_increase + self.overhang - 2,
802                                    temp.y,
803                                )
804                                .with_z(alt + previous_height),
805                                0.75,
806                            ),
807                        };
808                        if temp.y <= self.bounds.max.y && temp.y >= self.bounds.min.y {
809                            overhang_supports =
810                                painter.prim(Primitive::union(overhang_supports, support));
811                        }
812                    }
813                    let pillar = painter.prim(Primitive::Aabb(Aabb {
814                        min: site
815                            .tile_wpos(Vec2::new(self.tile_aabr.min.x - 4, y))
816                            .with_z(alt + previous_height),
817                        max: (site.tile_wpos(Vec2::new(self.tile_aabr.max.x + 4, y))
818                            + Vec2::unit_y())
819                        .with_z(alt + height),
820                    }));
821                    pillars_x = painter.prim(Primitive::union(pillars_x, pillar));
822                }
823                let front_wall = if self.overhang < -4 && i > 1 {
824                    painter.prim(Primitive::Empty)
825                } else {
826                    match self.front {
827                        Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
828                            min: Vec2::new(
829                                self.bounds.min.x - 1,
830                                self.bounds.max.y + storey_increase,
831                            )
832                            .with_z(alt + previous_height),
833                            max: Vec2::new(
834                                self.bounds.max.x + 1,
835                                self.bounds.max.y + storey_increase + 1,
836                            )
837                            .with_z(alt + height),
838                        })),
839                        Dir2::X => painter.prim(Primitive::Aabb(Aabb {
840                            min: Vec2::new(
841                                self.bounds.max.x + storey_increase,
842                                self.bounds.min.y - 1,
843                            )
844                            .with_z(alt + previous_height),
845                            max: Vec2::new(
846                                self.bounds.max.x + storey_increase + 1,
847                                self.bounds.max.y + 1,
848                            )
849                            .with_z(alt + height),
850                        })),
851                        Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
852                            min: Vec2::new(
853                                self.bounds.min.x - 1,
854                                self.bounds.min.y - storey_increase,
855                            )
856                            .with_z(alt + previous_height),
857                            max: Vec2::new(
858                                self.bounds.max.x + 1,
859                                self.bounds.min.y - storey_increase + 1,
860                            )
861                            .with_z(alt + height),
862                        })),
863                        _ => painter.prim(Primitive::Aabb(Aabb {
864                            min: Vec2::new(
865                                self.bounds.min.x - storey_increase,
866                                self.bounds.min.y - 1,
867                            )
868                            .with_z(alt + previous_height),
869                            max: Vec2::new(
870                                self.bounds.min.x - storey_increase + 1,
871                                self.bounds.max.y + 1,
872                            )
873                            .with_z(alt + height),
874                        })),
875                    }
876                };
877                let pillars1 = if self.front.is_y() {
878                    painter.prim(Primitive::intersect(pillars_y, front_wall))
879                } else {
880                    painter.prim(Primitive::intersect(pillars_x, front_wall))
881                };
882                let pillars2 = painter.prim(Primitive::intersect(pillars_x, pillars_y));
883                let pillars3 = painter.prim(Primitive::union(pillars1, pillars2));
884                let pillars4 = match self.front {
885                    Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
886                        min: Vec2::new(self.bounds.min.x - 1, self.bounds.min.y - 1)
887                            .with_z(alt + previous_height),
888                        max: Vec2::new(
889                            self.bounds.max.x + 1,
890                            self.bounds.max.y + storey_increase + 1,
891                        )
892                        .with_z(alt + previous_height + 1),
893                    })),
894                    Dir2::X => painter.prim(Primitive::Aabb(Aabb {
895                        min: Vec2::new(self.bounds.min.x - 1, self.bounds.min.y - 1)
896                            .with_z(alt + previous_height),
897                        max: Vec2::new(
898                            self.bounds.max.x + storey_increase + 1,
899                            self.bounds.max.y + 1,
900                        )
901                        .with_z(alt + previous_height + 1),
902                    })),
903                    Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
904                        min: Vec2::new(
905                            self.bounds.min.x - 1,
906                            self.bounds.min.y - storey_increase - 1,
907                        )
908                        .with_z(alt + previous_height),
909                        max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
910                            .with_z(alt + previous_height + 1),
911                    })),
912                    _ => painter.prim(Primitive::Aabb(Aabb {
913                        min: Vec2::new(
914                            self.bounds.min.x - storey_increase - 1,
915                            self.bounds.min.y - 1,
916                        )
917                        .with_z(alt + previous_height),
918                        max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
919                            .with_z(alt + previous_height + 1),
920                    })),
921                };
922                let pillars = if matches!(style, Style::Brick) {
923                    pillars4
924                } else {
925                    painter.prim(Primitive::union(pillars3, pillars4))
926                };
927                painter.fill(
928                    painter.prim(Primitive::intersect(walls, pillars)),
929                    pillar_fill.clone(),
930                );
931
932                painter.fill(overhang_supports, pillar_fill.clone());
933            }
934
935            // Windows x axis
936            {
937                let mut windows = painter.prim(Primitive::Empty);
938                for y in self.tile_aabr.min.y - 2..self.tile_aabr.max.y + 2 {
939                    let min = (site.tile_wpos(Vec2::new(self.tile_aabr.min.x - 4, y))
940                        + Vec2::unit_y() * 2)
941                        .with_z(alt + previous_height + 2);
942                    let max = (site.tile_wpos(Vec2::new(self.tile_aabr.max.x + 4, y + 1))
943                        + Vec2::new(1, -1))
944                    .with_z(alt + previous_height + 2 + window_height);
945                    let window = painter.prim(Primitive::Aabb(Aabb { min, max }));
946                    let add_windows = match self.front {
947                        Dir2::Y => {
948                            max.y < self.bounds.max.y + storey_increase && min.y > self.bounds.min.y
949                        },
950                        Dir2::X => max.y < self.bounds.max.y && min.y > self.bounds.min.y,
951                        Dir2::NegY => {
952                            max.y < self.bounds.max.y && min.y > self.bounds.min.y - storey_increase
953                        },
954                        _ => max.y < self.bounds.max.y && min.y > self.bounds.min.y,
955                    };
956                    if add_windows {
957                        windows = painter.prim(Primitive::union(windows, window));
958                    }
959                }
960                painter.fill(
961                    painter.prim(Primitive::intersect(walls, windows)),
962                    Fill::Block(Block::air(SpriteKind::Window1).with_ori(2).unwrap()),
963                );
964                // Wall lamps
965                if i == 1 {
966                    let mut torches_min = painter.prim(Primitive::Empty);
967                    let mut torches_max = painter.prim(Primitive::Empty);
968                    for y in self.tile_aabr.min.y..self.tile_aabr.max.y {
969                        let pos = site
970                            .tile_wpos(Vec2::new(self.tile_aabr.min.x, y))
971                            .with_z(alt + previous_height + 3)
972                            + Vec3::new(-1, 0, 0);
973                        let torch = painter.prim(Primitive::Aabb(Aabb {
974                            min: pos,
975                            max: pos + 1,
976                        }));
977                        torches_min = painter.prim(Primitive::union(torches_min, torch));
978
979                        let pos = site
980                            .tile_wpos(Vec2::new(self.tile_aabr.max.x, y + 1))
981                            .with_z(alt + previous_height + 3)
982                            + Vec3::new(1, 0, 0);
983                        let torch = painter.prim(Primitive::Aabb(Aabb {
984                            min: pos,
985                            max: pos + 1,
986                        }));
987                        torches_max = painter.prim(Primitive::union(torches_max, torch));
988                    }
989                    painter.fill(
990                        torches_min,
991                        Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(6).unwrap()),
992                    );
993                    painter.fill(
994                        torches_max,
995                        Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(2).unwrap()),
996                    );
997                }
998            }
999            // Windows y axis
1000            {
1001                let mut windows = painter.prim(Primitive::Empty);
1002                for x in self.tile_aabr.min.x - 2..self.tile_aabr.max.x + 2 {
1003                    let min = (site.tile_wpos(Vec2::new(x, self.tile_aabr.min.y - 4))
1004                        + Vec2::unit_x() * 2)
1005                        .with_z(alt + previous_height + 2);
1006                    let max = (site.tile_wpos(Vec2::new(x + 1, self.tile_aabr.max.y + 4))
1007                        + Vec2::new(-1, 1))
1008                    .with_z(alt + previous_height + 2 + window_height);
1009                    let window = painter.prim(Primitive::Aabb(Aabb { min, max }));
1010                    let add_windows = match self.front {
1011                        Dir2::Y => max.x < self.bounds.max.x && min.x > self.bounds.min.x,
1012                        Dir2::X => {
1013                            max.x < self.bounds.max.x + storey_increase && min.x > self.bounds.min.x
1014                        },
1015                        Dir2::NegY => max.x < self.bounds.max.x && min.x > self.bounds.min.x,
1016                        _ => {
1017                            max.x < self.bounds.max.x && min.x > self.bounds.min.x - storey_increase
1018                        },
1019                    };
1020                    if add_windows {
1021                        windows = painter.prim(Primitive::union(windows, window));
1022                    };
1023                }
1024                painter.fill(
1025                    painter.prim(Primitive::intersect(walls, windows)),
1026                    Fill::Block(Block::air(SpriteKind::Window1).with_ori(0).unwrap()),
1027                );
1028                // Wall lamps
1029                if i == 1 {
1030                    let mut torches_min = painter.prim(Primitive::Empty);
1031                    let mut torches_max = painter.prim(Primitive::Empty);
1032                    for x in self.tile_aabr.min.x..self.tile_aabr.max.x {
1033                        let pos = site
1034                            .tile_wpos(Vec2::new(x + 1, self.tile_aabr.min.y))
1035                            .with_z(alt + previous_height + 3)
1036                            + Vec3::new(0, -1, 0);
1037                        let torch = painter.prim(Primitive::Aabb(Aabb {
1038                            min: pos,
1039                            max: pos + 1,
1040                        }));
1041                        torches_min = painter.prim(Primitive::union(torches_min, torch));
1042
1043                        let pos = site
1044                            .tile_wpos(Vec2::new(x, self.tile_aabr.max.y))
1045                            .with_z(alt + previous_height + 3)
1046                            + Vec3::new(0, 1, 0);
1047                        let torch = painter.prim(Primitive::Aabb(Aabb {
1048                            min: pos,
1049                            max: pos + 1,
1050                        }));
1051                        torches_max = painter.prim(Primitive::union(torches_max, torch));
1052                    }
1053                    painter.fill(
1054                        torches_min,
1055                        Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(0).unwrap()),
1056                    );
1057                    painter.fill(
1058                        torches_max,
1059                        Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap()),
1060                    );
1061                }
1062            }
1063
1064            // Shed roof on negative overhangs
1065            if self.overhang < -4 && i > 1 {
1066                let shed = match self.front {
1067                    Dir2::Y => painter.prim(Primitive::Ramp {
1068                        aabb: Aabb {
1069                            min: Vec2::new(
1070                                self.bounds.min.x - 1,
1071                                self.bounds.max.y + storey_increase + 1,
1072                            )
1073                            .with_z(alt + previous_height),
1074                            max: Vec2::new(
1075                                self.bounds.max.x + 1,
1076                                self.bounds.max.y + storey_increase + self.overhang.abs() + 1,
1077                            )
1078                            .with_z(alt + height),
1079                        },
1080                        inset: storey,
1081                        dir: Dir2::NegY,
1082                    }),
1083                    Dir2::X => painter.prim(Primitive::Ramp {
1084                        aabb: Aabb {
1085                            min: Vec2::new(
1086                                self.bounds.max.x + storey_increase + 1,
1087                                self.bounds.min.y - 1,
1088                            )
1089                            .with_z(alt + previous_height),
1090                            max: Vec2::new(
1091                                self.bounds.max.x + storey_increase + self.overhang.abs() + 1,
1092                                self.bounds.max.y + 1,
1093                            )
1094                            .with_z(alt + height),
1095                        },
1096                        inset: storey,
1097                        dir: Dir2::NegX,
1098                    }),
1099                    Dir2::NegY => painter.prim(Primitive::Ramp {
1100                        aabb: Aabb {
1101                            min: Vec2::new(
1102                                self.bounds.min.x - 1,
1103                                self.bounds.min.y - storey_increase - self.overhang.abs(),
1104                            )
1105                            .with_z(alt + previous_height),
1106                            max: Vec2::new(
1107                                self.bounds.max.x + 2,
1108                                self.bounds.min.y - storey_increase,
1109                            )
1110                            .with_z(alt + height),
1111                        },
1112                        inset: storey,
1113                        dir: Dir2::Y,
1114                    }),
1115                    _ => painter.prim(Primitive::Ramp {
1116                        aabb: Aabb {
1117                            min: Vec2::new(
1118                                self.bounds.min.x - storey_increase - self.overhang.abs(),
1119                                self.bounds.min.y - 1,
1120                            )
1121                            .with_z(alt + previous_height),
1122                            max: Vec2::new(
1123                                self.bounds.min.x - storey_increase + 1,
1124                                self.bounds.max.y + 2,
1125                            )
1126                            .with_z(alt + height),
1127                        },
1128                        inset: storey,
1129                        dir: Dir2::X,
1130                    }),
1131                };
1132                let shed_empty = match self.front {
1133                    Dir2::Y => painter.prim(Primitive::Ramp {
1134                        aabb: Aabb {
1135                            min: Vec2::new(
1136                                self.bounds.min.x - 1,
1137                                self.bounds.max.y + storey_increase + 1,
1138                            )
1139                            .with_z(alt + previous_height),
1140                            max: Vec2::new(
1141                                self.bounds.max.x + 1,
1142                                self.bounds.max.y + storey_increase + self.overhang.abs(),
1143                            )
1144                            .with_z(alt + height - 1),
1145                        },
1146                        inset: storey - 1,
1147                        dir: Dir2::NegY,
1148                    }),
1149                    Dir2::X => painter.prim(Primitive::Ramp {
1150                        aabb: Aabb {
1151                            min: Vec2::new(
1152                                self.bounds.max.x + storey_increase + 1,
1153                                self.bounds.min.y - 1,
1154                            )
1155                            .with_z(alt + previous_height),
1156                            max: Vec2::new(
1157                                self.bounds.max.x + storey_increase + self.overhang.abs(),
1158                                self.bounds.max.y + 1,
1159                            )
1160                            .with_z(alt + height - 1),
1161                        },
1162                        inset: storey - 1,
1163                        dir: Dir2::NegX,
1164                    }),
1165                    Dir2::NegY => painter.prim(Primitive::Ramp {
1166                        aabb: Aabb {
1167                            min: Vec2::new(
1168                                self.bounds.min.x - 1,
1169                                self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1170                            )
1171                            .with_z(alt + previous_height),
1172                            max: Vec2::new(
1173                                self.bounds.max.x + 2,
1174                                self.bounds.min.y - storey_increase + 1,
1175                            )
1176                            .with_z(alt + height),
1177                        },
1178                        inset: storey - 1,
1179                        dir: Dir2::Y,
1180                    }),
1181                    _ => painter.prim(Primitive::Ramp {
1182                        aabb: Aabb {
1183                            min: Vec2::new(
1184                                self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1185                                self.bounds.min.y - 1,
1186                            )
1187                            .with_z(alt + previous_height),
1188                            max: Vec2::new(
1189                                self.bounds.min.x - storey_increase + 1,
1190                                self.bounds.max.y + 2,
1191                            )
1192                            .with_z(alt + height),
1193                        },
1194                        inset: storey - 1,
1195                        dir: Dir2::X,
1196                    }),
1197                };
1198                painter.fill(shed, Fill::Brick(BlockKind::Wood, self.roof_color, 24));
1199                painter.fill(shed_empty, Fill::Block(Block::empty()));
1200                let shed_left_wall = match self.front {
1201                    Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1202                        min: Vec2::new(self.bounds.min.x, self.bounds.max.y + storey_increase + 1)
1203                            .with_z(alt + previous_height),
1204                        max: Vec2::new(
1205                            self.bounds.min.x + 1,
1206                            self.bounds.max.y + storey_increase + self.overhang.abs(),
1207                        )
1208                        .with_z(alt + height - 1),
1209                    })),
1210                    Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1211                        min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.min.y)
1212                            .with_z(alt + previous_height),
1213                        max: Vec2::new(
1214                            self.bounds.max.x + storey_increase + self.overhang.abs(),
1215                            self.bounds.min.y + 1,
1216                        )
1217                        .with_z(alt + height - 1),
1218                    })),
1219                    Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1220                        min: Vec2::new(
1221                            self.bounds.max.x,
1222                            self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1223                        )
1224                        .with_z(alt + previous_height),
1225                        max: Vec2::new(
1226                            self.bounds.max.x + 1,
1227                            self.bounds.min.y - storey_increase + 1,
1228                        )
1229                        .with_z(alt + height),
1230                    })),
1231                    _ => painter.prim(Primitive::Aabb(Aabb {
1232                        min: Vec2::new(
1233                            self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1234                            self.bounds.max.y,
1235                        )
1236                        .with_z(alt + previous_height),
1237                        max: Vec2::new(
1238                            self.bounds.min.x - storey_increase + 1,
1239                            self.bounds.max.y + 1,
1240                        )
1241                        .with_z(alt + height),
1242                    })),
1243                };
1244                let shed_right_wall = match self.front {
1245                    Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1246                        min: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase + 1)
1247                            .with_z(alt + previous_height),
1248                        max: Vec2::new(
1249                            self.bounds.max.x + 1,
1250                            self.bounds.max.y + storey_increase + self.overhang.abs(),
1251                        )
1252                        .with_z(alt + height - 1),
1253                    })),
1254                    Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1255                        min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.max.y)
1256                            .with_z(alt + previous_height),
1257                        max: Vec2::new(
1258                            self.bounds.max.x + storey_increase + self.overhang.abs(),
1259                            self.bounds.max.y + 1,
1260                        )
1261                        .with_z(alt + height - 1),
1262                    })),
1263                    Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1264                        min: Vec2::new(
1265                            self.bounds.min.x,
1266                            self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1267                        )
1268                        .with_z(alt + previous_height),
1269                        max: Vec2::new(
1270                            self.bounds.min.x + 1,
1271                            self.bounds.min.y - storey_increase + 1,
1272                        )
1273                        .with_z(alt + height),
1274                    })),
1275                    _ => painter.prim(Primitive::Aabb(Aabb {
1276                        min: Vec2::new(
1277                            self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1278                            self.bounds.min.y,
1279                        )
1280                        .with_z(alt + previous_height),
1281                        max: Vec2::new(
1282                            self.bounds.min.x - storey_increase + 1,
1283                            self.bounds.min.y + 1,
1284                        )
1285                        .with_z(alt + height),
1286                    })),
1287                };
1288                let shed_wall_beams = match self.front {
1289                    Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1290                        min: Vec2::new(self.bounds.min.x, self.bounds.max.y + storey_increase + 1)
1291                            .with_z(alt + previous_height),
1292                        max: Vec2::new(
1293                            self.bounds.max.x + 1,
1294                            self.bounds.max.y + storey_increase + self.overhang.abs(),
1295                        )
1296                        .with_z(alt + previous_height + 1),
1297                    })),
1298                    Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1299                        min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.min.y)
1300                            .with_z(alt + previous_height),
1301                        max: Vec2::new(
1302                            self.bounds.max.x + storey_increase + self.overhang.abs(),
1303                            self.bounds.max.y + 1,
1304                        )
1305                        .with_z(alt + previous_height + 1),
1306                    })),
1307                    Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1308                        min: Vec2::new(
1309                            self.bounds.min.x,
1310                            self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1311                        )
1312                        .with_z(alt + previous_height),
1313                        max: Vec2::new(
1314                            self.bounds.max.x + 1,
1315                            self.bounds.min.y - storey_increase + 1,
1316                        )
1317                        .with_z(alt + previous_height + 1),
1318                    })),
1319                    _ => painter.prim(Primitive::Aabb(Aabb {
1320                        min: Vec2::new(
1321                            self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1322                            self.bounds.min.y,
1323                        )
1324                        .with_z(alt + previous_height),
1325                        max: Vec2::new(
1326                            self.bounds.min.x - storey_increase + 1,
1327                            self.bounds.max.y + 1,
1328                        )
1329                        .with_z(alt + previous_height + 1),
1330                    })),
1331                };
1332                let shed_walls = painter.prim(Primitive::union(shed_left_wall, shed_right_wall));
1333                painter.fill(
1334                    painter.prim(Primitive::intersect(shed_walls, shed_empty)),
1335                    wall_fill_upper.clone(),
1336                );
1337                painter.fill(
1338                    painter.prim(Primitive::intersect(shed_wall_beams, shed_walls)),
1339                    pillar_fill.clone(),
1340                );
1341
1342                // Dormers
1343                let range = if self.front.is_y() {
1344                    self.tile_aabr.min.x - 3..self.tile_aabr.max.x + 3
1345                } else {
1346                    self.tile_aabr.min.y - 3..self.tile_aabr.max.y + 3
1347                };
1348                for n in range {
1349                    let temp = match self.front {
1350                        Dir2::Y => site.tile_wpos(Vec2::new(n, self.tile_aabr.max.y)) - 4,
1351                        Dir2::X => site.tile_wpos(Vec2::new(self.tile_aabr.max.x, n)) - 4,
1352                        Dir2::NegY => site.tile_wpos(Vec2::new(n, self.tile_aabr.min.y)) - 4,
1353                        _ => site.tile_wpos(Vec2::new(self.tile_aabr.min.x, n)) - 4,
1354                    };
1355                    let dormer_box = match self.front {
1356                        Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1357                            min: Vec2::new(temp.x - 1, self.bounds.max.y + storey_increase + 1)
1358                                .with_z(alt + previous_height),
1359                            max: Vec2::new(
1360                                temp.x + 4,
1361                                self.bounds.max.y + storey_increase + self.overhang.abs(),
1362                            )
1363                            .with_z(alt + height - 1),
1364                        })),
1365                        Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1366                            min: Vec2::new(self.bounds.max.x + storey_increase + 1, temp.y - 1)
1367                                .with_z(alt + previous_height),
1368                            max: Vec2::new(
1369                                self.bounds.max.x + storey_increase + self.overhang.abs(),
1370                                temp.y + 4,
1371                            )
1372                            .with_z(alt + height - 1),
1373                        })),
1374                        Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1375                            min: Vec2::new(
1376                                temp.x - 1,
1377                                self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1378                            )
1379                            .with_z(alt + previous_height),
1380                            max: Vec2::new(temp.x + 4, self.bounds.min.y - storey_increase - 1)
1381                                .with_z(alt + height - 1),
1382                        })),
1383                        _ => painter.prim(Primitive::Aabb(Aabb {
1384                            min: Vec2::new(
1385                                self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1386                                temp.y - 1,
1387                            )
1388                            .with_z(alt + previous_height),
1389                            max: Vec2::new(self.bounds.min.x - storey_increase - 1, temp.y + 4)
1390                                .with_z(alt + height - 1),
1391                        })),
1392                    };
1393                    let dormer_roof = match self.front {
1394                        Dir2::Y => painter.prim(Primitive::Gable {
1395                            aabb: Aabb {
1396                                min: Vec2::new(temp.x - 1, self.bounds.max.y + storey_increase + 1)
1397                                    .with_z(alt + height - 2),
1398                                max: Vec2::new(
1399                                    temp.x + 4,
1400                                    self.bounds.max.y + storey_increase + self.overhang.abs(),
1401                                )
1402                                .with_z(alt + height + 1),
1403                            },
1404                            inset: 3,
1405                            dir: Dir2::Y,
1406                        }),
1407                        Dir2::X => painter.prim(Primitive::Gable {
1408                            aabb: Aabb {
1409                                min: Vec2::new(self.bounds.max.x + storey_increase + 1, temp.y - 1)
1410                                    .with_z(alt + height - 2),
1411                                max: Vec2::new(
1412                                    self.bounds.max.x + storey_increase + self.overhang.abs(),
1413                                    temp.y + 4,
1414                                )
1415                                .with_z(alt + height + 1),
1416                            },
1417                            inset: 3,
1418                            dir: Dir2::X,
1419                        }),
1420                        Dir2::NegY => painter.prim(Primitive::Gable {
1421                            aabb: Aabb {
1422                                min: Vec2::new(
1423                                    temp.x - 1,
1424                                    self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1425                                )
1426                                .with_z(alt + height - 2),
1427                                max: Vec2::new(temp.x + 4, self.bounds.min.y - storey_increase)
1428                                    .with_z(alt + height + 1),
1429                            },
1430                            inset: 3,
1431                            dir: Dir2::Y,
1432                        }),
1433                        _ => painter.prim(Primitive::Gable {
1434                            aabb: Aabb {
1435                                min: Vec2::new(
1436                                    self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1437                                    temp.y - 1,
1438                                )
1439                                .with_z(alt + height - 2),
1440                                max: Vec2::new(self.bounds.min.x - storey_increase, temp.y + 4)
1441                                    .with_z(alt + height + 1),
1442                            },
1443                            inset: 3,
1444                            dir: Dir2::X,
1445                        }),
1446                    };
1447                    let window_min = match self.front {
1448                        Dir2::Y => Vec2::new(
1449                            temp.x,
1450                            self.bounds.max.y + storey_increase + self.overhang.abs() - 1,
1451                        )
1452                        .with_z(alt + previous_height + 2),
1453                        Dir2::X => Vec2::new(
1454                            self.bounds.max.x + storey_increase + self.overhang.abs() - 1,
1455                            temp.y,
1456                        )
1457                        .with_z(alt + previous_height + 2),
1458                        Dir2::NegY => Vec2::new(
1459                            temp.x,
1460                            self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
1461                        )
1462                        .with_z(alt + previous_height + 2),
1463                        _ => Vec2::new(
1464                            self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
1465                            temp.y,
1466                        )
1467                        .with_z(alt + previous_height + 2),
1468                    };
1469                    let window_max = match self.front {
1470                        Dir2::Y => Vec2::new(
1471                            temp.x + 3,
1472                            self.bounds.max.y + storey_increase + self.overhang.abs(),
1473                        )
1474                        .with_z(alt + previous_height + 2 + window_height),
1475                        Dir2::X => Vec2::new(
1476                            self.bounds.max.x + storey_increase + self.overhang.abs(),
1477                            temp.y + 3,
1478                        )
1479                        .with_z(alt + previous_height + 2 + window_height),
1480                        Dir2::NegY => Vec2::new(
1481                            temp.x + 3,
1482                            self.bounds.min.y - storey_increase - self.overhang.abs() + 2,
1483                        )
1484                        .with_z(alt + previous_height + 2 + window_height),
1485                        _ => Vec2::new(
1486                            self.bounds.min.x - storey_increase - self.overhang.abs() + 2,
1487                            temp.y + 3,
1488                        )
1489                        .with_z(alt + previous_height + 2 + window_height),
1490                    };
1491                    let window = painter.prim(Primitive::Aabb(Aabb {
1492                        min: window_min,
1493                        max: window_max,
1494                    }));
1495                    let window_cavity = match self.front {
1496                        Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1497                            min: Vec2::new(temp.x, self.bounds.max.y + storey_increase)
1498                                .with_z(alt + previous_height),
1499                            max: Vec2::new(
1500                                temp.x + 3,
1501                                self.bounds.max.y + storey_increase + self.overhang.abs() - 1,
1502                            )
1503                            .with_z(alt + previous_height + 2 + window_height),
1504                        })),
1505                        Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1506                            min: Vec2::new(self.bounds.max.x + storey_increase, temp.y)
1507                                .with_z(alt + previous_height),
1508                            max: Vec2::new(
1509                                self.bounds.max.x + storey_increase + self.overhang.abs() - 1,
1510                                temp.y + 3,
1511                            )
1512                            .with_z(alt + previous_height + 2 + window_height),
1513                        })),
1514                        Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1515                            min: Vec2::new(
1516                                temp.x,
1517                                self.bounds.min.y - storey_increase - self.overhang.abs() + 2,
1518                            )
1519                            .with_z(alt + previous_height),
1520                            max: Vec2::new(temp.x + 3, self.bounds.min.y - storey_increase + 1)
1521                                .with_z(alt + previous_height + 2 + window_height),
1522                        })),
1523                        _ => painter.prim(Primitive::Aabb(Aabb {
1524                            min: Vec2::new(
1525                                self.bounds.min.x - storey_increase - self.overhang.abs() + 2,
1526                                temp.y,
1527                            )
1528                            .with_z(alt + previous_height),
1529                            max: Vec2::new(self.bounds.min.x - storey_increase + 1, temp.y + 3)
1530                                .with_z(alt + previous_height + 2 + window_height),
1531                        })),
1532                    };
1533                    let valid_dormer = if self.front.is_y() {
1534                        window_min.x > self.bounds.min.x && window_max.x < self.bounds.max.x
1535                    } else {
1536                        window_min.y > self.bounds.min.y && window_max.y < self.bounds.max.y
1537                    };
1538                    let window_ori = if self.front.is_y() { 0 } else { 2 };
1539                    if valid_dormer {
1540                        painter.fill(
1541                            painter.prim(Primitive::without(dormer_box, shed)),
1542                            wall_fill_upper.clone(),
1543                        );
1544                        painter.fill(
1545                            painter.prim(Primitive::without(dormer_roof, shed)),
1546                            Fill::Brick(BlockKind::Wood, self.roof_color, 24),
1547                        );
1548                        painter.fill(window_cavity, Fill::Block(Block::empty()));
1549                        painter.fill(
1550                            window,
1551                            Fill::Block(
1552                                Block::air(SpriteKind::Window1)
1553                                    .with_ori(window_ori)
1554                                    .unwrap(),
1555                            ),
1556                        );
1557                    }
1558                }
1559            }
1560
1561            // Floor
1562            // No extra floor needed for the ground floor
1563            if i > 1 {
1564                let floor = if self.overhang < -1 && i > 1 {
1565                    match self.front {
1566                        Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1567                            min: (self.bounds.min + 1).with_z(alt + previous_height),
1568                            max: Vec2::new(
1569                                self.bounds.max.x,
1570                                self.bounds.max.y + storey_increase + self.overhang.abs(),
1571                            )
1572                            .with_z(alt + previous_height + 1),
1573                        })),
1574                        Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1575                            min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1)
1576                                .with_z(alt + previous_height),
1577                            max: Vec2::new(
1578                                self.bounds.max.x + storey_increase + self.overhang.abs(),
1579                                self.bounds.max.y,
1580                            )
1581                            .with_z(alt + previous_height + 1),
1582                        })),
1583                        Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1584                            min: Vec2::new(
1585                                self.bounds.min.x + 1,
1586                                self.bounds.min.y + 1 - storey_increase - self.overhang.abs(),
1587                            )
1588                            .with_z(alt + previous_height),
1589                            max: Vec2::new(self.bounds.max.x, self.bounds.max.y)
1590                                .with_z(alt + previous_height + 1),
1591                        })),
1592                        _ => painter.prim(Primitive::Aabb(Aabb {
1593                            min: Vec2::new(
1594                                self.bounds.min.x + 1 - storey_increase - self.overhang.abs(),
1595                                self.bounds.min.y + 1,
1596                            )
1597                            .with_z(alt + previous_height),
1598                            max: Vec2::new(self.bounds.max.x, self.bounds.max.y)
1599                                .with_z(alt + previous_height + 1),
1600                        })),
1601                    }
1602                } else {
1603                    match self.front {
1604                        Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
1605                            min: (self.bounds.min + 1).with_z(alt + previous_height),
1606                            max: (Vec2::new(
1607                                self.bounds.max.x,
1608                                self.bounds.max.y + storey_increase,
1609                            ))
1610                            .with_z(alt + previous_height + 1),
1611                        })),
1612                        Dir2::X => painter.prim(Primitive::Aabb(Aabb {
1613                            min: (self.bounds.min + 1).with_z(alt + previous_height),
1614                            max: (Vec2::new(
1615                                self.bounds.max.x + storey_increase,
1616                                self.bounds.max.y,
1617                            ))
1618                            .with_z(alt + previous_height + 1),
1619                        })),
1620                        Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
1621                            min: Vec2::new(
1622                                self.bounds.min.x + 1,
1623                                self.bounds.min.y + 1 - storey_increase,
1624                            )
1625                            .with_z(alt + previous_height),
1626                            max: (Vec2::new(self.bounds.max.x, self.bounds.max.y))
1627                                .with_z(alt + previous_height + 1),
1628                        })),
1629                        _ => painter.prim(Primitive::Aabb(Aabb {
1630                            min: Vec2::new(
1631                                self.bounds.min.x + 1 - storey_increase,
1632                                self.bounds.min.y + 1,
1633                            )
1634                            .with_z(alt + previous_height),
1635                            max: (Vec2::new(self.bounds.max.x, self.bounds.max.y))
1636                                .with_z(alt + previous_height + 1),
1637                        })),
1638                    }
1639                };
1640                painter.fill(
1641                    floor,
1642                    Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
1643                );
1644            }
1645
1646            // interior furniture sprites
1647            let base = alt + (storey * (i as i32 - 1)).max(0);
1648            if i % 2 == 0 {
1649                // bedroom on even-leveled floors
1650                let bed_pos = match self.front {
1651                    Dir2::X => Vec2::new(half_x, quarter_y),
1652                    Dir2::NegY => Vec2::new(three_quarter_x, half_y),
1653                    _ => Vec2::new(half_x, half_y),
1654                };
1655                let bed_dir = self.front;
1656                let bed_aabr = painter.bed_wood_woodland(bed_pos.with_z(base), bed_dir);
1657                let nightstand_pos = bed_dir
1658                    .opposite()
1659                    .select_aabr_with(bed_aabr, bed_dir.rotated_ccw().select_aabr(bed_aabr))
1660                    .with_z(base)
1661                    + bed_dir.rotated_ccw().to_vec2();
1662                // drawer next to bed
1663                painter.sprite(nightstand_pos.with_z(base), SpriteKind::DrawerWoodWoodlandS);
1664                // collectible on top of drawer
1665                let rng0 = RandomField::new(0).get(nightstand_pos.with_z(base + 1));
1666                let rng1 = RandomField::new(1).get(nightstand_pos.with_z(base + 1));
1667                painter.owned_resource_sprite(
1668                    nightstand_pos.with_z(base + 1),
1669                    match rng0 % 5 {
1670                        0 => SpriteKind::Lantern,
1671                        1 => SpriteKind::PotionMinor,
1672                        2 => SpriteKind::VialEmpty,
1673                        3 => SpriteKind::Bowl,
1674                        _ => SpriteKind::Empty,
1675                    },
1676                    (rng1 % 4) as u8 * 2,
1677                );
1678                // wardrobe along wall in corner of the room
1679                let wardrobe_dir = self.front.rotated_cw();
1680                let bounds = Aabr {
1681                    min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1),
1682                    max: Vec2::new(self.bounds.max.x - 2, self.bounds.max.y - 1),
1683                };
1684                let wardrobe_pos = wardrobe_dir
1685                    .opposite()
1686                    .select_aabr_with(
1687                        bounds,
1688                        bounds.center()
1689                            + wardrobe_dir.vec2(bounds.half_size().w, bounds.half_size().h) / 2,
1690                    )
1691                    .with_z(base);
1692
1693                let sprite = if RandomField::new(0).chance(wardrobe_pos, 0.5) {
1694                    SpriteKind::WardrobedoubleWoodWoodland
1695                } else {
1696                    SpriteKind::WardrobedoubleWoodWoodland2
1697                };
1698                painter.mirrored2(wardrobe_pos, wardrobe_dir, sprite);
1699            } else {
1700                // living room with table + chairs + random
1701                for dir in DIRS {
1702                    // random accent pieces and loot
1703                    let sprite_pos = self.bounds.center() + dir * 5;
1704                    let rng0 = RandomField::new(0).get(sprite_pos.with_z(base));
1705                    let rng1 = RandomField::new(1).get(sprite_pos.with_z(base));
1706                    painter.owned_resource_sprite(
1707                        sprite_pos.with_z(base),
1708                        match rng0 % 32 {
1709                            0..=2 => SpriteKind::Crate,
1710                            3..=4 => SpriteKind::CoatrackWoodWoodland,
1711                            5..=7 => SpriteKind::FlowerpotWoodWoodlandS,
1712                            8..=9 => SpriteKind::Lantern,
1713                            _ => SpriteKind::Empty,
1714                        },
1715                        (rng1 % 4) as u8 * 2,
1716                    );
1717                }
1718
1719                if self.bounds.max.x - self.bounds.min.x < 16
1720                    || self.bounds.max.y - self.bounds.min.y < 16
1721                {
1722                    let table_pos = Vec2::new(half_x, half_y);
1723                    // room is smaller, so use small table
1724                    painter.sprite(
1725                        table_pos.with_z(base),
1726                        SpriteKind::DiningtableWoodWoodlandRound,
1727                    );
1728                    for dir in Dir2::iter() {
1729                        let chair_pos = table_pos + dir.to_vec2();
1730                        painter.rotated_sprite(
1731                            chair_pos.with_z(base),
1732                            SpriteKind::ChairWoodWoodland,
1733                            dir.opposite().sprite_ori(),
1734                        );
1735                    }
1736                } else {
1737                    // room is bigger, so use large table + chair positions
1738                    let table_pos = match self.front {
1739                        Dir2::Y => Vec2::new(half_x, three_quarter_y),
1740                        Dir2::X => Vec2::new(half_x, half_y),
1741                        _ => Vec2::new(quarter_x, half_y),
1742                    }
1743                    .with_z(base);
1744                    let table_axis = if RandomField::new(0).chance(table_pos, 0.5) {
1745                        Dir2::X
1746                    } else {
1747                        Dir2::Y
1748                    };
1749                    let table_bounds = painter.table_wood_fancy_woodland(table_pos, table_axis);
1750                    painter.chairs_around(SpriteKind::ChairWoodWoodland, 1, table_bounds, base);
1751                }
1752                // drawer along a wall
1753                let (drawer_pos, drawer_ori) = match self.front {
1754                    Dir2::Y => (Vec2::new(self.bounds.max.x - 1, self.bounds.max.y - 2), 6),
1755                    Dir2::X => (Vec2::new(self.bounds.max.x - 2, self.bounds.max.y - 1), 0),
1756                    Dir2::NegY => (Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 2), 6),
1757                    _ => (Vec2::new(self.bounds.min.x + 2, self.bounds.max.y - 1), 0),
1758                };
1759                painter.rotated_sprite(
1760                    drawer_pos.with_z(base),
1761                    SpriteKind::DrawerWoodWoodlandL1,
1762                    drawer_ori,
1763                );
1764            }
1765
1766            // Stairs
1767            if i > 1 {
1768                let stair_width = 3;
1769                let previous_floor_height = (storey * (i as i32 - 2)).max(0);
1770                let stair_origin = match self.front {
1771                    Dir2::Y => self.bounds.min + 1,
1772                    Dir2::X => self.bounds.min + 1,
1773                    Dir2::NegY => {
1774                        Vec2::new(self.bounds.max.x - 12, self.bounds.max.y - stair_width * 2)
1775                    },
1776                    _ => Vec2::new(self.bounds.max.x - 12, self.bounds.min.y + 1),
1777                };
1778                let staircase = if i < 2 {
1779                    painter.prim(Primitive::Empty)
1780                } else if i % 2 == 0 {
1781                    let ramp = /*match self.front */{
1782                        //0 => {
1783                            painter.prim(Primitive::Ramp {
1784                                aabb: Aabb {
1785                                    min: Vec2::new(stair_origin.x + 3, stair_origin.y).with_z(alt + previous_floor_height),
1786                                    max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
1787                                },
1788                                inset: storey,
1789                                dir: Dir2::X,
1790                            })
1791                        /*},
1792                        1 => {
1793                            painter.prim(Primitive::Ramp {
1794                                aabb: Aabb {
1795                                    min: Vec2::new(stair_origin.x, stair_origin.y + 3).with_z(alt + previous_floor_height),
1796                                    max: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 10).with_z(alt + previous_height + 1),
1797                                },
1798                                inset: storey,
1799                                dir: 0,
1800                            })
1801                        },
1802                        2 => {
1803                            painter.prim(Primitive::Ramp {
1804                                aabb: Aabb {
1805                                    min: Vec2::new(stair_origin.x + 3, stair_origin.y).with_z(alt + previous_floor_height),
1806                                    max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
1807                                },
1808                                inset: storey,
1809                                dir: 0,
1810                            })
1811                        },
1812                        _ => {
1813                            painter.prim(Primitive::Ramp {
1814                                aabb: Aabb {
1815                                    min: Vec2::new(stair_origin.x, stair_origin.y + 3).with_z(alt + previous_floor_height),
1816                                    max: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 10).with_z(alt + previous_height + 1),
1817                                },
1818                                inset: storey,
1819                                dir: 0,
1820                            })
1821                        }*/
1822                    };
1823                    let support = {
1824                        //match self.front {
1825                        //0 => {
1826                        painter.prim(Primitive::Aabb(Aabb {
1827                            min: Vec2::new(stair_origin.x + 10, stair_origin.y)
1828                                .with_z(alt + previous_floor_height),
1829                            max: Vec2::new(stair_origin.x + 12, stair_origin.y + stair_width)
1830                                .with_z(alt + previous_height + 1),
1831                        }))
1832                        //},
1833                        //1 => {
1834                        //    painter.prim(Primitive::Aabb(Aabb {
1835                        //        min: Vec2::new(stair_origin.x, stair_origin.y
1836                        // + 10).with_z(alt + previous_floor_height), max:
1837                        //   Vec2::new(stair_origin.x + stair_width,
1838                        // stair_origin.y + 12).with_z(alt + previous_height +
1839                        // 1),    }))
1840                        //},
1841                        //2 => {
1842                        //    painter.prim(Primitive::Aabb(Aabb {
1843                        //        min: Vec2::new(stair_origin.x + 10,
1844                        // stair_origin.y).with_z(alt + previous_floor_height),
1845                        //        max: Vec2::new(stair_origin.x + 12,
1846                        // stair_origin.y + stair_width).with_z(alt +
1847                        // previous_height + 1),    }))
1848                        //},
1849                        //_ => {
1850                        //    painter.prim(Primitive::Aabb(Aabb {
1851                        //        min: Vec2::new(stair_origin.x, stair_origin.y
1852                        // + 10).with_z(alt + previous_floor_height), max:
1853                        //   Vec2::new(stair_origin.x + stair_width,
1854                        // stair_origin.y + 12).with_z(alt + previous_height +
1855                        // 1),    }))
1856                        //},
1857                    };
1858                    painter.prim(Primitive::union(ramp, support))
1859                } else {
1860                    let ramp = /*match self.front */{
1861                        //0 => {
1862                            painter.prim(Primitive::Ramp {
1863                                aabb: Aabb {
1864                                    min: Vec2::new(stair_origin.x + 1, stair_origin.y + stair_width).with_z(alt + previous_floor_height),
1865                                    max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
1866                                },
1867                                inset: storey,
1868                                dir: Dir2::NegX,
1869                            })
1870                        /*},
1871                        1 => {
1872                            painter.prim(Primitive::Ramp {
1873                                aabb: Aabb {
1874                                    min: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 1).with_z(alt + previous_floor_height),
1875                                    max: Vec2::new(stair_origin.x + 2 * stair_width, stair_origin.y + 8).with_z(alt + previous_height + 1),
1876                                },
1877                                inset: storey,
1878                                dir: 1,
1879                            })
1880                        },
1881                        2 => {
1882                            painter.prim(Primitive::Ramp {
1883                                aabb: Aabb {
1884                                    min: Vec2::new(stair_origin.x + 1, stair_origin.y + stair_width).with_z(alt + previous_floor_height),
1885                                    max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
1886                                },
1887                                inset: storey,
1888                                dir: 1,
1889                            })
1890                        },
1891                        _ => {
1892                            painter.prim(Primitive::Ramp {
1893                                aabb: Aabb {
1894                                    min: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 1).with_z(alt + previous_floor_height),
1895                                    max: Vec2::new(stair_origin.x + 2 * stair_width, stair_origin.y + 8).with_z(alt + previous_height + 1),
1896                                },
1897                                inset: storey,
1898                                dir: 1,
1899                            })
1900                        },
1901                        */
1902                    };
1903                    let support = {
1904                        //match self.front {
1905                        //0 => {
1906                        painter.prim(Primitive::Aabb(Aabb {
1907                            min: Vec2::new(stair_origin.x, stair_origin.y + stair_width)
1908                                .with_z(alt + previous_floor_height),
1909                            max: Vec2::new(stair_origin.x + 2, stair_origin.y + 2 * stair_width)
1910                                .with_z(alt + previous_height + 1),
1911                        }))
1912                        //},
1913                        //1 => {
1914                        //    painter.prim(Primitive::Aabb(Aabb {
1915                        //        min: Vec2::new(stair_origin.x + stair_width,
1916                        // stair_origin.y).with_z(alt + previous_floor_height),
1917                        //        max: Vec2::new(stair_origin.x + 2 *
1918                        // stair_width, stair_origin.y + 2).with_z(alt +
1919                        // previous_height + 1),    }))
1920                        //},
1921                        //2 => {
1922                        //    painter.prim(Primitive::Aabb(Aabb {
1923                        //        min: Vec2::new(stair_origin.x, stair_origin.y
1924                        // + stair_width).with_z(alt + previous_floor_height),
1925                        //   max: Vec2::new(stair_origin.x + 2,
1926                        // stair_origin.y + 2 * stair_width).with_z(alt +
1927                        // previous_height + 1),    }))
1928                        //},
1929                        //_ => {
1930                        //    painter.prim(Primitive::Aabb(Aabb {
1931                        //        min: Vec2::new(stair_origin.x + stair_width,
1932                        // stair_origin.y).with_z(alt + previous_floor_height),
1933                        //        max: Vec2::new(stair_origin.x + 2 *
1934                        // stair_width, stair_origin.y + 2).with_z(alt +
1935                        // previous_height + 1),    }))
1936                        //},
1937                    };
1938                    painter.prim(Primitive::union(ramp, support))
1939                };
1940                let stairwell = if i < 2 {
1941                    painter.prim(Primitive::Empty)
1942                } else if i % 2 == 0 {
1943                    painter.prim(Primitive::Aabb(Aabb {
1944                        min: Vec2::new(stair_origin.x + 2, stair_origin.y)
1945                            .with_z(alt + previous_floor_height + 1),
1946                        max: Vec2::new(stair_origin.x + 9, stair_origin.y + stair_width)
1947                            .with_z(alt + previous_height + 1),
1948                    }))
1949                    //match self.front {
1950                    //    0 => {
1951                    //        painter.prim(Primitive::Aabb(Aabb {
1952                    //                min: Vec2::new(stair_origin.x,
1953                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1954                    //                max: Vec2::new(stair_origin.x + 9,
1955                    // stair_origin.y + stair_width).with_z(alt +
1956                    // previous_height + 1),        }))
1957                    //    },
1958                    //    1 => {
1959                    //        painter.prim(Primitive::Aabb(Aabb {
1960                    //                min: Vec2::new(stair_origin.x,
1961                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1962                    //                max: Vec2::new(stair_origin.x +
1963                    // stair_width, stair_origin.y + 9).with_z(alt +
1964                    // previous_height + 1),        }))
1965                    //    },
1966                    //    2 => {
1967                    //        painter.prim(Primitive::Aabb(Aabb {
1968                    //                min: Vec2::new(stair_origin.x,
1969                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1970                    //                max: Vec2::new(stair_origin.x + 9,
1971                    // stair_origin.y + stair_width).with_z(alt +
1972                    // previous_height + 1),        }))
1973                    //    },
1974                    //    _ => {
1975                    //        painter.prim(Primitive::Aabb(Aabb {
1976                    //                min: Vec2::new(stair_origin.x,
1977                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1978                    //                max: Vec2::new(stair_origin.x +
1979                    // stair_width, stair_origin.y + 9).with_z(alt +
1980                    // previous_height + 1),        }))
1981                    //    },
1982                    //}
1983                } else {
1984                    painter.prim(Primitive::Aabb(Aabb {
1985                        min: Vec2::new(stair_origin.x + 2, stair_origin.y + stair_width)
1986                            .with_z(alt + previous_floor_height + 1),
1987                        max: Vec2::new(stair_origin.x + 11, stair_origin.y + 2 * stair_width)
1988                            .with_z(alt + previous_height + 1),
1989                    }))
1990                    //match self.front {
1991                    //    0 => {
1992                    //        painter.prim(Primitive::Aabb(Aabb {
1993                    //                min: Vec2::new(stair_origin.x + 2,
1994                    // stair_origin.y + stair_width).with_z(alt +
1995                    // previous_floor_height + 1),
1996                    //                max: Vec2::new(stair_origin.x + 11,
1997                    // stair_origin.y + 2 * stair_width).with_z(alt +
1998                    // previous_height + 1),        }))
1999                    //    },
2000                    //    1 => {
2001                    //        painter.prim(Primitive::Aabb(Aabb {
2002                    //                min: Vec2::new(stair_origin.x +
2003                    // stair_width, stair_origin.y + 2).with_z(alt +
2004                    // previous_floor_height + 1),
2005                    //                max: Vec2::new(stair_origin.x + 2 *
2006                    // stair_width, stair_origin.y + 11).with_z(alt +
2007                    // previous_height + 1),        }))
2008                    //    },
2009                    //    2 => {
2010                    //        painter.prim(Primitive::Aabb(Aabb {
2011                    //                min: Vec2::new(stair_origin.x + 2,
2012                    // stair_origin.y + stair_width).with_z(alt +
2013                    // previous_floor_height + 1),
2014                    //                max: Vec2::new(stair_origin.x + 11,
2015                    // stair_origin.y + 2 * stair_width).with_z(alt +
2016                    // previous_height + 1),        }))
2017                    //    },
2018                    //    _ => {
2019                    //        painter.prim(Primitive::Aabb(Aabb {
2020                    //                min: Vec2::new(stair_origin.x +
2021                    // stair_width, stair_origin.y + 2).with_z(alt +
2022                    // previous_floor_height + 1),
2023                    //                max: Vec2::new(stair_origin.x + 2 *
2024                    // stair_width, stair_origin.y + 11).with_z(alt +
2025                    // previous_height + 1),        }))
2026                    //    },
2027                    //}
2028                };
2029
2030                painter.fill(stairwell, Fill::Block(Block::empty()));
2031                painter.fill(
2032                    staircase,
2033                    Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
2034                );
2035            }
2036        }
2037
2038        // Foundation
2039        painter.fill(
2040            painter.prim(Primitive::Aabb(Aabb {
2041                min: (self.bounds.min - 1).with_z(self.alt - foundations),
2042                max: (self.bounds.max + 2).with_z(self.alt + 1),
2043            })),
2044            Fill::Block(Block::new(BlockKind::Rock, Rgb::new(31, 33, 32))),
2045        );
2046
2047        // Fireplace and chimney
2048        let fireplace_origin = /*if self.levels > 1 {
2049            match self.front {
2050                0 => {
2051                    Vec2::new(self.bounds.min.x + 12, self.bounds.min.y + 1)
2052                },
2053                1 => {
2054                    Vec2::new(self.bounds.min.x + 1, self.bounds.max.y - 12)
2055                },
2056                2 => {
2057                    Vec2::new(self.bounds.max.x - 12, self.bounds.max.y - 1)
2058                },
2059                _ => {
2060                    Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 12)
2061                },
2062            }
2063        } else */{
2064            match self.front {
2065                Dir2::Y => {
2066                    Vec2::new(half_x, self.bounds.min.y + 1)
2067                },
2068                Dir2::X => {
2069                    Vec2::new(self.bounds.min.x + 1, half_y)
2070                },
2071                Dir2::NegY => {
2072                    Vec2::new(half_x - 4, self.bounds.max.y - 3)
2073                },
2074                _ => {
2075                    Vec2::new(self.bounds.max.x - 3, half_y)
2076                },
2077            }
2078        };
2079        let chimney = match self.front {
2080            Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
2081                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2082                max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
2083                    .with_z(alt + roof + roof_height + 2),
2084            })),
2085            Dir2::X => painter.prim(Primitive::Aabb(Aabb {
2086                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2087                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
2088                    .with_z(alt + roof + roof_height + 2),
2089            })),
2090            Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
2091                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2092                max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
2093                    .with_z(alt + roof + roof_height + 2),
2094            })),
2095            _ => painter.prim(Primitive::Aabb(Aabb {
2096                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2097                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
2098                    .with_z(alt + roof + roof_height + 2),
2099            })),
2100        };
2101
2102        let chimney_cavity = match self.front {
2103            Dir2::Y => painter.prim(Primitive::Aabb(Aabb {
2104                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2105                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
2106                    .with_z(alt + roof + roof_height + 2),
2107            })),
2108            Dir2::X => painter.prim(Primitive::Aabb(Aabb {
2109                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2110                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
2111                    .with_z(alt + roof + roof_height + 2),
2112            })),
2113            Dir2::NegY => painter.prim(Primitive::Aabb(Aabb {
2114                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2115                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
2116                    .with_z(alt + roof + roof_height + 2),
2117            })),
2118            _ => painter.prim(Primitive::Aabb(Aabb {
2119                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2120                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
2121                    .with_z(alt + roof + roof_height + 2),
2122            })),
2123        };
2124        let fire_embers = match self.front {
2125            Dir2::Y => Aabb {
2126                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2127                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 1),
2128            },
2129            Dir2::X => Aabb {
2130                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2131                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
2132            },
2133            Dir2::NegY => 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 + 2).with_z(alt + 1),
2136            },
2137            _ => Aabb {
2138                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2139                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
2140            },
2141        };
2142        let fireplace_cavity = match self.front {
2143            Dir2::Y => Aabb {
2144                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2145                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
2146            },
2147            Dir2::X => Aabb {
2148                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2149                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
2150            },
2151            Dir2::NegY => Aabb {
2152                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y).with_z(alt),
2153                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 2),
2154            },
2155            _ => Aabb {
2156                min: Vec2::new(fireplace_origin.x, fireplace_origin.y + 1).with_z(alt),
2157                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 2),
2158            },
2159        };
2160
2161        painter.fill(
2162            chimney,
2163            Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24),
2164        );
2165        painter.fill(chimney_cavity, Fill::Block(Block::empty()));
2166        painter.fill(
2167            painter.prim(Primitive::Aabb(fireplace_cavity)),
2168            Fill::Block(Block::empty()),
2169        );
2170        painter.fill(
2171            painter.prim(Primitive::Aabb(fire_embers)),
2172            Fill::Block(Block::air(SpriteKind::Ember)),
2173        );
2174
2175        // bedroom on first level corners in case there is no 2nd level
2176        if self.levels == 1 {
2177            // different positions for smaller houses
2178            let bed_pos = if self.bounds.max.x - self.bounds.min.x < 16
2179                || self.bounds.max.y - self.bounds.min.y < 16
2180            {
2181                match self.front {
2182                    Dir2::Y => Vec2::new(self.bounds.min.x + 4, self.bounds.min.y + 2),
2183                    Dir2::X => Vec2::new(self.bounds.min.x + 2, self.bounds.min.y + 4),
2184                    Dir2::NegY => Vec2::new(self.bounds.max.x - 4, self.bounds.max.y - 2),
2185                    _ => Vec2::new(self.bounds.max.x - 8, self.bounds.max.y - 2),
2186                }
2187            } else {
2188                match self.front {
2189                    Dir2::Y => Vec2::new(self.bounds.max.x - 4, self.bounds.min.y + 2),
2190                    Dir2::X => Vec2::new(self.bounds.min.x + 8, self.bounds.max.y - 2),
2191                    Dir2::NegY => Vec2::new(self.bounds.max.x - 4, self.bounds.max.y - 2),
2192                    _ => Vec2::new(self.bounds.max.x - 8, self.bounds.max.y - 2),
2193                }
2194            };
2195            let bed_dir = self.front.abs();
2196
2197            painter.bed_wood_woodland(bed_pos.with_z(alt), bed_dir);
2198        }
2199
2200        if self.christmas_decorations {
2201            let (wreath_pos, wreath_ori) = match self.front {
2202                Dir2::Y => (
2203                    Aabb {
2204                        min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 3)
2205                            .with_z(alt + 2),
2206                        max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 4)
2207                            .with_z(alt + 3),
2208                    },
2209                    4,
2210                ),
2211                Dir2::X => (
2212                    Aabb {
2213                        min: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 1)
2214                            .with_z(alt + 2),
2215                        max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 2)
2216                            .with_z(alt + 3),
2217                    },
2218                    2,
2219                ),
2220                Dir2::NegY => (
2221                    Aabb {
2222                        min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y - 1)
2223                            .with_z(alt + 2),
2224                        max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y).with_z(alt + 3),
2225                    },
2226                    0,
2227                ),
2228                _ => (
2229                    Aabb {
2230                        min: Vec2::new(fireplace_origin.x - 1, fireplace_origin.y + 1)
2231                            .with_z(alt + 2),
2232                        max: Vec2::new(fireplace_origin.x, fireplace_origin.y + 2).with_z(alt + 3),
2233                    },
2234                    6,
2235                ),
2236            };
2237            painter.fill(
2238                painter.prim(Primitive::Aabb(wreath_pos)),
2239                Fill::Block(
2240                    Block::air(SpriteKind::ChristmasWreath)
2241                        .with_ori(wreath_ori)
2242                        .unwrap(),
2243                ),
2244            );
2245        }
2246
2247        // Door
2248        // Fill around the door with wall
2249        let doorway1 = match self.front {
2250            Dir2::Y => Aabb {
2251                min: Vec2::new(door_tile_wpos.x - 1, self.bounds.max.y).with_z(alt),
2252                max: Vec2::new(door_tile_wpos.x + 3, self.bounds.max.y + 1).with_z(alt + 4),
2253            },
2254            Dir2::X => Aabb {
2255                min: Vec2::new(self.bounds.max.x, door_tile_wpos.y - 1).with_z(alt),
2256                max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 3).with_z(alt + 4),
2257            },
2258            Dir2::NegY => Aabb {
2259                min: Vec2::new(door_tile_wpos.x - 1, self.bounds.min.y).with_z(alt),
2260                max: Vec2::new(door_tile_wpos.x + 3, self.bounds.min.y + 1).with_z(alt + 4),
2261            },
2262            _ => Aabb {
2263                min: Vec2::new(self.bounds.min.x, door_tile_wpos.y - 1).with_z(alt),
2264                max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 3).with_z(alt + 4),
2265            },
2266        };
2267        painter.fill(painter.prim(Primitive::Aabb(doorway1)), wall_fill_lower);
2268
2269        // Carve out the doorway with air
2270        let doorway2 = match self.front {
2271            Dir2::Y => Aabb {
2272                min: Vec2::new(door_tile_wpos.x, self.bounds.max.y).with_z(alt),
2273                max: Vec2::new(door_tile_wpos.x + 2, self.bounds.max.y + 1).with_z(alt + 3),
2274            },
2275            Dir2::X => Aabb {
2276                min: Vec2::new(self.bounds.max.x, door_tile_wpos.y).with_z(alt),
2277                max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 2).with_z(alt + 3),
2278            },
2279            Dir2::NegY => Aabb {
2280                min: Vec2::new(door_tile_wpos.x, self.bounds.min.y).with_z(alt),
2281                max: Vec2::new(door_tile_wpos.x + 2, self.bounds.min.y + 1).with_z(alt + 3),
2282            },
2283            _ => Aabb {
2284                min: Vec2::new(self.bounds.min.x, door_tile_wpos.y).with_z(alt),
2285                max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 2).with_z(alt + 3),
2286            },
2287        };
2288        painter.fill(
2289            painter.prim(Primitive::Aabb(doorway2)),
2290            Fill::Block(Block::empty()),
2291        );
2292
2293        // Fill in the right and left side doors
2294        let (door_gap, door1, door1_ori, door2, door2_ori) = match self.front {
2295            Dir2::Y => (
2296                Aabb {
2297                    min: Vec2::new(door_tile_wpos.x - 1, self.bounds.max.y + 1).with_z(alt),
2298                    max: Vec2::new(door_tile_wpos.x + 3, self.bounds.max.y + 4).with_z(alt + 3),
2299                },
2300                Aabb {
2301                    min: Vec2::new(door_tile_wpos.x, self.bounds.max.y).with_z(alt),
2302                    max: Vec2::new(door_tile_wpos.x + 1, self.bounds.max.y + 1).with_z(alt + 1),
2303                },
2304                0,
2305                Aabb {
2306                    min: Vec2::new(door_tile_wpos.x + 1, self.bounds.max.y).with_z(alt),
2307                    max: Vec2::new(door_tile_wpos.x + 2, self.bounds.max.y + 1).with_z(alt + 1),
2308                },
2309                4,
2310            ),
2311            Dir2::X => (
2312                Aabb {
2313                    min: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y - 1).with_z(alt),
2314                    max: Vec2::new(self.bounds.max.x + 4, door_tile_wpos.y + 3).with_z(alt + 3),
2315                },
2316                Aabb {
2317                    min: Vec2::new(self.bounds.max.x, door_tile_wpos.y).with_z(alt),
2318                    max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 1).with_z(alt + 1),
2319                },
2320                2,
2321                Aabb {
2322                    min: Vec2::new(self.bounds.max.x, door_tile_wpos.y + 1).with_z(alt),
2323                    max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 2).with_z(alt + 1),
2324                },
2325                6,
2326            ),
2327            Dir2::NegY => (
2328                Aabb {
2329                    min: Vec2::new(door_tile_wpos.x - 1, self.bounds.min.y - 4).with_z(alt),
2330                    max: Vec2::new(door_tile_wpos.x + 3, self.bounds.min.y).with_z(alt + 3),
2331                },
2332                Aabb {
2333                    min: Vec2::new(door_tile_wpos.x, self.bounds.min.y).with_z(alt),
2334                    max: Vec2::new(door_tile_wpos.x + 1, self.bounds.min.y + 1).with_z(alt + 1),
2335                },
2336                0,
2337                Aabb {
2338                    min: Vec2::new(door_tile_wpos.x + 1, self.bounds.min.y).with_z(alt),
2339                    max: Vec2::new(door_tile_wpos.x + 2, self.bounds.min.y + 1).with_z(alt + 1),
2340                },
2341                4,
2342            ),
2343            _ => (
2344                Aabb {
2345                    min: Vec2::new(self.bounds.min.x - 4, door_tile_wpos.y - 1).with_z(alt),
2346                    max: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 3).with_z(alt + 3),
2347                },
2348                Aabb {
2349                    min: Vec2::new(self.bounds.min.x, door_tile_wpos.y).with_z(alt),
2350                    max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 1).with_z(alt + 1),
2351                },
2352                2,
2353                Aabb {
2354                    min: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 1).with_z(alt),
2355                    max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 2).with_z(alt + 1),
2356                },
2357                6,
2358            ),
2359        };
2360        painter.fill(
2361            painter.prim(Primitive::Aabb(door_gap)),
2362            Fill::Block(Block::air(SpriteKind::Empty)),
2363        );
2364        painter.fill(
2365            painter.prim(Primitive::Aabb(door1)),
2366            Fill::Block(Block::air(SpriteKind::Door).with_ori(door1_ori).unwrap()),
2367        );
2368        painter.fill(
2369            painter.prim(Primitive::Aabb(door2)),
2370            Fill::Block(Block::air(SpriteKind::Door).with_ori(door2_ori).unwrap()),
2371        );
2372        if self.christmas_decorations {
2373            // we need to randomize position to see both variants
2374            let rng = RandomField::new(0).get(door_tile_wpos.with_z(alt + 3));
2375            let right = (rng % 2) as i32;
2376            let (door_light_pos, door_light_ori) = match self.front {
2377                Dir2::Y => (
2378                    Aabb {
2379                        min: Vec2::new(door_tile_wpos.x + right, self.bounds.max.y + 1)
2380                            .with_z(alt + 3),
2381                        max: Vec2::new(door_tile_wpos.x + 1 + right, self.bounds.max.y + 2)
2382                            .with_z(alt + 4),
2383                    },
2384                    4,
2385                ),
2386                Dir2::X => (
2387                    Aabb {
2388                        min: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + right)
2389                            .with_z(alt + 3),
2390                        max: Vec2::new(self.bounds.max.x + 2, door_tile_wpos.y + 1 + right)
2391                            .with_z(alt + 4),
2392                    },
2393                    2,
2394                ),
2395                Dir2::NegY => (
2396                    Aabb {
2397                        min: Vec2::new(door_tile_wpos.x + right, self.bounds.min.y - 1)
2398                            .with_z(alt + 3),
2399                        max: Vec2::new(door_tile_wpos.x + 1 + right, self.bounds.min.y)
2400                            .with_z(alt + 4),
2401                    },
2402                    0,
2403                ),
2404                _ => (
2405                    Aabb {
2406                        min: Vec2::new(self.bounds.min.x - 1, door_tile_wpos.y + right)
2407                            .with_z(alt + 3),
2408                        max: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 1 + right)
2409                            .with_z(alt + 4),
2410                    },
2411                    6,
2412                ),
2413            };
2414            painter.fill(
2415                painter.prim(Primitive::Aabb(door_light_pos)),
2416                Fill::Block(
2417                    Block::air(SpriteKind::ChristmasOrnament)
2418                        .with_ori(door_light_ori)
2419                        .unwrap(),
2420                ),
2421            );
2422        }
2423    }
2424}