diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index fb04b9f253..914195fe32 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -9,6 +9,7 @@ mod last; mod location; mod phys; mod player; +pub mod projectile; mod stats; mod visual; @@ -24,5 +25,6 @@ pub use last::Last; pub use location::Waypoint; pub use phys::{ForceUpdate, Mass, Ori, PhysicsState, Pos, Scale, Vel}; pub use player::Player; +pub use projectile::Projectile; pub use stats::{Equipment, Exp, HealthSource, Level, Stats}; pub use visual::LightEmitter; diff --git a/common/src/comp/projectile.rs b/common/src/comp/projectile.rs new file mode 100644 index 0000000000..3ee9a5b836 --- /dev/null +++ b/common/src/comp/projectile.rs @@ -0,0 +1,18 @@ +use specs::{Component, FlaggedStorage, NullStorage}; +use specs_idvs::IDVStorage; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Effect { + Damage(u32), + Vanish, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Projectile { + pub hit_ground: Vec, + pub hit_entity: Vec, +} + +impl Component for Projectile { + type Storage = FlaggedStorage>; +} diff --git a/common/src/event.rs b/common/src/event.rs index 6c6a024ed0..3c743ca952 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -25,7 +25,7 @@ pub enum ServerEvent { pos: Vec3, radius: f32, }, - Die { + Destroy { entity: EcsEntity, cause: comp::HealthSource, }, diff --git a/common/src/state.rs b/common/src/state.rs index 488bd91a06..a3eb4101ba 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -157,6 +157,7 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); + ecs.register::(); // Register synced resources used by the ECS. ecs.insert_synced(TimeOfDay(0.0)); diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index adeee4c759..30ae5a959b 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -4,6 +4,7 @@ pub mod combat; pub mod controller; pub mod movement; pub mod phys; +mod projectile; mod stats; // External @@ -14,6 +15,7 @@ const AGENT_SYS: &str = "agent_sys"; const CONTROLLER_SYS: &str = "controller_sys"; const PHYS_SYS: &str = "phys_sys"; const MOVEMENT_SYS: &str = "movement_sys"; +const PROJECTILE_SYS: &str = "projectile_sys"; const COMBAT_SYS: &str = "combat_sys"; const STATS_SYS: &str = "stats_sys"; const CLEANUP_SYS: &str = "cleanup_sys"; @@ -22,7 +24,8 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[AGENT_SYS]); dispatch_builder.add(movement::Sys, MOVEMENT_SYS, &[]); - dispatch_builder.add(combat::Sys, COMBAT_SYS, &[CONTROLLER_SYS]); + dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[CONTROLLER_SYS]); + dispatch_builder.add(combat::Sys, COMBAT_SYS, &[PROJECTILE_SYS]); dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]); dispatch_builder.add( phys::Sys, diff --git a/common/src/sys/projectile.rs b/common/src/sys/projectile.rs new file mode 100644 index 0000000000..0d9d84a8b9 --- /dev/null +++ b/common/src/sys/projectile.rs @@ -0,0 +1,84 @@ +use crate::{ + comp::{ + projectile, ActionState::*, CharacterState, Controller, ForceUpdate, HealthSource, Ori, + PhysicsState, Pos, Projectile, Stats, Vel, + }, + event::{EventBus, ServerEvent}, + state::{DeltaTime, Uid}, +}; +use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; +use std::time::Duration; +use vek::*; + +/// This system is responsible for handling projectile effect triggers +pub struct Sys; +impl<'a> System<'a> for Sys { + type SystemData = ( + Entities<'a>, + ReadStorage<'a, Uid>, + Read<'a, DeltaTime>, + Read<'a, EventBus>, + ReadStorage<'a, Pos>, + ReadStorage<'a, Ori>, + ReadStorage<'a, Vel>, + ReadStorage<'a, PhysicsState>, + WriteStorage<'a, Projectile>, + WriteStorage<'a, Stats>, + ); + + fn run( + &mut self, + ( + entities, + uids, + dt, + server_bus, + positions, + velocities, + orientations, + physics_states, + mut projectiles, + mut stats, + ): Self::SystemData, + ) { + let mut server_emitter = server_bus.emitter(); + + // Attacks + for (entity, uid, pos, velocity, ori, physics, projectile) in ( + &entities, + &uids, + &positions, + &velocities, + &orientations, + &physics_states, + &mut projectiles, + ) + .join() + { + // Hit ground + if physics.on_ground { + for effect in projectile.hit_ground.drain(..) { + match effect { + projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy { + entity, + cause: HealthSource::World, + }), + _ => {} + } + } + } + // TODO: Check entity hit + if false { + for effect in projectile.hit_entity.drain(..) { + match effect { + projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy { + entity, + cause: HealthSource::World, + }), + _ => {} + } + } + } + } + } +} diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs index a943335970..5746777ef0 100644 --- a/common/src/sys/stats.rs +++ b/common/src/sys/stats.rs @@ -21,7 +21,7 @@ impl<'a> System<'a> for Sys { for (entity, mut stat) in (&entities, &mut stats).join() { if stat.should_die() && !stat.is_dead { - event_emitter.emit(ServerEvent::Die { + event_emitter.emit(ServerEvent::Destroy { entity, cause: match stat.health.last_change { Some(change) => change.2, diff --git a/server/src/lib.rs b/server/src/lib.rs index 3abdeadf19..7e0ecc4e5c 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -203,6 +203,7 @@ impl Server { pos: comp::Pos, vel: comp::Vel, body: comp::Body, + projectile: comp::Projectile, ) -> EcsEntityBuilder { state .ecs_mut() @@ -211,6 +212,7 @@ impl Server { .with(vel) .with(comp::Ori(Vec3::unit_y())) .with(body) + .with(projectile) } pub fn create_player_character( @@ -288,7 +290,7 @@ impl Server { } } - ServerEvent::Shoot(entity, dir) => { + ServerEvent::Shoot(entity, dir /*, projectile*/) => { let pos = state .ecs() .read_storage::() @@ -300,11 +302,15 @@ impl Server { comp::Pos(pos), comp::Vel(dir * 100.0), comp::Body::Object(comp::object::Body::Arrow), + comp::Projectile { + hit_ground: vec![comp::projectile::Effect::Vanish], + hit_entity: vec![], + }, ) .build(); } - ServerEvent::Die { entity, cause } => { + ServerEvent::Destroy { entity, cause } => { let ecs = state.ecs_mut(); // Chat message if let Some(player) = ecs.read_storage::().get(entity) { @@ -327,7 +333,7 @@ impl Server { clients.notify_registered(ServerMsg::kill(msg)); } - // Give EXP to the client + // Give EXP to the killer if entity had stats let mut stats = ecs.write_storage::(); if let Some(entity_stats) = stats.get(entity).cloned() {