From 0b1a820762c10d03fd778c0be2bb7ff50760cacf Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 30 Aug 2021 16:02:13 +0100 Subject: [PATCH] Make arrows 'bonk' hanging sprites --- common/src/comp/projectile.rs | 3 ++- common/src/event.rs | 5 ++++ common/src/terrain/block.rs | 8 ++++++ common/src/terrain/sprite.rs | 1 + common/systems/src/phys.rs | 7 +++-- common/systems/src/projectile.rs | 16 +++++++++++ server/src/events/entity_manipulation.rs | 34 ++++++++++++++++++++++-- server/src/events/mod.rs | 7 ++--- 8 files changed, 71 insertions(+), 10 deletions(-) diff --git a/common/src/comp/projectile.rs b/common/src/comp/projectile.rs index 27b5ce719b..742fd7283a 100644 --- a/common/src/comp/projectile.rs +++ b/common/src/comp/projectile.rs @@ -19,6 +19,7 @@ pub enum Effect { Vanish, Stick, Possess, + Bonk, // Knock/dislodge/change objects on hit } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -127,7 +128,7 @@ impl ProjectileConstructor { .with_combo_increment(); Projectile { - hit_solid: vec![Effect::Stick], + hit_solid: vec![Effect::Stick, Effect::Bonk], hit_entity: vec![Effect::Attack(attack), Effect::Vanish], time_left: Duration::from_secs(15), owner, diff --git a/common/src/event.rs b/common/src/event.rs index 1d48bac86b..79ae53fbdd 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -42,6 +42,11 @@ pub enum ServerEvent { explosion: Explosion, owner: Option, }, + Bonk { + pos: Vec3, + owner: Option, + target: Option, + }, Damage { entity: EcsEntity, change: comp::HealthChange, diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 5a99767d0b..5f653b2ce3 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -259,6 +259,14 @@ impl Block { .unwrap_or(false) } + #[inline] + pub fn is_bonkable(&self) -> bool { + match self.get_sprite() { + Some(SpriteKind::Apple | SpriteKind::Beehive | SpriteKind::Coconut) => self.is_solid(), + _ => false, + } + } + /// The tool required to mine this block. For blocks that cannot be mined, /// `None` is returned. #[inline] diff --git a/common/src/terrain/sprite.rs b/common/src/terrain/sprite.rs index 9c48b4282b..d7e918dd9d 100644 --- a/common/src/terrain/sprite.rs +++ b/common/src/terrain/sprite.rs @@ -238,6 +238,7 @@ impl SpriteKind { | SpriteKind::MedFlatCactus | SpriteKind::ShortFlatCactus | SpriteKind::Apple + | SpriteKind::Beehive | SpriteKind::Velorite | SpriteKind::VeloriteFrag | SpriteKind::Coconut diff --git a/common/systems/src/phys.rs b/common/systems/src/phys.rs index b75c7e9315..a83ba2ddce 100644 --- a/common/systems/src/phys.rs +++ b/common/systems/src/phys.rs @@ -872,15 +872,14 @@ impl<'a> PhysicsData<'a> { .terrain .get(pos.0.map(|e| e.floor() as i32)) .ok() - .filter(|b| b.is_filled()) - // TODO: `is_solid`, when arrows are special-cased + .filter(|b| b.is_solid()) { (0.0, Some(block)) } else { let (dist, block) = read .terrain .ray(pos.0, pos.0 + pos_delta) - .until(|block: &Block| block.is_filled()) + .until(|block: &Block| block.is_solid()) .ignore_error() .cast(); (dist, block.unwrap()) // Can't fail since we do ignore_error above @@ -897,7 +896,7 @@ impl<'a> PhysicsData<'a> { .zip(read.bodies.get(entity).copied()) { outcomes.push(Outcome::ProjectileHit { - pos: pos.0, + pos: pos.0 + pos_delta * dist, body, vel: vel.0, source: projectile.owner, diff --git a/common/systems/src/projectile.rs b/common/systems/src/projectile.rs index f5c4b3d4c8..44f7fe66cd 100644 --- a/common/systems/src/projectile.rs +++ b/common/systems/src/projectile.rs @@ -181,6 +181,13 @@ impl<'a> System<'a> for Sys { }); projectile_vanished = true; }, + projectile::Effect::Bonk => { + server_emitter.emit(ServerEvent::Bonk { + pos: pos.0, + owner: projectile.owner, + target: None, + }); + }, _ => {}, } } @@ -325,6 +332,15 @@ fn dispatch_hit( owner: owner_uid, }); }, + projectile::Effect::Bonk => { + let Pos(pos) = *projectile_info.pos; + let owner_uid = projectile_info.owner_uid; + server_emitter.emit(ServerEvent::Bonk { + pos, + owner: owner_uid, + target: Some(projectile_target_info.uid), + }); + }, projectile::Effect::Vanish => { let entity = projectile_info.entity; server_emitter.emit(ServerEvent::Destroy { diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 3adbcdbe9a..20ab8f2788 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -37,7 +37,7 @@ use common_state::BlockChange; use comp::chat::GenericChatMsg; use hashbrown::HashSet; use rand::Rng; -use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt}; +use specs::{join::Join, saveload::MarkerAllocator, Builder, Entity as EcsEntity, WorldExt}; use tracing::error; use vek::{Vec2, Vec3}; @@ -378,7 +378,6 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc { // Only drop loot if entity has agency (not a player), and if it is not owned by // another entity (not a pet) - use specs::Builder; // Decide for a loot drop before turning into a lootbag let old_body = state.ecs().write_storage::().remove(entity); @@ -1021,6 +1020,37 @@ pub fn handle_explosion(server: &Server, pos: Vec3, explosion: Explosion, o } } +pub fn handle_bonk(server: &mut Server, pos: Vec3, owner: Option, target: Option) { + let ecs = &server.state.ecs(); + let terrain = ecs.read_resource::(); + let mut block_change = ecs.write_resource::(); + + if let Some(_target) = target { + // TODO: bonk entities but do no damage? + drop(owner); + } else { + use common::terrain::SpriteKind; + let pos = pos.map(|e| e.floor() as i32); + if let Some(block) = terrain.get(pos).ok().copied().filter(|b| b.is_bonkable()) { + if let Some(item) = comp::Item::try_reclaim_from_block(block) { + if block_change + .try_set(pos, block.with_sprite(SpriteKind::Empty)) + .is_some() + { + drop(terrain); + drop(block_change); + server + .state + .create_object(Default::default(), comp::object::Body::Pouch) + .with(comp::Pos(pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0))) + .with(item) + .build(); + } + } + } + } +} + pub fn handle_aura(server: &mut Server, entity: EcsEntity, aura_change: aura::AuraChange) { let ecs = &server.state.ecs(); let mut auras_all = ecs.write_storage::(); diff --git a/server/src/events/mod.rs b/server/src/events/mod.rs index af3d2baeed..ee78736acc 100644 --- a/server/src/events/mod.rs +++ b/server/src/events/mod.rs @@ -6,9 +6,9 @@ use entity_creation::{ handle_initialize_character, handle_loaded_character_data, handle_shockwave, handle_shoot, }; use entity_manipulation::{ - handle_aura, handle_buff, handle_combo_change, handle_damage, handle_delete, handle_destroy, - handle_energy_change, handle_explosion, handle_knockback, handle_land_on_ground, handle_poise, - handle_respawn, handle_teleport_to, + handle_aura, handle_bonk, handle_buff, handle_combo_change, handle_damage, handle_delete, + handle_destroy, handle_energy_change, handle_explosion, handle_knockback, + handle_land_on_ground, handle_poise, handle_respawn, handle_teleport_to, }; use group_manip::handle_group; use information::handle_site_info; @@ -67,6 +67,7 @@ impl Server { explosion, owner, } => handle_explosion(self, pos, explosion, owner), + ServerEvent::Bonk { pos, owner, target } => handle_bonk(self, pos, owner, target), ServerEvent::Shoot { entity, dir,