veloren_world/site2/plot/
house.rs

1use super::*;
2use crate::{
3    Land,
4    site2::util::{Dir, sprites::PainterSpriteExt},
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 bounds = Aabr {
48            min: site.tile_wpos(tile_aabr.min),
49            max: site.tile_wpos(tile_aabr.max),
50        };
51
52        let front = match door_dir {
53            dir if dir.y < 0 => Dir::NegY,
54            dir if dir.x < 0 => Dir::NegX,
55            dir if dir.y > 0 => Dir::Y,
56            _ => Dir::X,
57        };
58
59        let christmas_decorations = calendar.is_some_and(|c| c.is_event(CalendarEvent::Christmas));
60
61        Self {
62            door_tile,
63            tile_aabr,
64            bounds,
65            alt: alt.unwrap_or_else(|| {
66                land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32
67            }),
68            levels,
69            overhang: if levels > 3 {
70                // Overhangs of 3 at this building height are ill-advised.
71                // Failure to comply with Veloren building code will result
72                // in a fine and a revoked building permit.
73                *[-5, 1, 2].choose(rng).unwrap_or(&-5)
74            } else if levels > 1 {
75                *[-5, 1, 2, 3].choose(rng).unwrap_or(&2)
76            } else {
77                // Single story buildings require no overhangs
78                0
79            },
80            roof_color: {
81                let colors = [
82                    Rgb::new(21, 43, 48),
83                    Rgb::new(11, 23, 38),
84                    Rgb::new(45, 28, 21),
85                    Rgb::new(10, 55, 40),
86                    Rgb::new(5, 35, 15),
87                    Rgb::new(40, 5, 11),
88                    Rgb::new(55, 45, 11),
89                ];
90                *colors.choose(rng).unwrap_or(&Rgb::new(21, 43, 48))
91            },
92            front,
93            christmas_decorations,
94        }
95    }
96
97    pub fn z_range(&self) -> Range<i32> { self.alt..self.alt + self.levels as i32 * STOREY }
98
99    pub fn roof_color(&self) -> Rgb<u8> { self.roof_color }
100}
101
102const STOREY: i32 = 5;
103
104impl Structure for House {
105    #[cfg(feature = "use-dyn-lib")]
106    const UPDATE_FN: &'static [u8] = b"render_house\0";
107
108    #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "render_house"))]
109    fn render_inner(&self, site: &Site, _land: &Land, painter: &Painter) {
110        let storey = STOREY;
111        let roof = storey * self.levels as i32 - 1;
112        let foundations = 20;
113        let alt = self.alt + 1;
114        let door_tile_wpos = site.tile_center_wpos(self.door_tile);
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 bed_dir = self.front;
1565                let bed_aabr = painter.bed_wood_woodland(bed_pos.with_z(base), bed_dir);
1566                let nightstand_pos = bed_dir
1567                    .opposite()
1568                    .select_aabr_with(bed_aabr, bed_dir.rotated_ccw().select_aabr(bed_aabr))
1569                    .with_z(base)
1570                    + bed_dir.rotated_ccw().to_vec2();
1571                // drawer next to bed
1572                painter.sprite(nightstand_pos.with_z(base), SpriteKind::DrawerWoodWoodlandS);
1573                // collectible on top of drawer
1574                let rng0 = RandomField::new(0).get(nightstand_pos.with_z(base + 1));
1575                let rng1 = RandomField::new(1).get(nightstand_pos.with_z(base + 1));
1576                painter.owned_resource_sprite(
1577                    nightstand_pos.with_z(base + 1),
1578                    match rng0 % 5 {
1579                        0 => SpriteKind::Lantern,
1580                        1 => SpriteKind::PotionMinor,
1581                        2 => SpriteKind::VialEmpty,
1582                        3 => SpriteKind::Bowl,
1583                        _ => SpriteKind::Empty,
1584                    },
1585                    (rng1 % 4) as u8 * 2,
1586                );
1587                // wardrobe along wall in corner of the room
1588                let wardrobe_dir = self.front.rotated_cw();
1589                let bounds = Aabr {
1590                    min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1),
1591                    max: Vec2::new(self.bounds.max.x - 2, self.bounds.max.y - 1),
1592                };
1593                let wardrobe_pos = wardrobe_dir
1594                    .opposite()
1595                    .select_aabr_with(
1596                        bounds,
1597                        bounds.center()
1598                            + wardrobe_dir.vec2(bounds.half_size().w, bounds.half_size().h) / 2,
1599                    )
1600                    .with_z(base);
1601
1602                let sprite = if RandomField::new(0).chance(wardrobe_pos, 0.5) {
1603                    SpriteKind::WardrobedoubleWoodWoodland
1604                } else {
1605                    SpriteKind::WardrobedoubleWoodWoodland2
1606                };
1607                painter.mirrored2(wardrobe_pos, wardrobe_dir, sprite);
1608            } else {
1609                // living room with table + chairs + random
1610                for dir in DIRS {
1611                    // random accent pieces and loot
1612                    let sprite_pos = self.bounds.center() + dir * 5;
1613                    let rng0 = RandomField::new(0).get(sprite_pos.with_z(base));
1614                    let rng1 = RandomField::new(1).get(sprite_pos.with_z(base));
1615                    painter.owned_resource_sprite(
1616                        sprite_pos.with_z(base),
1617                        match rng0 % 32 {
1618                            0..=2 => SpriteKind::Crate,
1619                            3..=4 => SpriteKind::CoatrackWoodWoodland,
1620                            5..=7 => SpriteKind::FlowerpotWoodWoodlandS,
1621                            8..=9 => SpriteKind::Lantern,
1622                            _ => SpriteKind::Empty,
1623                        },
1624                        (rng1 % 4) as u8 * 2,
1625                    );
1626                }
1627
1628                if self.bounds.max.x - self.bounds.min.x < 16
1629                    || self.bounds.max.y - self.bounds.min.y < 16
1630                {
1631                    let table_pos = Vec2::new(half_x, half_y);
1632                    // room is smaller, so use small table
1633                    painter.sprite(
1634                        table_pos.with_z(base),
1635                        SpriteKind::DiningtableWoodWoodlandRound,
1636                    );
1637                    for dir in Dir::iter() {
1638                        let chair_pos = table_pos + dir.to_vec2();
1639                        painter.rotated_sprite(
1640                            chair_pos.with_z(base),
1641                            SpriteKind::ChairWoodWoodland,
1642                            dir.opposite().sprite_ori(),
1643                        );
1644                    }
1645                } else {
1646                    // room is bigger, so use large table + chair positions
1647                    let table_pos = match self.front {
1648                        Dir::Y => Vec2::new(half_x, three_quarter_y),
1649                        Dir::X => Vec2::new(half_x, half_y),
1650                        _ => Vec2::new(quarter_x, half_y),
1651                    }
1652                    .with_z(base);
1653                    let table_axis = if RandomField::new(0).chance(table_pos, 0.5) {
1654                        Dir::X
1655                    } else {
1656                        Dir::Y
1657                    };
1658                    let table_bounds = painter.table_wood_fancy_woodland(table_pos, table_axis);
1659                    painter.chairs_around(SpriteKind::ChairWoodWoodland, 1, table_bounds, base);
1660                }
1661                // drawer along a wall
1662                let (drawer_pos, drawer_ori) = match self.front {
1663                    Dir::Y => (Vec2::new(self.bounds.max.x - 1, self.bounds.max.y - 2), 6),
1664                    Dir::X => (Vec2::new(self.bounds.max.x - 2, self.bounds.max.y - 1), 0),
1665                    Dir::NegY => (Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 2), 6),
1666                    _ => (Vec2::new(self.bounds.min.x + 2, self.bounds.max.y - 1), 0),
1667                };
1668                painter.rotated_sprite(
1669                    drawer_pos.with_z(base),
1670                    SpriteKind::DrawerWoodWoodlandL1,
1671                    drawer_ori,
1672                );
1673            }
1674
1675            // Stairs
1676            if i > 1 {
1677                let stair_width = 3;
1678                let previous_floor_height = (storey * (i as i32 - 2)).max(0);
1679                let stair_origin = match self.front {
1680                    Dir::Y => self.bounds.min + 1,
1681                    Dir::X => self.bounds.min + 1,
1682                    Dir::NegY => {
1683                        Vec2::new(self.bounds.max.x - 12, self.bounds.max.y - stair_width * 2)
1684                    },
1685                    _ => Vec2::new(self.bounds.max.x - 12, self.bounds.min.y + 1),
1686                };
1687                let staircase = if i < 2 {
1688                    painter.prim(Primitive::Empty)
1689                } else if i % 2 == 0 {
1690                    let ramp = /*match self.front */{
1691                        //0 => {
1692                            painter.prim(Primitive::Ramp {
1693                                aabb: Aabb {
1694                                    min: Vec2::new(stair_origin.x + 3, stair_origin.y).with_z(alt + previous_floor_height),
1695                                    max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
1696                                },
1697                                inset: storey,
1698                                dir: Dir::X,
1699                            })
1700                        /*},
1701                        1 => {
1702                            painter.prim(Primitive::Ramp {
1703                                aabb: Aabb {
1704                                    min: Vec2::new(stair_origin.x, stair_origin.y + 3).with_z(alt + previous_floor_height),
1705                                    max: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 10).with_z(alt + previous_height + 1),
1706                                },
1707                                inset: storey,
1708                                dir: 0,
1709                            })
1710                        },
1711                        2 => {
1712                            painter.prim(Primitive::Ramp {
1713                                aabb: Aabb {
1714                                    min: Vec2::new(stair_origin.x + 3, stair_origin.y).with_z(alt + previous_floor_height),
1715                                    max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
1716                                },
1717                                inset: storey,
1718                                dir: 0,
1719                            })
1720                        },
1721                        _ => {
1722                            painter.prim(Primitive::Ramp {
1723                                aabb: Aabb {
1724                                    min: Vec2::new(stair_origin.x, stair_origin.y + 3).with_z(alt + previous_floor_height),
1725                                    max: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 10).with_z(alt + previous_height + 1),
1726                                },
1727                                inset: storey,
1728                                dir: 0,
1729                            })
1730                        }*/
1731                    };
1732                    let support = {
1733                        //match self.front {
1734                        //0 => {
1735                        painter.prim(Primitive::Aabb(Aabb {
1736                            min: Vec2::new(stair_origin.x + 10, stair_origin.y)
1737                                .with_z(alt + previous_floor_height),
1738                            max: Vec2::new(stair_origin.x + 12, stair_origin.y + stair_width)
1739                                .with_z(alt + previous_height + 1),
1740                        }))
1741                        //},
1742                        //1 => {
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                        //2 => {
1751                        //    painter.prim(Primitive::Aabb(Aabb {
1752                        //        min: Vec2::new(stair_origin.x + 10,
1753                        // stair_origin.y).with_z(alt + previous_floor_height),
1754                        //        max: Vec2::new(stair_origin.x + 12,
1755                        // stair_origin.y + stair_width).with_z(alt +
1756                        // previous_height + 1),    }))
1757                        //},
1758                        //_ => {
1759                        //    painter.prim(Primitive::Aabb(Aabb {
1760                        //        min: Vec2::new(stair_origin.x, stair_origin.y
1761                        // + 10).with_z(alt + previous_floor_height), max:
1762                        //   Vec2::new(stair_origin.x + stair_width,
1763                        // stair_origin.y + 12).with_z(alt + previous_height +
1764                        // 1),    }))
1765                        //},
1766                    };
1767                    painter.prim(Primitive::union(ramp, support))
1768                } else {
1769                    let ramp = /*match self.front */{
1770                        //0 => {
1771                            painter.prim(Primitive::Ramp {
1772                                aabb: Aabb {
1773                                    min: Vec2::new(stair_origin.x + 1, stair_origin.y + stair_width).with_z(alt + previous_floor_height),
1774                                    max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
1775                                },
1776                                inset: storey,
1777                                dir: Dir::NegX,
1778                            })
1779                        /*},
1780                        1 => {
1781                            painter.prim(Primitive::Ramp {
1782                                aabb: Aabb {
1783                                    min: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 1).with_z(alt + previous_floor_height),
1784                                    max: Vec2::new(stair_origin.x + 2 * stair_width, stair_origin.y + 8).with_z(alt + previous_height + 1),
1785                                },
1786                                inset: storey,
1787                                dir: 1,
1788                            })
1789                        },
1790                        2 => {
1791                            painter.prim(Primitive::Ramp {
1792                                aabb: Aabb {
1793                                    min: Vec2::new(stair_origin.x + 1, stair_origin.y + stair_width).with_z(alt + previous_floor_height),
1794                                    max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
1795                                },
1796                                inset: storey,
1797                                dir: 1,
1798                            })
1799                        },
1800                        _ => {
1801                            painter.prim(Primitive::Ramp {
1802                                aabb: Aabb {
1803                                    min: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 1).with_z(alt + previous_floor_height),
1804                                    max: Vec2::new(stair_origin.x + 2 * stair_width, stair_origin.y + 8).with_z(alt + previous_height + 1),
1805                                },
1806                                inset: storey,
1807                                dir: 1,
1808                            })
1809                        },
1810                        */
1811                    };
1812                    let support = {
1813                        //match self.front {
1814                        //0 => {
1815                        painter.prim(Primitive::Aabb(Aabb {
1816                            min: Vec2::new(stair_origin.x, stair_origin.y + stair_width)
1817                                .with_z(alt + previous_floor_height),
1818                            max: Vec2::new(stair_origin.x + 2, stair_origin.y + 2 * stair_width)
1819                                .with_z(alt + previous_height + 1),
1820                        }))
1821                        //},
1822                        //1 => {
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                        //2 => {
1831                        //    painter.prim(Primitive::Aabb(Aabb {
1832                        //        min: Vec2::new(stair_origin.x, stair_origin.y
1833                        // + stair_width).with_z(alt + previous_floor_height),
1834                        //   max: Vec2::new(stair_origin.x + 2,
1835                        // stair_origin.y + 2 * stair_width).with_z(alt +
1836                        // previous_height + 1),    }))
1837                        //},
1838                        //_ => {
1839                        //    painter.prim(Primitive::Aabb(Aabb {
1840                        //        min: Vec2::new(stair_origin.x + stair_width,
1841                        // stair_origin.y).with_z(alt + previous_floor_height),
1842                        //        max: Vec2::new(stair_origin.x + 2 *
1843                        // stair_width, stair_origin.y + 2).with_z(alt +
1844                        // previous_height + 1),    }))
1845                        //},
1846                    };
1847                    painter.prim(Primitive::union(ramp, support))
1848                };
1849                let stairwell = if i < 2 {
1850                    painter.prim(Primitive::Empty)
1851                } else if i % 2 == 0 {
1852                    painter.prim(Primitive::Aabb(Aabb {
1853                        min: Vec2::new(stair_origin.x + 2, stair_origin.y)
1854                            .with_z(alt + previous_floor_height + 1),
1855                        max: Vec2::new(stair_origin.x + 9, stair_origin.y + stair_width)
1856                            .with_z(alt + previous_height + 1),
1857                    }))
1858                    //match self.front {
1859                    //    0 => {
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                    //    1 => {
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                    //    2 => {
1876                    //        painter.prim(Primitive::Aabb(Aabb {
1877                    //                min: Vec2::new(stair_origin.x,
1878                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1879                    //                max: Vec2::new(stair_origin.x + 9,
1880                    // stair_origin.y + stair_width).with_z(alt +
1881                    // previous_height + 1),        }))
1882                    //    },
1883                    //    _ => {
1884                    //        painter.prim(Primitive::Aabb(Aabb {
1885                    //                min: Vec2::new(stair_origin.x,
1886                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
1887                    //                max: Vec2::new(stair_origin.x +
1888                    // stair_width, stair_origin.y + 9).with_z(alt +
1889                    // previous_height + 1),        }))
1890                    //    },
1891                    //}
1892                } else {
1893                    painter.prim(Primitive::Aabb(Aabb {
1894                        min: Vec2::new(stair_origin.x + 2, stair_origin.y + stair_width)
1895                            .with_z(alt + previous_floor_height + 1),
1896                        max: Vec2::new(stair_origin.x + 11, stair_origin.y + 2 * stair_width)
1897                            .with_z(alt + previous_height + 1),
1898                    }))
1899                    //match self.front {
1900                    //    0 => {
1901                    //        painter.prim(Primitive::Aabb(Aabb {
1902                    //                min: Vec2::new(stair_origin.x + 2,
1903                    // stair_origin.y + stair_width).with_z(alt +
1904                    // previous_floor_height + 1),
1905                    //                max: Vec2::new(stair_origin.x + 11,
1906                    // stair_origin.y + 2 * stair_width).with_z(alt +
1907                    // previous_height + 1),        }))
1908                    //    },
1909                    //    1 => {
1910                    //        painter.prim(Primitive::Aabb(Aabb {
1911                    //                min: Vec2::new(stair_origin.x +
1912                    // stair_width, stair_origin.y + 2).with_z(alt +
1913                    // previous_floor_height + 1),
1914                    //                max: Vec2::new(stair_origin.x + 2 *
1915                    // stair_width, stair_origin.y + 11).with_z(alt +
1916                    // previous_height + 1),        }))
1917                    //    },
1918                    //    2 => {
1919                    //        painter.prim(Primitive::Aabb(Aabb {
1920                    //                min: Vec2::new(stair_origin.x + 2,
1921                    // stair_origin.y + stair_width).with_z(alt +
1922                    // previous_floor_height + 1),
1923                    //                max: Vec2::new(stair_origin.x + 11,
1924                    // stair_origin.y + 2 * stair_width).with_z(alt +
1925                    // previous_height + 1),        }))
1926                    //    },
1927                    //    _ => {
1928                    //        painter.prim(Primitive::Aabb(Aabb {
1929                    //                min: Vec2::new(stair_origin.x +
1930                    // stair_width, stair_origin.y + 2).with_z(alt +
1931                    // previous_floor_height + 1),
1932                    //                max: Vec2::new(stair_origin.x + 2 *
1933                    // stair_width, stair_origin.y + 11).with_z(alt +
1934                    // previous_height + 1),        }))
1935                    //    },
1936                    //}
1937                };
1938
1939                painter.fill(stairwell, Fill::Block(Block::empty()));
1940                painter.fill(
1941                    staircase,
1942                    Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
1943                );
1944            }
1945        }
1946
1947        // Foundation
1948        painter.fill(
1949            painter.prim(Primitive::Aabb(Aabb {
1950                min: (self.bounds.min - 1).with_z(self.alt - foundations),
1951                max: (self.bounds.max + 2).with_z(self.alt + 1),
1952            })),
1953            Fill::Block(Block::new(BlockKind::Rock, Rgb::new(31, 33, 32))),
1954        );
1955
1956        // Fireplace and chimney
1957        let fireplace_origin = /*if self.levels > 1 {
1958            match self.front {
1959                0 => {
1960                    Vec2::new(self.bounds.min.x + 12, self.bounds.min.y + 1)
1961                },
1962                1 => {
1963                    Vec2::new(self.bounds.min.x + 1, self.bounds.max.y - 12)
1964                },
1965                2 => {
1966                    Vec2::new(self.bounds.max.x - 12, self.bounds.max.y - 1)
1967                },
1968                _ => {
1969                    Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 12)
1970                },
1971            }
1972        } else */{
1973            match self.front {
1974                Dir::Y => {
1975                    Vec2::new(half_x, self.bounds.min.y + 1)
1976                },
1977                Dir::X => {
1978                    Vec2::new(self.bounds.min.x + 1, half_y)
1979                },
1980                Dir::NegY => {
1981                    Vec2::new(half_x - 4, self.bounds.max.y - 3)
1982                },
1983                _ => {
1984                    Vec2::new(self.bounds.max.x - 3, half_y)
1985                },
1986            }
1987        };
1988        let chimney = match self.front {
1989            Dir::Y => painter.prim(Primitive::Aabb(Aabb {
1990                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
1991                max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
1992                    .with_z(alt + roof + roof_height + 2),
1993            })),
1994            Dir::X => painter.prim(Primitive::Aabb(Aabb {
1995                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
1996                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
1997                    .with_z(alt + roof + roof_height + 2),
1998            })),
1999            Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
2000                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2001                max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
2002                    .with_z(alt + roof + roof_height + 2),
2003            })),
2004            _ => painter.prim(Primitive::Aabb(Aabb {
2005                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
2006                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
2007                    .with_z(alt + roof + roof_height + 2),
2008            })),
2009        };
2010
2011        let chimney_cavity = match self.front {
2012            Dir::Y => painter.prim(Primitive::Aabb(Aabb {
2013                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2014                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
2015                    .with_z(alt + roof + roof_height + 2),
2016            })),
2017            Dir::X => painter.prim(Primitive::Aabb(Aabb {
2018                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2019                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
2020                    .with_z(alt + roof + roof_height + 2),
2021            })),
2022            Dir::NegY => painter.prim(Primitive::Aabb(Aabb {
2023                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2024                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
2025                    .with_z(alt + roof + roof_height + 2),
2026            })),
2027            _ => painter.prim(Primitive::Aabb(Aabb {
2028                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2029                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
2030                    .with_z(alt + roof + roof_height + 2),
2031            })),
2032        };
2033        let fire_embers = match self.front {
2034            Dir::Y => Aabb {
2035                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2036                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 1),
2037            },
2038            Dir::X => Aabb {
2039                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2040                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
2041            },
2042            Dir::NegY => Aabb {
2043                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2044                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 1),
2045            },
2046            _ => Aabb {
2047                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2048                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
2049            },
2050        };
2051        let fireplace_cavity = match self.front {
2052            Dir::Y => Aabb {
2053                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2054                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
2055            },
2056            Dir::X => Aabb {
2057                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
2058                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
2059            },
2060            Dir::NegY => Aabb {
2061                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y).with_z(alt),
2062                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 2),
2063            },
2064            _ => Aabb {
2065                min: Vec2::new(fireplace_origin.x, fireplace_origin.y + 1).with_z(alt),
2066                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 2),
2067            },
2068        };
2069
2070        painter.fill(
2071            chimney,
2072            Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24),
2073        );
2074        painter.fill(chimney_cavity, Fill::Block(Block::empty()));
2075        painter.fill(
2076            painter.prim(Primitive::Aabb(fireplace_cavity)),
2077            Fill::Block(Block::empty()),
2078        );
2079        painter.fill(
2080            painter.prim(Primitive::Aabb(fire_embers)),
2081            Fill::Block(Block::air(SpriteKind::Ember)),
2082        );
2083
2084        // bedroom on first level corners in case there is no 2nd level
2085        if self.levels == 1 {
2086            // different positions for smaller houses
2087            let bed_pos = if self.bounds.max.x - self.bounds.min.x < 16
2088                || self.bounds.max.y - self.bounds.min.y < 16
2089            {
2090                match self.front {
2091                    Dir::Y => Vec2::new(self.bounds.min.x + 4, self.bounds.min.y + 2),
2092                    Dir::X => Vec2::new(self.bounds.min.x + 2, self.bounds.min.y + 4),
2093                    Dir::NegY => Vec2::new(self.bounds.max.x - 4, self.bounds.max.y - 2),
2094                    _ => Vec2::new(self.bounds.max.x - 8, self.bounds.max.y - 2),
2095                }
2096            } else {
2097                match self.front {
2098                    Dir::Y => Vec2::new(self.bounds.max.x - 4, self.bounds.min.y + 2),
2099                    Dir::X => Vec2::new(self.bounds.min.x + 8, self.bounds.max.y - 2),
2100                    Dir::NegY => Vec2::new(self.bounds.max.x - 4, self.bounds.max.y - 2),
2101                    _ => Vec2::new(self.bounds.max.x - 8, self.bounds.max.y - 2),
2102                }
2103            };
2104            let bed_dir = self.front.abs();
2105
2106            painter.bed_wood_woodland(bed_pos.with_z(alt), bed_dir);
2107        }
2108
2109        if self.christmas_decorations {
2110            let (wreath_pos, wreath_ori) = match self.front {
2111                Dir::Y => (
2112                    Aabb {
2113                        min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 3)
2114                            .with_z(alt + 2),
2115                        max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 4)
2116                            .with_z(alt + 3),
2117                    },
2118                    4,
2119                ),
2120                Dir::X => (
2121                    Aabb {
2122                        min: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 1)
2123                            .with_z(alt + 2),
2124                        max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 2)
2125                            .with_z(alt + 3),
2126                    },
2127                    2,
2128                ),
2129                Dir::NegY => (
2130                    Aabb {
2131                        min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y - 1)
2132                            .with_z(alt + 2),
2133                        max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y).with_z(alt + 3),
2134                    },
2135                    0,
2136                ),
2137                _ => (
2138                    Aabb {
2139                        min: Vec2::new(fireplace_origin.x - 1, fireplace_origin.y + 1)
2140                            .with_z(alt + 2),
2141                        max: Vec2::new(fireplace_origin.x, fireplace_origin.y + 2).with_z(alt + 3),
2142                    },
2143                    6,
2144                ),
2145            };
2146            painter.fill(
2147                painter.prim(Primitive::Aabb(wreath_pos)),
2148                Fill::Block(
2149                    Block::air(SpriteKind::ChristmasWreath)
2150                        .with_ori(wreath_ori)
2151                        .unwrap(),
2152                ),
2153            );
2154        }
2155
2156        // Door
2157        // Fill around the door with wall
2158        let doorway1 = match self.front {
2159            Dir::Y => Aabb {
2160                min: Vec2::new(door_tile_wpos.x - 1, self.bounds.max.y).with_z(alt),
2161                max: Vec2::new(door_tile_wpos.x + 3, self.bounds.max.y + 1).with_z(alt + 4),
2162            },
2163            Dir::X => Aabb {
2164                min: Vec2::new(self.bounds.max.x, door_tile_wpos.y - 1).with_z(alt),
2165                max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 3).with_z(alt + 4),
2166            },
2167            Dir::NegY => Aabb {
2168                min: Vec2::new(door_tile_wpos.x - 1, self.bounds.min.y).with_z(alt),
2169                max: Vec2::new(door_tile_wpos.x + 3, self.bounds.min.y + 1).with_z(alt + 4),
2170            },
2171            _ => Aabb {
2172                min: Vec2::new(self.bounds.min.x, door_tile_wpos.y - 1).with_z(alt),
2173                max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 3).with_z(alt + 4),
2174            },
2175        };
2176        painter.fill(
2177            painter.prim(Primitive::Aabb(doorway1)),
2178            Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24),
2179        );
2180
2181        // Carve out the doorway with air
2182        let doorway2 = match self.front {
2183            Dir::Y => Aabb {
2184                min: Vec2::new(door_tile_wpos.x, self.bounds.max.y).with_z(alt),
2185                max: Vec2::new(door_tile_wpos.x + 2, self.bounds.max.y + 1).with_z(alt + 3),
2186            },
2187            Dir::X => Aabb {
2188                min: Vec2::new(self.bounds.max.x, door_tile_wpos.y).with_z(alt),
2189                max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 2).with_z(alt + 3),
2190            },
2191            Dir::NegY => Aabb {
2192                min: Vec2::new(door_tile_wpos.x, self.bounds.min.y).with_z(alt),
2193                max: Vec2::new(door_tile_wpos.x + 2, self.bounds.min.y + 1).with_z(alt + 3),
2194            },
2195            _ => Aabb {
2196                min: Vec2::new(self.bounds.min.x, door_tile_wpos.y).with_z(alt),
2197                max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 2).with_z(alt + 3),
2198            },
2199        };
2200        painter.fill(
2201            painter.prim(Primitive::Aabb(doorway2)),
2202            Fill::Block(Block::empty()),
2203        );
2204
2205        // Fill in the right and left side doors
2206        let (door_gap, door1, door1_ori, door2, door2_ori) = match self.front {
2207            Dir::Y => (
2208                Aabb {
2209                    min: Vec2::new(door_tile_wpos.x - 1, self.bounds.max.y + 1).with_z(alt),
2210                    max: Vec2::new(door_tile_wpos.x + 3, self.bounds.max.y + 4).with_z(alt + 3),
2211                },
2212                Aabb {
2213                    min: Vec2::new(door_tile_wpos.x, self.bounds.max.y).with_z(alt),
2214                    max: Vec2::new(door_tile_wpos.x + 1, self.bounds.max.y + 1).with_z(alt + 1),
2215                },
2216                0,
2217                Aabb {
2218                    min: Vec2::new(door_tile_wpos.x + 1, self.bounds.max.y).with_z(alt),
2219                    max: Vec2::new(door_tile_wpos.x + 2, self.bounds.max.y + 1).with_z(alt + 1),
2220                },
2221                4,
2222            ),
2223            Dir::X => (
2224                Aabb {
2225                    min: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y - 1).with_z(alt),
2226                    max: Vec2::new(self.bounds.max.x + 4, door_tile_wpos.y + 3).with_z(alt + 3),
2227                },
2228                Aabb {
2229                    min: Vec2::new(self.bounds.max.x, door_tile_wpos.y).with_z(alt),
2230                    max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 1).with_z(alt + 1),
2231                },
2232                2,
2233                Aabb {
2234                    min: Vec2::new(self.bounds.max.x, door_tile_wpos.y + 1).with_z(alt),
2235                    max: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + 2).with_z(alt + 1),
2236                },
2237                6,
2238            ),
2239            Dir::NegY => (
2240                Aabb {
2241                    min: Vec2::new(door_tile_wpos.x - 1, self.bounds.min.y - 4).with_z(alt),
2242                    max: Vec2::new(door_tile_wpos.x + 3, self.bounds.min.y).with_z(alt + 3),
2243                },
2244                Aabb {
2245                    min: Vec2::new(door_tile_wpos.x, self.bounds.min.y).with_z(alt),
2246                    max: Vec2::new(door_tile_wpos.x + 1, self.bounds.min.y + 1).with_z(alt + 1),
2247                },
2248                0,
2249                Aabb {
2250                    min: Vec2::new(door_tile_wpos.x + 1, self.bounds.min.y).with_z(alt),
2251                    max: Vec2::new(door_tile_wpos.x + 2, self.bounds.min.y + 1).with_z(alt + 1),
2252                },
2253                4,
2254            ),
2255            _ => (
2256                Aabb {
2257                    min: Vec2::new(self.bounds.min.x - 4, door_tile_wpos.y - 1).with_z(alt),
2258                    max: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 3).with_z(alt + 3),
2259                },
2260                Aabb {
2261                    min: Vec2::new(self.bounds.min.x, door_tile_wpos.y).with_z(alt),
2262                    max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 1).with_z(alt + 1),
2263                },
2264                2,
2265                Aabb {
2266                    min: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 1).with_z(alt),
2267                    max: Vec2::new(self.bounds.min.x + 1, door_tile_wpos.y + 2).with_z(alt + 1),
2268                },
2269                6,
2270            ),
2271        };
2272        painter.fill(
2273            painter.prim(Primitive::Aabb(door_gap)),
2274            Fill::Block(Block::air(SpriteKind::Empty)),
2275        );
2276        painter.fill(
2277            painter.prim(Primitive::Aabb(door1)),
2278            Fill::Block(Block::air(SpriteKind::Door).with_ori(door1_ori).unwrap()),
2279        );
2280        painter.fill(
2281            painter.prim(Primitive::Aabb(door2)),
2282            Fill::Block(Block::air(SpriteKind::Door).with_ori(door2_ori).unwrap()),
2283        );
2284        if self.christmas_decorations {
2285            // we need to randomize position to see both variants
2286            let rng = RandomField::new(0).get(door_tile_wpos.with_z(alt + 3));
2287            let right = (rng % 2) as i32;
2288            let (door_light_pos, door_light_ori) = match self.front {
2289                Dir::Y => (
2290                    Aabb {
2291                        min: Vec2::new(door_tile_wpos.x + right, self.bounds.max.y + 1)
2292                            .with_z(alt + 3),
2293                        max: Vec2::new(door_tile_wpos.x + 1 + right, self.bounds.max.y + 2)
2294                            .with_z(alt + 4),
2295                    },
2296                    4,
2297                ),
2298                Dir::X => (
2299                    Aabb {
2300                        min: Vec2::new(self.bounds.max.x + 1, door_tile_wpos.y + right)
2301                            .with_z(alt + 3),
2302                        max: Vec2::new(self.bounds.max.x + 2, door_tile_wpos.y + 1 + right)
2303                            .with_z(alt + 4),
2304                    },
2305                    2,
2306                ),
2307                Dir::NegY => (
2308                    Aabb {
2309                        min: Vec2::new(door_tile_wpos.x + right, self.bounds.min.y - 1)
2310                            .with_z(alt + 3),
2311                        max: Vec2::new(door_tile_wpos.x + 1 + right, self.bounds.min.y)
2312                            .with_z(alt + 4),
2313                    },
2314                    0,
2315                ),
2316                _ => (
2317                    Aabb {
2318                        min: Vec2::new(self.bounds.min.x - 1, door_tile_wpos.y + right)
2319                            .with_z(alt + 3),
2320                        max: Vec2::new(self.bounds.min.x, door_tile_wpos.y + 1 + right)
2321                            .with_z(alt + 4),
2322                    },
2323                    6,
2324                ),
2325            };
2326            painter.fill(
2327                painter.prim(Primitive::Aabb(door_light_pos)),
2328                Fill::Block(
2329                    Block::air(SpriteKind::ChristmasOrnament)
2330                        .with_ori(door_light_ori)
2331                        .unwrap(),
2332                ),
2333            );
2334        }
2335    }
2336}