Added simple keeps

This commit is contained in:
Joshua Barretto 2020-06-14 14:03:48 +01:00
parent d936828c34
commit ecff9d6f46
6 changed files with 123 additions and 56 deletions

View File

@ -165,6 +165,7 @@ impl Archetype for House {
#[allow(clippy::int_plus_one)] // TODO: Pending review in #587 #[allow(clippy::int_plus_one)] // TODO: Pending review in #587
fn draw( fn draw(
&self, &self,
pos: Vec3<i32>,
dist: i32, dist: i32,
bound_offset: Vec2<i32>, bound_offset: Vec2<i32>,
center_offset: Vec2<i32>, center_offset: Vec2<i32>,

View File

@ -13,16 +13,16 @@ impl Archetype for Keep {
type Attr = (); type Attr = ();
fn generate<R: Rng>(rng: &mut R) -> (Self, Skeleton<Self::Attr>) { fn generate<R: Rng>(rng: &mut R) -> (Self, Skeleton<Self::Attr>) {
let len = rng.gen_range(-8, 12).max(0); let len = rng.gen_range(-8, 20).max(0);
let skel = Skeleton { let skel = Skeleton {
offset: -rng.gen_range(0, len + 7).clamped(0, len), offset: -rng.gen_range(0, len + 7).clamped(0, len),
ori: if rng.gen() { Ori::East } else { Ori::North }, ori: if rng.gen() { Ori::East } else { Ori::North },
root: Branch { root: Branch {
len, len,
attr: Self::Attr::default(), attr: Self::Attr::default(),
locus: 5 + rng.gen_range(0, 5), locus: 6 + rng.gen_range(0, 5),
border: 3, border: 3,
children: (0..rng.gen_range(0, 4)) children: (0..1)
.map(|_| { .map(|_| {
( (
rng.gen_range(-5, len + 5).clamped(0, len.max(1) - 1), 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 #[allow(clippy::if_same_then_else)] // TODO: Pending review in #587
fn draw( fn draw(
&self, &self,
pos: Vec3<i32>,
dist: i32, dist: i32,
bound_offset: Vec2<i32>, bound_offset: Vec2<i32>,
_center_offset: Vec2<i32>, _center_offset: Vec2<i32>,
z: i32, z: i32,
_ori: Ori, ori: Ori,
branch: &Branch<Self::Attr>, branch: &Branch<Self::Attr>,
) -> BlockMask { ) -> BlockMask {
let profile = Vec2::new(bound_offset.x, z); 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 = 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 foundation = make_block(100, 100, 100);
let wall = make_block(75, 100, 125); let wall = make_block(100, 100, 110);
let roof = make_block(150, 120, 50); let floor = make_block(120, 80, 50).with_priority(important_layer);
let empty = BlockMask::new(Block::empty(), 2); let internal = BlockMask::new(Block::empty(), internal_layer);
let empty = BlockMask::nothing();
let width = branch.locus; let width = branch.locus;
let rampart_width = 5 + branch.locus; let rampart_width = 2 + branch.locus;
let ceil_height = 16; 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 // Foundations
foundation foundation
} else if profile.y == ceil_height && dist < rampart_width { } else if profile.y == ceil_height && min_dist < rampart_width {
roof if min_dist < width {
} else if dist == rampart_width && profile.y >= ceil_height && profile.y < ceil_height + 4 { floor
} else {
wall
}
} else if bound_offset.x.abs() == 4 && min_dist == width + 1 && profile.y < ceil_height {
wall 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 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 { } else {
empty empty
} }

View File

@ -14,6 +14,7 @@ pub trait Archetype {
Self: Sized; Self: Sized;
fn draw( fn draw(
&self, &self,
pos: Vec3<i32>,
dist: i32, dist: i32,
bound_offset: Vec2<i32>, bound_offset: Vec2<i32>,
center_offset: Vec2<i32>, center_offset: Vec2<i32>,

View File

@ -10,6 +10,8 @@ use rand::prelude::*;
use vek::*; use vek::*;
pub type HouseBuilding = Building<archetype::house::House>; pub type HouseBuilding = Building<archetype::house::House>;
pub type KeepBuilding = Building<archetype::keep::Keep>;
pub struct Building<A: Archetype> { pub struct Building<A: Archetype> {
skel: Skeleton<A::Attr>, skel: Skeleton<A::Attr>,
@ -50,10 +52,10 @@ impl<A: Archetype> Building<A> {
let rpos = pos - self.origin; let rpos = pos - self.origin;
self.skel self.skel
.sample_closest( .sample_closest(
rpos.into(), rpos,
|dist, bound_offset, center_offset, ori, branch| { |pos, dist, bound_offset, center_offset, ori, branch| {
self.archetype self.archetype
.draw(dist, bound_offset, center_offset, rpos.z, ori, branch) .draw(pos, dist, bound_offset, center_offset, rpos.z, ori, branch)
}, },
) )
.finish() .finish()

View File

@ -76,8 +76,8 @@ impl<T> Skeleton<T> {
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587 #[allow(clippy::or_fun_call)] // TODO: Pending review in #587
pub fn sample_closest( pub fn sample_closest(
&self, &self,
pos: Vec2<i32>, pos: Vec3<i32>,
mut f: impl FnMut(i32, Vec2<i32>, Vec2<i32>, Ori, &Branch<T>) -> BlockMask, mut f: impl FnMut(Vec3<i32>, i32, Vec2<i32>, Vec2<i32>, Ori, &Branch<T>) -> BlockMask,
) -> BlockMask { ) -> BlockMask {
let mut min = None::<(_, BlockMask)>; let mut min = None::<(_, BlockMask)>;
self.for_each(|node, ori, branch, is_child, parent_locus| { self.for_each(|node, ori, branch, is_child, parent_locus| {
@ -117,7 +117,7 @@ impl<T> Skeleton<T> {
} }
|| true || 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 min = min
.map(|(_, bm)| (dist_locus, bm.resolve_with(new_bm))) .map(|(_, bm)| (dist_locus, bm.resolve_with(new_bm)))
.or(Some((dist_locus, new_bm))); .or(Some((dist_locus, new_bm)));

View File

@ -1,6 +1,6 @@
mod building; mod building;
use self::building::HouseBuilding; use self::building::{HouseBuilding, KeepBuilding};
use super::SpawnRules; use super::SpawnRules;
use crate::{ use crate::{
column::ColumnSample, 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 { pub enum StructureKind {
House(HouseBuilding), House(HouseBuilding),
Keep(KeepBuilding),
} }
pub struct Structure { pub struct Structure {
@ -93,6 +95,24 @@ impl Structure {
pub fn bounds_2d(&self) -> Aabr<i32> { pub fn bounds_2d(&self) -> Aabr<i32> {
match &self.kind { match &self.kind {
StructureKind::House(house) => house.bounds_2d(), StructureKind::House(house) => house.bounds_2d(),
StructureKind::Keep(keep) => keep.bounds_2d(),
}
}
pub fn bounds(&self) -> Aabb<i32> {
match &self.kind {
StructureKind::House(house) => house.bounds(),
StructureKind::Keep(keep) => keep.bounds(),
}
}
pub fn sample(&self, rpos: Vec3<i32>) -> Option<Block> {
match &self.kind {
StructureKind::House(house) => house.sample(rpos),
StructureKind::Keep(keep) => keep.sample(rpos),
} }
} }
} }
@ -326,9 +346,10 @@ impl Settlement {
return; return;
}; };
for tile in Spiral2d::new() for (i, tile) in Spiral2d::new()
.map(|offs| town_center + offs) .map(|offs| town_center + offs)
.take(16usize.pow(2)) .take(16usize.pow(2))
.enumerate()
{ {
// This is a stupid way to decide how to place buildings // This is a stupid way to decide how to place buildings
for _ in 0..ctx.rng.gen_range(2, 5) { for _ in 0..ctx.rng.gen_range(2, 5) {
@ -356,17 +377,31 @@ impl Settlement {
} }
let structure = Structure { let structure = Structure {
kind: StructureKind::House(HouseBuilding::generate( kind: if i == 0 {
ctx.rng, StructureKind::Keep(KeepBuilding::generate(
Vec3::new( ctx.rng,
house_pos.x, Vec3::new(
house_pos.y, house_pos.x,
ctx.sim house_pos.y,
.and_then(|sim| sim.get_alt_approx(self.origin + house_pos)) ctx.sim
.unwrap_or(0.0) .and_then(|sim| sim.get_alt_approx(self.origin + house_pos))
.ceil() as i32, .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(); let bounds = structure.bounds_2d();
@ -728,33 +763,26 @@ impl Settlement {
continue; continue;
} }
match &structure.kind { let bounds = structure.bounds();
StructureKind::House(b) => {
let bounds = b.bounds();
for x in bounds.min.x..bounds.max.x + 1 { for x in bounds.min.x..bounds.max.x + 1 {
for y in bounds.min.y..bounds.max.y + 1 { for y in bounds.min.y..bounds.max.y + 1 {
let col = if let Some(col) = let col = if let Some(col) = get_column(self.origin + Vec2::new(x, y) - wpos2d) {
get_column(self.origin + Vec2::new(x, y) - wpos2d) col
{ } else {
col continue;
} else { };
continue;
};
for z in bounds.min.z.min(col.alt.floor() as i32 - 1)..bounds.max.z + 1 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 rpos = Vec3::new(x, y, z); let wpos = Vec3::from(self.origin) + rpos;
let wpos = Vec3::from(self.origin) + rpos; let coffs = wpos - Vec3::from(wpos2d);
let coffs = wpos - Vec3::from(wpos2d);
if let Some(block) = b.sample(rpos) { if let Some(block) = structure.sample(rpos) {
let _ = vol.set(coffs, block); let _ = vol.set(coffs, block);
}
}
} }
} }
}, }
} }
} }
} }