mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added simple dungeon impl
This commit is contained in:
parent
568a8ab87c
commit
3ffc5a7d87
@ -19,7 +19,7 @@ use common::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
sim::{WorldSim, SimChunk},
|
sim::{WorldSim, SimChunk},
|
||||||
site::{Site as WorldSite, Settlement},
|
site::{Site as WorldSite, Settlement, Dungeon},
|
||||||
util::seed_expan,
|
util::seed_expan,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -76,6 +76,32 @@ impl Civs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _ in 0..256 {
|
||||||
|
attempt(5, || {
|
||||||
|
let loc = find_site_loc(&mut ctx, None)?;
|
||||||
|
this.establish_site(&mut ctx, loc, |place| Site {
|
||||||
|
kind: SiteKind::Dungeon,
|
||||||
|
center: loc,
|
||||||
|
place,
|
||||||
|
|
||||||
|
population: 0.0,
|
||||||
|
|
||||||
|
stocks: Stocks::from_default(100.0),
|
||||||
|
surplus: Stocks::from_default(0.0),
|
||||||
|
values: Stocks::from_default(None),
|
||||||
|
|
||||||
|
labors: MapVec::from_default(0.01),
|
||||||
|
yields: MapVec::from_default(1.0),
|
||||||
|
productivity: MapVec::from_default(1.0),
|
||||||
|
|
||||||
|
last_exports: Stocks::from_default(0.0),
|
||||||
|
export_targets: Stocks::from_default(0.0),
|
||||||
|
trade_states: Stocks::default(),
|
||||||
|
coin: 1000.0,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Tick
|
// Tick
|
||||||
const SIM_YEARS: usize = 1000;
|
const SIM_YEARS: usize = 1000;
|
||||||
for _ in 0..SIM_YEARS {
|
for _ in 0..SIM_YEARS {
|
||||||
@ -91,6 +117,10 @@ impl Civs {
|
|||||||
|
|
||||||
// Flatten ground around sites
|
// Flatten ground around sites
|
||||||
for site in this.sites.iter() {
|
for site in this.sites.iter() {
|
||||||
|
if let SiteKind::Settlement = &site.kind {} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@ -117,15 +147,18 @@ impl Civs {
|
|||||||
|
|
||||||
// Place sites in world
|
// Place sites in world
|
||||||
for site in this.sites.iter() {
|
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 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 world_site = match &site.kind {
|
||||||
|
SiteKind::Settlement => WorldSite::from(Settlement::generate(wpos, Some(ctx.sim), ctx.rng)),
|
||||||
|
SiteKind::Dungeon => WorldSite::from(Dungeon::generate(wpos, Some(ctx.sim), ctx.rng)),
|
||||||
|
};
|
||||||
|
|
||||||
for pos in Spiral2d::new().map(|offs| site.center + offs).take(radius.pow(2) as usize) {
|
let radius_chunks = (world_site.radius() / TerrainChunkSize::RECT_SIZE.x as f32).ceil() as usize;
|
||||||
|
for pos in Spiral2d::new().map(|offs| site.center + offs).take((radius_chunks * 2).pow(2)) {
|
||||||
ctx.sim
|
ctx.sim
|
||||||
.get_mut(pos)
|
.get_mut(pos)
|
||||||
.map(|chunk| chunk.sites.push(settlement.clone()));
|
.map(|chunk| chunk.sites.push(world_site.clone()));
|
||||||
}
|
}
|
||||||
println!("Placed site at {:?}", site.center);
|
println!("Placed site at {:?}", site.center);
|
||||||
}
|
}
|
||||||
@ -188,7 +221,26 @@ impl Civs {
|
|||||||
fn birth_civ(&mut self, ctx: &mut GenCtx<impl Rng>) -> Option<Id<Civ>> {
|
fn birth_civ(&mut self, ctx: &mut GenCtx<impl Rng>) -> Option<Id<Civ>> {
|
||||||
let site = attempt(5, || {
|
let site = attempt(5, || {
|
||||||
let loc = find_site_loc(ctx, None)?;
|
let loc = find_site_loc(ctx, None)?;
|
||||||
self.establish_site(ctx, loc)
|
self.establish_site(ctx, loc, |place| Site {
|
||||||
|
kind: SiteKind::Settlement,
|
||||||
|
center: loc,
|
||||||
|
place,
|
||||||
|
|
||||||
|
population: 24.0,
|
||||||
|
|
||||||
|
stocks: Stocks::from_default(100.0),
|
||||||
|
surplus: Stocks::from_default(0.0),
|
||||||
|
values: Stocks::from_default(None),
|
||||||
|
|
||||||
|
labors: MapVec::from_default(0.01),
|
||||||
|
yields: MapVec::from_default(1.0),
|
||||||
|
productivity: MapVec::from_default(1.0),
|
||||||
|
|
||||||
|
last_exports: Stocks::from_default(0.0),
|
||||||
|
export_targets: Stocks::from_default(0.0),
|
||||||
|
trade_states: Stocks::default(),
|
||||||
|
coin: 1000.0,
|
||||||
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let civ = self.civs.insert(Civ {
|
let civ = self.civs.insert(Civ {
|
||||||
@ -242,7 +294,7 @@ impl Civs {
|
|||||||
Some(place)
|
Some(place)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn establish_site(&mut self, ctx: &mut GenCtx<impl Rng>, loc: Vec2<i32>) -> Option<Id<Site>> {
|
fn establish_site(&mut self, ctx: &mut GenCtx<impl Rng>, loc: Vec2<i32>, site_fn: impl FnOnce(Id<Place>) -> Site) -> Option<Id<Site>> {
|
||||||
const SITE_AREA: Range<usize> = 64..256;
|
const SITE_AREA: Range<usize> = 64..256;
|
||||||
|
|
||||||
let place = match ctx.sim.get(loc).and_then(|site| site.place) {
|
let place = match ctx.sim.get(loc).and_then(|site| site.place) {
|
||||||
@ -250,26 +302,7 @@ impl Civs {
|
|||||||
None => self.establish_place(ctx, loc, SITE_AREA)?,
|
None => self.establish_place(ctx, loc, SITE_AREA)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let site = self.sites.insert(Site {
|
let site = self.sites.insert(site_fn(place));
|
||||||
kind: SiteKind::Settlement,
|
|
||||||
center: loc,
|
|
||||||
place: place,
|
|
||||||
|
|
||||||
population: 24.0,
|
|
||||||
|
|
||||||
stocks: Stocks::from_default(100.0),
|
|
||||||
surplus: Stocks::from_default(0.0),
|
|
||||||
values: Stocks::from_default(None),
|
|
||||||
|
|
||||||
labors: MapVec::from_default(0.01),
|
|
||||||
yields: MapVec::from_default(1.0),
|
|
||||||
productivity: MapVec::from_default(1.0),
|
|
||||||
|
|
||||||
last_exports: Stocks::from_default(0.0),
|
|
||||||
export_targets: Stocks::from_default(0.0),
|
|
||||||
trade_states: Stocks::default(),
|
|
||||||
coin: 1000.0,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Find neighbors
|
// Find neighbors
|
||||||
const MAX_NEIGHBOR_DISTANCE: f32 = 250.0;
|
const MAX_NEIGHBOR_DISTANCE: f32 = 250.0;
|
||||||
@ -531,6 +564,7 @@ impl fmt::Display for Site {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
SiteKind::Settlement => writeln!(f, "Settlement")?,
|
SiteKind::Settlement => writeln!(f, "Settlement")?,
|
||||||
|
SiteKind::Dungeon => writeln!(f, "Dungeon")?,
|
||||||
}
|
}
|
||||||
writeln!(f, "- population: {}", self.population.floor() as u32)?;
|
writeln!(f, "- population: {}", self.population.floor() as u32)?;
|
||||||
writeln!(f, "- coin: {}", self.coin.floor() as u32)?;
|
writeln!(f, "- coin: {}", self.coin.floor() as u32)?;
|
||||||
@ -558,6 +592,7 @@ impl fmt::Display for Site {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SiteKind {
|
pub enum SiteKind {
|
||||||
Settlement,
|
Settlement,
|
||||||
|
Dungeon,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Site {
|
impl Site {
|
||||||
|
198
world/src/site/dungeon/mod.rs
Normal file
198
world/src/site/dungeon/mod.rs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
use crate::{
|
||||||
|
column::ColumnSample,
|
||||||
|
sim::{SimChunk, WorldSim},
|
||||||
|
util::{Grid, RandomField, Sampler, StructureGen2d},
|
||||||
|
site::BlockMask,
|
||||||
|
};
|
||||||
|
use super::SpawnRules;
|
||||||
|
use common::{
|
||||||
|
astar::Astar,
|
||||||
|
path::Path,
|
||||||
|
spiral::Spiral2d,
|
||||||
|
terrain::{Block, BlockKind, TerrainChunkSize},
|
||||||
|
vol::{BaseVol, RectSizedVol, RectVolSize, ReadVol, WriteVol, Vox},
|
||||||
|
store::{Id, Store},
|
||||||
|
};
|
||||||
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
use rand::prelude::*;
|
||||||
|
use std::{collections::VecDeque, f32};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
impl WorldSim {
|
||||||
|
fn can_host_dungeon(&self, pos: Vec2<i32>) -> bool {
|
||||||
|
self
|
||||||
|
.get(pos)
|
||||||
|
.map(|chunk| {
|
||||||
|
!chunk.near_cliffs && !chunk.river.is_river() && !chunk.river.is_lake()
|
||||||
|
})
|
||||||
|
.unwrap_or(false)
|
||||||
|
&& self
|
||||||
|
.get_gradient_approx(pos)
|
||||||
|
.map(|grad| grad > 0.25 && grad < 1.5)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Dungeon {
|
||||||
|
origin: Vec2<i32>,
|
||||||
|
alt: i32,
|
||||||
|
noise: RandomField,
|
||||||
|
floors: Vec<Floor>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GenCtx<'a, R: Rng> {
|
||||||
|
sim: Option<&'a WorldSim>,
|
||||||
|
rng: &'a mut R,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dungeon {
|
||||||
|
pub fn generate(wpos: Vec2<i32>, sim: Option<&WorldSim>, rng: &mut impl Rng) -> Self {
|
||||||
|
let mut ctx = GenCtx { sim, rng };
|
||||||
|
let mut this = Self {
|
||||||
|
origin: wpos,
|
||||||
|
alt: ctx.sim.and_then(|sim| sim.get_alt_approx(wpos)).unwrap_or(0.0) as i32,
|
||||||
|
noise: RandomField::new(ctx.rng.gen()),
|
||||||
|
floors: (0..6)
|
||||||
|
.scan(Vec2::zero(), |stair_tile, _| {
|
||||||
|
let (floor, st) = Floor::generate(&mut ctx, *stair_tile);
|
||||||
|
*stair_tile = st;
|
||||||
|
Some(floor)
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn radius(&self) -> f32 { 1200.0 }
|
||||||
|
|
||||||
|
pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
|
||||||
|
SpawnRules {
|
||||||
|
..SpawnRules::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_to<'a>(
|
||||||
|
&'a self,
|
||||||
|
wpos2d: Vec2<i32>,
|
||||||
|
mut get_column: impl FnMut(Vec2<i32>) -> Option<&'a ColumnSample<'a>>,
|
||||||
|
vol: &mut (impl BaseVol<Vox = Block> + RectSizedVol + ReadVol + WriteVol),
|
||||||
|
) {
|
||||||
|
let rand_field = RandomField::new(0);
|
||||||
|
|
||||||
|
for y in 0..vol.size_xy().y as i32 {
|
||||||
|
for x in 0..vol.size_xy().x as i32 {
|
||||||
|
let offs = Vec2::new(x, y);
|
||||||
|
|
||||||
|
let wpos2d = wpos2d + offs;
|
||||||
|
let rpos = wpos2d - self.origin;
|
||||||
|
|
||||||
|
// Sample terrain
|
||||||
|
let col_sample = if let Some(col_sample) = get_column(offs) {
|
||||||
|
col_sample
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let surface_z = col_sample.riverless_alt.floor() as i32;
|
||||||
|
|
||||||
|
let make_staircase = |pos: Vec3<i32>, radius: f32, inner_radius: f32, stretch| {
|
||||||
|
if (pos.xy().magnitude_squared() as f32) < radius.powf(2.0) {
|
||||||
|
if ((pos.x as f32).atan2(pos.y as f32) / (f32::consts::PI * 2.0) * stretch + pos.z as f32) % stretch < 3.0
|
||||||
|
|| (pos.xy().magnitude_squared() as f32) < inner_radius.powf(2.0)
|
||||||
|
{
|
||||||
|
BlockMask::new(Block::new(BlockKind::Normal, Rgb::new(150, 150, 175)), 5)
|
||||||
|
} else {
|
||||||
|
BlockMask::new(Block::empty(), 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BlockMask::nothing()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let tile_pos = rpos.map(|e| e.div_euclid(TILE_SIZE));
|
||||||
|
let tile_center = tile_pos * TILE_SIZE + TILE_SIZE / 2;
|
||||||
|
|
||||||
|
let mut z = self.alt + 20;
|
||||||
|
for floor in &self.floors {
|
||||||
|
match floor.sample(tile_pos) {
|
||||||
|
Some(Tile::DownStair) | Some(Tile::Empty) => {
|
||||||
|
z -= floor.solid_depth;
|
||||||
|
for _ in 0..floor.hollow_depth {
|
||||||
|
vol.set(Vec3::new(offs.x, offs.y, z), Block::empty());
|
||||||
|
z -= 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(Tile::UpStair) => {
|
||||||
|
for i in 0..floor.solid_depth + floor.hollow_depth {
|
||||||
|
let rtile_pos = rpos - tile_center;
|
||||||
|
let mut block = make_staircase(Vec3::new(rtile_pos.x, rtile_pos.y, z), TILE_SIZE as f32 / 2.0, 1.5, 13.0);
|
||||||
|
if i >= floor.solid_depth {
|
||||||
|
block = block.resolve_with(BlockMask::new(Block::empty(), 1));
|
||||||
|
}
|
||||||
|
if let Some(block) = block.finish() {
|
||||||
|
vol.set(Vec3::new(offs.x, offs.y, z), block);
|
||||||
|
}
|
||||||
|
z -= 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => z -= floor.solid_depth + floor.hollow_depth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CARDINALS: [Vec2<i32>; 4] = [
|
||||||
|
Vec2::new(0, 1),
|
||||||
|
Vec2::new(1, 0),
|
||||||
|
Vec2::new(0, -1),
|
||||||
|
Vec2::new(-1, 0),
|
||||||
|
];
|
||||||
|
|
||||||
|
const TILE_SIZE: i32 = 17;
|
||||||
|
|
||||||
|
pub enum Tile {
|
||||||
|
UpStair,
|
||||||
|
DownStair,
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Floor {
|
||||||
|
tile_offset: Vec2<i32>,
|
||||||
|
tiles: Grid<Tile>,
|
||||||
|
solid_depth: i32,
|
||||||
|
hollow_depth: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Floor {
|
||||||
|
pub fn generate(ctx: &mut GenCtx<impl Rng>, stair_tile: Vec2<i32>) -> (Self, Vec2<i32>) {
|
||||||
|
let new_stair_tile = std::iter::from_fn(|| Some(FLOOR_SIZE.map(|sz| ctx.rng.gen_range(-sz / 2 + 1, sz / 2))))
|
||||||
|
.find(|pos| *pos != stair_tile)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
const FLOOR_SIZE: Vec2<i32> = Vec2::new(12, 12);
|
||||||
|
let tile_offset = -FLOOR_SIZE / 2;
|
||||||
|
let this = Floor {
|
||||||
|
tile_offset,
|
||||||
|
tiles: Grid::populate_from(FLOOR_SIZE, |pos| {
|
||||||
|
let tile_pos = tile_offset + pos;
|
||||||
|
if tile_pos == stair_tile {
|
||||||
|
Tile::UpStair
|
||||||
|
} else if tile_pos == new_stair_tile {
|
||||||
|
Tile::DownStair
|
||||||
|
} else {
|
||||||
|
Tile::Empty
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
solid_depth: 13 * 3,
|
||||||
|
hollow_depth: 13,
|
||||||
|
};
|
||||||
|
|
||||||
|
(this, new_stair_tile)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sample(&self, tile_pos: Vec2<i32>) -> Option<&Tile> {
|
||||||
|
self.tiles.get(tile_pos - self.tile_offset)
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
mod settlement;
|
mod settlement;
|
||||||
|
mod dungeon;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use self::settlement::Settlement;
|
pub use self::settlement::Settlement;
|
||||||
|
pub use self::dungeon::Dungeon;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
column::ColumnSample,
|
column::ColumnSample,
|
||||||
@ -9,30 +11,81 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
terrain::Block,
|
terrain::Block,
|
||||||
vol::{BaseVol, RectSizedVol, ReadVol, WriteVol},
|
vol::{Vox, BaseVol, RectSizedVol, ReadVol, WriteVol},
|
||||||
};
|
};
|
||||||
use std::{fmt, sync::Arc};
|
use std::{fmt, sync::Arc};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct BlockMask {
|
||||||
|
block: Block,
|
||||||
|
priority: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockMask {
|
||||||
|
pub fn new(block: Block, priority: i32) -> Self {
|
||||||
|
Self { block, priority }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nothing() -> Self {
|
||||||
|
Self {
|
||||||
|
block: Block::empty(),
|
||||||
|
priority: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_priority(mut self, priority: i32) -> Self {
|
||||||
|
self.priority = priority;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_with(self, other: Self) -> Self {
|
||||||
|
if self.priority >= other.priority {
|
||||||
|
self
|
||||||
|
} else {
|
||||||
|
other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> Option<Block> {
|
||||||
|
if self.priority > 0 {
|
||||||
|
Some(self.block)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SpawnRules {
|
pub struct SpawnRules {
|
||||||
pub trees: bool,
|
pub trees: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for SpawnRules {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
trees: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Site {
|
pub enum Site {
|
||||||
Settlement(Arc<Settlement>),
|
Settlement(Arc<Settlement>),
|
||||||
|
Dungeon(Arc<Dungeon>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Site {
|
impl Site {
|
||||||
pub fn radius(&self) -> f32 {
|
pub fn radius(&self) -> f32 {
|
||||||
match self {
|
match self {
|
||||||
Site::Settlement(settlement) => settlement.radius(),
|
Site::Settlement(settlement) => settlement.radius(),
|
||||||
|
Site::Dungeon(dungeon) => dungeon.radius(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
|
pub fn spawn_rules(&self, wpos: Vec2<i32>) -> SpawnRules {
|
||||||
match self {
|
match self {
|
||||||
Site::Settlement(s) => s.spawn_rules(wpos)
|
Site::Settlement(s) => s.spawn_rules(wpos),
|
||||||
|
Site::Dungeon(d) => d.spawn_rules(wpos),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +97,7 @@ impl Site {
|
|||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
Site::Settlement(settlement) => settlement.apply_to(wpos2d, get_column, vol),
|
Site::Settlement(settlement) => settlement.apply_to(wpos2d, get_column, vol),
|
||||||
|
Site::Dungeon(dungeon) => dungeon.apply_to(wpos2d, get_column, vol),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,10 +106,15 @@ impl From<Settlement> for Site {
|
|||||||
fn from(settlement: Settlement) -> Self { Site::Settlement(Arc::new(settlement)) }
|
fn from(settlement: Settlement) -> Self { Site::Settlement(Arc::new(settlement)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Dungeon> for Site {
|
||||||
|
fn from(dungeon: Dungeon) -> Self { Site::Dungeon(Arc::new(dungeon)) }
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Site {
|
impl fmt::Debug for Site {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Site::Settlement(_) => write!(f, "Settlement"),
|
Site::Settlement(_) => write!(f, "Settlement"),
|
||||||
|
Site::Dungeon(_) => write!(f, "Dungeon"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,12 @@ use common::{
|
|||||||
terrain::{Block, BlockKind},
|
terrain::{Block, BlockKind},
|
||||||
vol::Vox,
|
vol::Vox,
|
||||||
};
|
};
|
||||||
use crate::util::{RandomField, Sampler};
|
use crate::{
|
||||||
|
util::{RandomField, Sampler},
|
||||||
|
site::BlockMask,
|
||||||
|
};
|
||||||
use super::{
|
use super::{
|
||||||
Archetype,
|
Archetype,
|
||||||
BlockMask,
|
|
||||||
super::skeleton::*,
|
super::skeleton::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ use common::{
|
|||||||
};
|
};
|
||||||
use super::{
|
use super::{
|
||||||
Archetype,
|
Archetype,
|
||||||
BlockMask,
|
|
||||||
super::skeleton::*,
|
super::skeleton::*,
|
||||||
};
|
};
|
||||||
|
use crate::site::BlockMask;
|
||||||
|
|
||||||
pub struct Keep;
|
pub struct Keep;
|
||||||
|
|
||||||
|
@ -3,48 +3,8 @@ pub mod keep;
|
|||||||
|
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use common::{terrain::Block, vol::Vox};
|
|
||||||
use super::skeleton::*;
|
use super::skeleton::*;
|
||||||
|
use crate::site::BlockMask;
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct BlockMask {
|
|
||||||
block: Block,
|
|
||||||
priority: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockMask {
|
|
||||||
pub fn new(block: Block, priority: i32) -> Self {
|
|
||||||
Self { block, priority }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nothing() -> Self {
|
|
||||||
Self {
|
|
||||||
block: Block::empty(),
|
|
||||||
priority: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_priority(mut self, priority: i32) -> Self {
|
|
||||||
self.priority = priority;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resolve_with(self, other: Self) -> Self {
|
|
||||||
if self.priority >= other.priority {
|
|
||||||
self
|
|
||||||
} else {
|
|
||||||
other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) -> Option<Block> {
|
|
||||||
if self.priority > 0 {
|
|
||||||
Some(self.block)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Archetype {
|
pub trait Archetype {
|
||||||
type Attr;
|
type Attr;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
use super::archetype::BlockMask;
|
use crate::site::BlockMask;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum Ori {
|
pub enum Ori {
|
||||||
|
@ -451,6 +451,7 @@ impl Settlement {
|
|||||||
.plot
|
.plot
|
||||||
.map(|p| if let Plot::Hazard = p { true } else { false })
|
.map(|p| if let Plot::Hazard = p { true } else { false })
|
||||||
.unwrap_or(true),
|
.unwrap_or(true),
|
||||||
|
..SpawnRules::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,7 +642,7 @@ impl Settlement {
|
|||||||
// Skip this structure if it's not near this chunk
|
// Skip this structure if it's not near this chunk
|
||||||
if !bounds.collides_with_aabr(Aabr {
|
if !bounds.collides_with_aabr(Aabr {
|
||||||
min: wpos2d - self.origin,
|
min: wpos2d - self.origin,
|
||||||
max: wpos2d - self.origin + vol.size_xy().map(|e| e as i32),
|
max: wpos2d - self.origin + vol.size_xy().map(|e| e as i32 + 1),
|
||||||
}) {
|
}) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -659,7 +660,7 @@ impl Settlement {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
for z in bounds.min.z.min(col.alt 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);
|
||||||
|
Loading…
Reference in New Issue
Block a user