Added simple keeps

This commit is contained in:
Joshua Barretto 2020-06-14 14:03:48 +01:00
parent eea64f78ff
commit ae8195fac9
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
fn draw(
&self,
pos: Vec3<i32>,
dist: i32,
bound_offset: Vec2<i32>,
center_offset: Vec2<i32>,

View File

@ -13,16 +13,16 @@ impl Archetype for Keep {
type 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 {
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<i32>,
dist: i32,
bound_offset: Vec2<i32>,
_center_offset: Vec2<i32>,
z: i32,
_ori: Ori,
ori: Ori,
branch: &Branch<Self::Attr>,
) -> 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
}

View File

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

View File

@ -10,6 +10,8 @@ use rand::prelude::*;
use vek::*;
pub type HouseBuilding = Building<archetype::house::House>;
pub type KeepBuilding = Building<archetype::keep::Keep>;
pub struct Building<A: Archetype> {
skel: Skeleton<A::Attr>,
@ -50,10 +52,10 @@ impl<A: Archetype> Building<A> {
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()

View File

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

View File

@ -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<i32> {
match &self.kind {
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;
};
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);
}
}
},
}
}
}
}