From 02bba1e3434aa325d6239262f10cc573ca7e58a6 Mon Sep 17 00:00:00 2001 From: flo Date: Wed, 7 Jun 2023 18:45:12 +0000 Subject: [PATCH] clifftown rework --- world/src/civ/mod.rs | 2 +- world/src/site2/mod.rs | 4 +- world/src/site2/plot/cliff_tower.rs | 1503 ++++++++++++--------------- 3 files changed, 683 insertions(+), 826 deletions(-) diff --git a/world/src/civ/mod.rs b/world/src/civ/mod.rs index cd0735c696..410b3ca265 100644 --- a/world/src/civ/mod.rs +++ b/world/src/civ/mod.rs @@ -361,7 +361,7 @@ impl Civs { SiteKind::Dungeon => (8i32, 3.0), SiteKind::Castle => (16i32, 5.0), SiteKind::Refactor => (32i32, 10.0), - SiteKind::CliffTown => (32i32, 10.0), + SiteKind::CliffTown => (64i32, 25.0), SiteKind::SavannahPit => (48i32, 25.0), SiteKind::DesertCity => (64i32, 25.0), SiteKind::ChapelSite => (36i32, 10.0), diff --git a/world/src/site2/mod.rs b/world/src/site2/mod.rs index 95c3ed0ed4..864b9dcb5f 100644 --- a/world/src/site2/mod.rs +++ b/world/src/site2/mod.rs @@ -850,10 +850,10 @@ impl Site { site.make_plaza(land, &mut rng); for _ in 0..30 { // CliffTower - let size = (6.0 + rng.gen::().powf(5.0) * 1.0).round() as u32; + let size = (8.0 + rng.gen::().powf(5.0) * 1.0).round() as u32; let campfire = campfires < 4; if let Some((aabr, door_tile, door_dir)) = attempt(32, || { - site.find_roadside_aabr(&mut rng, 6..(size + 1).pow(2), Extent2::broadcast(size)) + site.find_roadside_aabr(&mut rng, 8..(size + 1).pow(2), Extent2::broadcast(size)) }) { let cliff_tower = plot::CliffTower::generate( land, diff --git a/world/src/site2/plot/cliff_tower.rs b/world/src/site2/plot/cliff_tower.rs index 15d47e2d20..b0015977c0 100644 --- a/world/src/site2/plot/cliff_tower.rs +++ b/world/src/site2/plot/cliff_tower.rs @@ -1,6 +1,6 @@ use super::*; use crate::{ - util::{RandomField, Sampler, LOCALITY}, + util::{RandomField, Sampler, DIAGONALS, LOCALITY}, Land, }; use common::{ @@ -8,16 +8,19 @@ use common::{ terrain::{BlockKind, SpriteKind}, }; use rand::prelude::*; -use std::{mem, sync::Arc}; +use std::{f32::consts::TAU, mem, sync::Arc}; use vek::*; /// Represents house data generated by the `generate()` method pub struct CliffTower { + /// Tile position of the door tile + pub door_tile: Vec2, /// Axis aligned bounding region for the house bounds: Aabr, /// Approximate altitude of the door tile pub(crate) alt: i32, campfire: bool, + door_dir: Vec2, } impl CliffTower { @@ -30,14 +33,17 @@ impl CliffTower { tile_aabr: Aabr, campfire: bool, ) -> Self { + 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), }; Self { + door_tile: door_tile_pos, bounds, alt: land.get_alt_approx(site.tile_center_wpos(door_tile + door_dir)) as i32, campfire, + door_dir, } } } @@ -49,852 +55,703 @@ impl Structure for CliffTower { #[cfg_attr(feature = "be-dyn-lib", export_name = "render_clifftower")] fn render_inner(&self, _site: &Site, _land: &Land, painter: &Painter) { let base = self.alt + 1; - let center = self.bounds.center(); - let variant_pos = center.with_z(base); - let variant = RandomField::new(0).get(variant_pos) as i32 % 10; - // common superquadric degree for rooms - let sq_type = 2.5; - let storeys = 5 + (variant / 2); - let mut length = 16 + (variant / 2); - let mut width = 7 * length / 8; - let mut height = 18 + variant / 2; - let (mut stair_pos1, mut stair_pos2) = (center - 3, center + 3); - let mut floor_level = base - 40; - let brick = Fill::Sampling(Arc::new(|variant_pos| { - Some( - match (RandomField::new(0).get(Vec3::new(variant_pos.z, 0, 0))) % 15 { - 0 => Block::new(BlockKind::Rock, Rgb::new(51, 89, 118)), - 1 => Block::new(BlockKind::Rock, Rgb::new(57, 96, 126)), - 2 => Block::new(BlockKind::Rock, Rgb::new(59, 103, 136)), - 3 => Block::new(BlockKind::Rock, Rgb::new(61, 109, 145)), - 4 => Block::new(BlockKind::Rock, Rgb::new(42, 66, 87)), - 5 => Block::new(BlockKind::Rock, Rgb::new(47, 76, 101)), - 6 => Block::new(BlockKind::Rock, Rgb::new(50, 84, 110)), - 7 => Block::new(BlockKind::Rock, Rgb::new(52, 85, 112)), - 8 => Block::new(BlockKind::Rock, Rgb::new(51, 60, 66)), - 9 => Block::new(BlockKind::Rock, Rgb::new(58, 74, 87)), - 10 => Block::new(BlockKind::Rock, Rgb::new(53, 104, 111)), - 11 => Block::new(BlockKind::Rock, Rgb::new(52, 63, 72)), - 12 => Block::new(BlockKind::Rock, Rgb::new(52, 63, 72)), - 13 => Block::new(BlockKind::Rock, Rgb::new(74, 128, 168)), - _ => Block::new(BlockKind::Rock, Rgb::new(69, 123, 162)), - }, - ) - })); - let wood = Fill::Brick(BlockKind::Wood, Rgb::new(106, 83, 51), 12); - let color = Fill::Block(Block::air(SpriteKind::CliffDecorBlock)); - let window = Fill::Block(Block::air(SpriteKind::WindowArabic)); - let window2 = Fill::Block(Block::air(SpriteKind::WindowArabic).with_ori(2).unwrap()); - for s in 0..storeys { - let x_offset = RandomField::new(0).get((center - length).with_z(base)) as i32 % 10; - let y_offset = RandomField::new(0).get((center + length).with_z(base)) as i32 % 10; - let super_center = Vec2::new(center.x - 3 + x_offset / 2, center.y - 3 + y_offset / 2); - let room1_type = RandomField::new(0).get((center - length).with_z(base)) as i32 % 2; - let room2_type = RandomField::new(0).get((center - length - 1).with_z(base)) as i32 % 2; - // CliffTower Hoodoo Overlay - painter - .cubic_bezier( - super_center.with_z(floor_level + (height / 2)), - (super_center - x_offset).with_z(floor_level + height), - (super_center - y_offset).with_z(floor_level + (height) + (height / 2)), - super_center.with_z(floor_level + (2 * height)), - (length - 1) as f32, + let plot_center = self.bounds.center(); + let door_dir = self.door_dir; + let tube_var = RandomField::new(0).get(plot_center.with_z(base)) as i32 % 6; + let radius = 10.0 + tube_var as f32; + let tubes = 3.0 + tube_var as f32; + let phi = TAU / tubes; + for n in 1..=tubes as i32 { + let center = Vec2::new( + plot_center.x + (radius * ((n as f32 * phi).cos())) as i32, + plot_center.y + (radius * ((n as f32 * phi).sin())) as i32, + ); + + let variant_pos = center.with_z(base); + let variant = RandomField::new(0).get(variant_pos) as i32 % 10; + // common superquadric degree for rooms + let sq_type = 3.5; + let storeys = 5 + (variant / 2); + let mut length = 16 + (variant / 2); + let mut width = 7 * length / 8; + let mut height = 18 + variant / 2; + let mut floor_level = base - 40; + let mut workshops = 0; + let mut ground_entry = 0; + let brick = Fill::Sampling(Arc::new(|variant_pos| { + Some( + match (RandomField::new(0).get(Vec3::new(variant_pos.z, 0, 0))) % 15 { + 0 => Block::new(BlockKind::Rock, Rgb::new(51, 89, 118)), + 1 => Block::new(BlockKind::Rock, Rgb::new(57, 96, 126)), + 2 => Block::new(BlockKind::Rock, Rgb::new(59, 103, 136)), + 3 => Block::new(BlockKind::Rock, Rgb::new(61, 109, 145)), + 4 => Block::new(BlockKind::Rock, Rgb::new(42, 66, 87)), + 5 => Block::new(BlockKind::Rock, Rgb::new(47, 76, 101)), + 6 => Block::new(BlockKind::Rock, Rgb::new(50, 84, 110)), + 7 => Block::new(BlockKind::Rock, Rgb::new(52, 85, 112)), + 8 => Block::new(BlockKind::Rock, Rgb::new(51, 60, 66)), + 9 => Block::new(BlockKind::Rock, Rgb::new(58, 74, 87)), + 10 => Block::new(BlockKind::Rock, Rgb::new(53, 104, 111)), + 11 => Block::new(BlockKind::Rock, Rgb::new(52, 63, 72)), + 12 => Block::new(BlockKind::Rock, Rgb::new(52, 63, 72)), + 13 => Block::new(BlockKind::Rock, Rgb::new(74, 128, 168)), + _ => Block::new(BlockKind::Rock, Rgb::new(69, 123, 162)), + }, ) - .fill(brick.clone()); - // only inhabit towers with enough storeys to have entries above ground - if storeys > 3 { - // wood or rocky platforms - // only spawn on upper storeys - if floor_level > base + 35 { - match RandomField::new(0).get((super_center - floor_level).with_z(base)) as i32 - % 2 - { - 0 => { + })); + let wood = Fill::Brick(BlockKind::Wood, Rgb::new(106, 83, 51), 12); + let color = Fill::Block(Block::air(SpriteKind::CliffDecorBlock)); + let window = Fill::Block(Block::air(SpriteKind::WindowArabic)); + let window2 = Fill::Block(Block::air(SpriteKind::WindowArabic).with_ori(2).unwrap()); + let rope = Fill::Block(Block::air(SpriteKind::Rope)); + for _ in 0..storeys { + let x_offset = RandomField::new(0).get((center - length).with_z(base)) as i32 % 10; + let y_offset = RandomField::new(0).get((center + length).with_z(base)) as i32 % 10; + let super_center = + Vec2::new(center.x - 3 + x_offset / 2, center.y - 3 + y_offset / 2); + + // CliffTower Hoodoo Overlay + painter + .cubic_bezier( + super_center.with_z(floor_level + (height / 2)), + (super_center - x_offset).with_z(floor_level + height), + (super_center - y_offset).with_z(floor_level + (height) + (height / 2)), + super_center.with_z(floor_level + (2 * height)), + (length - 1) as f32, + ) + .fill(brick.clone()); + // center tube with rooms + if n == tubes as i32 { + painter + .cubic_bezier( + plot_center.with_z(floor_level + (height / 2)), + (plot_center - x_offset).with_z(floor_level + height), + (plot_center - y_offset).with_z(floor_level + (height) + (height / 2)), + plot_center.with_z(floor_level + (2 * height)), + (length + 2) as f32, + ) + .fill(brick.clone()); + // platforms on some upper storeys + let balcony = RandomField::new(0).get((plot_center - floor_level).with_z(base)) + as i32 + % 2; + if storeys > 3 && floor_level > base + 25 && balcony == 0 { + let limit_up = painter.aabb(Aabb { + min: (plot_center - (2 * length) - 2).with_z(floor_level - 4), + max: (plot_center + (2 * length) + 2).with_z(floor_level + 1), + }); + painter + .superquadric( + Aabb { + min: (plot_center - (2 * length) - 2).with_z(floor_level - 4), + max: (plot_center + (2 * length) + 2).with_z(floor_level + 6), + }, + 4.0, + ) + .intersect(limit_up) + .fill(wood.clone()); + // lanterns & random sprites for wood platform corners + for dir in DIAGONALS { + let sprite_pos = plot_center + (dir * ((2 * length) - 4)); painter - .superquadric( - Aabb { - min: (super_center - (5 * (length / 3)) + 3) - .with_z(floor_level), - max: (super_center + (5 * (length / 3)) - 3) - .with_z(floor_level + 2), - }, - 6.0, - ) - .fill(wood.clone()); - painter - .prim(Primitive::without( - painter.superquadric( - Aabb { - min: (super_center - (5 * (length / 3)) + 2) - .with_z(floor_level + 1), - max: (super_center + (5 * (length / 3)) - 1) - .with_z(floor_level + 5), - }, - 6.0, - ), - painter.superquadric( - Aabb { - min: (super_center - (5 * (length / 3)) + 2) - .with_z(floor_level + 3), - max: (super_center + (5 * (length / 3)) - 2) - .with_z(floor_level + 5), - }, - 6.0, - ), - )) - .fill(wood.clone()); - // lanterns & random sprites for wood platform corners - for dir in SQUARE_4 { - let corner_pos = super_center - (5 * (length / 4)); - let sprite_pos = (corner_pos + (dir * (10 * (length / 4)))) - .with_z(floor_level + 4); - painter.sprite( - sprite_pos, - match (RandomField::new(0).get(sprite_pos)) % 10 { - 0 => SpriteKind::FireBowlGround, - 1 => SpriteKind::Bowl, - 3 => SpriteKind::VialEmpty, - 4 => SpriteKind::Crate, - 5 => SpriteKind::Pot, - _ => SpriteKind::Lantern, - }, + .aabb(Aabb { + min: sprite_pos.with_z(floor_level + 1), + max: (sprite_pos + 1).with_z(floor_level + 2), + }) + .clear(); + painter.sprite( + sprite_pos.with_z(floor_level + 1), + match (RandomField::new(0).get(sprite_pos.with_z(floor_level + 1))) + % 10 + { + 0 => SpriteKind::FireBowlGround, + 1 => SpriteKind::Bowl, + 3 => SpriteKind::VialEmpty, + 4 => SpriteKind::Crate, + 5 => SpriteKind::Pot, + _ => SpriteKind::Lantern, + }, + ); + } + // planters + for r in 0..2 { + for p in 0..((length / 2) - 2) { + let planter_pos_1 = Vec2::new( + plot_center.x - (2 * (length / 3)) + (p * (length / 3)), + plot_center.y - ((2 * length) + 1) + (r * ((4 * length) + 1)), + ); + painter + .aabb(Aabb { + min: Vec2::new(planter_pos_1.x - 1, planter_pos_1.y) + .with_z(floor_level + 1), + max: Vec2::new(planter_pos_1.x + 2, planter_pos_1.y + 1) + .with_z(floor_level + 3), + }) + .clear(); + painter.rotated_sprite( + planter_pos_1.with_z(floor_level + 1), + SpriteKind::Planter, + (4 - (r * 4)) as u8, + ); + let planter_pos_2 = Vec2::new( + plot_center.x - ((2 * length) + 1) + (r * ((4 * length) + 1)), + plot_center.y - (2 * (length / 3)) + (p * (length / 3)), + ); + painter + .aabb(Aabb { + min: Vec2::new(planter_pos_2.x, planter_pos_2.y - 1) + .with_z(floor_level + 1), + max: Vec2::new(planter_pos_2.x + 1, planter_pos_2.y + 2) + .with_z(floor_level + 3), + }) + .clear(); + painter.rotated_sprite( + planter_pos_2.with_z(floor_level + 1), + SpriteKind::Planter, + (6 - (r * 4)) as u8, ); } - // planters for larger wood platforms - if length > 11 { - for r in 0..2 { - for p in 0..((length / 2) - 2) { - let planter_pos = Vec2::new( - super_center.x - (2 * (length / 3)) - + (p * (length / 3)), - super_center.y - ((4 * (length / 3)) + 2) - + (r * ((8 * (length / 3)) + 4)), + } + } + + // clear rooms and entries & decor + if floor_level > (base - 6) { + // decor + painter + .line( + Vec2::new(plot_center.x, plot_center.y - length) + .with_z(floor_level + 5), + Vec2::new(plot_center.x, plot_center.y + length) + .with_z(floor_level + 5), + 4.0, + ) + .fill(color.clone()); + painter + .line( + Vec2::new(plot_center.x - length, plot_center.y) + .with_z(floor_level + 5), + Vec2::new(plot_center.x + length, plot_center.y) + .with_z(floor_level + 5), + 4.0, + ) + .fill(color.clone()); + // entries + painter + .line( + Vec2::new(plot_center.x, plot_center.y - (2 * length) - 4) + .with_z(floor_level + 4), + Vec2::new(plot_center.x, plot_center.y + (2 * length) + 4) + .with_z(floor_level + 4), + 4.0, + ) + .clear(); + painter + .line( + Vec2::new(plot_center.x - (2 * length) - 4, plot_center.y) + .with_z(floor_level + 4), + Vec2::new(plot_center.x + (2 * length) + 4, plot_center.y) + .with_z(floor_level + 4), + 4.0, + ) + .clear(); + painter + .superquadric( + Aabb { + min: (plot_center - length - 1).with_z(floor_level), + max: (plot_center + length + 1) + .with_z(floor_level + height - 4), + }, + sq_type, + ) + .clear(); + // room floor + painter + .cylinder(Aabb { + min: (plot_center - length - 3).with_z(floor_level), + max: (plot_center + length + 3).with_z(floor_level + 1), + }) + .fill(brick.clone()); + painter + .cylinder(Aabb { + min: (plot_center - length + 1).with_z(floor_level), + max: (plot_center + length - 1).with_z(floor_level + 1), + }) + .fill(color.clone()); + painter + .cylinder(Aabb { + min: (plot_center - length + 2).with_z(floor_level), + max: (plot_center + length - 2).with_z(floor_level + 1), + }) + .fill(brick.clone()); + // entry sprites + painter + .aabb(Aabb { + min: Vec2::new(plot_center.x - 3, plot_center.y + length) + .with_z(floor_level + 2), + max: Vec2::new(plot_center.x + 4, plot_center.y + length + 1) + .with_z(floor_level + 7), + }) + .fill(window2.clone()); + painter + .aabb(Aabb { + min: Vec2::new(plot_center.x - 2, plot_center.y + length) + .with_z(floor_level + 2), + max: Vec2::new(plot_center.x + 3, plot_center.y + length + 1) + .with_z(floor_level + 7), + }) + .clear(); + + painter + .aabb(Aabb { + min: Vec2::new(plot_center.x - 3, plot_center.y - length - 1) + .with_z(floor_level + 2), + max: Vec2::new(plot_center.x + 4, plot_center.y - length) + .with_z(floor_level + 7), + }) + .fill(window2.clone()); + painter + .aabb(Aabb { + min: Vec2::new(plot_center.x - 2, plot_center.y - length - 1) + .with_z(floor_level + 2), + max: Vec2::new(plot_center.x + 3, plot_center.y - length) + .with_z(floor_level + 7), + }) + .clear(); + painter + .aabb(Aabb { + min: Vec2::new(plot_center.x + length, plot_center.y - 3) + .with_z(floor_level + 2), + max: Vec2::new(plot_center.x + length + 1, plot_center.y + 4) + .with_z(floor_level + 7), + }) + .fill(window.clone()); + painter + .aabb(Aabb { + min: Vec2::new(plot_center.x + length, plot_center.y - 2) + .with_z(floor_level + 2), + max: Vec2::new(plot_center.x + length + 1, plot_center.y + 3) + .with_z(floor_level + 7), + }) + .clear(); + + painter + .aabb(Aabb { + min: Vec2::new(plot_center.x - length - 1, plot_center.y - 3) + .with_z(floor_level + 2), + max: Vec2::new(plot_center.x - length, plot_center.y + 4) + .with_z(floor_level + 7), + }) + .fill(window.clone()); + painter + .aabb(Aabb { + min: Vec2::new(plot_center.x - length - 1, plot_center.y - 2) + .with_z(floor_level + 2), + max: Vec2::new(plot_center.x - length, plot_center.y + 3) + .with_z(floor_level + 7), + }) + .clear(); + // furniture + if workshops < 1 { + painter + .aabb(Aabb { + min: (plot_center - 1).with_z(floor_level + 1), + max: (plot_center + 2).with_z(floor_level + 2), + }) + .fill(brick.clone()); + painter + .aabb(Aabb { + min: plot_center.with_z(floor_level), + max: (plot_center + 1).with_z(floor_level + 1), + }) + .fill(Fill::Block(Block::air(SpriteKind::FireBlock))); + + painter + .aabb(Aabb { + min: plot_center.with_z(floor_level + 1), + max: (plot_center + 1).with_z(floor_level + 2), + }) + .clear(); + let mut stations = vec![ + SpriteKind::CraftingBench, + SpriteKind::Forge, + SpriteKind::SpinningWheel, + SpriteKind::TanningRack, + SpriteKind::CookingPot, + SpriteKind::Cauldron, + SpriteKind::Loom, + SpriteKind::Anvil, + SpriteKind::DismantlingBench, + SpriteKind::RepairBench, + ]; + 'outer: for d in 0..3 { + for dir in CARDINALS { + if stations.is_empty() { + break 'outer; + } + let position = plot_center + dir * (3 + d * 2); + let cr_station = stations.swap_remove( + RandomField::new(0).get(position.with_z(base)) as usize + % stations.len(), + ); + painter.sprite(position.with_z(floor_level + 1), cr_station); + } + } + workshops += 1; + // forge tools + for d in 0..2 { + let pos = Vec2::new( + plot_center.x - 5 + (d * 10), + plot_center.y - length + (d * ((2 * length) - 1)), + ); + painter + .aabb(Aabb { + min: Vec2::new(pos.x - 2, pos.y - (4 * d)) + .with_z(floor_level + 1), + max: Vec2::new(pos.x + 3, pos.y + 5 - (4 * d)) + .with_z(floor_level + 4), + }) + .clear(); + painter.rotated_sprite( + pos.with_z(floor_level + 1), + SpriteKind::Hearth, + (4 * d) as u8, + ); + } + // forge tools + for d in 0..2 { + let pos = Vec2::new( + plot_center.x + 5 - (d * 10), + plot_center.y - length + (d * ((2 * length) - 1)), + ); + painter + .aabb(Aabb { + min: Vec2::new(pos.x - 2, pos.y - (4 * d)) + .with_z(floor_level + 1), + max: Vec2::new(pos.x + 3, pos.y + 5 - (4 * d)) + .with_z(floor_level + 4), + }) + .clear(); + painter.rotated_sprite( + pos.with_z(floor_level + 1), + SpriteKind::ForgeTools, + (4 * d) as u8, + ); + } + } else { + match (RandomField::new(0).get(plot_center.with_z(floor_level))) % 3 { + 0 => { + // living room + // distribute small sprites + for dir in LOCALITY { + let pos = plot_center + dir * ((length / 3) - 1); + painter.sprite( + pos.with_z(floor_level + 1), + match (RandomField::new(0).get(pos.with_z(floor_level))) + % 8 + { + 0 => SpriteKind::DrawerSmall, + 1 => SpriteKind::CoatRack, + 2 => SpriteKind::TableArabicSmall, + 3 => SpriteKind::CushionArabic, + 4 => SpriteKind::JugArabic, + 5 => SpriteKind::SepareArabic, + 6 => SpriteKind::Crate, + 7 => SpriteKind::Bowl, + _ => SpriteKind::Lantern, + }, + ); + } + // canapes + for d in 0..2 { + let pos = Vec2::new( + plot_center.x - length + 6 + (d * ((2 * length) - 12)), + plot_center.y - length + 5 + (d * ((2 * length) - 10)), ); painter .aabb(Aabb { - min: Vec2::new(planter_pos.x - 1, planter_pos.y) - .with_z(floor_level + 4), - max: Vec2::new( - planter_pos.x + 2, - planter_pos.y + 1, + min: Vec2::new( + pos.x - 1 - (3 * d), + pos.y - 1 - (3 * d), ) - .with_z(floor_level + 6), + .with_z(floor_level + 1), + max: Vec2::new( + pos.x + 5 - (3 * d), + pos.y + 5 - (3 * d), + ) + .with_z(floor_level + 5), }) .clear(); painter.rotated_sprite( - planter_pos.with_z(floor_level + 4), - SpriteKind::Planter, - (4 - (r * 4)) as u8, + pos.with_z(floor_level + 1), + SpriteKind::CanapeArabic, + (4 * d) as u8, ); } - } + // bookshelfs + for d in 0..2 { + let pos = Vec2::new( + plot_center.x + 5 - (d * 10), + plot_center.y - length + (d * ((2 * length) - 1)), + ); + painter.rotated_sprite( + pos.with_z(floor_level + 4), + SpriteKind::BookshelfArabic, + (4 * d) as u8, + ); + } + // decor set / separe / table large + for d in 0..2 { + let pos = Vec2::new( + plot_center.x - length + 8 + (d * ((2 * length) - 16)), + plot_center.y + length - 8 + (d * ((-2 * length) + 16)), + ); + painter + .aabb(Aabb { + min: Vec2::new(pos.x - 2, pos.y - 1) + .with_z(floor_level + 1), + max: Vec2::new(pos.x + 3, pos.y + 2) + .with_z(floor_level + 3), + }) + .clear(); + painter.sprite( + pos.with_z(floor_level + 1), + match (RandomField::new(0) + .get(pos.with_z(floor_level - d))) + % 3 + { + 0 => SpriteKind::TableArabicLarge, + 1 => SpriteKind::DecorSetArabic, + _ => SpriteKind::SepareArabic, + }, + ) + } + }, + 1 => { + // bath + // wall tables with varying items + for d in 0..2 { + let pos = Vec2::new( + plot_center.x - 5 + (d * 10), + plot_center.y - length + (d * ((2 * length) - 1)), + ); + painter.rotated_sprite( + pos.with_z(floor_level + 3), + SpriteKind::WallTableArabic, + (4 * d) as u8, + ); + painter.rotated_sprite( + pos.with_z(floor_level + 4), + match (RandomField::new(0).get(pos.with_z(floor_level))) + % 4 + { + 0 => SpriteKind::Bowl, + 1 => SpriteKind::VialEmpty, + 2 => SpriteKind::JugArabic, + _ => SpriteKind::JugAndBowlArabic, + }, + (4 * d) as u8, + ); + } + // distribute small sprites + for dir in LOCALITY { + let pos = plot_center + dir * ((length / 3) + 1); + painter.sprite( + pos.with_z(floor_level + 1), + match (RandomField::new(0).get(pos.with_z(floor_level))) + % 14 + { + 0 => SpriteKind::DrawerSmall, + 1 => SpriteKind::CoatRack, + 2 => SpriteKind::TableArabicSmall, + 3 => SpriteKind::CushionArabic, + 4 => SpriteKind::JugArabic, + 5 => SpriteKind::DrawerSmall, + 6 => SpriteKind::Crate, + 7 => SpriteKind::DecorSetArabic, + 8 => SpriteKind::VialEmpty, + 9 => SpriteKind::SepareArabic, + 10 => SpriteKind::TableArabicSmall, + 11 => SpriteKind::Lantern, + _ => SpriteKind::FountainArabic, + }, + ); + } + }, + _ => { + // kitchen + // cupbooards + for d in 0..2 { + let pos = Vec2::new( + plot_center.x + 5 - (d * 10), + plot_center.y - length + (d * ((2 * length) - 1)), + ); + painter.rotated_sprite( + pos.with_z(floor_level + 2), + SpriteKind::CupboardArabic, + (4 * d) as u8, + ); + } + // wall tables with varying items + for d in 0..2 { + let pos = Vec2::new( + plot_center.x - 5 + (d * 10), + plot_center.y - length + (d * ((2 * length) - 1)), + ); + painter.rotated_sprite( + pos.with_z(floor_level + 2), + SpriteKind::WallTableArabic, + (4 * d) as u8, + ); + painter.rotated_sprite( + pos.with_z(floor_level + 3), + match (RandomField::new(0).get(pos.with_z(floor_level))) + % 5 + { + 0 => SpriteKind::MelonCut, + 1 => SpriteKind::JugAndBowlArabic, + 2 => SpriteKind::Bowl, + 3 => SpriteKind::JugArabic, + _ => SpriteKind::VialEmpty, + }, + (4 * d) as u8, + ); + } + // distribute small sprites + for dir in LOCALITY { + let pos = plot_center + dir * ((length / 3) + 1); + painter.sprite( + pos.with_z(floor_level + 1), + match (RandomField::new(0).get(pos.with_z(floor_level))) + % 12 + { + 0 => SpriteKind::DrawerSmall, + 1 => SpriteKind::Cauldron, + 2 => SpriteKind::TableArabicSmall, + 3 => SpriteKind::CushionArabic, + 4 => SpriteKind::JugArabic, + 5 => SpriteKind::DrawerSmall, + 6 => SpriteKind::Crate, + 7 => SpriteKind::Bowl, + 8 => SpriteKind::VialEmpty, + 9 => SpriteKind::CookingPot, + 10 => SpriteKind::Lantern, + _ => SpriteKind::OvenArabic, + }, + ); + } + }, } - }, - _ => { - painter - .superquadric( - Aabb { - min: (center - length + 1).with_z(floor_level), - max: (center + length - 1).with_z(floor_level + 2), - }, - sq_type, - ) - .fill(brick.clone()); - painter - .prim(Primitive::without( - painter.superquadric( - Aabb { - min: (center - length).with_z(floor_level + 1), - max: (center + length).with_z(floor_level + 5), - }, - sq_type, - ), - painter.superquadric( - Aabb { - min: (center - length + 3).with_z(floor_level + 3), - max: (center + length - 3).with_z(floor_level + 5), - }, - sq_type, - ), - )) - .fill(brick.clone()); - }, + } } - } - // room - painter - .superquadric( - Aabb { - min: Vec2::new(super_center.x - length - 1, super_center.y - width - 1) - .with_z(floor_level), - max: Vec2::new(super_center.x + length + 1, super_center.y + width + 1) - .with_z(floor_level + height), - }, - sq_type, - ) - .fill(brick.clone()); - // clear room - leave some floor - painter - .prim(Primitive::without( - painter.superquadric( - Aabb { - min: Vec2::new( - super_center.x - length + 1, - super_center.y + 1 - width, - ) - .with_z(floor_level + 1), - max: Vec2::new( - super_center.x + length - 1, - super_center.y - 1 + width, - ) - .with_z(floor_level + height - 1), - }, - sq_type, - ), - painter.aabb(Aabb { - min: Vec2::new(super_center.x - length + 1, super_center.y + 1 - width) - .with_z(floor_level + 1), - max: Vec2::new(super_center.x + length - 1, super_center.y - 1 + width) - .with_z(floor_level + 4), - }), - )) - .clear(); - // entries - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - length, super_center.y - 2) - .with_z(floor_level + 3), - max: Vec2::new(super_center.x - length + 6, super_center.y + 2) - .with_z(floor_level + 4), - }) - .fill(brick.clone()); - painter - .aabb(Aabb { - min: Vec2::new(super_center.x + length - 6, super_center.y - 2) - .with_z(floor_level + 3), - max: Vec2::new(super_center.x + length, super_center.y + 2) - .with_z(floor_level + 4), - }) - .fill(brick.clone()); - // colored sills - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - length - 1, super_center.y - 2) - .with_z(floor_level + 3), - max: Vec2::new(super_center.x - length, super_center.y + 2) - .with_z(floor_level + 4), - }) - .fill(color.clone()); - painter - .aabb(Aabb { - min: Vec2::new(super_center.x + length, super_center.y - 2) - .with_z(floor_level + 3), - max: Vec2::new(super_center.x + length + 1, super_center.y + 2) - .with_z(floor_level + 4), - }) - .fill(color.clone()); - if floor_level > base { - // clear entries - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - length - 12, super_center.y - 2) - .with_z(floor_level + 4), - max: Vec2::new(super_center.x + length + 12, super_center.y + 2) - .with_z(floor_level + 7), - }) - .clear(); - // door sprites - painter - .prim(Primitive::without( - painter.aabb(Aabb { - min: Vec2::new(super_center.x - length + 1, super_center.y - 2) - .with_z(floor_level + 4), - max: Vec2::new(super_center.x - length + 2, super_center.y + 2) - .with_z(floor_level + 7), - }), - painter.aabb(Aabb { - min: Vec2::new(super_center.x - length + 1, super_center.y - 1) - .with_z(floor_level + 4), - max: Vec2::new(super_center.x - length + 2, super_center.y + 1) - .with_z(floor_level + 7), - }), - )) - .fill(window.clone()); - painter - .prim(Primitive::without( - painter.aabb(Aabb { - min: Vec2::new(super_center.x + length - 1, super_center.y - 2) - .with_z(floor_level + 4), - max: Vec2::new(super_center.x + length, super_center.y + 2) - .with_z(floor_level + 7), - }), - painter.aabb(Aabb { - min: Vec2::new(super_center.x + length - 1, super_center.y - 1) - .with_z(floor_level + 4), - max: Vec2::new(super_center.x + length, super_center.y + 1) - .with_z(floor_level + 7), - }), - )) - .fill(window.clone()); - // windows - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - 4, super_center.y - width) - .with_z(floor_level + 5), - max: Vec2::new(super_center.x + 4, super_center.y - width + 3) - .with_z(floor_level + 6), - }) - .fill(brick.clone()); - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - 4, super_center.y - width + 1) - .with_z(floor_level + 4), - max: Vec2::new(super_center.x + 4, super_center.y - width + 3) - .with_z(floor_level + 5), - }) - .fill(brick.clone()); - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - 4, super_center.y + width - 3) - .with_z(floor_level + 5), - max: Vec2::new(super_center.x + 4, super_center.y + width + 1) - .with_z(floor_level + 6), - }) - .fill(brick.clone()); - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - 4, super_center.y + width - 3) - .with_z(floor_level + 4), - max: Vec2::new(super_center.x + 4, super_center.y + width) - .with_z(floor_level + 5), - }) - .fill(brick.clone()); - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - 3, super_center.y - width - 1) - .with_z(floor_level + 5), - max: Vec2::new(super_center.x + 3, super_center.y - width) - .with_z(floor_level + 6), - }) - .fill(color.clone()); - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - 3, super_center.y + width + 1) - .with_z(floor_level + 5), - max: Vec2::new(super_center.x + 3, super_center.y + width + 2) - .with_z(floor_level + 6), - }) - .fill(color.clone()); - // clear windows - painter - .aabb(Aabb { - min: Vec2::new(super_center.x - 4, super_center.y - width - 12) - .with_z(floor_level + 6), - max: Vec2::new(super_center.x + 4, super_center.y + width + 12) - .with_z(floor_level + 9), - }) - .clear(); - // window sprites - painter - .prim(Primitive::without( - painter.aabb(Aabb { - min: Vec2::new(super_center.x - 4, super_center.y - width + 1) - .with_z(floor_level + 6), - max: Vec2::new(super_center.x + 4, super_center.y - width + 2) - .with_z(floor_level + 9), - }), - painter.aabb(Aabb { - min: Vec2::new(super_center.x - 1, super_center.y - width + 1) - .with_z(floor_level + 6), - max: Vec2::new(super_center.x + 1, super_center.y - width + 2) - .with_z(floor_level + 9), - }), - )) - .fill(window2.clone()); - painter - .prim(Primitive::without( - painter.aabb(Aabb { - min: Vec2::new(super_center.x - 4, super_center.y + width - 1) - .with_z(floor_level + 6), - max: Vec2::new(super_center.x + 4, super_center.y + width) - .with_z(floor_level + 9), - }), - painter.aabb(Aabb { - min: Vec2::new(super_center.x - 1, super_center.y + width - 1) - .with_z(floor_level + 6), - max: Vec2::new(super_center.x + 1, super_center.y + width) - .with_z(floor_level + 9), - }), - )) - .fill(window2.clone()); - } - // room wall lamps - for d in 0..2 { - let door_lamp_pos = Vec2::new( - super_center.x - length + 2 + (d * ((2 * length) - 4)), - super_center.y, - ) - .with_z(floor_level + 9); - painter.rotated_sprite( - door_lamp_pos, - SpriteKind::WallLampSmall, - 2 + ((d * 4) as u8), - ); + // stairs + if floor_level > (base + 8) { + let stairs_level = floor_level + 1; + let stairs_start = plot_center + door_dir * ((2 * length) - 7); + let mid_dir = if door_dir.x != 0 { + door_dir.x + } else { + door_dir.y + }; + let stairs_mid = Vec2::new( + plot_center.x + mid_dir * (3 * (length / 2)), + plot_center.y + mid_dir * (3 * (length / 2)), + ); + let stairs_end = Vec2::new( + plot_center.x + door_dir.y * ((2 * length) - 7), + plot_center.y + door_dir.x * ((2 * length) - 7), + ); + let rope_pos = Vec2::new( + plot_center.x + mid_dir * ((3 * (length / 2)) + 2), + plot_center.y + mid_dir * ((3 * (length / 2)) + 2), + ); - let window_lamp_pos = Vec2::new( - super_center.x, - super_center.y - width + 2 + (d * ((2 * width) - 4)), - ) - .with_z(floor_level + 9); - painter.rotated_sprite( - window_lamp_pos, - SpriteKind::WallLampSmall, - 4 - ((d * 4) as u8), - ); - } - // furniture sprites in room1(living_room, workshop), room2(kitchen, bath) - // dont spawn sprites on stairways - let stairway_clear_1 = Aabb { - min: (stair_pos1 - 5).with_z(floor_level + 3), - max: (stair_pos1 + 5).with_z(floor_level + 5), - }; - let stairway_clear_2 = Aabb { - min: (stair_pos2 - 5).with_z(floor_level + 3), - max: (stair_pos2 + 5).with_z(floor_level + 5), - }; - if length > width { - match room1_type { - 0 => { - // living room - // distribute small sprites - let mut liv_sprites = vec![ - SpriteKind::DrawerSmall, - SpriteKind::CoatRack, - SpriteKind::TableArabicSmall, - SpriteKind::CushionArabic, - SpriteKind::JugArabic, - SpriteKind::SpinningWheel, - SpriteKind::TanningRack, - SpriteKind::Loom, - ]; - for dir in LOCALITY { - let pos = super_center + dir * (width / 3); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - && !liv_sprites.is_empty() - { - let sprite = liv_sprites.swap_remove( - RandomField::new(0).get(pos.with_z(base)) as usize - % liv_sprites.len(), - ); - painter.sprite(pos.with_z(floor_level + 4), sprite); - } - } - // bookshelfs - for d in 0..2 { - let pos = Vec2::new( - super_center.x, - super_center.y + width - 3 + (d * ((-2 * width) + 6)), + painter + .cylinder(Aabb { + min: (stairs_start - 6).with_z(stairs_level - 1), + max: (stairs_start + 6).with_z(stairs_level), + }) + .fill(wood.clone()); + + painter + .cylinder(Aabb { + min: (stairs_mid - 6).with_z(stairs_level - (height / 2) - 1), + max: (stairs_mid + 6).with_z(stairs_level - (height / 2)), + }) + .fill(wood.clone()); + + painter + .cylinder(Aabb { + min: (stairs_end - 6).with_z(stairs_level - height - 1), + max: (stairs_end + 6).with_z(stairs_level - height), + }) + .fill(wood.clone()); + + for n in 0..2 { + let stairs = painter + .line( + stairs_start.with_z(stairs_level + (n * 2)), + stairs_mid.with_z(stairs_level - (height / 2) + (n * 2)), + 4.0 + (n as f32 / 2.0), + ) + .union(painter.line( + stairs_mid.with_z(stairs_level - (height / 2) + (n * 2)), + stairs_end.with_z(stairs_level - height + (n * 2)), + 4.0 + (n as f32 / 2.0), + )); + match n { + 0 => stairs.fill(wood.clone()), + _ => stairs.clear(), + }; + } + painter + .line( + rope_pos.with_z(stairs_level + (height / 2) - 3), + (plot_center - (length / 2)) + .with_z(stairs_level + (height / 2) + 2), + 1.5, + ) + .fill(wood.clone()); + + painter + .aabb(Aabb { + min: rope_pos.with_z(stairs_level - (height / 2) - 1), + max: (rope_pos + 1).with_z(stairs_level + (height / 2) - 3), + }) + .fill(rope.clone()); + } + if floor_level > (base - 6) { + // ensure ground entry toward door_dir + if ground_entry < 1 { + let door_start = plot_center + door_dir * ((3 * (length / 2)) + 1); + let door_end = plot_center + door_dir * ((3 * length) - 1); + + for n in 0..2 { + let door_stairs = painter.line( + door_start.with_z(floor_level + 1 + (n * 2)), + door_end.with_z(base + (n * 2)), + 4.0 + (n as f32 / 2.0), ); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: Vec2::new(pos.x - 2, pos.y - 2 + (2 * d)) - .with_z(floor_level + 4), - max: Vec2::new(pos.x + 3, pos.y + 1 + (2 * d)) - .with_z(floor_level + 6), - }) - .clear(); - painter.rotated_sprite( - pos.with_z(floor_level + 6), - SpriteKind::BookshelfArabic, - (4 * d) as u8, - ); - } - } - // canapes - for d in 0..2 { - let pos = Vec2::new( - super_center.x - length + 10 + (d * ((2 * length) - 20)), - super_center.y - width + 4 + (d * ((2 * width) - 8)), - ); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: Vec2::new( - pos.x - 1 - (3 * d), - pos.y - 1 - (3 * d), - ) - .with_z(floor_level + 4), - max: Vec2::new( - pos.x + 5 - (3 * d), - pos.y + 5 - (3 * d), - ) - .with_z(floor_level + 8), - }) - .clear(); - painter.rotated_sprite( - pos.with_z(floor_level + 4), - SpriteKind::CanapeArabic, - (4 * d) as u8, - ); - } - } - // decor set / separe / table large - for d in 0..2 { - let pos = Vec2::new( - super_center.x - length + 8 + (d * ((2 * length) - 16)), - super_center.y + width - 8 + (d * ((-2 * width) + 16)), - ); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: Vec2::new(pos.x - 2, pos.y - 1) - .with_z(floor_level + 4), - max: Vec2::new(pos.x + 3, pos.y + 2) - .with_z(floor_level + 6), - }) - .clear(); - painter.sprite( - pos.with_z(floor_level + 4), - match (RandomField::new(0).get(pos.with_z(floor_level - d))) - % 3 - { - 0 => SpriteKind::TableArabicLarge, - 1 => SpriteKind::DecorSetArabic, - _ => SpriteKind::SepareArabic, - }, - ) + door_stairs.fill(wood.clone()); + match n { + 0 => door_stairs.fill(wood.clone()), + _ => door_stairs.clear(), }; } - }, - _ => { - // workshop - for d in 0..2 { - // forge tools - let ft_pos = Vec2::new( - super_center.x - 4 + (d * 6), - super_center.y - width + 3 + (d * ((2 * width) - 6)), - ); - if !stairway_clear_1.contains_point(ft_pos.with_z(floor_level + 4)) - && !stairway_clear_2 - .contains_point(ft_pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: Vec2::new(ft_pos.x - 2 + d, ft_pos.y - (3 * d)) - .with_z(floor_level + 4), - max: Vec2::new( - ft_pos.x + 2 + d, - ft_pos.y + 4 - (3 * d), - ) - .with_z(floor_level + 7), - }) - .clear(); - painter.rotated_sprite( - ft_pos.with_z(floor_level + 4), - SpriteKind::ForgeTools, - (4 * d) as u8, - ); - } - // hearth - let pos = Vec2::new( - super_center.x + length - 12 + (d * ((-2 * length) + 24)), - super_center.y - width + 3 + (d * ((2 * width) - 6)), - ); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: Vec2::new(pos.x - 2, pos.y - (4 * d)) - .with_z(floor_level + 4), - max: Vec2::new(pos.x + 3, pos.y + 5 - (4 * d)) - .with_z(floor_level + 6), - }) - .clear(); - painter.rotated_sprite( - pos.with_z(floor_level + 4), - SpriteKind::Hearth, - (4 * d) as u8, - ); - } - } - // crafting stations - let mut ws_sprites = vec![ - SpriteKind::CraftingBench, - SpriteKind::Forge, - SpriteKind::DismantlingBench, - SpriteKind::Anvil, - SpriteKind::RepairBench, - ]; - for dir in LOCALITY { - let pos = super_center + dir * (width / 3); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - && !ws_sprites.is_empty() - { - let sprite = ws_sprites.swap_remove( - RandomField::new(0).get(pos.with_z(base)) as usize - % ws_sprites.len(), - ); - painter.sprite(pos.with_z(floor_level + 4), sprite); - } - } - }, + ground_entry += 1; + } } - } else { - match room2_type { - 0 => { - // bath - // wall tables with varying items - for d in 0..2 { - let pos = Vec2::new( - super_center.x, - super_center.y - width + 3 + (d * ((2 * width) - 7)), - ); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: Vec2::new(pos.x - 2, pos.y - (d * 3)) - .with_z(floor_level + 4), - max: Vec2::new(pos.x + 3, pos.y + 4 - (d * 3)) - .with_z(floor_level + 7), - }) - .clear(); - painter.rotated_sprite( - pos.with_z(floor_level + 4), - SpriteKind::WallTableArabic, - (4 * d) as u8, - ); - painter.rotated_sprite( - pos.with_z(floor_level + 5), - match (RandomField::new(0) - .get((pos - d).with_z(floor_level))) - % 4 - { - 0 => SpriteKind::Bowl, - 1 => SpriteKind::VialEmpty, - 2 => SpriteKind::JugArabic, - _ => SpriteKind::JugAndBowlArabic, - }, - (4 * d) as u8, - ); - } - } - // distribute smaller sprites - let mut ba_sprites = vec![ - SpriteKind::DrawerSmall, - SpriteKind::CoatRack, - SpriteKind::Crate, - SpriteKind::TableArabicSmall, - SpriteKind::SepareArabic, - SpriteKind::DecorSetArabic, - ]; - for dir in LOCALITY { - let pos = super_center + dir * (width / 3); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - && !ba_sprites.is_empty() - { - let sprite = ba_sprites.swap_remove( - RandomField::new(0).get(pos.with_z(base)) as usize - % ba_sprites.len(), - ); - painter.sprite(pos.with_z(floor_level + 4), sprite) - } - } - // fountains - for d in 0..2 { - let pos = Vec2::new( - super_center.x - length + 8 + (d * ((2 * length) - 16)), - super_center.y + width - 8 + (d * ((-2 * width) + 16)), - ); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: (pos - 1).with_z(floor_level + 4), - max: (pos + 2).with_z(floor_level + 5), - }) - .clear(); - painter.sprite( - pos.with_z(floor_level + 4), - SpriteKind::FountainArabic, - ) - }; - } - }, - _ => { - // kitchen - // cupboards / ovens / cushions / jugs - for d in 0..2 { - let pos = Vec2::new( - super_center.x + 3 - (d * 6), - super_center.y - width + 3, - ); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: Vec2::new(pos.x - 1, pos.y) - .with_z(floor_level + 4), - max: Vec2::new(pos.x + 2, pos.y + 4) - .with_z(floor_level + 7), - }) - .clear(); - painter.rotated_sprite( - pos.with_z(floor_level + 4), - match (RandomField::new(0).get(pos.with_z(floor_level))) % 2 - { - 0 => SpriteKind::CupboardArabic, - _ => SpriteKind::OvenArabic, - }, - 4, - ); - } - } - for d in 0..2 { - let pos = Vec2::new( - super_center.x + 3 - (d * 6), - super_center.y + width - 3, - ); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: Vec2::new(pos.x - 1, pos.y - 3) - .with_z(floor_level + 4), - max: Vec2::new(pos.x + 2, pos.y + 1) - .with_z(floor_level + 7), - }) - .clear(); - painter.rotated_sprite( - pos.with_z(floor_level + 4), - match (RandomField::new(0).get(pos.with_z(floor_level))) % 4 - { - 0 => SpriteKind::CupboardArabic, - 1 => SpriteKind::OvenArabic, - 2 => SpriteKind::CushionArabic, - _ => SpriteKind::JugArabic, - }, - 0, - ); - } - } - // wall tables with varying items - for d in 0..2 { - let pos = Vec2::new( - super_center.x, - super_center.y - width + 3 + (d * ((2 * width) - 6)), - ); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - { - painter - .aabb(Aabb { - min: Vec2::new(pos.x - 2, pos.y - (3 * d)) - .with_z(floor_level + 4), - max: Vec2::new(pos.x + 2, pos.y + 4 - (3 * d)) - .with_z(floor_level + 7), - }) - .clear(); - painter.rotated_sprite( - pos.with_z(floor_level + 4), - SpriteKind::WallTableArabic, - (4 * d) as u8, - ); - painter.rotated_sprite( - pos.with_z(floor_level + 5), - match (RandomField::new(0).get(pos.with_z(floor_level))) % 5 - { - 0 => SpriteKind::MelonCut, - 1 => SpriteKind::JugAndBowlArabic, - 2 => SpriteKind::Bowl, - 3 => SpriteKind::JugArabic, - _ => SpriteKind::VialEmpty, - }, - (4 * d) as u8, - ); - } - } - // distribute small sprites - let mut kit_sprites = vec![ - SpriteKind::DrawerSmall, - SpriteKind::Crate, - SpriteKind::VialEmpty, - SpriteKind::Bowl, - SpriteKind::TableArabicSmall, - SpriteKind::JugArabic, - SpriteKind::CookingPot, - SpriteKind::Cauldron, - ]; - for dir in LOCALITY { - let pos = super_center + dir * (width / 3); - if !stairway_clear_1.contains_point(pos.with_z(floor_level + 4)) - && !stairway_clear_2.contains_point(pos.with_z(floor_level + 4)) - && !kit_sprites.is_empty() - { - let sprite = kit_sprites.swap_remove( - RandomField::new(0).get(pos.with_z(base)) as usize - % kit_sprites.len(), - ); - painter.sprite(pos.with_z(floor_level + 4), sprite); - } - } - }, - } - }; - // stairways starting from 2nd storey - if s > 0 { - //clear stairway - painter - .cylinder(Aabb { - min: (stair_pos1 - 3).with_z(floor_level - height + 4), - max: (stair_pos1 + 3).with_z(floor_level + 7), - }) - .clear(); - //stairway - let stair_radius1 = 4.0; - let stairs_clear1 = painter.prim(Primitive::Cylinder(Aabb { - min: (stair_pos1 - stair_radius1 as i32).with_z(floor_level - height), - max: (stair_pos1 + stair_radius1 as i32).with_z(floor_level + 4), - })); - painter - .prim(Primitive::sampling( - stairs_clear1, - dungeon::spiral_staircase( - stair_pos1.with_z(floor_level + 4), - stair_radius1, - 0.5, - 7.0, - ), - )) - .fill(brick.clone()); } + // vary next storey + length += -1; + width += -1; + height += -1; + floor_level += height; + mem::swap(&mut length, &mut width); } - // vary next storey - length += -1; - width += -1; - height += -1; - floor_level += height; - mem::swap(&mut length, &mut width); - mem::swap(&mut stair_pos1, &mut stair_pos2); } // spawn campfire next to some clifftowers if self.campfire { - let campfire_pos = (center - 20).with_z(self.alt + 18); + let campfire_pos = (plot_center - 20).with_z(self.alt + 18); painter.spawn(EntityInfo::at(campfire_pos.map(|e| e as f32)).into_waypoint()); } }