Added labour value to economy, castle improvements

This commit is contained in:
Joshua Barretto 2020-07-14 16:21:57 +01:00
parent bdb39b8e7f
commit 1763693f5f
10 changed files with 226 additions and 149 deletions

View File

@ -1 +0,0 @@
,joshua,archbox.localdomain,17.06.2020 16:07,file:///home/joshua/.config/libreoffice/4;

View File

@ -15,7 +15,7 @@ use common::{
sync::{Uid, WorldSyncExt}, sync::{Uid, WorldSyncExt},
terrain::{Block, BlockKind, TerrainChunkSize}, terrain::{Block, BlockKind, TerrainChunkSize},
util::Dir, util::Dir,
vol::{RectVolSize, WriteVol}, vol::RectVolSize,
LoadoutBuilder, LoadoutBuilder,
}; };
use rand::Rng; use rand::Rng;

View File

@ -127,7 +127,7 @@ impl Civs {
let wpos = site.center * TerrainChunkSize::RECT_SIZE.map(|e: u32| e as i32); let wpos = site.center * TerrainChunkSize::RECT_SIZE.map(|e: u32| e as i32);
let flatten_radius = match &site.kind { let flatten_radius = match &site.kind {
SiteKind::Settlement => 8.0, SiteKind::Settlement => 10.0,
SiteKind::Dungeon => 2.0, SiteKind::Dungeon => 2.0,
SiteKind::Castle => 5.0, SiteKind::Castle => 5.0,
}; };
@ -148,9 +148,10 @@ impl Civs {
0.0 0.0
}; // Raise the town centre up a little }; // Raise the town centre up a little
let pos = site.center + offs; let pos = site.center + offs;
let factor = (1.0 let factor = ((1.0
- (site.center - pos).map(|e| e as f32).magnitude() / flatten_radius) - (site.center - pos).map(|e| e as f32).magnitude() / flatten_radius)
* 0.8; * 1.25)
.min(1.0);
ctx.sim ctx.sim
.get_mut(pos) .get_mut(pos)
// Don't disrupt chunks that are near water // Don't disrupt chunks that are near water
@ -170,7 +171,9 @@ impl Civs {
let mut cnt = 0; let mut cnt = 0;
for sim_site in this.sites.values() { for sim_site in this.sites.values() {
cnt += 1; cnt += 1;
let wpos = sim_site.center.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| { let wpos = sim_site
.center
.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
e * sz as i32 + sz as i32 / 2 e * sz as i32 + sz as i32 / 2
}); });

View File

@ -26,6 +26,7 @@ pub use self::{
use crate::{ use crate::{
all::ForestKind, all::ForestKind,
civ::Place, civ::Place,
column::{ColumnGen, ColumnSample},
site::Site, site::Site,
util::{seed_expan, FastNoise, RandomField, StructureGen2d, LOCALITY, NEIGHBORS}, util::{seed_expan, FastNoise, RandomField, StructureGen2d, LOCALITY, NEIGHBORS},
Index, CONFIG, Index, CONFIG,
@ -1699,8 +1700,9 @@ impl WorldSim {
Some(z0 + z1 + z2 + z3) Some(z0 + z1 + z2 + z3)
} }
/// Return the distance to the nearest path in blocks, along with the closest point on the /// Return the distance to the nearest path in blocks, along with the
/// path, the path metadata, and the tangent vector of that path. /// closest point on the path, the path metadata, and the tangent vector
/// of that path.
pub fn get_nearest_path(&self, wpos: Vec2<i32>) -> Option<(f32, Vec2<f32>, Path, Vec2<f32>)> { pub fn get_nearest_path(&self, wpos: Vec2<i32>) -> Option<(f32, Vec2<f32>, Path, Vec2<f32>)> {
let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| { let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
e.div_euclid(sz as i32) e.div_euclid(sz as i32)

View File

@ -23,7 +23,7 @@ pub fn simulate(index: &mut Index, world: &mut WorldSim) {
write!(f, "{:?} Value,", g).unwrap(); write!(f, "{:?} Value,", g).unwrap();
} }
for g in Good::list() { for g in Good::list() {
write!(f, "{:?} Price,", g).unwrap(); write!(f, "{:?} LaborVal,", g).unwrap();
} }
for g in Good::list() { for g in Good::list() {
write!(f, "{:?} Stock,", g).unwrap(); write!(f, "{:?} Stock,", g).unwrap();
@ -37,6 +37,9 @@ pub fn simulate(index: &mut Index, world: &mut WorldSim) {
for l in Labor::list() { for l in Labor::list() {
write!(f, "{:?} Productivity,", l).unwrap(); write!(f, "{:?} Productivity,", l).unwrap();
} }
for l in Labor::list() {
write!(f, "{:?} Yields,", l).unwrap();
}
writeln!(f, "").unwrap(); writeln!(f, "").unwrap();
for i in 0..(HISTORY_DAYS / TICK_PERIOD) as i32 { for i in 0..(HISTORY_DAYS / TICK_PERIOD) as i32 {
@ -53,7 +56,7 @@ pub fn simulate(index: &mut Index, world: &mut WorldSim) {
write!(f, "{:?},", site.economy.values[*g].unwrap_or(-1.0)).unwrap(); write!(f, "{:?},", site.economy.values[*g].unwrap_or(-1.0)).unwrap();
} }
for g in Good::list() { for g in Good::list() {
write!(f, "{:?},", site.economy.prices[*g]).unwrap(); write!(f, "{:?},", site.economy.labor_values[*g]).unwrap();
} }
for g in Good::list() { for g in Good::list() {
write!(f, "{:?},", site.economy.stocks[*g]).unwrap(); write!(f, "{:?},", site.economy.stocks[*g]).unwrap();
@ -67,6 +70,9 @@ pub fn simulate(index: &mut Index, world: &mut WorldSim) {
for l in Labor::list() { for l in Labor::list() {
write!(f, "{:?},", site.economy.productivity[*l]).unwrap(); write!(f, "{:?},", site.economy.productivity[*l]).unwrap();
} }
for l in Labor::list() {
write!(f, "{:?},", site.economy.yields[*l]).unwrap();
}
writeln!(f, "").unwrap(); writeln!(f, "").unwrap();
} }
} }
@ -144,11 +150,6 @@ pub fn tick_site_economy(index: &mut Index, site: Id<Site>, dt: f32) {
}; };
}); });
site.economy.prices = site.economy.stocks.clone().map(|g, stock| {
// Price rationalisation
demand[g] / (supply[g] + stocks[g])
});
// Update export targets based on relative values // Update export targets based on relative values
let value_avg = values let value_avg = values
.iter() .iter()
@ -169,7 +170,8 @@ pub fn tick_site_economy(index: &mut Index, site: Id<Site>, dt: f32) {
// Redistribute workforce according to relative good values // Redistribute workforce according to relative good values
let labor_ratios = productivity.clone().map(|labor, (output_good, _)| { let labor_ratios = productivity.clone().map(|labor, (output_good, _)| {
site.economy.values[output_good].unwrap_or(0.0) * site.economy.productivity[labor] site.economy.values[output_good].unwrap_or(0.0) * site.economy.yields[labor]
//(site.economy.prices[output_good] - site.economy.material_costs[output_good]) * site.economy.yields[labor]
//* demand[output_good] / supply[output_good].max(0.001) //* demand[output_good] / supply[output_good].max(0.001)
}); });
let labor_ratio_sum = labor_ratios.iter().map(|(_, r)| *r).sum::<f32>().max(0.01); let labor_ratio_sum = labor_ratios.iter().map(|(_, r)| *r).sum::<f32>().max(0.01);
@ -182,6 +184,7 @@ pub fn tick_site_economy(index: &mut Index, site: Id<Site>, dt: f32) {
// Production // Production
let stocks_before = site.economy.stocks.clone(); let stocks_before = site.economy.stocks.clone();
site.economy.labor_values = Default::default();
for (labor, orders) in orders.iter() { for (labor, orders) in orders.iter() {
let scale = if let Some(labor) = labor { let scale = if let Some(labor) = labor {
site.economy.labors[*labor] site.economy.labors[*labor]
@ -207,12 +210,16 @@ pub fn tick_site_economy(index: &mut Index, site: Id<Site>, dt: f32) {
.min_by(|a, b| a.partial_cmp(b).unwrap()) .min_by(|a, b| a.partial_cmp(b).unwrap())
.unwrap_or_else(|| panic!("Industry {:?} requires at least one input order", labor)); .unwrap_or_else(|| panic!("Industry {:?} requires at least one input order", labor));
let mut total_materials_cost = 0.0;
for (good, amount) in orders { for (good, amount) in orders {
// What quantity is this order requesting? // What quantity is this order requesting?
let quantity = *amount * scale; let quantity = *amount * scale;
// What amount gets actually used in production? // What amount gets actually used in production?
let used = quantity * labor_productivity; let used = quantity * labor_productivity;
// Material cost of each factor of production
total_materials_cost += used * site.economy.labor_values[*good];
// Deplete stocks accordingly // Deplete stocks accordingly
site.economy.stocks[*good] = (site.economy.stocks[*good] - used).max(0.0); site.economy.stocks[*good] = (site.economy.stocks[*good] - used).max(0.0);
} }
@ -222,10 +229,19 @@ pub fn tick_site_economy(index: &mut Index, site: Id<Site>, dt: f32) {
let (stock, rate) = productivity[*labor]; let (stock, rate) = productivity[*labor];
let workers = site.economy.labors[*labor] * site.economy.pop; let workers = site.economy.labors[*labor] * site.economy.pop;
let final_rate = rate; let final_rate = rate;
let yield_per_worker = labor_productivity * final_rate; let yield_per_worker = labor_productivity * final_rate * (1.0 + workers / 100.0);
site.economy.yields[*labor] = yield_per_worker; site.economy.yields[*labor] = yield_per_worker;
site.economy.productivity[*labor] = labor_productivity; site.economy.productivity[*labor] = labor_productivity;
site.economy.stocks[stock] += yield_per_worker * workers.powf(1.1); let total_output = yield_per_worker * workers;
site.economy.stocks[stock] += total_output;
// Materials cost per unit
let material_cost_per_unit = total_materials_cost / total_output.max(0.001);
site.economy.material_costs[stock] = material_cost_per_unit;
site.economy.labor_values[stock] += material_cost_per_unit;
// Labor costs
let wages = 1.0;
site.economy.labor_values[stock] += workers * wages / total_output.max(0.001);
} }
} }

View File

@ -69,19 +69,6 @@ impl Castle {
let radius = 150; let radius = 150;
// Adjust ground
if let Some(sim) = ctx.sim.as_mut() {
for rpos in Spiral2d::new()
.radius((radius as f32 * 0.7) as i32 / TerrainChunkSize::RECT_SIZE.x as i32)
{
sim.get_mut(wpos / TerrainChunkSize::RECT_SIZE.map(|e| e as i32) + rpos)
.map(|chunk| {
chunk.surface_veg = 0.0;
chunk.path.clear();
});
}
}
let this = Self { let this = Self {
origin: wpos, origin: wpos,
alt: ctx alt: ctx
@ -157,6 +144,23 @@ impl Castle {
this this
} }
pub fn contains_point(&self, wpos: Vec2<i32>) -> bool {
let lpos = wpos - self.origin;
for i in 0..self.towers.len() {
let tower0 = &self.towers[i];
let tower1 = &self.towers[(i + 1) % self.towers.len()];
if lpos.determine_side(Vec2::zero(), tower0.offset) > 0
&& lpos.determine_side(Vec2::zero(), tower1.offset) <= 0
&& lpos.determine_side(tower0.offset, tower1.offset) > 0
{
return true;
}
}
false
}
pub fn get_origin(&self) -> Vec2<i32> { self.origin } pub fn get_origin(&self) -> Vec2<i32> { self.origin }
pub fn radius(&self) -> f32 { 1200.0 } pub fn radius(&self) -> f32 { 1200.0 }
@ -182,13 +186,38 @@ impl Castle {
let wpos2d = wpos2d + offs; let wpos2d = wpos2d + offs;
let rpos = wpos2d - self.origin; let rpos = wpos2d - self.origin;
// Apply the dungeon entrance if rpos.magnitude_squared() > (self.radius + 64).pow(2) {
continue;
}
let col_sample = if let Some(col) = get_column(offs) { let col_sample = if let Some(col) = get_column(offs) {
col col
} else { } else {
continue; continue;
}; };
// Inner ground
if self.contains_point(wpos2d) {
let surface_z = col_sample.alt as i32;
for z in -5..3 {
let pos = Vec3::new(offs.x, offs.y, surface_z + z);
if z >= 0 {
if vol.get(pos).unwrap().kind() != BlockKind::Water {
let _ = vol.set(pos, Block::empty());
}
} else {
let _ = vol.set(
pos,
Block::new(
BlockKind::Normal,
col_sample.sub_surface_color.map(|e| (e * 255.0) as u8),
),
);
}
}
}
let (wall_dist, wall_pos, wall_alt, wall_ori, towers) = (0..self.towers.len()) let (wall_dist, wall_pos, wall_alt, wall_ori, towers) = (0..self.towers.len())
.map(|i| { .map(|i| {
let tower0 = &self.towers[i]; let tower0 = &self.towers[i];

View File

@ -35,7 +35,9 @@ pub struct Economy {
pub surplus: MapVec<Good, f32>, pub surplus: MapVec<Good, f32>,
pub marginal_surplus: MapVec<Good, f32>, pub marginal_surplus: MapVec<Good, f32>,
pub values: MapVec<Good, Option<f32>>, pub values: MapVec<Good, Option<f32>>,
pub prices: MapVec<Good, f32>,
pub labor_values: MapVec<Good, f32>,
pub material_costs: MapVec<Good, f32>,
pub labors: MapVec<Labor, f32>, pub labors: MapVec<Labor, f32>,
pub yields: MapVec<Labor, f32>, pub yields: MapVec<Labor, f32>,
@ -51,7 +53,9 @@ impl Default for Economy {
surplus: Default::default(), surplus: Default::default(),
marginal_surplus: Default::default(), marginal_surplus: Default::default(),
values: Default::default(), values: Default::default(),
prices: Default::default(),
labor_values: Default::default(),
material_costs: Default::default(),
labors: Default::default(), labors: Default::default(),
yields: Default::default(), yields: Default::default(),

View File

@ -12,28 +12,60 @@ use common::{
use rand::prelude::*; use rand::prelude::*;
use vek::*; use vek::*;
const COLOR_THEMES: [Rgb<u8>; 17] = [ pub struct ColorTheme {
Rgb::new(0x1D, 0x4D, 0x45), roof: Rgb<u8>,
Rgb::new(0xB3, 0x7D, 0x60), wall: Rgb<u8>,
Rgb::new(0xAC, 0x5D, 0x26), support: Rgb<u8>,
Rgb::new(0x32, 0x46, 0x6B), }
Rgb::new(0x2B, 0x19, 0x0F),
Rgb::new(0x93, 0x78, 0x51), const ROOF_COLORS: &[Rgb<u8>] = &[
Rgb::new(0x92, 0x57, 0x24), // Rgb::new(0x1D, 0x4D, 0x45),
Rgb::new(0x4A, 0x4E, 0x4E), // Rgb::new(0xB3, 0x7D, 0x60),
Rgb::new(0x2F, 0x32, 0x47), // Rgb::new(0xAC, 0x5D, 0x26),
Rgb::new(0x8F, 0x35, 0x43), // Rgb::new(0x32, 0x46, 0x6B),
Rgb::new(0x6D, 0x1E, 0x3A), // Rgb::new(0x2B, 0x19, 0x0F),
Rgb::new(0x6D, 0xA7, 0x80), // Rgb::new(0x93, 0x78, 0x51),
Rgb::new(0x4F, 0xA0, 0x95), // Rgb::new(0x92, 0x57, 0x24),
Rgb::new(0xE2, 0xB9, 0x99), // Rgb::new(0x4A, 0x4E, 0x4E),
Rgb::new(0x7A, 0x30, 0x22), // Rgb::new(0x2F, 0x32, 0x47),
Rgb::new(0x4A, 0x06, 0x08), // Rgb::new(0x8F, 0x35, 0x43),
Rgb::new(0x8E, 0xB4, 0x57), // Rgb::new(0x6D, 0x1E, 0x3A),
// Rgb::new(0x6D, 0xA7, 0x80),
// Rgb::new(0x4F, 0xA0, 0x95),
// Rgb::new(0xE2, 0xB9, 0x99),
// Rgb::new(0x7A, 0x30, 0x22),
// Rgb::new(0x4A, 0x06, 0x08),
// Rgb::new(0x8E, 0xB4, 0x57),
Rgb::new(0x99, 0x5E, 0x54),
Rgb::new(0x43, 0x63, 0x64),
Rgb::new(0x76, 0x6D, 0x68),
Rgb::new(0x7B, 0x41, 0x61),
Rgb::new(0x52, 0x20, 0x20),
Rgb::new(0x1A, 0x4A, 0x59),
Rgb::new(0xCC, 0x76, 0x4E),
];
const WALL_COLORS: &[Rgb<u8>] = &[
Rgb::new(200, 180, 150),
Rgb::new(0xB8, 0xB4, 0xA4),
Rgb::new(0x76, 0x6D, 0x68),
Rgb::new(0xF3, 0xC9, 0x8F),
Rgb::new(0xD3, 0xB7, 0x99),
Rgb::new(0xE1, 0xAB, 0x91),
Rgb::new(0x82, 0x57, 0x4C),
Rgb::new(0xB9, 0x96, 0x77),
Rgb::new(0x6E, 0x4D, 0x3C),
];
const SUPPORT_COLORS: &[Rgb<u8>] = &[
Rgb::new(60, 45, 30),
Rgb::new(0x65, 0x55, 0x56),
Rgb::new(0x53, 0x33, 0x13),
Rgb::new(0x58, 0x42, 0x33),
]; ];
pub struct House { pub struct House {
pub roof_color: Rgb<u8>, pub colors: ColorTheme,
pub noise: RandomField, pub noise: RandomField,
pub roof_ribbing: bool, pub roof_ribbing: bool,
pub roof_ribbing_diagonal: bool, pub roof_ribbing_diagonal: bool,
@ -126,6 +158,7 @@ impl Archetype for House {
let len = rng.gen_range(-8, 24).clamped(0, 20); let len = rng.gen_range(-8, 24).clamped(0, 20);
let locus = 6 + rng.gen_range(0, 5); let locus = 6 + rng.gen_range(0, 5);
let branches_per_side = 1 + len as usize / 20; let branches_per_side = 1 + len as usize / 20;
let levels = rng.gen_range(1, 3);
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 },
@ -139,7 +172,7 @@ impl Archetype for House {
1 => Pillar::Tower(5 + rng.gen_range(1, 5)), 1 => Pillar::Tower(5 + rng.gen_range(1, 5)),
_ => Pillar::None, _ => Pillar::None,
}, },
levels: rng.gen_range(1, 4), levels,
..Attr::generate(rng, locus) ..Attr::generate(rng, locus)
}, },
locus, locus,
@ -154,7 +187,10 @@ impl Archetype for House {
i as i32 * len / (branches_per_side - 1).max(1) as i32, i as i32 * len / (branches_per_side - 1).max(1) as i32,
Branch { Branch {
len: rng.gen_range(8, 16) * flip, len: rng.gen_range(8, 16) * flip,
attr: Attr::generate(rng, locus), attr: Attr {
levels: rng.gen_range(1, 4).min(levels),
..Attr::generate(rng, locus)
},
locus: (6 + rng.gen_range(0, 3)).min(locus), locus: (6 + rng.gen_range(0, 3)).min(locus),
border: 4, border: 4,
children: Vec::new(), children: Vec::new(),
@ -169,7 +205,11 @@ impl Archetype for House {
}; };
let this = Self { let this = Self {
roof_color: *COLOR_THEMES.choose(rng).unwrap(), colors: ColorTheme {
roof: *ROOF_COLORS.choose(rng).unwrap(),
wall: *WALL_COLORS.choose(rng).unwrap(),
support: *SUPPORT_COLORS.choose(rng).unwrap(),
},
noise: RandomField::new(rng.gen()), noise: RandomField::new(rng.gen()),
roof_ribbing: rng.gen(), roof_ribbing: rng.gen(),
roof_ribbing_diagonal: rng.gen(), roof_ribbing_diagonal: rng.gen(),
@ -205,7 +245,7 @@ impl Archetype for House {
) )
}; };
let make_block = |r, g, b| { let make_block = |(r, g, b)| {
let nz = self let nz = self
.noise .noise
.get(Vec3::new(center_offset.x, center_offset.y, z * 8)); .get(Vec3::new(center_offset.x, center_offset.y, z * 8));
@ -225,12 +265,11 @@ impl Archetype for House {
let foundation_layer = internal_layer + 1; let foundation_layer = internal_layer + 1;
let floor_layer = foundation_layer + 1; let floor_layer = foundation_layer + 1;
let foundation = make_block(100, 100, 100).with_priority(foundation_layer); let foundation = make_block((100, 100, 100)).with_priority(foundation_layer);
let log = make_block(60, 45, 30); let log = make_block(self.colors.support.into_tuple());
let floor = make_block(100, 75, 50); let floor = make_block((100, 75, 50));
let wall = make_block(200, 180, 150).with_priority(facade_layer); let wall = make_block(self.colors.wall.into_tuple()).with_priority(facade_layer);
let roof = make_block(self.roof_color.r, self.roof_color.g, self.roof_color.b) let roof = make_block(self.colors.roof.into_tuple()).with_priority(facade_layer - 1);
.with_priority(facade_layer - 1);
let empty = BlockMask::nothing(); let empty = BlockMask::nothing();
let internal = BlockMask::new(Block::empty(), internal_layer); let internal = BlockMask::new(Block::empty(), internal_layer);
let end_window = BlockMask::new( let end_window = BlockMask::new(

View File

@ -2,15 +2,15 @@ pub mod archetype;
pub mod skeleton; pub mod skeleton;
// Reexports // Reexports
pub use self::{archetype::Archetype, skeleton::*}; pub use self::{
archetype::{house::House, keep::Keep, Archetype},
skeleton::*,
};
use common::terrain::Block; use common::terrain::Block;
use rand::prelude::*; use rand::prelude::*;
use vek::*; use vek::*;
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>,
archetype: A, archetype: A,

View File

@ -2,7 +2,7 @@ pub mod building;
mod town; mod town;
use self::{ use self::{
building::{HouseBuilding, KeepBuilding}, building::{Building, House, Keep},
town::{District, Town}, town::{District, Town},
}; };
use super::SpawnRules; use super::SpawnRules;
@ -86,8 +86,8 @@ const AREA_SIZE: u32 = 32;
fn to_tile(e: i32) -> i32 { ((e as f32).div_euclid(AREA_SIZE as f32)).floor() as i32 } fn to_tile(e: i32) -> i32 { ((e as f32).div_euclid(AREA_SIZE as f32)).floor() as i32 }
pub enum StructureKind { pub enum StructureKind {
House(HouseBuilding), House(Building<House>),
Keep(KeepBuilding), Keep(Building<Keep>),
} }
pub struct Structure { pub struct Structure {
@ -403,12 +403,12 @@ impl Settlement {
let structure = Structure { let structure = Structure {
kind: if tile == town_center && i == 0 { kind: if tile == town_center && i == 0 {
StructureKind::Keep(KeepBuilding::generate( StructureKind::Keep(Building::<Keep>::generate(
ctx.rng, ctx.rng,
Vec3::new(house_pos.x, house_pos.y, alt), Vec3::new(house_pos.x, house_pos.y, alt),
)) ))
} else { } else {
StructureKind::House(HouseBuilding::generate( StructureKind::House(Building::<House>::generate(
ctx.rng, ctx.rng,
Vec3::new(house_pos.x, house_pos.y, alt), Vec3::new(house_pos.x, house_pos.y, alt),
)) ))
@ -671,17 +671,6 @@ impl Settlement {
})) }))
}, },
Some(Plot::Field { seed, crop, .. }) => { Some(Plot::Field { seed, crop, .. }) => {
if let Some(color) = col_sample.path.and_then(|(dist, _, path, _)| {
if dist < path.width {
Some(path.surface_color(
col_sample.sub_surface_color.map(|e| (e * 255.0) as u8),
))
} else {
None
}
}) {
Some(color)
} else {
let furrow_dirs = [ let furrow_dirs = [
Vec2::new(1, 0), Vec2::new(1, 0),
Vec2::new(0, 1), Vec2::new(0, 1),
@ -692,14 +681,12 @@ impl Settlement {
let in_furrow = (wpos2d * furrow_dir).sum().rem_euclid(5) < 2; let in_furrow = (wpos2d * furrow_dir).sum().rem_euclid(5) < 2;
let dirt = Rgb::new(80, 55, 35).map(|e| { let dirt = Rgb::new(80, 55, 35).map(|e| {
e + (self.noise.get(Vec3::broadcast((seed % 4096 + 0) as i32)) e + (self.noise.get(Vec3::broadcast((seed % 4096 + 0) as i32)) % 32)
% 32) as u8 as u8
}); });
let mound = let mound =
Rgb::new(70, 80, 30).map(|e| e + roll(0, 8) as u8).map(|e| { Rgb::new(70, 80, 30).map(|e| e + roll(0, 8) as u8).map(|e| {
e + (self e + (self.noise.get(Vec3::broadcast((seed % 4096 + 1) as i32))
.noise
.get(Vec3::broadcast((seed % 4096 + 1) as i32))
% 32) as u8 % 32) as u8
}); });
@ -718,18 +705,10 @@ impl Settlement {
Some(BlockKind::Pumpkin) Some(BlockKind::Pumpkin)
}, },
Crop::Flax if roll(4, 2) == 0 => Some(BlockKind::Flax), Crop::Flax if roll(4, 2) == 0 => Some(BlockKind::Flax),
Crop::Carrot if roll(5, 2) == 0 => { Crop::Carrot if roll(5, 2) == 0 => Some(BlockKind::Carrot),
Some(BlockKind::Carrot) Crop::Tomato if roll(6, 2) == 0 => Some(BlockKind::Tomato),
}, Crop::Radish if roll(7, 2) == 0 => Some(BlockKind::Radish),
Crop::Tomato if roll(6, 2) == 0 => { Crop::Turnip if roll(8, 2) == 0 => Some(BlockKind::Turnip),
Some(BlockKind::Tomato)
},
Crop::Radish if roll(7, 2) == 0 => {
Some(BlockKind::Radish)
},
Crop::Turnip if roll(8, 2) == 0 => {
Some(BlockKind::Turnip)
},
Crop::Sunflower => Some(BlockKind::Sunflower), Crop::Sunflower => Some(BlockKind::Sunflower),
_ => None, _ => None,
} }
@ -751,14 +730,20 @@ impl Settlement {
} }
Some(if in_furrow { dirt } else { mound }) Some(if in_furrow { dirt } else { mound })
}
}, },
_ => None, _ => None,
}; };
if let Some(color) = color { if let Some(color) = color {
if col_sample.water_dist.map(|dist| dist > 2.0).unwrap_or(true) { let is_path = col_sample
.path
.map(|(dist, _, path, _)| dist < path.width)
.unwrap_or(false);
if col_sample.water_dist.map(|dist| dist > 2.0).unwrap_or(true) && !is_path
{
let diff = (surface_z - land_surface_z).abs(); let diff = (surface_z - land_surface_z).abs();
for z in -8 - diff..3 + diff { for z in -8 - diff..3 + diff {
let pos = Vec3::new(offs.x, offs.y, surface_z + z); let pos = Vec3::new(offs.x, offs.y, surface_z + z);