diff --git a/world/src/site/settlement/building/archetype/house.rs b/world/src/site/settlement/building/archetype/house.rs index a462551a9c..e9a4d2129c 100644 --- a/world/src/site/settlement/building/archetype/house.rs +++ b/world/src/site/settlement/building/archetype/house.rs @@ -165,6 +165,7 @@ impl Archetype for House { #[allow(clippy::int_plus_one)] // TODO: Pending review in #587 fn draw( &self, + pos: Vec3, dist: i32, bound_offset: Vec2, center_offset: Vec2, diff --git a/world/src/site/settlement/building/archetype/keep.rs b/world/src/site/settlement/building/archetype/keep.rs index 0d3d87dbe8..5d957a66cb 100644 --- a/world/src/site/settlement/building/archetype/keep.rs +++ b/world/src/site/settlement/building/archetype/keep.rs @@ -13,16 +13,16 @@ impl Archetype for Keep { type Attr = (); fn generate(rng: &mut R) -> (Self, Skeleton) { - let len = rng.gen_range(-8, 12).max(0); + let len = rng.gen_range(-8, 20).max(0); let skel = Skeleton { offset: -rng.gen_range(0, len + 7).clamped(0, len), ori: if rng.gen() { Ori::East } else { Ori::North }, root: Branch { len, attr: Self::Attr::default(), - locus: 5 + rng.gen_range(0, 5), + locus: 6 + rng.gen_range(0, 5), border: 3, - children: (0..rng.gen_range(0, 4)) + children: (0..1) .map(|_| { ( rng.gen_range(-5, len + 5).clamped(0, len.max(1) - 1), @@ -45,36 +45,71 @@ impl Archetype for Keep { #[allow(clippy::if_same_then_else)] // TODO: Pending review in #587 fn draw( &self, + pos: Vec3, dist: i32, bound_offset: Vec2, _center_offset: Vec2, z: i32, - _ori: Ori, + ori: Ori, branch: &Branch, ) -> BlockMask { let profile = Vec2::new(bound_offset.x, z); + let weak_layer = 1; + let normal_layer = weak_layer + 1; + let important_layer = normal_layer + 1; + let internal_layer = important_layer + 1; + let make_block = - |r, g, b| BlockMask::new(Block::new(BlockKind::Normal, Rgb::new(r, g, b)), 2); + |r, g, b| BlockMask::new(Block::new(BlockKind::Normal, Rgb::new(r, g, b)), normal_layer); let foundation = make_block(100, 100, 100); - let wall = make_block(75, 100, 125); - let roof = make_block(150, 120, 50); - let empty = BlockMask::new(Block::empty(), 2); + let wall = make_block(100, 100, 110); + let floor = make_block(120, 80, 50).with_priority(important_layer); + let internal = BlockMask::new(Block::empty(), internal_layer); + let empty = BlockMask::nothing(); let width = branch.locus; - let rampart_width = 5 + branch.locus; - let ceil_height = 16; + let rampart_width = 2 + branch.locus; + let ceil_height = 12; + let door_height = 6; + let edge_pos = if (bound_offset.x == rampart_width) ^ (ori == Ori::East) { + pos.y + } else { + pos.x + }; + let rampart_height = ceil_height + if edge_pos % 2 == 0 { 3 } else { 4 }; + let min_dist = bound_offset.reduce_max(); - if profile.y <= 1 - (dist - width - 1).max(0) && dist < width + 3 { + if profile.y <= 0 - (min_dist - width - 1).max(0) && min_dist < width + 3 { // Foundations foundation - } else if profile.y == ceil_height && dist < rampart_width { - roof - } else if dist == rampart_width && profile.y >= ceil_height && profile.y < ceil_height + 4 { + } else if profile.y == ceil_height && min_dist < rampart_width { + if min_dist < width { + floor + } else { + wall + } + } else if bound_offset.x.abs() == 4 && min_dist == width + 1 && profile.y < ceil_height { wall - } else if dist == width && profile.y <= ceil_height { + } else if bound_offset.x.abs() < 3 && profile.y < door_height - bound_offset.x.abs() && profile.y > 0 { + internal + } else if min_dist == width && profile.y <= ceil_height { wall + } else if profile.y >= ceil_height { + if profile.y > ceil_height && min_dist < rampart_width { + internal + } else if min_dist == rampart_width { + if profile.y < rampart_height { + wall + } else { + internal + } + } else { + empty + } + } else if profile.y < ceil_height && min_dist < width { + internal } else { empty } diff --git a/world/src/site/settlement/building/archetype/mod.rs b/world/src/site/settlement/building/archetype/mod.rs index 89ca5dca24..6da93ab50d 100644 --- a/world/src/site/settlement/building/archetype/mod.rs +++ b/world/src/site/settlement/building/archetype/mod.rs @@ -14,6 +14,7 @@ pub trait Archetype { Self: Sized; fn draw( &self, + pos: Vec3, dist: i32, bound_offset: Vec2, center_offset: Vec2, diff --git a/world/src/site/settlement/building/mod.rs b/world/src/site/settlement/building/mod.rs index 7687bd4bf9..6c578e94e6 100644 --- a/world/src/site/settlement/building/mod.rs +++ b/world/src/site/settlement/building/mod.rs @@ -10,6 +10,8 @@ use rand::prelude::*; use vek::*; pub type HouseBuilding = Building; +pub type KeepBuilding = Building; + pub struct Building { skel: Skeleton, @@ -50,10 +52,10 @@ impl Building { let rpos = pos - self.origin; self.skel .sample_closest( - rpos.into(), - |dist, bound_offset, center_offset, ori, branch| { + rpos, + |pos, dist, bound_offset, center_offset, ori, branch| { self.archetype - .draw(dist, bound_offset, center_offset, rpos.z, ori, branch) + .draw(pos, dist, bound_offset, center_offset, rpos.z, ori, branch) }, ) .finish() diff --git a/world/src/site/settlement/building/skeleton.rs b/world/src/site/settlement/building/skeleton.rs index 2014810b8f..01827a958d 100644 --- a/world/src/site/settlement/building/skeleton.rs +++ b/world/src/site/settlement/building/skeleton.rs @@ -76,8 +76,8 @@ impl Skeleton { #[allow(clippy::or_fun_call)] // TODO: Pending review in #587 pub fn sample_closest( &self, - pos: Vec2, - mut f: impl FnMut(i32, Vec2, Vec2, Ori, &Branch) -> BlockMask, + pos: Vec3, + mut f: impl FnMut(Vec3, i32, Vec2, Vec2, Ori, &Branch) -> BlockMask, ) -> BlockMask { let mut min = None::<(_, BlockMask)>; self.for_each(|node, ori, branch, is_child, parent_locus| { @@ -117,7 +117,7 @@ impl Skeleton { } || true { - let new_bm = f(dist, bound_offset, center_offset, ori, branch); + let new_bm = f(pos, dist, bound_offset, center_offset, ori, branch); min = min .map(|(_, bm)| (dist_locus, bm.resolve_with(new_bm))) .or(Some((dist_locus, new_bm))); diff --git a/world/src/site/settlement/mod.rs b/world/src/site/settlement/mod.rs index 7571df7aab..5fd57221e2 100644 --- a/world/src/site/settlement/mod.rs +++ b/world/src/site/settlement/mod.rs @@ -1,6 +1,6 @@ mod building; -use self::building::HouseBuilding; +use self::building::{HouseBuilding, KeepBuilding}; use super::SpawnRules; use crate::{ column::ColumnSample, @@ -83,6 +83,8 @@ fn to_tile(e: i32) -> i32 { ((e as f32).div_euclid(AREA_SIZE as f32)).floor() as pub enum StructureKind { House(HouseBuilding), + Keep(KeepBuilding), + } pub struct Structure { @@ -93,6 +95,24 @@ impl Structure { pub fn bounds_2d(&self) -> Aabr { match &self.kind { StructureKind::House(house) => house.bounds_2d(), + StructureKind::Keep(keep) => keep.bounds_2d(), + + } + } + + pub fn bounds(&self) -> Aabb { + match &self.kind { + StructureKind::House(house) => house.bounds(), + StructureKind::Keep(keep) => keep.bounds(), + + } + } + + pub fn sample(&self, rpos: Vec3) -> Option { + match &self.kind { + StructureKind::House(house) => house.sample(rpos), + StructureKind::Keep(keep) => keep.sample(rpos), + } } } @@ -326,9 +346,10 @@ impl Settlement { return; }; - for tile in Spiral2d::new() + for (i, tile) in Spiral2d::new() .map(|offs| town_center + offs) .take(16usize.pow(2)) + .enumerate() { // This is a stupid way to decide how to place buildings for _ in 0..ctx.rng.gen_range(2, 5) { @@ -356,17 +377,31 @@ impl Settlement { } let structure = Structure { - kind: StructureKind::House(HouseBuilding::generate( - ctx.rng, - Vec3::new( - house_pos.x, - house_pos.y, - ctx.sim - .and_then(|sim| sim.get_alt_approx(self.origin + house_pos)) - .unwrap_or(0.0) - .ceil() as i32, - ), - )), + kind: if i == 0 { + StructureKind::Keep(KeepBuilding::generate( + ctx.rng, + Vec3::new( + house_pos.x, + house_pos.y, + ctx.sim + .and_then(|sim| sim.get_alt_approx(self.origin + house_pos)) + .unwrap_or(0.0) + .ceil() as i32, + ), + )) + } else { + StructureKind::House(HouseBuilding::generate( + ctx.rng, + Vec3::new( + house_pos.x, + house_pos.y, + ctx.sim + .and_then(|sim| sim.get_alt_approx(self.origin + house_pos)) + .unwrap_or(0.0) + .ceil() as i32, + ), + )) + }, }; let bounds = structure.bounds_2d(); @@ -728,33 +763,26 @@ impl Settlement { continue; } - match &structure.kind { - StructureKind::House(b) => { - let bounds = b.bounds(); + let bounds = structure.bounds(); - for x in bounds.min.x..bounds.max.x + 1 { - for y in bounds.min.y..bounds.max.y + 1 { - let col = if let Some(col) = - get_column(self.origin + Vec2::new(x, y) - wpos2d) - { - col - } else { - continue; - }; + for x in bounds.min.x..bounds.max.x + 1 { + for y in bounds.min.y..bounds.max.y + 1 { + let col = if let Some(col) = get_column(self.origin + Vec2::new(x, y) - wpos2d) { + col + } else { + continue; + }; - for z in bounds.min.z.min(col.alt.floor() as i32 - 1)..bounds.max.z + 1 - { - let rpos = Vec3::new(x, y, z); - let wpos = Vec3::from(self.origin) + rpos; - let coffs = wpos - Vec3::from(wpos2d); + for z in bounds.min.z.min(col.alt.floor() as i32 - 1)..bounds.max.z + 1 { + let rpos = Vec3::new(x, y, z); + let wpos = Vec3::from(self.origin) + rpos; + let coffs = wpos - Vec3::from(wpos2d); - if let Some(block) = b.sample(rpos) { - let _ = vol.set(coffs, block); - } - } + if let Some(block) = structure.sample(rpos) { + let _ = vol.set(coffs, block); } } - }, + } } } }