use super::*;
use crate::{
    site2::util::Dir,
    util::{RandomField, Sampler, DIRS},
    Land,
};
use common::terrain::{Block, BlockKind, SpriteKind};
use rand::prelude::*;
use vek::*;

/// Represents house data generated by the `generate()` method
pub struct House {
    /// Tile position of the door tile
    door_tile: Vec2<i32>,
    /// Axis aligned bounding region of tiles
    tile_aabr: Aabr<i32>,
    /// Axis aligned bounding region for the house
    bounds: Aabr<i32>,
    /// Approximate altitude of the door tile
    pub(crate) alt: i32,
    /// Number of floors
    levels: u32,
    /// Difference between a level and the floor above
    overhang: i32,
    /// Color of the roof
    roof_color: Rgb<u8>,
    front: u8,
}

impl House {
    pub fn generate(
        land: &Land,
        rng: &mut impl Rng,
        site: &Site,
        door_tile: Vec2<i32>,
        door_dir: Vec2<i32>,
        tile_aabr: Aabr<i32>,
    ) -> Self {
        let levels = rng.gen_range(1..2 + (tile_aabr.max - tile_aabr.min).product() / 6) as u32;
        let door_tile_pos = site.tile_center_wpos(door_tile);
        let bounds = Aabr {
            min: site.tile_wpos(tile_aabr.min),
            max: site.tile_wpos(tile_aabr.max),
        };
        let front = if door_dir.y < 0 {
            2
        } else if door_dir.x < 0 {
            3
        } else if door_dir.y > 0 {
            0
        } else {
            1
        };

        Self {
            door_tile: door_tile_pos,
            tile_aabr,
            bounds,
            alt: land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32,
            levels,
            overhang: if levels > 3 {
                // Overhangs of 3 at this building height are ill-advised.
                // Failure to comply with Veloren building code will result
                // in a fine and a revoked building permit.
                *[-5, 1, 2].choose(rng).unwrap_or(&-5)
            } else if levels > 1 {
                *[-5, 1, 2, 3].choose(rng).unwrap_or(&2)
            } else {
                // Single story buildings require no overhangs
                0
            },
            roof_color: {
                let colors = [
                    Rgb::new(21, 43, 48),
                    Rgb::new(11, 23, 38),
                    Rgb::new(45, 28, 21),
                    Rgb::new(10, 55, 40),
                    Rgb::new(5, 35, 15),
                    Rgb::new(40, 5, 11),
                    Rgb::new(55, 45, 11),
                ];
                *colors.choose(rng).unwrap_or(&Rgb::new(21, 43, 48))
            },
            front,
        }
    }

    pub fn z_range(&self) -> Range<i32> { self.alt..self.alt + self.levels as i32 * STOREY }
}

const STOREY: i32 = 5;

impl Structure for House {
    fn render(&self, site: &Site, _land: &Land, painter: &Painter) {
        let storey = STOREY;
        let roof = storey * self.levels as i32 - 1;
        let foundations = 12;
        let alt = self.alt + 1;

        // Roof
        let roof_lip = 1;
        let roof_height = (self.bounds.min - self.bounds.max)
            .map(|e| e.abs())
            .reduce_min()
            / 2
            + roof_lip
            + 1;

        let (roof_primitive, roof_empty) = match self.front {
            0 => {
                (
                    painter.prim(Primitive::Gable {
                        aabb: Aabb {
                            min: (self.bounds.min - roof_lip).with_z(alt + roof),
                            max: (Vec2::new(
                                self.bounds.max.x + 1 + roof_lip,
                                self.bounds.max.y
                                    + 1
                                    + roof_lip
                                    + (self.levels as i32 - 1) * self.overhang,
                            ))
                            .with_z(alt + roof + roof_height),
                        },
                        inset: roof_height,
                        dir: Dir::Y,
                    }),
                    painter.prim(Primitive::Gable {
                        aabb: Aabb {
                            min: (Vec2::new(self.bounds.min.x, self.bounds.min.y - 1))
                                .with_z(alt + roof), /* self.bounds.min - roof_lip).with_z(alt +
                                                      * roof), */
                            max: (Vec2::new(
                                self.bounds.max.x + 1,
                                self.bounds.max.y
                                    + 1
                                    + (self.levels as i32 - 1) * self.overhang
                                    + 1,
                            ))
                            .with_z(alt + roof + roof_height - 1),
                        },
                        inset: roof_height - 1,
                        dir: Dir::Y,
                    }),
                )
            },
            1 => {
                (
                    painter.prim(Primitive::Gable {
                        aabb: Aabb {
                            min: (self.bounds.min - roof_lip).with_z(alt + roof),
                            max: Vec2::new(
                                self.bounds.max.x
                                    + 1
                                    + roof_lip
                                    + (self.levels as i32 - 1) * self.overhang,
                                self.bounds.max.y + 1 + roof_lip,
                            )
                            .with_z(alt + roof + roof_height),
                        },
                        inset: roof_height,
                        dir: Dir::X,
                    }),
                    painter.prim(Primitive::Gable {
                        aabb: Aabb {
                            min: (Vec2::new(self.bounds.min.x - 1, self.bounds.min.y))
                                .with_z(alt + roof), /* self.bounds.min - roof_lip).with_z(alt +
                                                      * roof), */
                            max: Vec2::new(
                                self.bounds.max.x
                                    + 1
                                    + (self.levels as i32 - 1) * self.overhang
                                    + 1,
                                self.bounds.max.y + 1,
                            )
                            .with_z(alt + roof + roof_height - 1),
                        },
                        inset: roof_height - 1,
                        dir: Dir::X,
                    }),
                )
            },
            2 => (
                painter.prim(Primitive::Gable {
                    aabb: Aabb {
                        min: Vec2::new(
                            self.bounds.min.x - roof_lip,
                            self.bounds.min.y - roof_lip - (self.levels as i32 - 1) * self.overhang,
                        )
                        .with_z(alt + roof),
                        max: Vec2::new(
                            self.bounds.max.x + 1 + roof_lip,
                            self.bounds.max.y + roof_lip + 1,
                        )
                        .with_z(alt + roof + roof_height),
                    },
                    inset: roof_height,
                    dir: Dir::Y,
                }),
                painter.prim(Primitive::Gable {
                    aabb: Aabb {
                        min: Vec2::new(
                            self.bounds.min.x,
                            self.bounds.min.y - 1 - (self.levels as i32 - 1) * self.overhang - 1,
                        )
                        .with_z(alt + roof),
                        max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + roof_lip + 1)
                            .with_z(alt + roof + roof_height - 1),
                    },
                    inset: roof_height - 1,
                    dir: Dir::Y,
                }),
            ),
            _ => (
                painter.prim(Primitive::Gable {
                    aabb: Aabb {
                        min: Vec2::new(
                            self.bounds.min.x - roof_lip - (self.levels as i32 - 1) * self.overhang,
                            self.bounds.min.y - roof_lip,
                        )
                        .with_z(alt + roof),
                        max: Vec2::new(
                            self.bounds.max.x + 1 + roof_lip,
                            self.bounds.max.y + 1 + roof_lip,
                        )
                        .with_z(alt + roof + roof_height),
                    },
                    inset: roof_height,
                    dir: Dir::X,
                }),
                painter.prim(Primitive::Gable {
                    aabb: Aabb {
                        min: Vec2::new(
                            self.bounds.min.x
                                - roof_lip
                                - 1
                                - (self.levels as i32 - 1) * self.overhang,
                            self.bounds.min.y,
                        )
                        .with_z(alt + roof),
                        max: Vec2::new(self.bounds.max.x + 1 + roof_lip, self.bounds.max.y + 1)
                            .with_z(alt + roof + roof_height - 1),
                    },
                    inset: roof_height - 1,
                    dir: Dir::X,
                }),
            ),
        };

        let (roof_front_wall, roof_rear_wall) = match self.front {
            0 => (
                painter.prim(Primitive::Aabb(Aabb {
                    min: (Vec2::new(
                        self.bounds.min.x,
                        self.bounds.max.y + (self.levels as i32 - 1) * self.overhang,
                    ))
                    .with_z(alt + roof),
                    max: (Vec2::new(
                        self.bounds.max.x + 1,
                        self.bounds.max.y + (self.levels as i32 - 1) * self.overhang + 1,
                    ))
                    .with_z(alt + roof + roof_height),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: (Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof)),
                    max: (Vec2::new(self.bounds.max.x + 1, self.bounds.min.y + 1)
                        .with_z(alt + roof + roof_height)),
                })),
            ),
            1 => (
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(
                        self.bounds.max.x + (self.levels as i32 - 1) * self.overhang,
                        self.bounds.min.y,
                    )
                    .with_z(alt + roof),
                    max: Vec2::new(
                        self.bounds.max.x + (self.levels as i32 - 1) * self.overhang + 1,
                        self.bounds.max.y + 1,
                    )
                    .with_z(alt + roof + roof_height),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
                    max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + roof_height),
                })),
            ),
            2 => (
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(
                        self.bounds.min.x,
                        self.bounds.min.y - (self.levels as i32 - 1) * self.overhang,
                    )
                    .with_z(alt + roof),
                    max: Vec2::new(
                        self.bounds.max.x + 1,
                        self.bounds.min.y - (self.levels as i32 - 1) * self.overhang + 1,
                    )
                    .with_z(alt + roof + roof_height),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.max.y).with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + roof_height),
                })),
            ),
            _ => (
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(
                        self.bounds.min.x - (self.levels as i32 - 1) * self.overhang,
                        self.bounds.min.y,
                    )
                    .with_z(alt + roof),
                    max: Vec2::new(
                        self.bounds.min.x - (self.levels as i32 - 1) * self.overhang + 1,
                        self.bounds.max.y + 1,
                    )
                    .with_z(alt + roof + roof_height),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.max.x, self.bounds.min.y).with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + roof_height),
                })),
            ),
        };
        let roof_front = painter.prim(Primitive::intersect(roof_empty, roof_front_wall));
        let roof_rear = painter.prim(Primitive::intersect(roof_empty, roof_rear_wall));
        painter.fill(
            roof_primitive,
            Fill::Brick(BlockKind::Wood, self.roof_color, 24),
        );
        painter.fill(roof_empty, Fill::Block(Block::empty()));
        let roof_walls = painter.prim(Primitive::union(roof_front, roof_rear));
        painter.fill(
            roof_walls,
            Fill::Brick(BlockKind::Wood, Rgb::new(200, 180, 150), 24),
        );
        let max_overhang = (self.levels as i32 - 1) * self.overhang;
        let (roof_beam, roof_beam_right, roof_beam_left) = match self.front {
            0 => (
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1 + max_overhang)
                        .with_z(alt + roof + 1),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
                    max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1 + max_overhang)
                        .with_z(alt + roof + 1),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.max.x, self.bounds.min.y).with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1 + max_overhang)
                        .with_z(alt + roof + 1),
                })),
            ),
            1 => (
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + 1),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y).with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.min.y + 1)
                        .with_z(alt + roof + 1),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.max.y).with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + max_overhang + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + 1),
                })),
            ),
            2 => (
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y - max_overhang)
                        .with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + 1),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.max.x, self.bounds.min.y - max_overhang)
                        .with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + 1),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y - max_overhang)
                        .with_z(alt + roof),
                    max: Vec2::new(self.bounds.min.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + 1),
                })),
            ),
            _ => (
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x - max_overhang - 1, self.bounds.min.y)
                        .with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + 1),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x - max_overhang, self.bounds.min.y)
                        .with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.min.y + 1)
                        .with_z(alt + roof + 1),
                })),
                painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x - max_overhang, self.bounds.max.y)
                        .with_z(alt + roof),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + roof + 1),
                })),
            ),
        };
        let quarter_x = self.bounds.min.x + (self.bounds.max.x - self.bounds.min.x) / 4;
        let quarter_y = self.bounds.min.y + (self.bounds.max.y - self.bounds.min.y) / 4;
        let half_x = self.bounds.min.x + (self.bounds.max.x - self.bounds.min.x) / 2;
        let half_y = self.bounds.min.y + (self.bounds.max.y - self.bounds.min.y) / 2;
        let three_quarter_x = self.bounds.min.x + 3 * (self.bounds.max.x - self.bounds.min.x) / 4;
        let three_quarter_y = self.bounds.min.y + 3 * (self.bounds.max.y - self.bounds.min.y) / 4;
        let top_rafter = if self.front % 2 == 0 {
            painter.prim(Primitive::Aabb(Aabb {
                min: (Vec2::new(half_x, self.bounds.min.y - 2 - max_overhang.abs())
                    .with_z(alt + roof)),
                max: (Vec2::new(half_x + 1, self.bounds.max.y + 2 + max_overhang.abs()))
                    .with_z(alt + roof + roof_height),
            }))
        } else {
            painter.prim(Primitive::Aabb(Aabb {
                min: (Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y)
                    .with_z(alt + roof)),
                max: (Vec2::new(self.bounds.max.x + 1 + max_overhang.abs(), half_y + 1))
                    .with_z(alt + roof + roof_height),
            }))
        };
        let left_rafter = if self.front % 2 == 0 {
            painter.prim(Primitive::Plane(
                Aabr {
                    min: Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()),
                    max: Vec2::new(
                        three_quarter_x + 1,
                        self.bounds.max.y + 1 + max_overhang.abs(),
                    ),
                },
                Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()).with_z(alt + roof),
                Vec2::new(1.0, 0.0),
            ))
        } else {
            painter.prim(Primitive::Plane(
                Aabr {
                    min: Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y),
                    max: Vec2::new(
                        self.bounds.max.x + 1 + max_overhang.abs(),
                        three_quarter_y + 1,
                    ),
                },
                Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y).with_z(alt + roof),
                Vec2::new(0.0, 1.0),
            ))
        };
        let right_rafter = if self.front % 2 == 0 {
            painter.prim(Primitive::Plane(
                Aabr {
                    min: Vec2::new(quarter_x, self.bounds.min.y - 1 - max_overhang.abs()),
                    max: Vec2::new(half_x + 1, self.bounds.max.y + 1 + max_overhang.abs()),
                },
                Vec2::new(half_x, self.bounds.min.y - 1 - max_overhang.abs()).with_z(alt + roof),
                Vec2::new(1.0, 0.0),
            ))
        } else {
            painter.prim(Primitive::Plane(
                Aabr {
                    min: Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), quarter_y),
                    max: Vec2::new(self.bounds.max.x + 1 + max_overhang.abs(), half_y + 1),
                },
                Vec2::new(self.bounds.min.x - 1 - max_overhang.abs(), half_y).with_z(alt + roof),
                Vec2::new(0.0, 1.0),
            ))
        };
        let rafters1 = painter.prim(Primitive::union(left_rafter, right_rafter));
        let rafters2 = painter.prim(Primitive::union(rafters1, top_rafter));

        painter.fill(
            painter.prim(Primitive::intersect(roof_beam, roof_walls)),
            Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
        );
        painter.fill(
            painter.prim(Primitive::union(roof_beam_left, roof_beam_right)),
            Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
        );
        painter.fill(
            painter.prim(Primitive::intersect(rafters2, roof_walls)),
            Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
        );

        // Walls
        // For each storey...
        for i in 1..self.levels + 1 {
            let previous_height = (storey * (i as i32 - 1) - 1).max(-1);
            let height = storey * i as i32 - 1;
            let window_height = storey - 3;
            let storey_increase = (i as i32 - 1) * self.overhang;

            // Walls
            let inner_level = if self.overhang < -4 && i > 1 {
                match self.front {
                    0 => painter.prim(Primitive::Aabb(Aabb {
                        min: (self.bounds.min + 1).with_z(alt + previous_height),
                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase + 1)
                            .with_z(alt + height),
                    })),
                    1 => painter.prim(Primitive::Aabb(Aabb {
                        min: (self.bounds.min + 1).with_z(alt + previous_height),
                        max: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.max.y)
                            .with_z(alt + height),
                    })),
                    2 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x + 1,
                            self.bounds.min.y - storey_increase + 1,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
                    })),
                    _ => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x - storey_increase + 1,
                            self.bounds.min.y + 1,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
                    })),
                }
            } else {
                match self.front {
                    0 => painter.prim(Primitive::Aabb(Aabb {
                        min: (self.bounds.min + 1).with_z(alt + previous_height),
                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase)
                            .with_z(alt + height),
                    })),
                    1 => painter.prim(Primitive::Aabb(Aabb {
                        min: (self.bounds.min + 1).with_z(alt + previous_height),
                        max: (Vec2::new(self.bounds.max.x + storey_increase, self.bounds.max.y))
                            .with_z(alt + height),
                    })),
                    2 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x + 1,
                            self.bounds.min.y - storey_increase + 1,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
                    })),
                    _ => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x - storey_increase + 1,
                            self.bounds.min.y + 1,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(self.bounds.max.x, self.bounds.max.y).with_z(alt + height),
                    })),
                }
            };
            let outer_level = match self.front {
                0 => painter.prim(Primitive::Aabb(Aabb {
                    min: self.bounds.min.with_z(alt + previous_height),
                    max: (Vec2::new(
                        self.bounds.max.x + 1,
                        self.bounds.max.y + storey_increase + 1,
                    ))
                    .with_z(alt + height),
                })),
                1 => painter.prim(Primitive::Aabb(Aabb {
                    min: self.bounds.min.with_z(alt + previous_height),
                    max: Vec2::new(
                        self.bounds.max.x + storey_increase + 1,
                        self.bounds.max.y + 1,
                    )
                    .with_z(alt + height),
                })),
                2 => painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x, self.bounds.min.y - storey_increase)
                        .with_z(alt + previous_height),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + height),
                })),
                _ => painter.prim(Primitive::Aabb(Aabb {
                    min: Vec2::new(self.bounds.min.x - storey_increase, self.bounds.min.y)
                        .with_z(alt + previous_height),
                    max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                        .with_z(alt + height),
                })),
            };

            // Ground floor has rock walls
            let wall_block_fill = if i < 2 {
                Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24)
            } else {
                Fill::Brick(BlockKind::Wood, Rgb::new(200, 180, 150), 24)
            };
            painter.fill(outer_level, wall_block_fill);
            painter.fill(inner_level, Fill::Block(Block::empty()));

            let walls = outer_level
                .union(inner_level)
                .without(outer_level.intersect(inner_level));

            // Wall Pillars
            // Only upper non-stone floors have wooden beams in the walls
            if i > 1 {
                let mut pillars_y = painter.prim(Primitive::Empty);
                let mut overhang_supports = painter.prim(Primitive::Empty);

                for x in self.tile_aabr.min.x - 2..self.tile_aabr.max.x + 2 {
                    if self.overhang >= 2 && self.front % 2 == 0 {
                        let temp = match self.front {
                            0 => site.tile_wpos(Vec2::new(x, self.tile_aabr.max.y)),
                            //2 => site.tile_wpos(Vec2::new(x, self.tile_aabr.min.y)),
                            _ => Vec2::zero(),
                        };
                        // NOTE: Orientation 2 doesn't work for some reason. I believe it is
                        // something to do with AABBs with min and max not smaller in the right
                        // order. The same thing is true for orientation 3.
                        let support = match self.front {
                            0 => painter.line(
                                Vec2::new(
                                    temp.x,
                                    self.bounds.max.y + storey_increase - self.overhang + 1,
                                )
                                .with_z(alt + previous_height - 3),
                                Vec2::new(
                                    temp.x,
                                    self.bounds.max.y + storey_increase - self.overhang + 2,
                                )
                                .with_z(alt + previous_height),
                                0.75,
                            ),
                            //2 => {
                            //    painter.line(
                            //    Vec2::new(temp.x, self.bounds.min.y - storey_increase -
                            // 6).with_z(alt + previous_height + 30),
                            //    Vec2::new(temp.x + 1, self.bounds.min.y - storey_increase
                            // - 3).with_z(alt + previous_height - 3), 1.0)
                            //},
                            _ => painter.prim(Primitive::Empty),
                        };
                        if temp.x <= self.bounds.max.x && temp.x >= self.bounds.min.x {
                            overhang_supports =
                                painter.prim(Primitive::union(overhang_supports, support));
                        }
                    }
                    let pillar = painter.prim(Primitive::Aabb(Aabb {
                        min: site
                            .tile_wpos(Vec2::new(x, self.tile_aabr.min.y - 4))
                            .with_z(alt + previous_height),
                        max: (site.tile_wpos(Vec2::new(x, self.tile_aabr.max.y + 4))
                            + Vec2::unit_x())
                        .with_z(alt + height),
                    }));
                    pillars_y = painter.prim(Primitive::union(pillars_y, pillar));
                }
                let mut pillars_x = painter.prim(Primitive::Empty);
                for y in self.tile_aabr.min.y - 2..self.tile_aabr.max.y + 2 {
                    if self.overhang >= 2 && self.front % 2 != 0 {
                        let temp = match self.front {
                            0 => Vec2::zero(),
                            1 => site.tile_wpos(Vec2::new(self.tile_aabr.max.x, y)),
                            2 => Vec2::zero(),
                            _ => site.tile_wpos(Vec2::new(self.tile_aabr.min.x, y)),
                        };
                        let support = match self.front {
                            0 => painter.prim(Primitive::Empty),
                            1 => painter.line(
                                Vec2::new(
                                    self.bounds.max.x + storey_increase - self.overhang + 1,
                                    temp.y,
                                )
                                .with_z(alt + previous_height - 3),
                                Vec2::new(
                                    self.bounds.max.x + storey_increase - self.overhang + 2,
                                    temp.y,
                                )
                                .with_z(alt + previous_height),
                                0.75,
                            ),
                            2 => painter.prim(Primitive::Empty),
                            _ => painter.line(
                                Vec2::new(
                                    self.bounds.min.x - storey_increase + self.overhang - 1,
                                    temp.y,
                                )
                                .with_z(alt + previous_height - 3),
                                Vec2::new(
                                    self.bounds.min.x - storey_increase + self.overhang - 2,
                                    temp.y,
                                )
                                .with_z(alt + previous_height),
                                0.75,
                            ),
                        };
                        if temp.y <= self.bounds.max.y && temp.y >= self.bounds.min.y {
                            overhang_supports =
                                painter.prim(Primitive::union(overhang_supports, support));
                        }
                    }
                    let pillar = painter.prim(Primitive::Aabb(Aabb {
                        min: site
                            .tile_wpos(Vec2::new(self.tile_aabr.min.x - 4, y))
                            .with_z(alt + previous_height),
                        max: (site.tile_wpos(Vec2::new(self.tile_aabr.max.x + 4, y))
                            + Vec2::unit_y())
                        .with_z(alt + height),
                    }));
                    pillars_x = painter.prim(Primitive::union(pillars_x, pillar));
                }
                let front_wall = if self.overhang < -4 && i > 1 {
                    painter.prim(Primitive::Empty)
                } else {
                    match self.front {
                        0 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - 1,
                                self.bounds.max.y + storey_increase,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + 1,
                                self.bounds.max.y + storey_increase + 1,
                            )
                            .with_z(alt + height),
                        })),
                        1 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.max.x + storey_increase,
                                self.bounds.min.y - 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + storey_increase + 1,
                                self.bounds.max.y + 1,
                            )
                            .with_z(alt + height),
                        })),
                        2 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - 1,
                                self.bounds.min.y - storey_increase,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + 1,
                                self.bounds.min.y - storey_increase + 1,
                            )
                            .with_z(alt + height),
                        })),
                        _ => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - storey_increase,
                                self.bounds.min.y - 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.min.x - storey_increase + 1,
                                self.bounds.max.y + 1,
                            )
                            .with_z(alt + height),
                        })),
                    }
                };
                let pillars1 = if self.front % 2 == 0 {
                    painter.prim(Primitive::intersect(pillars_y, front_wall))
                } else {
                    painter.prim(Primitive::intersect(pillars_x, front_wall))
                };
                let pillars2 = painter.prim(Primitive::intersect(pillars_x, pillars_y));
                let pillars3 = painter.prim(Primitive::union(pillars1, pillars2));
                let pillars4 = match self.front {
                    0 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(self.bounds.min.x - 1, self.bounds.min.y - 1)
                            .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.max.x + 1,
                            self.bounds.max.y + storey_increase + 1,
                        )
                        .with_z(alt + previous_height + 1),
                    })),
                    1 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(self.bounds.min.x - 1, self.bounds.min.y - 1)
                            .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.max.x + storey_increase + 1,
                            self.bounds.max.y + 1,
                        )
                        .with_z(alt + previous_height + 1),
                    })),
                    2 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x - 1,
                            self.bounds.min.y - storey_increase - 1,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                            .with_z(alt + previous_height + 1),
                    })),
                    _ => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x - storey_increase - 1,
                            self.bounds.min.y - 1,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(self.bounds.max.x + 1, self.bounds.max.y + 1)
                            .with_z(alt + previous_height + 1),
                    })),
                };
                let pillars = painter.prim(Primitive::union(pillars3, pillars4));
                painter.fill(
                    painter.prim(Primitive::intersect(walls, pillars)),
                    Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
                );

                painter.fill(
                    overhang_supports,
                    Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
                );
            }

            // Windows x axis
            {
                let mut windows = painter.prim(Primitive::Empty);
                for y in self.tile_aabr.min.y - 2..self.tile_aabr.max.y + 2 {
                    let min = (site.tile_wpos(Vec2::new(self.tile_aabr.min.x - 4, y))
                        + Vec2::unit_y() * 2)
                        .with_z(alt + previous_height + 2);
                    let max = (site.tile_wpos(Vec2::new(self.tile_aabr.max.x + 4, y + 1))
                        + Vec2::new(1, -1))
                    .with_z(alt + previous_height + 2 + window_height);
                    let window = painter.prim(Primitive::Aabb(Aabb { min, max }));
                    let add_windows = match self.front {
                        0 => {
                            max.y < self.bounds.max.y + storey_increase && min.y > self.bounds.min.y
                        },
                        1 => max.y < self.bounds.max.y && min.y > self.bounds.min.y,
                        2 => {
                            max.y < self.bounds.max.y && min.y > self.bounds.min.y - storey_increase
                        },
                        _ => max.y < self.bounds.max.y && min.y > self.bounds.min.y,
                    };
                    if add_windows {
                        windows = painter.prim(Primitive::union(windows, window));
                    }
                }
                painter.fill(
                    painter.prim(Primitive::intersect(walls, windows)),
                    Fill::Block(Block::air(SpriteKind::Window1).with_ori(2).unwrap()),
                );
                // Wall lamps
                if i == 1 {
                    let mut torches_min = painter.prim(Primitive::Empty);
                    let mut torches_max = painter.prim(Primitive::Empty);
                    for y in self.tile_aabr.min.y..self.tile_aabr.max.y {
                        let pos = site
                            .tile_wpos(Vec2::new(self.tile_aabr.min.x, y))
                            .with_z(alt + previous_height + 3)
                            + Vec3::new(-1, 0, 0);
                        let torch = painter.prim(Primitive::Aabb(Aabb {
                            min: pos,
                            max: pos + 1,
                        }));
                        torches_min = painter.prim(Primitive::union(torches_min, torch));

                        let pos = site
                            .tile_wpos(Vec2::new(self.tile_aabr.max.x, y + 1))
                            .with_z(alt + previous_height + 3)
                            + Vec3::new(1, 0, 0);
                        let torch = painter.prim(Primitive::Aabb(Aabb {
                            min: pos,
                            max: pos + 1,
                        }));
                        torches_max = painter.prim(Primitive::union(torches_max, torch));
                    }
                    painter.fill(
                        torches_min,
                        Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(6).unwrap()),
                    );
                    painter.fill(
                        torches_max,
                        Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(2).unwrap()),
                    );
                }
            }
            // Windows y axis
            {
                let mut windows = painter.prim(Primitive::Empty);
                for x in self.tile_aabr.min.x - 2..self.tile_aabr.max.x + 2 {
                    let min = (site.tile_wpos(Vec2::new(x, self.tile_aabr.min.y - 4))
                        + Vec2::unit_x() * 2)
                        .with_z(alt + previous_height + 2);
                    let max = (site.tile_wpos(Vec2::new(x + 1, self.tile_aabr.max.y + 4))
                        + Vec2::new(-1, 1))
                    .with_z(alt + previous_height + 2 + window_height);
                    let window = painter.prim(Primitive::Aabb(Aabb { min, max }));
                    let add_windows = match self.front {
                        0 => max.x < self.bounds.max.x && min.x > self.bounds.min.x,
                        1 => {
                            max.x < self.bounds.max.x + storey_increase && min.x > self.bounds.min.x
                        },
                        2 => max.x < self.bounds.max.x && min.x > self.bounds.min.x,
                        _ => {
                            max.x < self.bounds.max.x && min.x > self.bounds.min.x - storey_increase
                        },
                    };
                    if add_windows {
                        windows = painter.prim(Primitive::union(windows, window));
                    };
                }
                painter.fill(
                    painter.prim(Primitive::intersect(walls, windows)),
                    Fill::Block(Block::air(SpriteKind::Window1).with_ori(0).unwrap()),
                );
                // Wall lamps
                if i == 1 {
                    let mut torches_min = painter.prim(Primitive::Empty);
                    let mut torches_max = painter.prim(Primitive::Empty);
                    for x in self.tile_aabr.min.x..self.tile_aabr.max.x {
                        let pos = site
                            .tile_wpos(Vec2::new(x + 1, self.tile_aabr.min.y))
                            .with_z(alt + previous_height + 3)
                            + Vec3::new(0, -1, 0);
                        let torch = painter.prim(Primitive::Aabb(Aabb {
                            min: pos,
                            max: pos + 1,
                        }));
                        torches_min = painter.prim(Primitive::union(torches_min, torch));

                        let pos = site
                            .tile_wpos(Vec2::new(x, self.tile_aabr.max.y))
                            .with_z(alt + previous_height + 3)
                            + Vec3::new(0, 1, 0);
                        let torch = painter.prim(Primitive::Aabb(Aabb {
                            min: pos,
                            max: pos + 1,
                        }));
                        torches_max = painter.prim(Primitive::union(torches_max, torch));
                    }
                    painter.fill(
                        torches_min,
                        Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(0).unwrap()),
                    );
                    painter.fill(
                        torches_max,
                        Fill::Block(Block::air(SpriteKind::WallLampSmall).with_ori(4).unwrap()),
                    );
                }
            }

            // Shed roof on negative overhangs
            if self.overhang < -4 && i > 1 {
                let shed = match self.front {
                    0 => painter.prim(Primitive::Ramp {
                        aabb: Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - 1,
                                self.bounds.max.y + storey_increase + 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + 1,
                                self.bounds.max.y + storey_increase + self.overhang.abs() + 1,
                            )
                            .with_z(alt + height),
                        },
                        inset: storey,
                        dir: Dir::NegY,
                    }),
                    1 => painter.prim(Primitive::Ramp {
                        aabb: Aabb {
                            min: Vec2::new(
                                self.bounds.max.x + storey_increase + 1,
                                self.bounds.min.y - 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + storey_increase + self.overhang.abs() + 1,
                                self.bounds.max.y + 1,
                            )
                            .with_z(alt + height),
                        },
                        inset: storey,
                        dir: Dir::NegX,
                    }),
                    2 => painter.prim(Primitive::Ramp {
                        aabb: Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - 1,
                                self.bounds.min.y - storey_increase - self.overhang.abs(),
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + 2,
                                self.bounds.min.y - storey_increase,
                            )
                            .with_z(alt + height),
                        },
                        inset: storey,
                        dir: Dir::Y,
                    }),
                    _ => painter.prim(Primitive::Ramp {
                        aabb: Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - storey_increase - self.overhang.abs(),
                                self.bounds.min.y - 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.min.x - storey_increase + 1,
                                self.bounds.max.y + 2,
                            )
                            .with_z(alt + height),
                        },
                        inset: storey,
                        dir: Dir::X,
                    }),
                };
                let shed_empty = match self.front {
                    0 => painter.prim(Primitive::Ramp {
                        aabb: Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - 1,
                                self.bounds.max.y + storey_increase + 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + 1,
                                self.bounds.max.y + storey_increase + self.overhang.abs(),
                            )
                            .with_z(alt + height - 1),
                        },
                        inset: storey - 1,
                        dir: Dir::NegY,
                    }),
                    1 => painter.prim(Primitive::Ramp {
                        aabb: Aabb {
                            min: Vec2::new(
                                self.bounds.max.x + storey_increase + 1,
                                self.bounds.min.y - 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + storey_increase + self.overhang.abs(),
                                self.bounds.max.y + 1,
                            )
                            .with_z(alt + height - 1),
                        },
                        inset: storey - 1,
                        dir: Dir::NegX,
                    }),
                    2 => painter.prim(Primitive::Ramp {
                        aabb: Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - 1,
                                self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + 2,
                                self.bounds.min.y - storey_increase + 1,
                            )
                            .with_z(alt + height),
                        },
                        inset: storey - 1,
                        dir: Dir::Y,
                    }),
                    _ => painter.prim(Primitive::Ramp {
                        aabb: Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
                                self.bounds.min.y - 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.min.x - storey_increase + 1,
                                self.bounds.max.y + 2,
                            )
                            .with_z(alt + height),
                        },
                        inset: storey - 1,
                        dir: Dir::X,
                    }),
                };
                painter.fill(shed, Fill::Brick(BlockKind::Wood, self.roof_color, 24));
                painter.fill(shed_empty, Fill::Block(Block::empty()));
                let shed_left_wall = match self.front {
                    0 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(self.bounds.min.x, self.bounds.max.y + storey_increase + 1)
                            .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.min.x + 1,
                            self.bounds.max.y + storey_increase + self.overhang.abs(),
                        )
                        .with_z(alt + height - 1),
                    })),
                    1 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.min.y)
                            .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.max.x + storey_increase + self.overhang.abs(),
                            self.bounds.min.y + 1,
                        )
                        .with_z(alt + height - 1),
                    })),
                    2 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.max.x,
                            self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.max.x + 1,
                            self.bounds.min.y - storey_increase + 1,
                        )
                        .with_z(alt + height),
                    })),
                    _ => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
                            self.bounds.max.y,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.min.x - storey_increase + 1,
                            self.bounds.max.y + 1,
                        )
                        .with_z(alt + height),
                    })),
                };
                let shed_right_wall = match self.front {
                    0 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(self.bounds.max.x, self.bounds.max.y + storey_increase + 1)
                            .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.max.x + 1,
                            self.bounds.max.y + storey_increase + self.overhang.abs(),
                        )
                        .with_z(alt + height - 1),
                    })),
                    1 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.max.y)
                            .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.max.x + storey_increase + self.overhang.abs(),
                            self.bounds.max.y + 1,
                        )
                        .with_z(alt + height - 1),
                    })),
                    2 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x,
                            self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.min.x + 1,
                            self.bounds.min.y - storey_increase + 1,
                        )
                        .with_z(alt + height),
                    })),
                    _ => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
                            self.bounds.min.y,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.min.x - storey_increase + 1,
                            self.bounds.min.y + 1,
                        )
                        .with_z(alt + height),
                    })),
                };
                let shed_wall_beams = match self.front {
                    0 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(self.bounds.min.x, self.bounds.max.y + storey_increase + 1)
                            .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.max.x + 1,
                            self.bounds.max.y + storey_increase + self.overhang.abs(),
                        )
                        .with_z(alt + previous_height + 1),
                    })),
                    1 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(self.bounds.max.x + storey_increase + 1, self.bounds.min.y)
                            .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.max.x + storey_increase + self.overhang.abs(),
                            self.bounds.max.y + 1,
                        )
                        .with_z(alt + previous_height + 1),
                    })),
                    2 => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x,
                            self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.max.x + 1,
                            self.bounds.min.y - storey_increase + 1,
                        )
                        .with_z(alt + previous_height + 1),
                    })),
                    _ => painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(
                            self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
                            self.bounds.min.y,
                        )
                        .with_z(alt + previous_height),
                        max: Vec2::new(
                            self.bounds.min.x - storey_increase + 1,
                            self.bounds.max.y + 1,
                        )
                        .with_z(alt + previous_height + 1),
                    })),
                };
                let shed_walls = painter.prim(Primitive::union(shed_left_wall, shed_right_wall));
                painter.fill(
                    painter.prim(Primitive::intersect(shed_walls, shed_empty)),
                    Fill::Brick(BlockKind::Wood, Rgb::new(200, 180, 150), 24),
                );
                painter.fill(
                    painter.prim(Primitive::intersect(shed_wall_beams, shed_walls)),
                    Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
                );

                // Dormers
                let range = if self.front % 2 == 0 {
                    self.tile_aabr.min.x - 3..self.tile_aabr.max.x + 3
                } else {
                    self.tile_aabr.min.y - 3..self.tile_aabr.max.y + 3
                };
                for n in range {
                    let temp = match self.front {
                        0 => site.tile_wpos(Vec2::new(n, self.tile_aabr.max.y)) - 4,
                        1 => site.tile_wpos(Vec2::new(self.tile_aabr.max.x, n)) - 4,
                        2 => site.tile_wpos(Vec2::new(n, self.tile_aabr.min.y)) - 4,
                        _ => site.tile_wpos(Vec2::new(self.tile_aabr.min.x, n)) - 4,
                    };
                    let dormer_box = match self.front {
                        0 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(temp.x - 1, self.bounds.max.y + storey_increase + 1)
                                .with_z(alt + previous_height),
                            max: Vec2::new(
                                temp.x + 4,
                                self.bounds.max.y + storey_increase + self.overhang.abs(),
                            )
                            .with_z(alt + height - 1),
                        })),
                        1 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(self.bounds.max.x + storey_increase + 1, temp.y - 1)
                                .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + storey_increase + self.overhang.abs(),
                                temp.y + 4,
                            )
                            .with_z(alt + height - 1),
                        })),
                        2 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                temp.x - 1,
                                self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(temp.x + 4, self.bounds.min.y - storey_increase - 1)
                                .with_z(alt + height - 1),
                        })),
                        _ => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
                                temp.y - 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(self.bounds.min.x - storey_increase - 1, temp.y + 4)
                                .with_z(alt + height - 1),
                        })),
                    };
                    let dormer_roof = match self.front {
                        0 => painter.prim(Primitive::Gable {
                            aabb: Aabb {
                                min: Vec2::new(temp.x - 1, self.bounds.max.y + storey_increase + 1)
                                    .with_z(alt + height - 2),
                                max: Vec2::new(
                                    temp.x + 4,
                                    self.bounds.max.y + storey_increase + self.overhang.abs(),
                                )
                                .with_z(alt + height + 1),
                            },
                            inset: 3,
                            dir: Dir::Y,
                        }),
                        1 => painter.prim(Primitive::Gable {
                            aabb: Aabb {
                                min: Vec2::new(self.bounds.max.x + storey_increase + 1, temp.y - 1)
                                    .with_z(alt + height - 2),
                                max: Vec2::new(
                                    self.bounds.max.x + storey_increase + self.overhang.abs(),
                                    temp.y + 4,
                                )
                                .with_z(alt + height + 1),
                            },
                            inset: 3,
                            dir: Dir::X,
                        }),
                        2 => painter.prim(Primitive::Gable {
                            aabb: Aabb {
                                min: Vec2::new(
                                    temp.x - 1,
                                    self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
                                )
                                .with_z(alt + height - 2),
                                max: Vec2::new(temp.x + 4, self.bounds.min.y - storey_increase)
                                    .with_z(alt + height + 1),
                            },
                            inset: 3,
                            dir: Dir::Y,
                        }),
                        _ => painter.prim(Primitive::Gable {
                            aabb: Aabb {
                                min: Vec2::new(
                                    self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
                                    temp.y - 1,
                                )
                                .with_z(alt + height - 2),
                                max: Vec2::new(self.bounds.min.x - storey_increase, temp.y + 4)
                                    .with_z(alt + height + 1),
                            },
                            inset: 3,
                            dir: Dir::X,
                        }),
                    };
                    let window_min = match self.front {
                        0 => Vec2::new(
                            temp.x,
                            self.bounds.max.y + storey_increase + self.overhang.abs() - 1,
                        )
                        .with_z(alt + previous_height + 2),
                        1 => Vec2::new(
                            self.bounds.max.x + storey_increase + self.overhang.abs() - 1,
                            temp.y,
                        )
                        .with_z(alt + previous_height + 2),
                        2 => Vec2::new(
                            temp.x,
                            self.bounds.min.y - storey_increase - self.overhang.abs() + 1,
                        )
                        .with_z(alt + previous_height + 2),
                        _ => Vec2::new(
                            self.bounds.min.x - storey_increase - self.overhang.abs() + 1,
                            temp.y,
                        )
                        .with_z(alt + previous_height + 2),
                    };
                    let window_max = match self.front {
                        0 => Vec2::new(
                            temp.x + 3,
                            self.bounds.max.y + storey_increase + self.overhang.abs(),
                        )
                        .with_z(alt + previous_height + 2 + window_height),
                        1 => Vec2::new(
                            self.bounds.max.x + storey_increase + self.overhang.abs(),
                            temp.y + 3,
                        )
                        .with_z(alt + previous_height + 2 + window_height),
                        2 => Vec2::new(
                            temp.x + 3,
                            self.bounds.min.y - storey_increase - self.overhang.abs() + 2,
                        )
                        .with_z(alt + previous_height + 2 + window_height),
                        _ => Vec2::new(
                            self.bounds.min.x - storey_increase - self.overhang.abs() + 2,
                            temp.y + 3,
                        )
                        .with_z(alt + previous_height + 2 + window_height),
                    };
                    let window = painter.prim(Primitive::Aabb(Aabb {
                        min: window_min,
                        max: window_max,
                    }));
                    let window_cavity = match self.front {
                        0 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(temp.x, self.bounds.max.y + storey_increase)
                                .with_z(alt + previous_height),
                            max: Vec2::new(
                                temp.x + 3,
                                self.bounds.max.y + storey_increase + self.overhang.abs() - 1,
                            )
                            .with_z(alt + previous_height + 2 + window_height),
                        })),
                        1 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(self.bounds.max.x + storey_increase, temp.y)
                                .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + storey_increase + self.overhang.abs() - 1,
                                temp.y + 3,
                            )
                            .with_z(alt + previous_height + 2 + window_height),
                        })),
                        2 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                temp.x,
                                self.bounds.min.y - storey_increase - self.overhang.abs() + 2,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(temp.x + 3, self.bounds.min.y - storey_increase + 1)
                                .with_z(alt + previous_height + 2 + window_height),
                        })),
                        _ => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.min.x - storey_increase - self.overhang.abs() + 2,
                                temp.y,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(self.bounds.min.x - storey_increase + 1, temp.y + 3)
                                .with_z(alt + previous_height + 2 + window_height),
                        })),
                    };
                    let valid_dormer = if self.front % 2 == 0 {
                        window_min.x > self.bounds.min.x && window_max.x < self.bounds.max.x
                    } else {
                        window_min.y > self.bounds.min.y && window_max.y < self.bounds.max.y
                    };
                    let window_ori = if self.front % 2 == 0 { 0 } else { 2 };
                    if valid_dormer {
                        painter.fill(
                            painter.prim(Primitive::without(dormer_box, shed)),
                            Fill::Brick(BlockKind::Wood, Rgb::new(200, 180, 150), 24),
                        );
                        painter.fill(
                            painter.prim(Primitive::without(dormer_roof, shed)),
                            Fill::Brick(BlockKind::Wood, self.roof_color, 24),
                        );
                        painter.fill(window_cavity, Fill::Block(Block::empty()));
                        painter.fill(
                            window,
                            Fill::Block(
                                Block::air(SpriteKind::Window1)
                                    .with_ori(window_ori)
                                    .unwrap(),
                            ),
                        );
                    }
                }
            }

            // Floor
            // No extra floor needed for the ground floor
            if i > 1 {
                let floor = if self.overhang < -1 && i > 1 {
                    match self.front {
                        0 => painter.prim(Primitive::Aabb(Aabb {
                            min: (self.bounds.min + 1).with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x,
                                self.bounds.max.y + storey_increase + self.overhang.abs(),
                            )
                            .with_z(alt + previous_height + 1),
                        })),
                        1 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(self.bounds.min.x + 1, self.bounds.min.y + 1)
                                .with_z(alt + previous_height),
                            max: Vec2::new(
                                self.bounds.max.x + storey_increase + self.overhang.abs(),
                                self.bounds.max.y,
                            )
                            .with_z(alt + previous_height + 1),
                        })),
                        2 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.min.x + 1,
                                self.bounds.min.y + 1 - storey_increase - self.overhang.abs(),
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(self.bounds.max.x, self.bounds.max.y)
                                .with_z(alt + previous_height + 1),
                        })),
                        _ => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.min.x + 1 - storey_increase - self.overhang.abs(),
                                self.bounds.min.y + 1,
                            )
                            .with_z(alt + previous_height),
                            max: Vec2::new(self.bounds.max.x, self.bounds.max.y)
                                .with_z(alt + previous_height + 1),
                        })),
                    }
                } else {
                    match self.front {
                        0 => painter.prim(Primitive::Aabb(Aabb {
                            min: (self.bounds.min + 1).with_z(alt + previous_height),
                            max: (Vec2::new(
                                self.bounds.max.x,
                                self.bounds.max.y + storey_increase,
                            ))
                            .with_z(alt + previous_height + 1),
                        })),
                        1 => painter.prim(Primitive::Aabb(Aabb {
                            min: (self.bounds.min + 1).with_z(alt + previous_height),
                            max: (Vec2::new(
                                self.bounds.max.x + storey_increase,
                                self.bounds.max.y,
                            ))
                            .with_z(alt + previous_height + 1),
                        })),
                        2 => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.min.x + 1,
                                self.bounds.min.y + 1 - storey_increase,
                            )
                            .with_z(alt + previous_height),
                            max: (Vec2::new(self.bounds.max.x, self.bounds.max.y))
                                .with_z(alt + previous_height + 1),
                        })),
                        _ => painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(
                                self.bounds.min.x + 1 - storey_increase,
                                self.bounds.min.y + 1,
                            )
                            .with_z(alt + previous_height),
                            max: (Vec2::new(self.bounds.max.x, self.bounds.max.y))
                                .with_z(alt + previous_height + 1),
                        })),
                    }
                };
                painter.fill(
                    floor,
                    Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
                );
            }

            // interior furniture sprites
            let base = alt + (storey * (i as i32 - 1)).max(0);
            if i % 2 == 0 {
                // bedroom on even-leveled floors
                let bed_pos = match self.front {
                    1 => Vec2::new(half_x, quarter_y),
                    2 => Vec2::new(three_quarter_x, half_y),
                    _ => Vec2::new(half_x, half_y),
                };
                let nightstand_pos = Vec2::new(bed_pos.x + 2, bed_pos.y + 1);
                painter.sprite(bed_pos.with_z(base), SpriteKind::Bed);
                // drawer next to bed
                painter.sprite(nightstand_pos.with_z(base), SpriteKind::DrawerSmall);
                // collectible on top of drawer
                let rng = RandomField::new(0).get(nightstand_pos.with_z(base + 1));
                painter.sprite(nightstand_pos.with_z(base + 1), match rng % 5 {
                    0 => SpriteKind::Lantern,
                    1 => SpriteKind::PotionMinor,
                    2 => SpriteKind::VialEmpty,
                    3 => SpriteKind::Bowl,
                    _ => SpriteKind::Empty,
                });
                // wardrobe along wall in corner of the room
                let (wardrobe_pos, drawer_ori) = match self.front {
                    0 => (Vec2::new(self.bounds.max.x - 2, self.bounds.min.y + 1), 4),
                    1 => (Vec2::new(self.bounds.min.x + 6, self.bounds.max.y - 1), 0),
                    2 => (Vec2::new(self.bounds.min.x + 2, self.bounds.max.y - 1), 0),
                    _ => (Vec2::new(self.bounds.max.x - 6, self.bounds.max.y - 1), 0),
                };
                painter.rotated_sprite(
                    wardrobe_pos.with_z(base),
                    SpriteKind::WardrobeDouble,
                    drawer_ori,
                );
            } else {
                // living room with table + chairs + random
                for dir in DIRS {
                    // random accent pieces and loot
                    let sprite_pos = self.bounds.center() + dir * 5;
                    let rng = RandomField::new(0).get(sprite_pos.with_z(base));
                    painter.sprite(sprite_pos.with_z(base), match rng % 32 {
                        0..=2 => SpriteKind::Crate,
                        3..=4 => SpriteKind::CoatRack,
                        5..=7 => SpriteKind::Pot,
                        8..=9 => SpriteKind::Lantern,
                        _ => SpriteKind::Empty,
                    });
                }

                if self.bounds.max.x - self.bounds.min.x < 16
                    || self.bounds.max.y - self.bounds.min.y < 16
                {
                    let table_pos = Vec2::new(half_x, half_y);
                    // room is smaller, so use small table
                    painter.sprite(table_pos.with_z(base), SpriteKind::TableDining);
                    for (idx, dir) in CARDINALS.iter().enumerate() {
                        let chair_pos = table_pos + dir;
                        painter.rotated_sprite(
                            chair_pos.with_z(base),
                            SpriteKind::ChairSingle,
                            (idx * 2 + ((idx % 2) * 4)) as u8,
                        );
                    }
                } else {
                    // room is bigger, so use large table + chair positions
                    let table_pos = match self.front {
                        0 => Vec2::new(half_x, three_quarter_y),
                        1 => Vec2::new(half_x, half_y),
                        _ => Vec2::new(quarter_x, half_y),
                    };
                    painter.sprite(table_pos.with_z(base), SpriteKind::TableDouble);
                    for (idx, dir) in CARDINALS.iter().enumerate() {
                        let chair_pos = table_pos + dir * (1 + idx % 2) as i32;
                        painter.rotated_sprite(
                            chair_pos.with_z(base),
                            SpriteKind::ChairSingle,
                            (idx * 2 + ((idx % 2) * 4)) as u8,
                        );
                    }
                }
                // drawer along a wall
                let (drawer_pos, drawer_ori) = match self.front {
                    0 => (Vec2::new(self.bounds.max.x - 1, self.bounds.max.y - 2), 6),
                    1 => (Vec2::new(self.bounds.max.x - 2, self.bounds.max.y - 1), 0),
                    2 => (Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 2), 6),
                    _ => (Vec2::new(self.bounds.min.x + 2, self.bounds.max.y - 1), 0),
                };
                painter.rotated_sprite(
                    drawer_pos.with_z(base),
                    SpriteKind::DrawerLarge,
                    drawer_ori,
                );
            }

            // Stairs
            if i > 1 {
                let stair_width = 3;
                let previous_floor_height = (storey * (i as i32 - 2)).max(0);
                let stair_origin = match self.front {
                    0 => self.bounds.min + 1,
                    1 => self.bounds.min + 1,
                    2 => Vec2::new(self.bounds.max.x - 12, self.bounds.max.y - stair_width * 2),
                    _ => Vec2::new(self.bounds.max.x - 12, self.bounds.min.y + 1),
                };
                let staircase = if i < 2 {
                    painter.prim(Primitive::Empty)
                } else if i % 2 == 0 {
                    let ramp = /*match self.front */{
                        //0 => {
                            painter.prim(Primitive::Ramp {
                                aabb: Aabb {
                                    min: Vec2::new(stair_origin.x + 3, stair_origin.y).with_z(alt + previous_floor_height),
                                    max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
                                },
                                inset: storey,
                                dir: Dir::X,
                            })
                        /*},
                        1 => {
                            painter.prim(Primitive::Ramp {
                                aabb: Aabb {
                                    min: Vec2::new(stair_origin.x, stair_origin.y + 3).with_z(alt + previous_floor_height),
                                    max: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 10).with_z(alt + previous_height + 1),
                                },
                                inset: storey,
                                dir: 0,
                            })
                        },
                        2 => {
                            painter.prim(Primitive::Ramp {
                                aabb: Aabb {
                                    min: Vec2::new(stair_origin.x + 3, stair_origin.y).with_z(alt + previous_floor_height),
                                    max: Vec2::new(stair_origin.x + 10, stair_origin.y + stair_width).with_z(alt + previous_height + 1),
                                },
                                inset: storey,
                                dir: 0,
                            })
                        },
                        _ => {
                            painter.prim(Primitive::Ramp {
                                aabb: Aabb {
                                    min: Vec2::new(stair_origin.x, stair_origin.y + 3).with_z(alt + previous_floor_height),
                                    max: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 10).with_z(alt + previous_height + 1),
                                },
                                inset: storey,
                                dir: 0,
                            })
                        }*/
                    };
                    let support = {
                        //match self.front {
                        //0 => {
                        painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(stair_origin.x + 10, stair_origin.y)
                                .with_z(alt + previous_floor_height),
                            max: Vec2::new(stair_origin.x + 12, stair_origin.y + stair_width)
                                .with_z(alt + previous_height + 1),
                        }))
                        //},
                        //1 => {
                        //    painter.prim(Primitive::Aabb(Aabb {
                        //        min: Vec2::new(stair_origin.x, stair_origin.y
                        // + 10).with_z(alt + previous_floor_height),
                        //        max: Vec2::new(stair_origin.x + stair_width,
                        // stair_origin.y + 12).with_z(alt + previous_height +
                        // 1),    }))
                        //},
                        //2 => {
                        //    painter.prim(Primitive::Aabb(Aabb {
                        //        min: Vec2::new(stair_origin.x + 10,
                        // stair_origin.y).with_z(alt + previous_floor_height),
                        //        max: Vec2::new(stair_origin.x + 12,
                        // stair_origin.y + stair_width).with_z(alt +
                        // previous_height + 1),    }))
                        //},
                        //_ => {
                        //    painter.prim(Primitive::Aabb(Aabb {
                        //        min: Vec2::new(stair_origin.x, stair_origin.y
                        // + 10).with_z(alt + previous_floor_height),
                        //        max: Vec2::new(stair_origin.x + stair_width,
                        // stair_origin.y + 12).with_z(alt + previous_height +
                        // 1),    }))
                        //},
                    };
                    painter.prim(Primitive::union(ramp, support))
                } else {
                    let ramp = /*match self.front */{
                        //0 => {
                            painter.prim(Primitive::Ramp {
                                aabb: Aabb {
                                    min: Vec2::new(stair_origin.x + 1, stair_origin.y + stair_width).with_z(alt + previous_floor_height),
                                    max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
                                },
                                inset: storey,
                                dir: Dir::NegX,
                            })
                        /*},
                        1 => {
                            painter.prim(Primitive::Ramp {
                                aabb: Aabb {
                                    min: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 1).with_z(alt + previous_floor_height),
                                    max: Vec2::new(stair_origin.x + 2 * stair_width, stair_origin.y + 8).with_z(alt + previous_height + 1),
                                },
                                inset: storey,
                                dir: 1,
                            })
                        },
                        2 => {
                            painter.prim(Primitive::Ramp {
                                aabb: Aabb {
                                    min: Vec2::new(stair_origin.x + 1, stair_origin.y + stair_width).with_z(alt + previous_floor_height),
                                    max: Vec2::new(stair_origin.x + 8, stair_origin.y + 2 * stair_width).with_z(alt + previous_height + 1),
                                },
                                inset: storey,
                                dir: 1,
                            })
                        },
                        _ => {
                            painter.prim(Primitive::Ramp {
                                aabb: Aabb {
                                    min: Vec2::new(stair_origin.x + stair_width, stair_origin.y + 1).with_z(alt + previous_floor_height),
                                    max: Vec2::new(stair_origin.x + 2 * stair_width, stair_origin.y + 8).with_z(alt + previous_height + 1),
                                },
                                inset: storey,
                                dir: 1,
                            })
                        },
                        */
                    };
                    let support = {
                        //match self.front {
                        //0 => {
                        painter.prim(Primitive::Aabb(Aabb {
                            min: Vec2::new(stair_origin.x, stair_origin.y + stair_width)
                                .with_z(alt + previous_floor_height),
                            max: Vec2::new(stair_origin.x + 2, stair_origin.y + 2 * stair_width)
                                .with_z(alt + previous_height + 1),
                        }))
                        //},
                        //1 => {
                        //    painter.prim(Primitive::Aabb(Aabb {
                        //        min: Vec2::new(stair_origin.x + stair_width,
                        // stair_origin.y).with_z(alt + previous_floor_height),
                        //        max: Vec2::new(stair_origin.x + 2 *
                        // stair_width, stair_origin.y + 2).with_z(alt +
                        // previous_height + 1),    }))
                        //},
                        //2 => {
                        //    painter.prim(Primitive::Aabb(Aabb {
                        //        min: Vec2::new(stair_origin.x, stair_origin.y
                        // + stair_width).with_z(alt + previous_floor_height),
                        //        max: Vec2::new(stair_origin.x + 2,
                        // stair_origin.y + 2 * stair_width).with_z(alt +
                        // previous_height + 1),    }))
                        //},
                        //_ => {
                        //    painter.prim(Primitive::Aabb(Aabb {
                        //        min: Vec2::new(stair_origin.x + stair_width,
                        // stair_origin.y).with_z(alt + previous_floor_height),
                        //        max: Vec2::new(stair_origin.x + 2 *
                        // stair_width, stair_origin.y + 2).with_z(alt +
                        // previous_height + 1),    }))
                        //},
                    };
                    painter.prim(Primitive::union(ramp, support))
                };
                let stairwell = if i < 2 {
                    painter.prim(Primitive::Empty)
                } else if i % 2 == 0 {
                    painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(stair_origin.x + 2, stair_origin.y)
                            .with_z(alt + previous_floor_height + 1),
                        max: Vec2::new(stair_origin.x + 9, stair_origin.y + stair_width)
                            .with_z(alt + previous_height + 1),
                    }))
                    //match self.front {
                    //    0 => {
                    //        painter.prim(Primitive::Aabb(Aabb {
                    //                min: Vec2::new(stair_origin.x,
                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
                    //                max: Vec2::new(stair_origin.x + 9,
                    // stair_origin.y + stair_width).with_z(alt +
                    // previous_height + 1),        }))
                    //    },
                    //    1 => {
                    //        painter.prim(Primitive::Aabb(Aabb {
                    //                min: Vec2::new(stair_origin.x,
                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
                    //                max: Vec2::new(stair_origin.x +
                    // stair_width, stair_origin.y + 9).with_z(alt +
                    // previous_height + 1),        }))
                    //    },
                    //    2 => {
                    //        painter.prim(Primitive::Aabb(Aabb {
                    //                min: Vec2::new(stair_origin.x,
                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
                    //                max: Vec2::new(stair_origin.x + 9,
                    // stair_origin.y + stair_width).with_z(alt +
                    // previous_height + 1),        }))
                    //    },
                    //    _ => {
                    //        painter.prim(Primitive::Aabb(Aabb {
                    //                min: Vec2::new(stair_origin.x,
                    // stair_origin.y).with_z(alt + previous_floor_height + 1),
                    //                max: Vec2::new(stair_origin.x +
                    // stair_width, stair_origin.y + 9).with_z(alt +
                    // previous_height + 1),        }))
                    //    },
                    //}
                } else {
                    painter.prim(Primitive::Aabb(Aabb {
                        min: Vec2::new(stair_origin.x + 2, stair_origin.y + stair_width)
                            .with_z(alt + previous_floor_height + 1),
                        max: Vec2::new(stair_origin.x + 11, stair_origin.y + 2 * stair_width)
                            .with_z(alt + previous_height + 1),
                    }))
                    //match self.front {
                    //    0 => {
                    //        painter.prim(Primitive::Aabb(Aabb {
                    //                min: Vec2::new(stair_origin.x + 2,
                    // stair_origin.y + stair_width).with_z(alt +
                    // previous_floor_height + 1),
                    //                max: Vec2::new(stair_origin.x + 11,
                    // stair_origin.y + 2 * stair_width).with_z(alt +
                    // previous_height + 1),        }))
                    //    },
                    //    1 => {
                    //        painter.prim(Primitive::Aabb(Aabb {
                    //                min: Vec2::new(stair_origin.x +
                    // stair_width, stair_origin.y + 2).with_z(alt +
                    // previous_floor_height + 1),
                    //                max: Vec2::new(stair_origin.x + 2 *
                    // stair_width, stair_origin.y + 11).with_z(alt +
                    // previous_height + 1),        }))
                    //    },
                    //    2 => {
                    //        painter.prim(Primitive::Aabb(Aabb {
                    //                min: Vec2::new(stair_origin.x + 2,
                    // stair_origin.y + stair_width).with_z(alt +
                    // previous_floor_height + 1),
                    //                max: Vec2::new(stair_origin.x + 11,
                    // stair_origin.y + 2 * stair_width).with_z(alt +
                    // previous_height + 1),        }))
                    //    },
                    //    _ => {
                    //        painter.prim(Primitive::Aabb(Aabb {
                    //                min: Vec2::new(stair_origin.x +
                    // stair_width, stair_origin.y + 2).with_z(alt +
                    // previous_floor_height + 1),
                    //                max: Vec2::new(stair_origin.x + 2 *
                    // stair_width, stair_origin.y + 11).with_z(alt +
                    // previous_height + 1),        }))
                    //    },
                    //}
                };

                painter.fill(stairwell, Fill::Block(Block::empty()));
                painter.fill(
                    staircase,
                    Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
                );
            }
        }

        // Foundation
        painter.fill(
            painter.prim(Primitive::Aabb(Aabb {
                min: (self.bounds.min - 1).with_z(self.alt - foundations),
                max: (self.bounds.max + 2).with_z(self.alt + 1),
            })),
            Fill::Block(Block::new(BlockKind::Rock, Rgb::new(31, 33, 32))),
        );

        // Fireplace and chimney
        let fireplace_origin = /*if self.levels > 1 {
            match self.front {
                0 => {
                    Vec2::new(self.bounds.min.x + 12, self.bounds.min.y + 1)
                },
                1 => {
                    Vec2::new(self.bounds.min.x + 1, self.bounds.max.y - 12)
                },
                2 => {
                    Vec2::new(self.bounds.max.x - 12, self.bounds.max.y - 1)
                },
                _ => {
                    Vec2::new(self.bounds.max.x - 1, self.bounds.min.y + 12)
                },
            }
        } else */{
            match self.front {
                0 => {
                    Vec2::new(half_x, self.bounds.min.y + 1)
                },
                1 => {
                    Vec2::new(self.bounds.min.x + 1, half_y)
                },
                2 => {
                    Vec2::new(half_x - 4, self.bounds.max.y - 3)
                },
                _ => {
                    Vec2::new(self.bounds.max.x - 3, half_y)
                },
            }
        };
        let chimney = match self.front {
            0 => painter.prim(Primitive::Aabb(Aabb {
                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
                    .with_z(alt + roof + roof_height + 2),
            })),
            1 => painter.prim(Primitive::Aabb(Aabb {
                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
                    .with_z(alt + roof + roof_height + 2),
            })),
            2 => painter.prim(Primitive::Aabb(Aabb {
                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 4, fireplace_origin.y + 3)
                    .with_z(alt + roof + roof_height + 2),
            })),
            _ => painter.prim(Primitive::Aabb(Aabb {
                min: Vec2::new(fireplace_origin.x, fireplace_origin.y).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 4)
                    .with_z(alt + roof + roof_height + 2),
            })),
        };

        let chimney_cavity = match self.front {
            0 => painter.prim(Primitive::Aabb(Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
                    .with_z(alt + roof + roof_height + 2),
            })),
            1 => painter.prim(Primitive::Aabb(Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
                    .with_z(alt + roof + roof_height + 2),
            })),
            2 => painter.prim(Primitive::Aabb(Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2)
                    .with_z(alt + roof + roof_height + 2),
            })),
            _ => painter.prim(Primitive::Aabb(Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3)
                    .with_z(alt + roof + roof_height + 2),
            })),
        };
        let fire_embers = match self.front {
            0 => Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 1),
            },
            1 => Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
            },
            2 => Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 1),
            },
            _ => Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 1),
            },
        };
        let fireplace_cavity = match self.front {
            0 => Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
            },
            1 => Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 3).with_z(alt + 2),
            },
            2 => Aabb {
                min: Vec2::new(fireplace_origin.x + 1, fireplace_origin.y).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 3, fireplace_origin.y + 2).with_z(alt + 2),
            },
            _ => Aabb {
                min: Vec2::new(fireplace_origin.x, fireplace_origin.y + 1).with_z(alt),
                max: Vec2::new(fireplace_origin.x + 2, fireplace_origin.y + 3).with_z(alt + 2),
            },
        };

        painter.fill(
            chimney,
            Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24),
        );
        painter.fill(chimney_cavity, Fill::Block(Block::empty()));
        painter.fill(
            painter.prim(Primitive::Aabb(fireplace_cavity)),
            Fill::Block(Block::empty()),
        );
        painter.fill(
            painter.prim(Primitive::Aabb(fire_embers)),
            Fill::Block(Block::air(SpriteKind::Ember)),
        );

        // Door
        // Fill around the door with wall
        let doorway1 = match self.front {
            0 => Aabb {
                min: Vec2::new(self.door_tile.x - 1, self.bounds.max.y).with_z(alt),
                max: Vec2::new(self.door_tile.x + 3, self.bounds.max.y + 1).with_z(alt + 4),
            },
            1 => Aabb {
                min: Vec2::new(self.bounds.max.x, self.door_tile.y - 1).with_z(alt),
                max: Vec2::new(self.bounds.max.x + 1, self.door_tile.y + 3).with_z(alt + 4),
            },
            2 => Aabb {
                min: Vec2::new(self.door_tile.x - 1, self.bounds.min.y).with_z(alt),
                max: Vec2::new(self.door_tile.x + 3, self.bounds.min.y + 1).with_z(alt + 4),
            },
            _ => Aabb {
                min: Vec2::new(self.bounds.min.x, self.door_tile.y - 1).with_z(alt),
                max: Vec2::new(self.bounds.min.x + 1, self.door_tile.y + 3).with_z(alt + 4),
            },
        };
        painter.fill(
            painter.prim(Primitive::Aabb(doorway1)),
            Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24),
        );

        // Carve out the doorway with air
        let doorway2 = match self.front {
            0 => Aabb {
                min: Vec2::new(self.door_tile.x, self.bounds.max.y).with_z(alt),
                max: Vec2::new(self.door_tile.x + 2, self.bounds.max.y + 1).with_z(alt + 3),
            },
            1 => Aabb {
                min: Vec2::new(self.bounds.max.x, self.door_tile.y).with_z(alt),
                max: Vec2::new(self.bounds.max.x + 1, self.door_tile.y + 2).with_z(alt + 3),
            },
            2 => Aabb {
                min: Vec2::new(self.door_tile.x, self.bounds.min.y).with_z(alt),
                max: Vec2::new(self.door_tile.x + 2, self.bounds.min.y + 1).with_z(alt + 3),
            },
            _ => Aabb {
                min: Vec2::new(self.bounds.min.x, self.door_tile.y).with_z(alt),
                max: Vec2::new(self.bounds.min.x + 1, self.door_tile.y + 2).with_z(alt + 3),
            },
        };
        painter.fill(
            painter.prim(Primitive::Aabb(doorway2)),
            Fill::Block(Block::empty()),
        );

        // Fill in the right and left side doors
        let (door_gap, door1, door1_ori, door2, door2_ori) = match self.front {
            0 => (
                Aabb {
                    min: Vec2::new(self.door_tile.x - 1, self.bounds.max.y + 1).with_z(alt),
                    max: Vec2::new(self.door_tile.x + 3, self.bounds.max.y + 4).with_z(alt + 3),
                },
                Aabb {
                    min: Vec2::new(self.door_tile.x, self.bounds.max.y).with_z(alt),
                    max: Vec2::new(self.door_tile.x + 1, self.bounds.max.y + 1).with_z(alt + 1),
                },
                0,
                Aabb {
                    min: Vec2::new(self.door_tile.x + 1, self.bounds.max.y).with_z(alt),
                    max: Vec2::new(self.door_tile.x + 2, self.bounds.max.y + 1).with_z(alt + 1),
                },
                4,
            ),
            1 => (
                Aabb {
                    min: Vec2::new(self.bounds.max.x + 1, self.door_tile.y - 1).with_z(alt),
                    max: Vec2::new(self.bounds.max.x + 4, self.door_tile.y + 3).with_z(alt + 3),
                },
                Aabb {
                    min: Vec2::new(self.bounds.max.x, self.door_tile.y).with_z(alt),
                    max: Vec2::new(self.bounds.max.x + 1, self.door_tile.y + 1).with_z(alt + 1),
                },
                2,
                Aabb {
                    min: Vec2::new(self.bounds.max.x, self.door_tile.y + 1).with_z(alt),
                    max: Vec2::new(self.bounds.max.x + 1, self.door_tile.y + 2).with_z(alt + 1),
                },
                6,
            ),
            2 => (
                Aabb {
                    min: Vec2::new(self.door_tile.x - 1, self.bounds.min.y - 4).with_z(alt),
                    max: Vec2::new(self.door_tile.x + 3, self.bounds.min.y).with_z(alt + 3),
                },
                Aabb {
                    min: Vec2::new(self.door_tile.x, self.bounds.min.y).with_z(alt),
                    max: Vec2::new(self.door_tile.x + 1, self.bounds.min.y + 1).with_z(alt + 1),
                },
                0,
                Aabb {
                    min: Vec2::new(self.door_tile.x + 1, self.bounds.min.y).with_z(alt),
                    max: Vec2::new(self.door_tile.x + 2, self.bounds.min.y + 1).with_z(alt + 1),
                },
                4,
            ),
            _ => (
                Aabb {
                    min: Vec2::new(self.bounds.min.x - 4, self.door_tile.y - 1).with_z(alt),
                    max: Vec2::new(self.bounds.min.x, self.door_tile.y + 3).with_z(alt + 3),
                },
                Aabb {
                    min: Vec2::new(self.bounds.min.x, self.door_tile.y).with_z(alt),
                    max: Vec2::new(self.bounds.min.x + 1, self.door_tile.y + 1).with_z(alt + 1),
                },
                2,
                Aabb {
                    min: Vec2::new(self.bounds.min.x, self.door_tile.y + 1).with_z(alt),
                    max: Vec2::new(self.bounds.min.x + 1, self.door_tile.y + 2).with_z(alt + 1),
                },
                6,
            ),
        };
        painter.fill(
            painter.prim(Primitive::Aabb(door_gap)),
            Fill::Block(Block::air(SpriteKind::Empty)),
        );
        painter.fill(
            painter.prim(Primitive::Aabb(door1)),
            Fill::Block(Block::air(SpriteKind::Door).with_ori(door1_ori).unwrap()),
        );
        painter.fill(
            painter.prim(Primitive::Aabb(door2)),
            Fill::Block(Block::air(SpriteKind::Door).with_ori(door2_ori).unwrap()),
        );
    }
}
