diff --git a/common/src/lib.rs b/common/src/lib.rs index 6f0632e0b6..f5bf9ef71a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -22,6 +22,7 @@ pub mod event; pub mod figure; pub mod generation; pub mod loadout_builder; +pub mod lottery; pub mod msg; pub mod npc; pub mod outcome; @@ -39,6 +40,5 @@ pub mod terrain; pub mod util; pub mod vol; pub mod volumes; -pub mod lottery; pub use loadout_builder::LoadoutBuilder; diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs index 8dc66fae2b..6dc9d5cf42 100644 --- a/common/src/sys/agent.rs +++ b/common/src/sys/agent.rs @@ -151,6 +151,7 @@ impl<'a> System<'a> for Sys { const SEARCH_DIST: f32 = 48.0; const SIGHT_DIST: f32 = 128.0; const MIN_ATTACK_DIST: f32 = 3.5; + const MAX_FLEE_DIST: f32 = 32.0; let scale = scales.get(entity).map(|s| s.0).unwrap_or(1.0); @@ -306,27 +307,31 @@ impl<'a> System<'a> for Sys { // Flee if 1.0 - agent.psyche.aggro > damage { - if let Some((bearing, speed)) = chaser.chase( - &*terrain, - pos.0, - vel.0, - // Away from the target (ironically) - tgt_pos.0 + (pos.0 - tgt_pos.0) - .try_normalized() - .unwrap_or_else(Vec3::unit_y) * 32.0, - TraversalConfig { - node_tolerance, - slow_factor, - on_ground: physics_state.on_ground, - min_tgt_dist: 1.25, - }, - ) { - inputs.move_dir = Vec2::from(bearing) - .try_normalized() - .unwrap_or(Vec2::zero()) - * speed; - inputs.jump.set_state(bearing.z > 1.5); - inputs.swim.set_state(bearing.z > 0.5); + if dist_sqrd < MAX_FLEE_DIST.powf(2.0) { + if let Some((bearing, speed)) = chaser.chase( + &*terrain, + pos.0, + vel.0, + // Away from the target (ironically) + pos.0 + (pos.0 - tgt_pos.0) + .try_normalized() + .unwrap_or_else(Vec3::unit_y) * 8.0, + TraversalConfig { + node_tolerance, + slow_factor, + on_ground: physics_state.on_ground, + min_tgt_dist: 1.25, + }, + ) { + inputs.move_dir = Vec2::from(bearing) + .try_normalized() + .unwrap_or(Vec2::zero()) + * speed; + inputs.jump.set_state(bearing.z > 1.5); + inputs.swim.set_state(bearing.z > 0.5); + } + } else { + do_idle = true; } } else if dist_sqrd < (MIN_ATTACK_DIST * scale).powf(2.0) { // Close-range attack diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 0df848919c..b3cec5dca2 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -157,9 +157,9 @@ impl<'a> System<'a> for Sys { z_max, } => { // Scale collider - let radius = *radius * scale; - let z_min = *z_min * scale; - let z_max = *z_max * scale; + let radius = *radius;// * scale; + let z_min = *z_min;// * scale; + let z_max = *z_max;// * scale; // Probe distances let hdist = radius.ceil() as i32; diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index e37ceb1847..739d1988b1 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -319,12 +319,12 @@ impl<'a> System<'a> for Sys { pos: Pos(entity.pos), stats, loadout, - body, agent: if entity.has_agency { - Some(comp::Agent::new(entity.pos, can_speak)) + Some(comp::Agent::new(entity.pos, can_speak, &body)) } else { None }, + body, alignment, scale: comp::Scale(scale), drop_item: entity.loot_drop, diff --git a/world/src/layer/mod.rs b/world/src/layer/mod.rs index fde2b3fa49..687eb44bd8 100644 --- a/world/src/layer/mod.rs +++ b/world/src/layer/mod.rs @@ -4,13 +4,16 @@ use crate::{ Index, }; use common::{ + assets, + lottery::Lottery, terrain::{Block, BlockKind}, vol::{BaseVol, ReadVol, RectSizedVol, Vox, WriteVol}, - lottery::Lottery, - assets, }; use noise::NoiseFn; -use std::{f32, ops::{Sub, Mul}}; +use std::{ + f32, + ops::{Mul, Sub}, +}; use vek::*; pub fn apply_paths_to<'a>( @@ -136,28 +139,49 @@ pub fn apply_caves_to<'a>( let cave_roof = (cave.alt + cave_height) as i32; for z in cave_base..cave_roof { - let _ = vol.set(Vec3::new(offs.x, offs.y, z), Block::empty()); + if cave_x < 0.95 + || index.noise.cave_nz.get( + Vec3::new(wpos2d.x, wpos2d.y, z) + .map(|e| e as f64 * 0.15) + .into_array(), + ) < 0.0 + { + let _ = vol.set(Vec3::new(offs.x, offs.y, z), Block::empty()); + } } // Stalagtites - let stalagtites = index.noise.cave_nz - .get(wpos2d.map(|e| e as f64 * 0.1).into_array()) - .sub(0.6) + let stalagtites = index + .noise + .cave_nz + .get(wpos2d.map(|e| e as f64 * 0.125).into_array()) + .sub(0.5) .max(0.0) - .mul((col_sample.alt - cave_roof as f32 - 5.0).mul(0.15).clamped(0.0, 1.0) as f64) - .mul(40.0) as i32; + .mul( + (col_sample.alt - cave_roof as f32 - 5.0) + .mul(0.15) + .clamped(0.0, 1.0) as f64, + ) + .mul(45.0) as i32; for z in cave_roof - stalagtites..cave_roof { - let _ = vol.set(Vec3::new(offs.x, offs.y, z), Block::new(BlockKind::Normal, Rgb::broadcast(200))); + let _ = vol.set( + Vec3::new(offs.x, offs.y, z), + Block::new(BlockKind::Rock, Rgb::broadcast(200)), + ); } // Scatter things in caves - if RandomField::new(index.seed).chance(wpos2d.into(), 0.001) && cave_base < surface_z as i32 - 25 { + if RandomField::new(index.seed).chance(wpos2d.into(), 0.001) + && cave_base < surface_z as i32 - 25 + { let kind = *assets::load_expect::>("common.cave_scatter") .choose_seeded(RandomField::new(index.seed + 1).get(wpos2d.into())); - let _ = vol.set(Vec3::new(offs.x, offs.y, cave_base), Block::new(kind, Rgb::zero())); + let _ = vol.set( + Vec3::new(offs.x, offs.y, cave_base), + Block::new(kind, Rgb::zero()), + ); } - } } } diff --git a/world/src/site/castle/mod.rs b/world/src/site/castle/mod.rs index 307c888568..60b570bb99 100644 --- a/world/src/site/castle/mod.rs +++ b/world/src/site/castle/mod.rs @@ -33,7 +33,7 @@ use vek::*; struct Keep { offset: Vec2, locus: i32, - height: i32, + storeys: i32, is_tower: bool, alt: i32, } @@ -123,12 +123,12 @@ impl Castle { let locus = ctx.rng.gen_range(20, 26); let offset = (dir * dist).map(|e| e as i32); - let height = ctx.rng.gen_range(25, 70).clamped(30, 48); + let storeys = ctx.rng.gen_range(1, 5).clamped(2, 3); Keep { offset, locus, - height, + storeys, is_tower: true, alt: ctx .sim @@ -301,7 +301,7 @@ impl Castle { 4, 0, &Attr { - height: 16, + storeys: 1, is_tower: false, ridged: false, rounded: true, @@ -336,7 +336,7 @@ impl Castle { tower_locus, 0, &Attr { - height: 28, + storeys: 2, is_tower: true, ridged: false, rounded: self.rounded_towers, @@ -371,7 +371,7 @@ impl Castle { keep.locus, 0, &Attr { - height: keep.height, + storeys: keep.storeys, is_tower: keep.is_tower, ridged: true, rounded: self.rounded_towers, diff --git a/world/src/site/dungeon/mod.rs b/world/src/site/dungeon/mod.rs index 42476f53c6..f95adc2cf8 100644 --- a/world/src/site/dungeon/mod.rs +++ b/world/src/site/dungeon/mod.rs @@ -408,10 +408,12 @@ impl Floor { * FLOOR_SIZE.x as f32 / 2.0 - 8.0; - supplement.add_entity( - EntityInfo::at((origin + stair_rcenter).map(|e| e as f32) + Vec3::from(offs)) - .into_waypoint(), - ); + if !self.final_level { + supplement.add_entity( + EntityInfo::at((origin + stair_rcenter).map(|e| e as f32) + Vec3::from(offs)) + .into_waypoint(), + ); + } } for x in area.min.x..area.max.x { diff --git a/world/src/site/settlement/building/archetype/keep.rs b/world/src/site/settlement/building/archetype/keep.rs index 3f234dc737..ee197e3848 100644 --- a/world/src/site/settlement/building/archetype/keep.rs +++ b/world/src/site/settlement/building/archetype/keep.rs @@ -1,5 +1,8 @@ use super::{super::skeleton::*, Archetype}; -use crate::site::BlockMask; +use crate::{ + site::BlockMask, + util::{RandomField, Sampler}, +}; use common::{ terrain::{Block, BlockKind}, vol::Vox, @@ -12,7 +15,7 @@ pub struct Keep { } pub struct Attr { - pub height: i32, + pub storeys: i32, pub is_tower: bool, pub ridged: bool, pub rounded: bool, @@ -29,7 +32,7 @@ impl Archetype for Keep { root: Branch { len, attr: Attr { - height: rng.gen_range(12, 16), + storeys: 1, is_tower: false, ridged: false, rounded: true, @@ -43,12 +46,12 @@ impl Archetype for Keep { Branch { len: 0, attr: Attr { - height: rng.gen_range(20, 28), + storeys: 2, is_tower: true, ridged: false, rounded: true, }, - locus: 4 + rng.gen_range(0, 5), + locus: 6 + rng.gen_range(0, 3), border: 3, children: Vec::new(), }, @@ -93,8 +96,10 @@ impl Archetype for Keep { ) }; - let foundation = make_block(100, 100, 100); - let wall = make_block(100, 100, 110); + let brick_tex_pos = (pos + Vec3::new(pos.z, pos.z, 0)) / Vec3::new(2, 2, 1); + let brick_tex = RandomField::new(0).get(brick_tex_pos) as u8 % 24; + let foundation = make_block(80 + brick_tex, 80 + brick_tex, 80 + brick_tex); + let wall = make_block(100 + brick_tex, 100 + brick_tex, 110 + brick_tex); let floor = make_block( 80 + (pos.y.abs() % 2) as u8 * 15, 60 + (pos.y.abs() % 2) as u8 * 15, @@ -107,6 +112,26 @@ impl Archetype for Keep { let internal = BlockMask::new(Block::empty(), internal_layer); let empty = BlockMask::nothing(); + let make_staircase = move |pos: Vec3, radius: f32, inner_radius: f32, stretch: f32| { + let stone = BlockMask::new(Block::new(BlockKind::Normal, Rgb::new(150, 150, 175)), 5); + + if (pos.xy().magnitude_squared() as f32) < inner_radius.powf(2.0) { + stone + } else if (pos.xy().magnitude_squared() as f32) < radius.powf(2.0) { + if ((pos.x as f32).atan2(pos.y as f32) / (std::f32::consts::PI * 2.0) * stretch + + pos.z as f32) + .rem_euclid(stretch) + < 1.5 + { + stone + } else { + internal + } + } else { + BlockMask::nothing() + } + }; + let edge_pos = if (bound_offset.x.abs() > bound_offset.y.abs()) ^ (ori == Ori::East) { pos.y } else { @@ -114,15 +139,16 @@ impl Archetype for Keep { }; let width = locus - + if edge_pos % 4 == 0 && attr.ridged && !attr.rounded { + + if (edge_pos + 1000) % 8 < 4 && attr.ridged && !attr.rounded { 1 } else { 0 }; let rampart_width = 2 + width; - let ceil_height = attr.height; + let storey_height = 16; + let roof_height = attr.storeys * storey_height; let door_height = 6; - let rampart_height = ceil_height + if edge_pos % 2 == 0 { 3 } else { 4 }; + let rampart_height = roof_height + if edge_pos % 2 == 0 { 3 } else { 4 }; let min_dist = if attr.rounded { bound_offset.map(|e| e.pow(2) as f32).sum().powf(0.5) as i32 } else { @@ -132,31 +158,32 @@ impl Archetype for Keep { if profile.y <= 0 - (min_dist - width - 1).max(0) && min_dist < width + 3 { // Foundations foundation - } else if profile.y == ceil_height && min_dist < rampart_width { + } else if (0..=roof_height).contains(&profile.y) && profile.y % storey_height == 0 && min_dist < rampart_width { if min_dist < width { floor } else { wall } } else if !attr.is_tower && bound_offset.x.abs() == 4 && min_dist == width + 1 - && profile.y < ceil_height + && profile.y < roof_height { wall } else if bound_offset.x.abs() < 3 && profile.y < door_height - bound_offset.x.abs() && profile.y > 0 + && min_dist >= width - 2 { internal - } else if min_dist == width && profile.y <= ceil_height { + } else if min_dist == width && profile.y <= roof_height { wall - } else if profile.y >= ceil_height { - if profile.y > ceil_height && min_dist < rampart_width { - if attr.is_tower && center_offset == Vec2::zero() && profile.y < ceil_height + 16 { + } else if profile.y >= roof_height { + if profile.y > roof_height && min_dist < rampart_width { + if attr.is_tower && center_offset == Vec2::zero() && profile.y < roof_height + 16 { pole } else if attr.is_tower && center_offset.x == 0 && center_offset.y > 0 && center_offset.y < 8 - && profile.y > ceil_height + 8 - && profile.y < ceil_height + 14 + && profile.y > roof_height + 8 + && profile.y < roof_height + 14 { flag } else { @@ -171,10 +198,20 @@ impl Archetype for Keep { } else { empty } - } else if profile.y < ceil_height && min_dist < width { + } else if profile.y < roof_height && min_dist < width { internal } else { empty } + .resolve_with(if attr.is_tower && profile.y > 0 && profile.y <= roof_height { + make_staircase( + Vec3::new(center_offset.x, center_offset.y, pos.z), + 7.0f32.min(width as f32 - 1.0), + 0.5, + 9.0, + ) + } else { + BlockMask::nothing() + }) } }