From c77270b799357c63637fd7aef5eae732fe9dc207 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 12 Feb 2022 20:52:01 -0500 Subject: [PATCH] Addressed feedback --- Cargo.lock | 1 - common/src/comp/body.rs | 10 +++- server/src/sys/agent/attack.rs | 38 ++++++++++++-- server/src/sys/agent/util.rs | 11 +++- world/Cargo.toml | 2 +- world/src/civ/mod.rs | 2 +- world/src/lib.rs | 13 ++++- world/src/site/mod.rs | 3 ++ world/src/site2/mod.rs | 13 ++++- world/src/site2/plot/gnarling.rs | 90 +++++++++++++++----------------- 10 files changed, 120 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d2c0880804..e6da5aea7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6656,7 +6656,6 @@ dependencies = [ "fxhash", "hashbrown 0.11.2", "image", - "inline_tweak", "itertools", "kiddo 0.2.1", "lazy_static", diff --git a/common/src/comp/body.rs b/common/src/comp/body.rs index 97f9e5462c..782fc0a2d0 100644 --- a/common/src/comp/body.rs +++ b/common/src/comp/body.rs @@ -700,6 +700,7 @@ impl Body { _ => 1000, }, Body::Golem(golem) => match golem.species { + golem::Species::WoodGolem => 200, golem::Species::ClayGolem => 450, _ => 1000, }, @@ -778,7 +779,14 @@ impl Body { _ => false, }, BuffKind::Regeneration => { - matches!(self, Body::Object(object::Body::GnarlingTotemGreen)) + matches!( + self, + Body::Object( + object::Body::GnarlingTotemRed + | object::Body::GnarlingTotemGreen + | object::Body::GnarlingTotemWhite + ) + ) }, _ => false, } diff --git a/server/src/sys/agent/attack.rs b/server/src/sys/agent/attack.rs index e0fe4e8b5b..b82651f943 100644 --- a/server/src/sys/agent/attack.rs +++ b/server/src/sys/agent/attack.rs @@ -142,10 +142,24 @@ impl<'a> AgentData<'a> { ..self.traversal_config }, ) { - controller.inputs.move_dir = - -bearing.xy().try_normalized().unwrap_or_else(Vec2::zero); - if !self.char_state.is_attack() { - controller.inputs.look_dir = -controller.inputs.look_dir; + let flee_dir = -bearing.xy().try_normalized().unwrap_or_else(Vec2::zero); + let pos = self.pos.0.xy().with_z(self.pos.0.z + 1.5); + if read_data + .terrain + .ray(pos, pos + flee_dir * 2.0) + .until(|b| b.is_solid() || b.get_sprite().is_none()) + .cast() + .0 + > 1.0 + { + // If able to flee, flee + controller.inputs.move_dir = flee_dir; + if !self.char_state.is_attack() { + controller.inputs.look_dir = -controller.inputs.look_dir; + } + } else { + // Otherwise, fight to the death + controller.push_basic_input(InputKind::Primary); } } } else if attack_data.dist_sqrd < PREF_DIST.powi(2) { @@ -2272,7 +2286,21 @@ impl<'a> AgentData<'a> { } else if agent.action_state.timer > TOTEM_TIMER { // If time to summon a totem, do it let input = rng.gen_range(1..=3); - controller.push_basic_input(InputKind::Ability(input)); + let buff_kind = match input { + 2 => Some(BuffKind::Regeneration), + 3 => Some(BuffKind::Hastened), + _ => None, + }; + if buff_kind.map_or(true, |b| self.has_buff(read_data, b)) + && matches!(self.char_state, CharacterState::Wielding { .. }) + { + // If already under effects of buff from totem that would be summoned, don't + // summon totem (doesn't work for red totems since that applies debuff to + // enemies instead) + agent.action_state.timer = 0.0; + } else { + controller.push_basic_input(InputKind::Ability(input)); + } } else if agent.action_state.counter > HEAVY_ATTACK_WAIT_TIME { // Else if time for a heavy attack if attack_data.in_min_range() { diff --git a/server/src/sys/agent/util.rs b/server/src/sys/agent/util.rs index 46dd91e07b..ac17813ffb 100644 --- a/server/src/sys/agent/util.rs +++ b/server/src/sys/agent/util.rs @@ -1,4 +1,4 @@ -use crate::sys::agent::ReadData; +use crate::sys::agent::{AgentData, ReadData}; use common::{ comp::{buff::BuffKind, Alignment, Pos}, consts::GRAVITY, @@ -70,3 +70,12 @@ pub fn aim_projectile(speed: f32, pos: Vec3, tgt: Vec3) -> Option pub fn get_entity_by_id(id: u64, read_data: &ReadData) -> Option { read_data.uid_allocator.retrieve_entity_internal(id) } + +impl<'a> AgentData<'a> { + pub fn has_buff(&self, read_data: &ReadData, buff: BuffKind) -> bool { + read_data + .buffs + .get(*self.entity) + .map_or(false, |b| b.kinds.contains_key(&buff)) + } +} diff --git a/world/Cargo.toml b/world/Cargo.toml index a4f3892384..7d96e0c93b 100644 --- a/world/Cargo.toml +++ b/world/Cargo.toml @@ -35,7 +35,7 @@ packed_simd = { package = "packed_simd_2", version = "0.3.5", optional = true } rayon = "1.5" serde = { version = "1.0.110", features = ["derive"] } ron = { version = "0.7", default-features = false } -inline_tweak = "1.0.2" +# inline_tweak = "1.0.2" kiddo = "0.2" # compression benchmarks diff --git a/world/src/civ/mod.rs b/world/src/civ/mod.rs index 948e24ffdb..f69026743b 100644 --- a/world/src/civ/mod.rs +++ b/world/src/civ/mod.rs @@ -137,7 +137,7 @@ impl Civs { SiteKind::Refactor => (32i32, 10.0), SiteKind::Tree => (12i32, 8.0), SiteKind::GiantTree => (12i32, 8.0), - SiteKind::Gnarling => (16i32, 5.0), + SiteKind::Gnarling => (16i32, 10.0), }; let (raise, raise_dist, make_waypoint): (f32, i32, bool) = match &site.kind { diff --git a/world/src/lib.rs b/world/src/lib.rs index 0c559b608a..6079a8b3f8 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -44,7 +44,7 @@ use crate::{ column::ColumnGen, index::Index, layer::spot::Spot, - site::SiteKind, + site::{SiteKind, SpawnRules}, util::{Grid, Sampler}, }; use common::{ @@ -410,7 +410,16 @@ impl World { }; if sim_chunk.contains_waypoint { - supplement.add_entity(EntityInfo::at(gen_entity_pos(&mut dynamic_rng)).into_waypoint()); + let waypoint_pos = gen_entity_pos(&mut dynamic_rng); + if sim_chunk + .sites + .iter() + .map(|site| index.sites[*site].spawn_rules(waypoint_pos.xy().as_())) + .fold(SpawnRules::default(), |a, b| a.combine(b)) + .waypoints + { + supplement.add_entity(EntityInfo::at(waypoint_pos).into_waypoint()); + } } // Apply layer supplement diff --git a/world/src/site/mod.rs b/world/src/site/mod.rs index b360e4aeb2..259c2a4eb1 100644 --- a/world/src/site/mod.rs +++ b/world/src/site/mod.rs @@ -27,6 +27,7 @@ pub struct SpawnRules { pub trees: bool, pub max_warp: f32, pub paths: bool, + pub waypoints: bool, } impl SpawnRules { @@ -37,6 +38,7 @@ impl SpawnRules { trees: self.trees && other.trees, max_warp: self.max_warp.min(other.max_warp), paths: self.paths && other.paths, + waypoints: self.waypoints && other.waypoints, } } } @@ -47,6 +49,7 @@ impl Default for SpawnRules { trees: true, max_warp: 1.0, paths: true, + waypoints: true, } } } diff --git a/world/src/site2/mod.rs b/world/src/site2/mod.rs index 9b01c6da9e..dc5d17ae6f 100644 --- a/world/src/site2/mod.rs +++ b/world/src/site2/mod.rs @@ -88,11 +88,20 @@ impl Site { .min_by_key(|d2| *d2 as i32) .map(|d2| d2.sqrt() as f32 / TILE_SIZE as f32) .unwrap_or(1.0); - SpawnRules { + let base_spawn_rules = SpawnRules { trees: max_warp == 1.0, max_warp, paths: max_warp > std::f32::EPSILON, - } + waypoints: true, + }; + self.plots + .values() + .filter_map(|plot| match &plot.kind { + PlotKind::Dungeon(d) => Some(d.spawn_rules(wpos)), + PlotKind::Gnarling(g) => Some(g.spawn_rules(wpos)), + _ => None, + }) + .fold(base_spawn_rules, |a, b| a.combine(b)) } pub fn bounds(&self) -> Aabr { diff --git a/world/src/site2/plot/gnarling.rs b/world/src/site2/plot/gnarling.rs index 8c6046a20d..24e90b0de6 100644 --- a/world/src/site2/plot/gnarling.rs +++ b/world/src/site2/plot/gnarling.rs @@ -221,11 +221,15 @@ impl GnarlingFortification { + corner_2.as_() * corner_2_weight) .as_(); - // Check that structure not too close to another structure - if structure_locations.iter().any(|(kind, loc, _door_dir)| { - structure_center.distance_squared(loc.xy()) - < structure_kind.required_separation(kind).pow(2) - }) { + // Check that structure not in the water or too close to another structure + if land + .get_chunk_wpos(structure_center + origin) + .map_or(false, |c| c.is_underwater()) + || structure_locations.iter().any(|(kind, loc, _door_dir)| { + structure_center.distance_squared(loc.xy()) + < structure_kind.required_separation(kind).pow(2) + }) + { None } else { Some(( @@ -316,6 +320,15 @@ impl GnarlingFortification { pub fn radius(&self) -> i32 { self.radius } + pub fn spawn_rules(&self, wpos: Vec2) -> SpawnRules { + SpawnRules { + trees: wpos.distance_squared(self.origin) > self.wall_radius.pow(2), + waypoints: false, + ..SpawnRules::default() + } + } + + // TODO: Find a better way of spawning entities in site2 pub fn apply_supplement<'a>( &'a self, // NOTE: Used only for dynamic elements like chests and entities! @@ -362,47 +375,45 @@ impl GnarlingFortification { )); } - for (loc, pos, ori) in &self.structure_locations { + for (loc, pos, _ori) in &self.structure_locations { let wpos = *pos + self.origin; if area.contains_point(pos.xy()) { match loc { GnarlingStructure::Hut => { - supplement.add_entity(random_gnarling(wpos, dynamic_rng)); + let num = dynamic_rng.gen_range(2..=3); + for _ in 0..num { + supplement.add_entity(random_gnarling(wpos, dynamic_rng)); + } }, GnarlingStructure::VeloriteHut => { - supplement.add_entity(random_gnarling(wpos, dynamic_rng)); - }, - GnarlingStructure::Banner => { - supplement.add_entity(random_gnarling(wpos, dynamic_rng)); + let num = dynamic_rng.gen_range(2..=6); + for _ in 0..num { + supplement.add_entity(random_gnarling( + wpos.xy().with_z(wpos.z + 12), + dynamic_rng, + )); + } }, + GnarlingStructure::Banner => {}, GnarlingStructure::ChieftainHut => { - supplement.add_entity(gnarling_chieftain( - wpos.xy().with_z(wpos.z + 8), - dynamic_rng, - )); - let left_inner_guard_pos = wpos + ori.dir() * 8 + ori.cw().dir() * 2; - supplement.add_entity(wood_golem(left_inner_guard_pos, dynamic_rng)); - let right_inner_guard_pos = wpos + ori.dir() * 8 + ori.ccw().dir() * 2; - supplement.add_entity(wood_golem(right_inner_guard_pos, dynamic_rng)); - let left_outer_guard_pos = wpos + ori.dir() * 16 + ori.cw().dir() * 2; - supplement.add_entity(random_gnarling(left_outer_guard_pos, dynamic_rng)); - let right_outer_guard_pos = wpos + ori.dir() * 16 + ori.ccw().dir() * 2; - supplement.add_entity(random_gnarling(right_outer_guard_pos, dynamic_rng)); + let pos = wpos.xy().with_z(wpos.z + 8); + supplement.add_entity(gnarling_chieftain(pos, dynamic_rng)); + for _ in 0..2 { + supplement.add_entity(wood_golem(pos, dynamic_rng)); + } }, GnarlingStructure::WatchTower => { supplement.add_entity(wood_golem(wpos, dynamic_rng)); let spawn_pos = wpos.xy().with_z(wpos.z + 27); - for _ in 0..4 { + let num = dynamic_rng.gen_range(2..=4); + for _ in 0..num { supplement.add_entity(gnarling_stalker( spawn_pos + Vec2::broadcast(4), dynamic_rng, )); } }, - GnarlingStructure::Totem => { - let spawn_pos = wpos + pos.xy().map(|x| x.signum() * -5); - supplement.add_entity(wood_golem(spawn_pos, dynamic_rng)); - }, + GnarlingStructure::Totem => {}, } } } @@ -511,7 +522,7 @@ impl Structure for GnarlingFortification { painter .segment_prism(start, end, wall_mid_thickness, wall_mid_height) - .fill(darkwood.clone()); + .fill(darkwood); let start = start_wpos .as_() @@ -850,12 +861,7 @@ impl Structure for GnarlingFortification { painter: &Painter, wpos: Vec2, alt: i32, - _door_dir: Ori, - hut_radius: f32, - _hut_wall_height: f32, - _door_height: i32, roof_height: f32, - _roof_overhang: f32, ) { let darkwood = Fill::Brick(BlockKind::Wood, Rgb::new(55, 25, 8), 12); let lightwood = Fill::Brick(BlockKind::Wood, Rgb::new(71, 33, 11), 12); @@ -1300,23 +1306,9 @@ impl Structure for GnarlingFortification { .fill(Fill::Prefab(Box::new(totem), totem_pos, self.seed)); }, GnarlingStructure::ChieftainHut => { - let hut_radius = 5.0; - let hut_wall_height = 15.0; - let door_height = 3; let roof_height = 3.0; - let roof_overhang = 1.0; - generate_chieftainhut( - painter, - wpos, - alt, - *door_dir, - hut_radius, - hut_wall_height, - door_height, - roof_height, - roof_overhang, - ); + generate_chieftainhut(painter, wpos, alt, roof_height); }, GnarlingStructure::Banner => {