diff --git a/common/src/comp/event.rs b/common/src/comp/event.rs new file mode 100644 index 0000000000..bed74d4669 --- /dev/null +++ b/common/src/comp/event.rs @@ -0,0 +1,30 @@ +use specs::Component; +use specs_idvs::IDVStorage; +use std::ops::{Deref, DerefMut}; +use vek::*; + +#[derive(Clone, Debug, Default)] +pub struct Events(pub Vec); + +impl Deref for Events { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Events { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Component for Events { + type Storage = IDVStorage; +} + +#[derive(Clone, Debug)] +pub enum EntityEvent { + HitGround { vel: Vec3 }, +} diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index bee5458a2c..54ac7dd856 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -3,6 +3,7 @@ mod agent; mod animation; mod body; mod controller; +mod event; mod inputs; mod inventory; mod last; @@ -17,6 +18,7 @@ pub use agent::Agent; pub use animation::{Animation, AnimationInfo}; pub use body::{humanoid, object, quadruped, quadruped_medium, Body}; pub use controller::Controller; +pub use event::{EntityEvent, Events}; pub use inputs::{ Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding, }; diff --git a/common/src/state.rs b/common/src/state.rs index 0a5a4ef7af..81cfc2d7bb 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -161,6 +161,7 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); + ecs.register::(); // Controller effects ecs.register::(); ecs.register::(); diff --git a/common/src/sys/event_handler.rs b/common/src/sys/event_handler.rs new file mode 100644 index 0000000000..c7f6e72198 --- /dev/null +++ b/common/src/sys/event_handler.rs @@ -0,0 +1,33 @@ +use crate::{ + comp::{EntityEvent, Events, HealthSource, Stats}, + state::DeltaTime, +}; +use log::warn; +use specs::{Entities, Join, Read, System, WriteStorage}; + +/// This system kills players +pub struct Sys; +impl<'a> System<'a> for Sys { + type SystemData = ( + Entities<'a>, + WriteStorage<'a, Events>, + WriteStorage<'a, Stats>, + ); + + fn run(&mut self, (entities, mut events, mut stats): Self::SystemData) { + for (entity, mut events) in (&entities, &mut events).join() { + for event in events.drain(..) { + match event { + EntityEvent::HitGround { vel } => { + if let Some(stat) = stats.get_mut(entity) { + let falldmg = (vel.z / 1.5 + 6.0) as i32; + if falldmg < 0 { + stat.health.change_by(falldmg, HealthSource::World); + } + } + } + } + } + } + } +} diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index 7664b4af8a..a71a03bdcb 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -3,6 +3,7 @@ pub mod agent; pub mod animation; pub mod combat; pub mod controller; +mod event_handler; pub mod movement; pub mod phys; mod stats; @@ -19,6 +20,7 @@ const MOVEMENT_SYS: &str = "movement_sys"; const COMBAT_SYS: &str = "combat_sys"; const ANIMATION_SYS: &str = "animation_sys"; const STATS_SYS: &str = "stats_sys"; +const EVENT_HANDLER_SYS: &str = "event_handler_sys"; pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); @@ -33,4 +35,9 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(combat::Sys, COMBAT_SYS, &[ACTION_STATE_SYS]); dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[ACTION_STATE_SYS]); dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]); + dispatch_builder.add( + event_handler::Sys, + EVENT_HANDLER_SYS, + &[AGENT_SYS, PHYS_SYS, ACTION_STATE_SYS, COMBAT_SYS], + ); } diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index de3045b0a6..674e7cd5fb 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -1,8 +1,8 @@ use crate::{ comp::HealthSource, comp::{ - ActionState, Body, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, Scale, Stats, Vel, - Wielding, + ActionState, Body, EntityEvent, Events, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, + Scale, Stats, Vel, Wielding, }, state::DeltaTime, terrain::TerrainMap, @@ -42,7 +42,7 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Ori>, - WriteStorage<'a, Stats>, + WriteStorage<'a, Events>, ); fn run( @@ -58,11 +58,11 @@ impl<'a> System<'a> for Sys { mut positions, mut velocities, mut orientations, - mut stats, + mut events, ): Self::SystemData, ) { // Apply movement inputs - for (entity, a, scale, b, mut pos, mut vel, mut ori, mut stat) in ( + for (entity, a, scale, b, mut pos, mut vel, mut ori) in ( &entities, &action_states, scales.maybe(), @@ -70,7 +70,6 @@ impl<'a> System<'a> for Sys { &mut positions, &mut velocities, &mut orientations, - &mut stats, ) .join() { @@ -210,12 +209,18 @@ impl<'a> System<'a> for Sys { // When the resolution direction is pointing upwards, we must be on the ground if resolve_dir.z > 0.0 && vel.0.z <= 0.0 { - // Check for fall damage - let falldmg = (vel.0.z / 1.5 + 6.0) as i32; - if falldmg < 0 { - stat.health.change_by(falldmg, HealthSource::World); - } on_ground = true; + + // Hitting the ground + const COLLISION_VEL: f32 = GRAVITY * 0.75; // Falling for 0.75 seconds + if vel.0.z < -COLLISION_VEL { + if events.get(entity).is_none() { + events.insert(entity, Events::default()); + } + events + .get_mut(entity) // TODO: Use get_mut_or_default when updating to SPECS 15 + .map(|e| e.push(EntityEvent::HitGround { vel: vel.0 })); + } } // When the resolution direction is non-vertical, we must be colliding with a wall