veloren_world/site2/plot/
house.rs

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