This commit is contained in:
Joshua Barretto 2020-04-23 17:00:48 +01:00
parent 0c491bb558
commit 2a6a19f7ef
18 changed files with 177 additions and 129 deletions

View File

@ -75,7 +75,8 @@ impl Route {
None None
} else { } else {
let next_tgt = next.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0); let next_tgt = next.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0);
if ((pos - (next_tgt + Vec3::unit_z() * 0.5)) * Vec3::new(1.0, 1.0, 0.3)).magnitude_squared() if ((pos - (next_tgt + Vec3::unit_z() * 0.5)) * Vec3::new(1.0, 1.0, 0.3))
.magnitude_squared()
< (traversal_tolerance * 2.0).powf(2.0) < (traversal_tolerance * 2.0).powf(2.0)
{ {
self.next_idx += 1; self.next_idx += 1;

View File

@ -115,9 +115,10 @@ impl<'a> System<'a> for Sys {
let scale = scales.get(entity).map(|s| s.0).unwrap_or(1.0); let scale = scales.get(entity).map(|s| s.0).unwrap_or(1.0);
// This controls how picky NPCs are about their pathfinding. Giants are larger and so // This controls how picky NPCs are about their pathfinding. Giants are larger
// can afford to be less precise when trying to move around the world (especially since // and so can afford to be less precise when trying to move around
// they would otherwise get stuck on obstacles that smaller entities would not). // the world (especially since they would otherwise get stuck on
// obstacles that smaller entities would not).
let traversal_tolerance = scale; let traversal_tolerance = scale;
let mut do_idle = false; let mut do_idle = false;

View File

@ -317,13 +317,14 @@ impl<'a> System<'a> for Sys {
&& was_on_ground && was_on_ground
&& !collision_with( && !collision_with(
pos.0 - Vec3::unit_z() * 0.05, pos.0 - Vec3::unit_z() * 0.05,
&|block| block.is_solid() && block.get_height() >= (pos.0.z - 0.05).rem_euclid(1.0), &|block| {
block.is_solid() && block.get_height() >= (pos.0.z - 0.05).rem_euclid(1.0)
},
near_iter.clone(), near_iter.clone(),
) )
{ {
let snap_height = terrain let snap_height = terrain
.get(Vec3::new(pos.0.x, pos.0.y, pos.0.z - 0.05) .get(Vec3::new(pos.0.x, pos.0.y, pos.0.z - 0.05).map(|e| e.floor() as i32))
.map(|e| e.floor() as i32))
.ok() .ok()
.filter(|block| block.is_solid()) .filter(|block| block.is_solid())
.map(|block| block.get_height()) .map(|block| block.get_height())
@ -340,7 +341,11 @@ impl<'a> System<'a> for Sys {
]; ];
if let (wall_dir, true) = dirs.iter().fold((Vec3::zero(), false), |(a, hit), dir| { if let (wall_dir, true) = dirs.iter().fold((Vec3::zero(), false), |(a, hit), dir| {
if collision_with(pos.0 + *dir * 0.01, &|block| block.is_solid(), near_iter.clone()) { if collision_with(
pos.0 + *dir * 0.01,
&|block| block.is_solid(),
near_iter.clone(),
) {
(a + dir, true) (a + dir, true)
} else { } else {
(a, hit) (a, hit)
@ -352,7 +357,8 @@ impl<'a> System<'a> for Sys {
} }
// Figure out if we're in water // Figure out if we're in water
physics_state.in_fluid = collision_with(pos.0, &|block| block.is_fluid(), near_iter.clone()); physics_state.in_fluid =
collision_with(pos.0, &|block| block.is_fluid(), near_iter.clone());
let _ = physics_states.insert(entity, physics_state); let _ = physics_states.insert(entity, physics_state);
} }

View File

@ -303,9 +303,11 @@ impl Block {
pub fn get_ori(&self) -> Option<u8> { pub fn get_ori(&self) -> Option<u8> {
match self.kind { match self.kind {
BlockKind::Window1 | BlockKind::Window2 | BlockKind::Window3 | BlockKind::Window4 | BlockKind::Door => { BlockKind::Window1
Some(self.color[0] & 0b111) | BlockKind::Window2
}, | BlockKind::Window3
| BlockKind::Window4
| BlockKind::Door => Some(self.color[0] & 0b111),
_ => None, _ => None,
} }
} }

View File

@ -49,9 +49,9 @@ use uvth::{ThreadPool, ThreadPoolBuilder};
use vek::*; use vek::*;
#[cfg(feature = "worldgen")] #[cfg(feature = "worldgen")]
use world::{ use world::{
civ::SiteKind,
sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP, WORLD_SIZE}, sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP, WORLD_SIZE},
World, World,
civ::SiteKind,
}; };
const CLIENT_TIMEOUT: f64 = 20.0; // Seconds const CLIENT_TIMEOUT: f64 = 20.0; // Seconds
@ -141,7 +141,9 @@ impl Server {
// calculate the absolute position of the chunk in the world // calculate the absolute position of the chunk in the world
// (we could add TerrainChunkSize::RECT_SIZE / 2 here, to spawn in the midde of // (we could add TerrainChunkSize::RECT_SIZE / 2 here, to spawn in the midde of
// the chunk) // the chunk)
let spawn_location = spawn_chunk.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e as i32 * sz as i32 + sz as i32 / 2); let spawn_location = spawn_chunk.map2(TerrainChunkSize::RECT_SIZE, |e, sz| {
e as i32 * sz as i32 + sz as i32 / 2
});
// get a z cache for the collumn in which we want to spawn // get a z cache for the collumn in which we want to spawn
let mut block_sampler = world.sample_blocks(); let mut block_sampler = world.sample_blocks();

View File

@ -4,11 +4,11 @@ use common::{
assets, assets,
comp::{self, item, CharacterAbility, Item, ItemConfig, Player, Pos}, comp::{self, item, CharacterAbility, Item, ItemConfig, Player, Pos},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
generation::get_npc_name,
msg::ServerMsg, msg::ServerMsg,
npc::NPC_NAMES, npc::NPC_NAMES,
state::TerrainChanges, state::TerrainChanges,
terrain::TerrainGrid, terrain::TerrainGrid,
generation::get_npc_name,
}; };
use rand::Rng; use rand::Rng;
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect, WriteStorage}; use specs::{Join, Read, ReadStorage, System, Write, WriteExpect, WriteStorage};

View File

@ -302,9 +302,8 @@ impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeli
for j in 0..3 { for j in 0..3 {
for k in 0..3 { for k in 0..3 {
blocks[k][j][i] = Some(flat_get( blocks[k][j][i] = Some(flat_get(
Vec3::new(x, y, z_start) Vec3::new(x, y, z_start) + Vec3::new(i as i32, j as i32, k as i32)
+ Vec3::new(i as i32, j as i32, k as i32) - 1,
- 1
)); ));
} }
} }
@ -314,14 +313,20 @@ impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeli
for i in 0..3 { for i in 0..3 {
for j in 0..3 { for j in 0..3 {
for k in 0..3 { for k in 0..3 {
lights[k][j][i] = if blocks[k][j][i].map(|block| block.is_opaque()).unwrap_or(false) { lights[k][j][i] = if blocks[k][j][i]
.map(|block| block.is_opaque())
.unwrap_or(false)
{
None None
} else { } else {
Some(light(Vec3::new( Some(light(
Vec3::new(
x + range.min.x, x + range.min.x,
y + range.min.y, y + range.min.y,
z_start + range.min.z, z_start + range.min.z,
) + Vec3::new(i as i32, j as i32, k as i32) - 1)) ) + Vec3::new(i as i32, j as i32, k as i32)
- 1,
))
}; };
} }
} }
@ -344,7 +349,6 @@ impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeli
blocks[0] = blocks[1]; blocks[0] = blocks[1];
blocks[1] = blocks[2]; blocks[1] = blocks[2];
for i in 0..3 { for i in 0..3 {
for j in 0..3 { for j in 0..3 {
let block = Some(flat_get(pos + Vec3::new(i as i32, j as i32, 2) - 1)); let block = Some(flat_get(pos + Vec3::new(i as i32, j as i32, 2) - 1));
@ -353,10 +357,15 @@ impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeli
} }
for i in 0..3 { for i in 0..3 {
for j in 0..3 { for j in 0..3 {
lights[2][j][i] = if blocks[2][j][i].map(|block| block.is_opaque()).unwrap_or(false) { lights[2][j][i] = if blocks[2][j][i]
.map(|block| block.is_opaque())
.unwrap_or(false)
{
None None
} else { } else {
Some(light(pos + range.min + Vec3::new(i as i32, j as i32, 2) - 1)) Some(light(
pos + range.min + Vec3::new(i as i32, j as i32, 2) - 1,
))
}; };
} }
} }

View File

@ -39,10 +39,8 @@ fn get_ao_quad(
for x in 0..2 { for x in 0..2 {
for y in 0..2 { for y in 0..2 {
let dark_pos = shift + offs[0] * x + offs[1] * y + 1; let dark_pos = shift + offs[0] * x + offs[1] * y + 1;
if let Some(dark) = darknesses if let Some(dark) =
[dark_pos.z as usize] darknesses[dark_pos.z as usize][dark_pos.y as usize][dark_pos.x as usize]
[dark_pos.y as usize]
[dark_pos.x as usize]
{ {
darkness += dark; darkness += dark;
total += 1.0; total += 1.0;

View File

@ -369,10 +369,13 @@ impl Civs {
.expect("Track locations must be neighbors") .expect("Track locations must be neighbors")
.0; .0;
ctx.sim.get_mut(locs[0]).unwrap().path.neighbors |= 1 << ((to_prev_idx as u8 + 4) % 8); ctx.sim.get_mut(locs[0]).unwrap().path.neighbors |=
ctx.sim.get_mut(locs[2]).unwrap().path.neighbors |= 1 << ((to_next_idx as u8 + 4) % 8); 1 << ((to_prev_idx as u8 + 4) % 8);
ctx.sim.get_mut(locs[2]).unwrap().path.neighbors |=
1 << ((to_next_idx as u8 + 4) % 8);
let mut chunk = ctx.sim.get_mut(locs[1]).unwrap(); let mut chunk = ctx.sim.get_mut(locs[1]).unwrap();
chunk.path.neighbors |= (1 << (to_prev_idx as u8)) | (1 << (to_next_idx as u8)); chunk.path.neighbors |=
(1 << (to_prev_idx as u8)) | (1 << (to_next_idx as u8));
chunk.path.offset = Vec2::new( chunk.path.offset = Vec2::new(
ctx.rng.gen_range(-16.0, 16.0), ctx.rng.gen_range(-16.0, 16.0),
ctx.rng.gen_range(-16.0, 16.0), ctx.rng.gen_range(-16.0, 16.0),

View File

@ -221,7 +221,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
sim.gen_ctx.turb_x_nz.get((wposf.div(48.0)).into_array()) as f32, sim.gen_ctx.turb_x_nz.get((wposf.div(48.0)).into_array()) as f32,
sim.gen_ctx.turb_y_nz.get((wposf.div(48.0)).into_array()) as f32, sim.gen_ctx.turb_y_nz.get((wposf.div(48.0)).into_array()) as f32,
) * 12.0; ) * 12.0;
let wposf_turb = wposf;// + turb.map(|e| e as f64); let wposf_turb = wposf; // + turb.map(|e| e as f64);
let chaos = sim.get_interpolated(wpos, |chunk| chunk.chaos)?; let chaos = sim.get_interpolated(wpos, |chunk| chunk.chaos)?;
let temp = sim.get_interpolated(wpos, |chunk| chunk.temp)?; let temp = sim.get_interpolated(wpos, |chunk| chunk.temp)?;
@ -590,12 +590,9 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
let near_cliffs = sim_chunk.near_cliffs; let near_cliffs = sim_chunk.near_cliffs;
let river_gouge = 0.5; let river_gouge = 0.5;
let (_in_water, water_dist, alt_, water_level, riverless_alt, warp_factor) = if let Some(( let (_in_water, water_dist, alt_, water_level, riverless_alt, warp_factor) = if let Some(
max_border_river_pos, (max_border_river_pos, river_chunk, max_border_river, max_border_river_dist),
river_chunk, ) =
max_border_river,
max_border_river_dist,
)) =
max_river max_river
{ {
// This is flowing into a lake, or a lake, or is at least a non-ocean tile. // This is flowing into a lake, or a lake, or is at least a non-ocean tile.

View File

@ -1,13 +1,13 @@
use std::f32;
use vek::*;
use common::{
terrain::{Block, BlockKind},
vol::{BaseVol, ReadVol, RectSizedVol, Vox, WriteVol},
};
use crate::{ use crate::{
column::ColumnSample, column::ColumnSample,
util::{RandomField, Sampler}, util::{RandomField, Sampler},
}; };
use common::{
terrain::{Block, BlockKind},
vol::{BaseVol, ReadVol, RectSizedVol, Vox, WriteVol},
};
use std::f32;
use vek::*;
pub fn apply_paths_to<'a>( pub fn apply_paths_to<'a>(
wpos2d: Vec2<i32>, wpos2d: Vec2<i32>,
@ -37,7 +37,8 @@ pub fn apply_paths_to<'a>(
}) })
}; };
if let Some((path_dist, path_nearest)) = col_sample.path.filter(|(dist, _)| *dist < 5.0) { if let Some((path_dist, path_nearest)) = col_sample.path.filter(|(dist, _)| *dist < 5.0)
{
let inset = 0; let inset = 0;
// Try to use the column at the centre of the path for sampling to make them // Try to use the column at the centre of the path for sampling to make them
@ -47,7 +48,9 @@ pub fn apply_paths_to<'a>(
let col10 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 0)); let col10 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 0));
let col01 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 1)); let col01 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 1));
let col11 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 1)); let col11 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 1));
let col_attr = |col: &ColumnSample| Vec3::new(col.riverless_alt, col.alt, col.water_dist.unwrap_or(1000.0)); let col_attr = |col: &ColumnSample| {
Vec3::new(col.riverless_alt, col.alt, col.water_dist.unwrap_or(1000.0))
};
let [riverless_alt, alt, water_dist] = match (col00, col10, col01, col11) { let [riverless_alt, alt, water_dist] = match (col00, col10, col01, col11) {
(Some(col00), Some(col10), Some(col01), Some(col11)) => Lerp::lerp( (Some(col00), Some(col10), Some(col01), Some(col11)) => Lerp::lerp(
Lerp::lerp(col_attr(col00), col_attr(col10), path_nearest.x.fract()), Lerp::lerp(col_attr(col00), col_attr(col10), path_nearest.x.fract()),
@ -55,7 +58,8 @@ pub fn apply_paths_to<'a>(
path_nearest.y.fract(), path_nearest.y.fract(),
), ),
_ => col_attr(col_sample), _ => col_attr(col_sample),
}.into_array(); }
.into_array();
let (bridge_offset, depth) = ( let (bridge_offset, depth) = (
((water_dist.max(0.0) * 0.2).min(f32::consts::PI).cos() + 1.0) * 5.0, ((water_dist.max(0.0) * 0.2).min(f32::consts::PI).cos() + 1.0) * 5.0,
((1.0 - ((water_dist + 2.0) * 0.3).min(0.0).cos().abs()) ((1.0 - ((water_dist + 2.0) * 0.3).min(0.0).cos().abs())
@ -71,7 +75,9 @@ pub fn apply_paths_to<'a>(
if bridge_offset >= 2.0 && path_dist >= 3.0 || z < inset - 1 { if bridge_offset >= 2.0 && path_dist >= 3.0 || z < inset - 1 {
Block::new(BlockKind::Normal, noisy_color(Rgb::new(80, 80, 100), 8)) Block::new(BlockKind::Normal, noisy_color(Rgb::new(80, 80, 100), 8))
} else { } else {
let path_color = col_sample.sub_surface_color.map(|e| (e * 255.0 * 0.7) as u8); let path_color = col_sample
.sub_surface_color
.map(|e| (e * 255.0 * 0.7) as u8);
Block::new(BlockKind::Normal, noisy_color(path_color, 8)) Block::new(BlockKind::Normal, noisy_color(path_color, 8))
}, },
); );

View File

@ -7,9 +7,9 @@ mod block;
pub mod civ; pub mod civ;
mod column; mod column;
pub mod config; pub mod config;
pub mod layer;
pub mod sim; pub mod sim;
pub mod site; pub mod site;
pub mod layer;
pub mod util; pub mod util;
// Reexports // Reexports

View File

@ -147,8 +147,16 @@ impl MapConfig {
let pos = let pos =
(focus_rect + Vec2::new(i as f64, j as f64) * scale).map(|e: f64| e as i32); (focus_rect + Vec2::new(i as f64, j as f64) * scale).map(|e: f64| e as i32);
let (alt, basement, water_alt, humidity, temperature, downhill, river_kind, is_path) = let (
sampler alt,
basement,
water_alt,
humidity,
temperature,
downhill,
river_kind,
is_path,
) = sampler
.get(pos) .get(pos)
.map(|sample| { .map(|sample| {
( (

View File

@ -27,10 +27,7 @@ use crate::{
all::ForestKind, all::ForestKind,
civ::Place, civ::Place,
site::Site, site::Site,
util::{ util::{seed_expan, FastNoise, RandomField, StructureGen2d, LOCALITY, NEIGHBORS},
seed_expan, FastNoise, RandomField, StructureGen2d, LOCALITY,
NEIGHBORS,
},
CONFIG, CONFIG,
}; };
use common::{ use common::{

View File

@ -8,9 +8,7 @@ pub struct PathData {
} }
impl PathData { impl PathData {
pub fn is_path(&self) -> bool { pub fn is_path(&self) -> bool { self.neighbors != 0 }
self.neighbors != 0
}
} }
impl Default for PathData { impl Default for PathData {

View File

@ -3,7 +3,7 @@ use crate::{
column::ColumnSample, column::ColumnSample,
sim::WorldSim, sim::WorldSim,
site::BlockMask, site::BlockMask,
util::{attempt, DIRS, CARDINALS, Grid, RandomField, Sampler}, util::{attempt, Grid, RandomField, Sampler, CARDINALS, DIRS},
}; };
use common::{ use common::{
assets, assets,
@ -118,16 +118,17 @@ impl Dungeon {
}; };
if area.contains_point(Vec2::zero()) { if area.contains_point(Vec2::zero()) {
let offs = Vec2::new( let offs = Vec2::new(rng.gen_range(-1.0, 1.0), rng.gen_range(-1.0, 1.0))
rng.gen_range(-1.0, 1.0), .try_normalized()
rng.gen_range(-1.0, 1.0), .unwrap_or(Vec2::unit_y())
).try_normalized().unwrap_or(Vec2::unit_y()) * 16.0; * 16.0;
supplement.add_entity(EntityInfo::at(Vec3::new( supplement.add_entity(
self.origin.x, EntityInfo::at(
self.origin.y, Vec3::new(self.origin.x, self.origin.y, self.alt + 4).map(|e| e as f32)
self.alt + 4, + Vec3::from(offs),
).map(|e| e as f32) + Vec3::from(offs)) )
.into_waypoint()); .into_waypoint(),
);
} }
let mut z = self.alt; let mut z = self.alt;

View File

@ -312,19 +312,28 @@ impl Archetype for House {
if dist == width && profile.y < roof_level { if dist == width && profile.y < roof_level {
// Doors // Doors
if center_offset.x > 0 && center_offset.y > 0 if center_offset.x > 0
&& bound_offset.x > 0 && bound_offset.x < width && center_offset.y > 0
&& bound_offset.x > 0
&& bound_offset.x < width
&& profile.y < ceil_height && profile.y < ceil_height
&& branch.attr.storey_fill.has_lower() && branch.attr.storey_fill.has_lower()
{ {
return Some(if (bound_offset.x == (width - 1) / 2 || bound_offset.x == (width - 1) / 2 + 1) && profile.y <= foundation_height + 3 { return Some(
if (bound_offset.x == (width - 1) / 2
|| bound_offset.x == (width - 1) / 2 + 1)
&& profile.y <= foundation_height + 3
{
if profile.y == foundation_height + 1 { if profile.y == foundation_height + 1 {
BlockMask::new( BlockMask::new(
Block::new(BlockKind::Door, if bound_offset.x == (width - 1) / 2 { Block::new(
BlockKind::Door,
if bound_offset.x == (width - 1) / 2 {
make_meta(ori.flip()) make_meta(ori.flip())
} else { } else {
make_meta(ori.flip()) + Rgb::new(4, 0, 0) make_meta(ori.flip()) + Rgb::new(4, 0, 0)
}), },
),
structural_layer, structural_layer,
) )
} else { } else {
@ -332,7 +341,8 @@ impl Archetype for House {
} }
} else { } else {
wall wall
}); },
);
} }
if bound_offset.x == bound_offset.y || profile.y == ceil_height { if bound_offset.x == bound_offset.y || profile.y == ceil_height {

View File

@ -8,6 +8,7 @@ use crate::{
util::{RandomField, Sampler, StructureGen2d}, util::{RandomField, Sampler, StructureGen2d},
}; };
use common::{ use common::{
assets,
astar::Astar, astar::Astar,
comp::{self, bird_medium, humanoid, quadruped_small}, comp::{self, bird_medium, humanoid, quadruped_small},
generation::{ChunkSupplement, EntityInfo}, generation::{ChunkSupplement, EntityInfo},
@ -16,7 +17,6 @@ use common::{
store::{Id, Store}, store::{Id, Store},
terrain::{Block, BlockKind, TerrainChunkSize}, terrain::{Block, BlockKind, TerrainChunkSize},
vol::{BaseVol, ReadVol, RectSizedVol, RectVolSize, Vox, WriteVol}, vol::{BaseVol, ReadVol, RectSizedVol, RectVolSize, Vox, WriteVol},
assets,
}; };
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use rand::prelude::*; use rand::prelude::*;
@ -341,7 +341,8 @@ impl Settlement {
.tile_at(tile_pos) .tile_at(tile_pos)
.map(|t| t.contains(WayKind::Path)) .map(|t| t.contains(WayKind::Path))
.unwrap_or(true) .unwrap_or(true)
|| ctx.sim || ctx
.sim
.and_then(|sim| sim.get_nearest_path(self.origin + house_pos)) .and_then(|sim| sim.get_nearest_path(self.origin + house_pos))
.map(|(dist, _)| dist < 28.0) .map(|(dist, _)| dist < 28.0)
.unwrap_or(false) .unwrap_or(false)
@ -548,9 +549,8 @@ impl Settlement {
} else { } else {
let mut surface_block = None; let mut surface_block = None;
let roll = |seed, n| { let roll =
self.noise.get(Vec3::new(wpos2d.x, wpos2d.y, seed * 5)) % n |seed, n| self.noise.get(Vec3::new(wpos2d.x, wpos2d.y, seed * 5)) % n;
};
let color = match sample.plot { let color = match sample.plot {
Some(Plot::Dirt) => Some(Rgb::new(90, 70, 50)), Some(Plot::Dirt) => Some(Rgb::new(90, 70, 50)),
@ -558,16 +558,21 @@ impl Settlement {
Some(Plot::Water) => Some(Rgb::new(100, 150, 250)), Some(Plot::Water) => Some(Rgb::new(100, 150, 250)),
Some(Plot::Town) => { Some(Plot::Town) => {
if let Some((_, path_nearest)) = col_sample.path { if let Some((_, path_nearest)) = col_sample.path {
let path_dir = (path_nearest - wpos2d.map(|e| e as f32)).rotated_z(f32::consts::PI / 2.0).normalized(); let path_dir = (path_nearest - wpos2d.map(|e| e as f32))
.rotated_z(f32::consts::PI / 2.0)
.normalized();
let is_lamp = if path_dir.x.abs() > path_dir.y.abs() { let is_lamp = if path_dir.x.abs() > path_dir.y.abs() {
wpos2d.x as f32 % 20.0 / path_dir.dot(Vec2::unit_y()).abs() <= 1.0 wpos2d.x as f32 % 20.0 / path_dir.dot(Vec2::unit_y()).abs()
<= 1.0
} else { } else {
wpos2d.y as f32 % 20.0 / path_dir.dot(Vec2::unit_x()).abs() <= 1.0 wpos2d.y as f32 % 20.0 / path_dir.dot(Vec2::unit_x()).abs()
<= 1.0
}; };
if (col_sample.path.map(|(dist, _)| dist > 6.0 && dist < 7.0).unwrap_or(false) && is_lamp) //roll(0, 50) == 0) if (col_sample.path.map(|(dist, _)| dist > 6.0 && dist < 7.0).unwrap_or(false) && is_lamp) //roll(0, 50) == 0)
|| roll(0, 2000) == 0 || roll(0, 2000) == 0
{ {
surface_block = Some(Block::new(BlockKind::StreetLamp, Rgb::white())); surface_block =
Some(Block::new(BlockKind::StreetLamp, Rgb::white()));
} }
} }
@ -804,14 +809,18 @@ impl Settlement {
}, },
_ => comp::Body::Humanoid(humanoid::Body::random()), _ => comp::Body::Humanoid(humanoid::Body::random()),
}) })
.do_if(rng.gen(), |entity| entity.with_main_tool(assets::load_expect_cloned(match rng.gen_range(0, 6) { .do_if(rng.gen(), |entity| {
entity.with_main_tool(assets::load_expect_cloned(
match rng.gen_range(0, 6) {
0 => "common.items.weapons.starter_axe", 0 => "common.items.weapons.starter_axe",
1 => "common.items.weapons.starter_sword", 1 => "common.items.weapons.starter_sword",
2 => "common.items.weapons.short_sword_0", 2 => "common.items.weapons.short_sword_0",
3 => "common.items.weapons.hammer_1", 3 => "common.items.weapons.hammer_1",
4 => "common.items.weapons.starter_staff", 4 => "common.items.weapons.starter_staff",
_ => "common.items.weapons.starter_bow", _ => "common.items.weapons.starter_bow",
}))) },
))
})
.with_automatic_name(); .with_automatic_name();
supplement.add_entity(entity); supplement.add_entity(entity);