Allow projectiles to react to triggers

This commit is contained in:
timokoesters 2019-09-17 14:43:19 +02:00
parent 39e5530d45
commit e3c02f8ac1
No known key found for this signature in database
GPG Key ID: CD80BE9AAEE78097
8 changed files with 120 additions and 6 deletions

View File

@ -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;

View File

@ -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<Effect>,
pub hit_entity: Vec<Effect>,
}
impl Component for Projectile {
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}

View File

@ -25,7 +25,7 @@ pub enum ServerEvent {
pos: Vec3<f32>,
radius: f32,
},
Die {
Destroy {
entity: EcsEntity,
cause: comp::HealthSource,
},

View File

@ -157,6 +157,7 @@ impl State {
ecs.register::<comp::Inventory>();
ecs.register::<comp::Admin>();
ecs.register::<comp::Waypoint>();
ecs.register::<comp::Projectile>();
// Register synced resources used by the ECS.
ecs.insert_synced(TimeOfDay(0.0));

View File

@ -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,

View File

@ -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<ServerEvent>>,
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,
}),
_ => {}
}
}
}
}
}
}

View File

@ -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,

View File

@ -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::<comp::Pos>()
@ -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::<comp::Player>().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::<comp::Stats>();
if let Some(entity_stats) = stats.get(entity).cloned() {