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:
@ -89,17 +89,15 @@ impl Civs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place sites in world
|
// Flatten ground around sites
|
||||||
for site in this.sites.iter() {
|
for site in this.sites.iter() {
|
||||||
let radius = 48i32;
|
let radius = 48i32;
|
||||||
|
|
||||||
let wpos = site.center * Vec2::from(TerrainChunkSize::RECT_SIZE).map(|e: u32| e as i32);
|
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
|
// Flatten ground
|
||||||
let flatten_radius = 12.0;
|
let flatten_radius = 12.0;
|
||||||
if let Some(center_alt) = ctx.sim.get_alt_approx(wpos) {
|
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;
|
let factor = (1.0 - (site.center - pos).map(|e| e as f32).magnitude() / flatten_radius) * 1.15;
|
||||||
ctx.sim
|
ctx.sim
|
||||||
.get_mut(pos)
|
.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));
|
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
|
ctx.sim
|
||||||
.get_mut(pos)
|
.get_mut(pos)
|
||||||
.map(|chunk| chunk.sites.push(settlement.clone()));
|
.map(|chunk| chunk.sites.push(settlement.clone()));
|
||||||
|
@ -13,26 +13,70 @@ use super::{
|
|||||||
pub struct House {
|
pub struct House {
|
||||||
roof_color: Rgb<u8>,
|
roof_color: Rgb<u8>,
|
||||||
noise: RandomField,
|
noise: RandomField,
|
||||||
roof_ribbing: bool,
|
|
||||||
central_supports: bool,
|
|
||||||
chimney: Option<i32>,
|
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 {
|
impl Archetype for House {
|
||||||
type Attr = ();
|
type Attr = Attr;
|
||||||
|
|
||||||
fn generate<R: Rng>(rng: &mut R) -> Self {
|
fn generate<R: Rng>(rng: &mut R) -> (Self, Skeleton<Self::Attr>) {
|
||||||
Self {
|
let this = Self {
|
||||||
roof_color: Rgb::new(
|
roof_color: Rgb::new(
|
||||||
rng.gen_range(50, 200),
|
rng.gen_range(50, 200),
|
||||||
rng.gen_range(50, 200),
|
rng.gen_range(50, 200),
|
||||||
rng.gen_range(50, 200),
|
rng.gen_range(50, 200),
|
||||||
),
|
),
|
||||||
noise: RandomField::new(rng.gen()),
|
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 },
|
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(
|
fn draw(
|
||||||
@ -59,7 +103,9 @@ impl Archetype for House {
|
|||||||
let fire = Some(Some(Block::new(BlockKind::Ember, Rgb::white())));
|
let fire = Some(Some(Block::new(BlockKind::Ember, Rgb::white())));
|
||||||
|
|
||||||
let ceil_height = 6;
|
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 foundation_height = 0 - (dist - width - 1).max(0);
|
||||||
let roof_height = 8 + width;
|
let roof_height = 8 + width;
|
||||||
|
|
||||||
@ -67,7 +113,7 @@ impl Archetype for House {
|
|||||||
// Chimney shaft
|
// Chimney shaft
|
||||||
if center_offset.map(|e| e.abs()).reduce_max() == 0 && profile.y >= foundation_height + 1 {
|
if center_offset.map(|e| e.abs()).reduce_max() == 0 && profile.y >= foundation_height + 1 {
|
||||||
return if profile.y == foundation_height + 1 {
|
return if profile.y == foundation_height + 1 {
|
||||||
empty//fire
|
fire
|
||||||
} else {
|
} else {
|
||||||
empty
|
empty
|
||||||
};
|
};
|
||||||
@ -85,36 +131,55 @@ impl Archetype for House {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if profile.y <= foundation_height && dist < width + 3 { // Foundations
|
if profile.y <= foundation_height && dist < width + 3 { // Foundations
|
||||||
|
if branch.attr.lower_walls {
|
||||||
if dist == width - 1 { // Floor lining
|
if dist == width - 1 { // Floor lining
|
||||||
return log;
|
return log;
|
||||||
} else if dist < width - 1 && profile.y == foundation_height { // Floor
|
} else if dist < width - 1 && profile.y == foundation_height { // Floor
|
||||||
return floor;
|
return floor;
|
||||||
} else if dist < width && profile.y >= foundation_height - 3 { // Basement
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if dist < width && profile.y < foundation_height && profile.y >= foundation_height - 3 { // Basement
|
||||||
return empty;
|
return empty;
|
||||||
} else {
|
} else {
|
||||||
return foundation;
|
return foundation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let do_roof = |profile: Vec2<i32>, dist, roof_height, roof_width| {
|
||||||
if profile.y > roof_height - profile.x { // Air above roof
|
if profile.y > roof_height - profile.x { // Air above roof
|
||||||
return Some(None);
|
return Some(Some(None));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Roof
|
// Roof
|
||||||
if profile.y == roof_height - profile.x
|
if profile.y == roof_height - profile.x
|
||||||
&& profile.y >= ceil_height
|
&& dist <= roof_width
|
||||||
&& dist <= width + 2
|
|
||||||
{
|
{
|
||||||
let is_ribbing = (roof_height - profile.y) % 3 == 0 && self.roof_ribbing;
|
let is_ribbing = (roof_height - profile.y) % 3 == 0 && self.roof_ribbing;
|
||||||
if profile.x == 0 || dist == width + 2 || is_ribbing { // Eaves
|
if profile.x == 0 || dist == roof_width|| is_ribbing { // Eaves
|
||||||
return log;
|
return Some(log);
|
||||||
} else {
|
} else {
|
||||||
return roof;
|
return Some(roof);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(block) = do_roof(profile, dist, roof_height, width + 2) {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
// Walls
|
// 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 {
|
let frame_bounds = if profile.y >= ceil_height {
|
||||||
Aabr {
|
Aabr {
|
||||||
min: Vec2::new(-1, ceil_height + 2),
|
min: Vec2::new(-1, ceil_height + 2),
|
||||||
@ -142,15 +207,7 @@ impl Archetype for House {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wall
|
// Wall
|
||||||
return if
|
return wall;
|
||||||
bound_offset.x == bound_offset.y ||
|
|
||||||
(profile.x == 0 && self.central_supports) ||
|
|
||||||
profile.y == ceil_height
|
|
||||||
{ // Support beams
|
|
||||||
log
|
|
||||||
} else {
|
|
||||||
wall
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if dist < width { // Internals
|
if dist < width { // Internals
|
||||||
|
@ -14,8 +14,27 @@ pub struct Keep;
|
|||||||
impl Archetype for Keep {
|
impl Archetype for Keep {
|
||||||
type Attr = ();
|
type Attr = ();
|
||||||
|
|
||||||
fn generate<R: Rng>(rng: &mut R) -> Self {
|
fn generate<R: Rng>(rng: &mut R) -> (Self, Skeleton<Self::Attr>) {
|
||||||
Self
|
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(
|
fn draw(
|
||||||
|
@ -7,9 +7,9 @@ use common::terrain::Block;
|
|||||||
use super::skeleton::*;
|
use super::skeleton::*;
|
||||||
|
|
||||||
pub trait Archetype {
|
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(
|
fn draw(
|
||||||
&self,
|
&self,
|
||||||
dist: i32,
|
dist: i32,
|
||||||
|
@ -22,25 +22,9 @@ impl<A: Archetype> Building<A> {
|
|||||||
where A: Sized
|
where A: Sized
|
||||||
{
|
{
|
||||||
let len = rng.gen_range(-8, 12).max(0);
|
let len = rng.gen_range(-8, 12).max(0);
|
||||||
let archetype = A::generate(rng);
|
let (archetype, skel) = A::generate(rng);
|
||||||
Self {
|
Self {
|
||||||
skel: Skeleton {
|
skel,
|
||||||
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(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
archetype,
|
archetype,
|
||||||
origin,
|
origin,
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ impl<T> Skeleton<T> {
|
|||||||
bounds
|
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;
|
let mut min = None;
|
||||||
self.for_each(|node, ori, branch| {
|
self.for_each(|node, ori, branch| {
|
||||||
let node2 = node + ori.dir() * branch.len;
|
let node2 = node + ori.dir() * branch.len;
|
||||||
@ -87,7 +87,7 @@ impl<T> Skeleton<T> {
|
|||||||
let dist = bound_offset.reduce_max();
|
let dist = bound_offset.reduce_max();
|
||||||
let dist_locus = dist - branch.locus;
|
let dist_locus = dist - branch.locus;
|
||||||
if min.as_ref().map(|(min_dist_locus, _)| dist_locus < *min_dist_locus).unwrap_or(true) {
|
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)
|
min.map(|(_, r)| r)
|
||||||
|
@ -376,8 +376,8 @@ impl Settlement {
|
|||||||
.find_tile_near(Vec2::zero(), |plot| plot.is_none())
|
.find_tile_near(Vec2::zero(), |plot| plot.is_none())
|
||||||
{
|
{
|
||||||
// Farm
|
// Farm
|
||||||
let farmhouse = self.land.new_plot(Plot::Dirt);
|
//let farmhouse = self.land.new_plot(Plot::Dirt);
|
||||||
self.land.set(base_tile, farmhouse);
|
//self.land.set(base_tile, farmhouse);
|
||||||
|
|
||||||
// Farmhouses
|
// Farmhouses
|
||||||
// for _ in 0..ctx.rng.gen_range(1, 3) {
|
// for _ in 0..ctx.rng.gen_range(1, 3) {
|
||||||
|
Reference in New Issue
Block a user