mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added house overhangs, better per-wing generation options
This commit is contained in:
parent
a754b34105
commit
c1945a1445
@ -89,17 +89,15 @@ impl Civs {
|
||||
}
|
||||
}
|
||||
|
||||
// Place sites in world
|
||||
// Flatten ground around sites
|
||||
for site in this.sites.iter() {
|
||||
let radius = 48i32;
|
||||
|
||||
let wpos = site.center * Vec2::from(TerrainChunkSize::RECT_SIZE).map(|e: u32| e as i32);
|
||||
let nearby_chunks = Spiral2d::new().map(|offs| site.center + offs).take(radius.pow(2) as usize);
|
||||
|
||||
// Flatten ground
|
||||
let flatten_radius = 12.0;
|
||||
if let Some(center_alt) = ctx.sim.get_alt_approx(wpos) {
|
||||
for pos in nearby_chunks.clone() {
|
||||
for pos in Spiral2d::new().map(|offs| site.center + offs).take(radius.pow(2) as usize) {
|
||||
let factor = (1.0 - (site.center - pos).map(|e| e as f32).magnitude() / flatten_radius) * 1.15;
|
||||
ctx.sim
|
||||
.get_mut(pos)
|
||||
@ -113,10 +111,16 @@ impl Civs {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Place sites in world
|
||||
for site in this.sites.iter() {
|
||||
let radius = 48i32;
|
||||
let wpos = site.center * Vec2::from(TerrainChunkSize::RECT_SIZE).map(|e: u32| e as i32);
|
||||
|
||||
let settlement = WorldSite::from(Settlement::generate(wpos, Some(ctx.sim), ctx.rng));
|
||||
|
||||
for pos in nearby_chunks {
|
||||
for pos in Spiral2d::new().map(|offs| site.center + offs).take(radius.pow(2) as usize) {
|
||||
ctx.sim
|
||||
.get_mut(pos)
|
||||
.map(|chunk| chunk.sites.push(settlement.clone()));
|
||||
|
@ -13,26 +13,70 @@ use super::{
|
||||
pub struct House {
|
||||
roof_color: Rgb<u8>,
|
||||
noise: RandomField,
|
||||
roof_ribbing: bool,
|
||||
central_supports: bool,
|
||||
chimney: Option<i32>,
|
||||
roof_ribbing: bool,
|
||||
}
|
||||
|
||||
pub struct Attr {
|
||||
central_supports: bool,
|
||||
lower_walls: bool,
|
||||
}
|
||||
|
||||
impl Attr {
|
||||
fn generate<R: Rng>(rng: &mut R) -> Self {
|
||||
Self {
|
||||
central_supports: rng.gen(),
|
||||
lower_walls: rng.gen(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Archetype for House {
|
||||
type Attr = ();
|
||||
type Attr = Attr;
|
||||
|
||||
fn generate<R: Rng>(rng: &mut R) -> Self {
|
||||
Self {
|
||||
fn generate<R: Rng>(rng: &mut R) -> (Self, Skeleton<Self::Attr>) {
|
||||
let this = Self {
|
||||
roof_color: Rgb::new(
|
||||
rng.gen_range(50, 200),
|
||||
rng.gen_range(50, 200),
|
||||
rng.gen_range(50, 200),
|
||||
),
|
||||
noise: RandomField::new(rng.gen()),
|
||||
roof_ribbing: rng.gen(),
|
||||
central_supports: rng.gen(),
|
||||
chimney: if rng.gen() { Some(rng.gen_range(1, 6)) } else { None },
|
||||
}
|
||||
roof_ribbing: rng.gen(),
|
||||
};
|
||||
|
||||
let len = rng.gen_range(-8, 20).clamped(0, 16);
|
||||
let branches_per_side = 1 + len as usize / 16;
|
||||
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: Attr {
|
||||
central_supports: rng.gen(),
|
||||
lower_walls: true,
|
||||
},
|
||||
locus: 8 + rng.gen_range(0, 5),
|
||||
children: [1, -1]
|
||||
.iter()
|
||||
.map(|flip| (0..branches_per_side).map(move |i| (i, *flip)))
|
||||
.flatten()
|
||||
.filter_map(move |(i, flip)| if rng.gen() {
|
||||
Some((i as i32 * len / (branches_per_side - 1).max(1) as i32, Branch {
|
||||
len: rng.gen_range(0, 12) * flip,
|
||||
attr: Attr::generate(rng),
|
||||
locus: 8 + rng.gen_range(0, 3),
|
||||
children: Vec::new(),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
};
|
||||
|
||||
(this, skel)
|
||||
}
|
||||
|
||||
fn draw(
|
||||
@ -59,7 +103,9 @@ impl Archetype for House {
|
||||
let fire = Some(Some(Block::new(BlockKind::Ember, Rgb::white())));
|
||||
|
||||
let ceil_height = 6;
|
||||
let width = -3 + branch.locus + if profile.y >= ceil_height { 1 } else { 0 };
|
||||
let lower_width = -3 + branch.locus;
|
||||
let upper_width = -2 + branch.locus;
|
||||
let width = if profile.y >= ceil_height { upper_width } else { lower_width };
|
||||
let foundation_height = 0 - (dist - width - 1).max(0);
|
||||
let roof_height = 8 + width;
|
||||
|
||||
@ -67,7 +113,7 @@ impl Archetype for House {
|
||||
// Chimney shaft
|
||||
if center_offset.map(|e| e.abs()).reduce_max() == 0 && profile.y >= foundation_height + 1 {
|
||||
return if profile.y == foundation_height + 1 {
|
||||
empty//fire
|
||||
fire
|
||||
} else {
|
||||
empty
|
||||
};
|
||||
@ -85,36 +131,55 @@ impl Archetype for House {
|
||||
}
|
||||
|
||||
if profile.y <= foundation_height && dist < width + 3 { // Foundations
|
||||
if dist == width - 1 { // Floor lining
|
||||
return log;
|
||||
} else if dist < width - 1 && profile.y == foundation_height { // Floor
|
||||
return floor;
|
||||
} else if dist < width && profile.y >= foundation_height - 3 { // Basement
|
||||
if branch.attr.lower_walls {
|
||||
if dist == width - 1 { // Floor lining
|
||||
return log;
|
||||
} else if dist < width - 1 && profile.y == foundation_height { // Floor
|
||||
return floor;
|
||||
}
|
||||
}
|
||||
|
||||
if dist < width && profile.y < foundation_height && profile.y >= foundation_height - 3 { // Basement
|
||||
return empty;
|
||||
} else {
|
||||
return foundation;
|
||||
}
|
||||
}
|
||||
|
||||
if profile.y > roof_height - profile.x { // Air above roof
|
||||
return Some(None);
|
||||
}
|
||||
|
||||
// Roof
|
||||
if profile.y == roof_height - profile.x
|
||||
&& profile.y >= ceil_height
|
||||
&& dist <= width + 2
|
||||
{
|
||||
let is_ribbing = (roof_height - profile.y) % 3 == 0 && self.roof_ribbing;
|
||||
if profile.x == 0 || dist == width + 2 || is_ribbing { // Eaves
|
||||
return log;
|
||||
} else {
|
||||
return roof;
|
||||
let do_roof = |profile: Vec2<i32>, dist, roof_height, roof_width| {
|
||||
if profile.y > roof_height - profile.x { // Air above roof
|
||||
return Some(Some(None));
|
||||
}
|
||||
|
||||
// Roof
|
||||
if profile.y == roof_height - profile.x
|
||||
&& dist <= roof_width
|
||||
{
|
||||
let is_ribbing = (roof_height - profile.y) % 3 == 0 && self.roof_ribbing;
|
||||
if profile.x == 0 || dist == roof_width|| is_ribbing { // Eaves
|
||||
return Some(log);
|
||||
} else {
|
||||
return Some(roof);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(block) = do_roof(profile, dist, roof_height, width + 2) {
|
||||
return block;
|
||||
}
|
||||
|
||||
// Walls
|
||||
if dist == width {
|
||||
if dist == width && (
|
||||
bound_offset.x == bound_offset.y ||
|
||||
(profile.x == 0 && branch.attr.central_supports) ||
|
||||
profile.y == ceil_height
|
||||
) { // Support beams
|
||||
return log;
|
||||
} else if !branch.attr.lower_walls && profile.y < ceil_height {
|
||||
return None;
|
||||
} else if dist == width {
|
||||
let frame_bounds = if profile.y >= ceil_height {
|
||||
Aabr {
|
||||
min: Vec2::new(-1, ceil_height + 2),
|
||||
@ -142,15 +207,7 @@ impl Archetype for House {
|
||||
}
|
||||
|
||||
// Wall
|
||||
return if
|
||||
bound_offset.x == bound_offset.y ||
|
||||
(profile.x == 0 && self.central_supports) ||
|
||||
profile.y == ceil_height
|
||||
{ // Support beams
|
||||
log
|
||||
} else {
|
||||
wall
|
||||
};
|
||||
return wall;
|
||||
}
|
||||
|
||||
if dist < width { // Internals
|
||||
|
@ -14,8 +14,27 @@ pub struct Keep;
|
||||
impl Archetype for Keep {
|
||||
type Attr = ();
|
||||
|
||||
fn generate<R: Rng>(rng: &mut R) -> Self {
|
||||
Self
|
||||
fn generate<R: Rng>(rng: &mut R) -> (Self, Skeleton<Self::Attr>) {
|
||||
let len = rng.gen_range(-8, 12).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: 8 + rng.gen_range(0, 5),
|
||||
children: (0..rng.gen_range(0, 4))
|
||||
.map(|_| (rng.gen_range(-5, len + 5).clamped(0, len.max(1) - 1), Branch {
|
||||
len: rng.gen_range(5, 12) * if rng.gen() { 1 } else { -1 },
|
||||
attr: Self::Attr::default(),
|
||||
locus: 8 + rng.gen_range(0, 3),
|
||||
children: Vec::new(),
|
||||
}))
|
||||
.collect(),
|
||||
},
|
||||
};
|
||||
|
||||
(Self, skel)
|
||||
}
|
||||
|
||||
fn draw(
|
||||
|
@ -7,9 +7,9 @@ use common::terrain::Block;
|
||||
use super::skeleton::*;
|
||||
|
||||
pub trait Archetype {
|
||||
type Attr: Default;
|
||||
type Attr;
|
||||
|
||||
fn generate<R: Rng>(rng: &mut R) -> Self where Self: Sized;
|
||||
fn generate<R: Rng>(rng: &mut R) -> (Self, Skeleton<Self::Attr>) where Self: Sized;
|
||||
fn draw(
|
||||
&self,
|
||||
dist: i32,
|
||||
|
@ -22,25 +22,9 @@ impl<A: Archetype> Building<A> {
|
||||
where A: Sized
|
||||
{
|
||||
let len = rng.gen_range(-8, 12).max(0);
|
||||
let archetype = A::generate(rng);
|
||||
let (archetype, skel) = A::generate(rng);
|
||||
Self {
|
||||
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: A::Attr::default(),
|
||||
locus: 8 + rng.gen_range(0, 5),
|
||||
children: (0..rng.gen_range(0, 4))
|
||||
.map(|_| (rng.gen_range(-5, len + 5).clamped(0, len.max(1) - 1), Branch {
|
||||
len: rng.gen_range(5, 12) * if rng.gen() { 1 } else { -1 },
|
||||
attr: A::Attr::default(),
|
||||
locus: 8 + rng.gen_range(0, 3),
|
||||
children: Vec::new(),
|
||||
}))
|
||||
.collect(),
|
||||
},
|
||||
},
|
||||
skel,
|
||||
archetype,
|
||||
origin,
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ impl<T> Skeleton<T> {
|
||||
bounds
|
||||
}
|
||||
|
||||
pub fn closest<R>(&self, pos: Vec2<i32>, mut f: impl FnMut(i32, Vec2<i32>, Vec2<i32>, &Branch<T>) -> Option<R>) -> Option<R> {
|
||||
pub fn closest<R: Clone>(&self, pos: Vec2<i32>, mut f: impl FnMut(i32, Vec2<i32>, Vec2<i32>, &Branch<T>) -> Option<R>) -> Option<R> {
|
||||
let mut min = None;
|
||||
self.for_each(|node, ori, branch| {
|
||||
let node2 = node + ori.dir() * branch.len;
|
||||
@ -87,7 +87,7 @@ impl<T> Skeleton<T> {
|
||||
let dist = bound_offset.reduce_max();
|
||||
let dist_locus = dist - branch.locus;
|
||||
if min.as_ref().map(|(min_dist_locus, _)| dist_locus < *min_dist_locus).unwrap_or(true) {
|
||||
min = f(dist, bound_offset, center_offset, branch).map(|r| (dist_locus, r));
|
||||
min = f(dist, bound_offset, center_offset, branch).map(|r| (dist_locus, r)).or(min.clone());
|
||||
}
|
||||
});
|
||||
min.map(|(_, r)| r)
|
||||
|
@ -376,8 +376,8 @@ impl Settlement {
|
||||
.find_tile_near(Vec2::zero(), |plot| plot.is_none())
|
||||
{
|
||||
// Farm
|
||||
let farmhouse = self.land.new_plot(Plot::Dirt);
|
||||
self.land.set(base_tile, farmhouse);
|
||||
//let farmhouse = self.land.new_plot(Plot::Dirt);
|
||||
//self.land.set(base_tile, farmhouse);
|
||||
|
||||
// Farmhouses
|
||||
// for _ in 0..ctx.rng.gen_range(1, 3) {
|
||||
|
Loading…
Reference in New Issue
Block a user