Energy and health change server events now reference EcsEntity instead of Uid. Added TargetGroup to use to determine targets of effects/damage. Added Entity(TargetGroup, Effect) to RadiusEffect enum.

This commit is contained in:
Sam 2020-11-01 18:26:01 -06:00
parent 87bff41a66
commit d38f1d319c
14 changed files with 172 additions and 104 deletions

View File

@ -21,8 +21,11 @@ pub struct Damages {
impl Damages { impl Damages {
pub fn new(enemy: Option<Damage>, group: Option<Damage>) -> Self { Damages { enemy, group } } pub fn new(enemy: Option<Damage>, group: Option<Damage>) -> Self { Damages { enemy, group } }
pub fn get_damage(self, same_group: bool) -> Option<Damage> { pub fn get_damage(self, group_target: GroupTarget) -> Option<Damage> {
if same_group { self.group } else { self.enemy } match group_target {
GroupTarget::InGroup => self.group,
GroupTarget::OutOfGroup => self.enemy,
}
} }
pub fn contains_damage(self, source: DamageSource) -> bool { pub fn contains_damage(self, source: DamageSource) -> bool {
@ -31,6 +34,12 @@ impl Damages {
} }
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum GroupTarget {
InGroup,
OutOfGroup,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum DamageSource { pub enum DamageSource {
Melee, Melee,

View File

@ -34,7 +34,7 @@ pub enum ServerEvent {
reagent: Option<Reagent>, reagent: Option<Reagent>,
}, },
Damage { Damage {
uid: Uid, entity: EcsEntity,
change: comp::HealthChange, change: comp::HealthChange,
}, },
Destroy { Destroy {
@ -111,7 +111,7 @@ pub enum ServerEvent {
buff_change: comp::BuffChange, buff_change: comp::BuffChange,
}, },
EnergyChange { EnergyChange {
uid: Uid, entity: EcsEntity,
change: comp::EnergyChange, change: comp::EnergyChange,
}, },
} }

View File

@ -1,4 +1,7 @@
use crate::{combat::Damages, effect::Effect}; use crate::{
combat::{Damages, GroupTarget},
effect::Effect,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -12,5 +15,5 @@ pub struct Explosion {
pub enum RadiusEffect { pub enum RadiusEffect {
Damages(Damages), Damages(Damages),
TerrainDestruction(f32), TerrainDestruction(f32),
EntityEffect(Effect), Entity(Option<GroupTarget>, Effect),
} }

View File

@ -53,6 +53,6 @@ pub mod util;
pub mod vol; pub mod vol;
pub mod volumes; pub mod volumes;
pub use combat::{Damage, DamageSource, Damages, Knockback}; pub use combat::{Damage, DamageSource, Damages, GroupTarget, Knockback};
pub use explosion::{Explosion, RadiusEffect}; pub use explosion::{Explosion, RadiusEffect};
pub use loadout_builder::LoadoutBuilder; pub use loadout_builder::LoadoutBuilder;

View File

@ -6,7 +6,7 @@ use crate::{
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
state::{DeltaTime, Time}, state::{DeltaTime, Time},
sync::{Uid, UidAllocator}, sync::{Uid, UidAllocator},
DamageSource, DamageSource, GroupTarget,
}; };
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage}; use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
use std::time::Duration; use std::time::Duration;
@ -68,8 +68,8 @@ impl<'a> System<'a> for Sys {
let dt = dt.0; let dt = dt.0;
// Beams // Beams
for (entity, uid, pos, ori, beam_segment) in for (entity, pos, ori, beam_segment) in
(&entities, &uids, &positions, &orientations, &beam_segments).join() (&entities, &positions, &orientations, &beam_segments).join()
{ {
let creation_time = match beam_segment.creation { let creation_time = match beam_segment.creation {
Some(time) => time, Some(time) => time,
@ -163,12 +163,19 @@ impl<'a> System<'a> for Sys {
.map(|group_a| Some(group_a) == groups.get(b)) .map(|group_a| Some(group_a) == groups.get(b))
.unwrap_or(Some(*uid_b) == beam_segment.owner); .unwrap_or(Some(*uid_b) == beam_segment.owner);
let target_group = if same_group {
GroupTarget::InGroup
} else {
GroupTarget::OutOfGroup
};
// If owner, shouldn't heal or damage // If owner, shouldn't heal or damage
if Some(*uid_b) == beam_segment.owner { if Some(*uid_b) == beam_segment.owner {
continue; continue;
} }
let damage = if let Some(damage) = beam_segment.damages.get_damage(same_group) { let damage = if let Some(damage) = beam_segment.damages.get_damage(target_group)
{
damage damage
} else { } else {
continue; continue;
@ -181,25 +188,22 @@ impl<'a> System<'a> for Sys {
let change = damage.modify_damage(block, loadouts.get(b), beam_segment.owner); let change = damage.modify_damage(block, loadouts.get(b), beam_segment.owner);
if !matches!(damage.source, DamageSource::Healing) { if !matches!(damage.source, DamageSource::Healing) {
server_emitter.emit(ServerEvent::Damage { server_emitter.emit(ServerEvent::Damage { entity: b, change });
uid: *uid_b, if let Some(entity) = beam_owner {
change, if beam_segment.lifesteal_eff > 0.0 {
}); server_emitter.emit(ServerEvent::Damage {
if beam_segment.lifesteal_eff > 0.0 { entity,
server_emitter.emit(ServerEvent::Damage { change: HealthChange {
uid: beam_segment.owner.unwrap_or(*uid), amount: (-change.amount as f32 * beam_segment.lifesteal_eff)
change: HealthChange { as i32,
amount: (-change.amount as f32 * beam_segment.lifesteal_eff) cause: HealthSource::Healing {
as i32, by: beam_segment.owner,
cause: HealthSource::Healing { },
by: beam_segment.owner,
}, },
}, });
}); }
}
if let Some(uid) = beam_segment.owner {
server_emitter.emit(ServerEvent::EnergyChange { server_emitter.emit(ServerEvent::EnergyChange {
uid, entity,
change: EnergyChange { change: EnergyChange {
amount: beam_segment.energy_regen as i32, amount: beam_segment.energy_regen as i32,
source: EnergySource::HitEnemy, source: EnergySource::HitEnemy,
@ -208,19 +212,15 @@ impl<'a> System<'a> for Sys {
} }
} else if let Some(energy) = beam_owner.and_then(|o| energies.get(o)) { } else if let Some(energy) = beam_owner.and_then(|o| energies.get(o)) {
if energy.current() > beam_segment.energy_cost { if energy.current() > beam_segment.energy_cost {
if let Some(uid) = beam_segment.owner { server_emitter.emit(ServerEvent::EnergyChange {
server_emitter.emit(ServerEvent::EnergyChange { entity: beam_owner.unwrap(), /* If it's able to get an energy
uid, * component, the entity exists */
change: EnergyChange { change: EnergyChange {
amount: -(beam_segment.energy_cost as i32), // Stamina use amount: -(beam_segment.energy_cost as i32), // Stamina use
source: EnergySource::Ability, source: EnergySource::Ability,
}, },
})
}
server_emitter.emit(ServerEvent::Damage {
uid: *uid_b,
change,
}); });
server_emitter.emit(ServerEvent::Damage { entity: b, change });
} }
} }
// Adds entities that were hit to the hit_entities list on the beam, sees if it // Adds entities that were hit to the hit_entities list on the beam, sees if it

View File

@ -5,7 +5,6 @@ use crate::{
}, },
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
state::DeltaTime, state::DeltaTime,
sync::Uid,
}; };
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage}; use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
use std::time::Duration; use std::time::Duration;
@ -17,7 +16,6 @@ impl<'a> System<'a> for Sys {
Entities<'a>, Entities<'a>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
ReadStorage<'a, Uid>,
ReadStorage<'a, Loadout>, ReadStorage<'a, Loadout>,
WriteStorage<'a, Health>, WriteStorage<'a, Health>,
WriteStorage<'a, Buffs>, WriteStorage<'a, Buffs>,
@ -25,14 +23,13 @@ impl<'a> System<'a> for Sys {
fn run( fn run(
&mut self, &mut self,
(entities, dt, server_bus, uids, loadouts, mut healths, mut buffs): Self::SystemData, (entities, dt, server_bus, loadouts, mut healths, mut buffs): Self::SystemData,
) { ) {
let mut server_emitter = server_bus.emitter(); let mut server_emitter = server_bus.emitter();
// Set to false to avoid spamming server // Set to false to avoid spamming server
buffs.set_event_emission(false); buffs.set_event_emission(false);
healths.set_event_emission(false); healths.set_event_emission(false);
for (entity, buff_comp, uid, health) in (&entities, &mut buffs, &uids, &mut healths).join() for (entity, buff_comp, health) in (&entities, &mut buffs, &mut healths).join() {
{
let mut expired_buffs = Vec::<BuffId>::new(); let mut expired_buffs = Vec::<BuffId>::new();
for (id, buff) in buff_comp.buffs.iter_mut() { for (id, buff) in buff_comp.buffs.iter_mut() {
// Tick the buff and subtract delta from it // Tick the buff and subtract delta from it
@ -94,7 +91,7 @@ impl<'a> System<'a> for Sys {
HealthSource::Buff { owner: buff_owner } HealthSource::Buff { owner: buff_owner }
}; };
server_emitter.emit(ServerEvent::Damage { server_emitter.emit(ServerEvent::Damage {
uid: *uid, entity,
change: HealthChange { change: HealthChange {
amount: *accumulated as i32, amount: *accumulated as i32,
cause, cause,

View File

@ -5,6 +5,7 @@ use crate::{
span, span,
sync::Uid, sync::Uid,
util::Dir, util::Dir,
GroupTarget,
}; };
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}; use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
@ -75,9 +76,8 @@ impl<'a> System<'a> for Sys {
attack.applied = true; attack.applied = true;
// Go through all other entities // Go through all other entities
for (b, uid_b, pos_b, ori_b, scale_b_maybe, character_b, health_b, body_b) in ( for (b, pos_b, ori_b, scale_b_maybe, character_b, health_b, body_b) in (
&entities, &entities,
&uids,
&positions, &positions,
&orientations, &orientations,
scales.maybe(), scales.maybe(),
@ -110,7 +110,13 @@ impl<'a> System<'a> for Sys {
.map(|group_a| Some(group_a) == groups.get(b)) .map(|group_a| Some(group_a) == groups.get(b))
.unwrap_or(false); .unwrap_or(false);
let damage = if let Some(damage) = attack.damages.get_damage(same_group) { let target_group = if same_group {
GroupTarget::InGroup
} else {
GroupTarget::OutOfGroup
};
let damage = if let Some(damage) = attack.damages.get_damage(target_group) {
damage damage
} else { } else {
continue; continue;
@ -122,10 +128,7 @@ impl<'a> System<'a> for Sys {
let change = damage.modify_damage(block, loadouts.get(b), Some(*uid)); let change = damage.modify_damage(block, loadouts.get(b), Some(*uid));
if change.amount != 0 { if change.amount != 0 {
server_emitter.emit(ServerEvent::Damage { server_emitter.emit(ServerEvent::Damage { entity: b, change });
uid: *uid_b,
change,
});
// Apply bleeding buff on melee hits with 10% chance // Apply bleeding buff on melee hits with 10% chance
// TODO: Don't have buff uniformly applied on all melee attacks // TODO: Don't have buff uniformly applied on all melee attacks

View File

@ -9,6 +9,7 @@ use crate::{
span, span,
state::DeltaTime, state::DeltaTime,
sync::UidAllocator, sync::UidAllocator,
GroupTarget,
}; };
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use specs::{ use specs::{
@ -83,6 +84,13 @@ impl<'a> System<'a> for Sys {
.retrieve_entity_internal(other.into()) .retrieve_entity_internal(other.into())
.and_then(|e| groups.get(e)) .and_then(|e| groups.get(e))
); );
let target_group = if same_group {
GroupTarget::InGroup
} else {
GroupTarget::OutOfGroup
};
if projectile.ignore_group if projectile.ignore_group
// Skip if in the same group // Skip if in the same group
&& same_group && same_group
@ -100,36 +108,49 @@ impl<'a> System<'a> for Sys {
if Some(other) == projectile.owner { if Some(other) == projectile.owner {
continue; continue;
} }
let damage = if let Some(damage) = damages.get_damage(same_group) { let damage = if let Some(damage) = damages.get_damage(target_group) {
damage damage
} else { } else {
continue; continue;
}; };
let other_entity_loadout = uid_allocator if let Some(other_entity) =
.retrieve_entity_internal(other.into()) uid_allocator.retrieve_entity_internal(other.into())
.and_then(|e| loadouts.get(e)); {
let change = let other_entity_loadout = loadouts.get(other_entity);
damage.modify_damage(false, other_entity_loadout, projectile.owner); let change = damage.modify_damage(
false,
other_entity_loadout,
projectile.owner,
);
if change.amount != 0 { if change.amount != 0 {
server_emitter.emit(ServerEvent::Damage { uid: other, change }); server_emitter.emit(ServerEvent::Damage {
entity: other_entity,
change,
});
}
} }
}, },
projectile::Effect::Knockback(knockback) => { projectile::Effect::Knockback(knockback) => {
if let Some(entity) = if let Some(other_entity) =
uid_allocator.retrieve_entity_internal(other.into()) uid_allocator.retrieve_entity_internal(other.into())
{ {
let impulse = knockback.calculate_impulse(ori.0); let impulse = knockback.calculate_impulse(ori.0);
if !impulse.is_approx_zero() { if !impulse.is_approx_zero() {
local_emitter local_emitter.emit(LocalEvent::ApplyImpulse {
.emit(LocalEvent::ApplyImpulse { entity, impulse }); entity: other_entity,
impulse,
});
} }
} }
}, },
projectile::Effect::RewardEnergy(energy) => { projectile::Effect::RewardEnergy(energy) => {
if let Some(uid) = projectile.owner { if let Some(entity_owner) = projectile
.owner
.and_then(|u| uid_allocator.retrieve_entity_internal(u.into()))
{
server_emitter.emit(ServerEvent::EnergyChange { server_emitter.emit(ServerEvent::EnergyChange {
uid, entity: entity_owner,
change: EnergyChange { change: EnergyChange {
amount: energy as i32, amount: energy as i32,
source: EnergySource::HitEnemy, source: EnergySource::HitEnemy,

View File

@ -7,6 +7,7 @@ use crate::{
state::{DeltaTime, Time}, state::{DeltaTime, Time},
sync::{Uid, UidAllocator}, sync::{Uid, UidAllocator},
util::Dir, util::Dir,
GroupTarget,
}; };
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage}; use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
use vek::*; use vek::*;
@ -177,6 +178,12 @@ impl<'a> System<'a> for Sys {
.map(|group_a| Some(group_a) == groups.get(b)) .map(|group_a| Some(group_a) == groups.get(b))
.unwrap_or(Some(*uid_b) == shockwave.owner); .unwrap_or(Some(*uid_b) == shockwave.owner);
let target_group = if same_group {
GroupTarget::InGroup
} else {
GroupTarget::OutOfGroup
};
// Check if it is a hit // Check if it is a hit
let hit = entity != b let hit = entity != b
&& !health_b.is_dead && !health_b.is_dead
@ -192,7 +199,7 @@ impl<'a> System<'a> for Sys {
&& (!shockwave.requires_ground || physics_state_b.on_ground); && (!shockwave.requires_ground || physics_state_b.on_ground);
if hit { if hit {
let damage = if let Some(damage) = shockwave.damages.get_damage(same_group) { let damage = if let Some(damage) = shockwave.damages.get_damage(target_group) {
damage damage
} else { } else {
continue; continue;
@ -205,10 +212,7 @@ impl<'a> System<'a> for Sys {
let change = damage.modify_damage(block, loadouts.get(b), Some(owner_uid)); let change = damage.modify_damage(block, loadouts.get(b), Some(owner_uid));
if change.amount != 0 { if change.amount != 0 {
server_emitter.emit(ServerEvent::Damage { server_emitter.emit(ServerEvent::Damage { entity: b, change });
uid: *uid_b,
change,
});
shockwave_hit_list.hit_entities.push(*uid_b); shockwave_hit_list.hit_entities.push(*uid_b);
let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0)); let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
let impulse = shockwave.knockback.calculate_impulse(kb_dir); let impulse = shockwave.knockback.calculate_impulse(kb_dir);

View File

@ -1158,10 +1158,13 @@ fn handle_explosion(
pos: pos.0, pos: pos.0,
explosion: Explosion { explosion: Explosion {
effects: vec![ effects: vec![
RadiusEffect::EntityEffect(Effect::Health(comp::HealthChange { RadiusEffect::Entity(
amount: (-100.0 * power) as i32, None,
cause: comp::HealthSource::Explosion { owner: None }, Effect::Health(comp::HealthChange {
})), amount: (-100.0 * power) as i32,
cause: comp::HealthSource::Explosion { owner: None },
}),
),
RadiusEffect::TerrainDestruction(power), RadiusEffect::TerrainDestruction(power),
], ],
radius: 3.0 * power, radius: 3.0 * power,

View File

@ -19,7 +19,7 @@ use common::{
sys::melee::BLOCK_ANGLE, sys::melee::BLOCK_ANGLE,
terrain::{Block, TerrainGrid}, terrain::{Block, TerrainGrid},
vol::ReadVol, vol::ReadVol,
Damage, DamageSource, Explosion, RadiusEffect, Damage, DamageSource, Explosion, GroupTarget, RadiusEffect,
}; };
use comp::item::Reagent; use comp::item::Reagent;
use rand::prelude::*; use rand::prelude::*;
@ -27,12 +27,10 @@ use specs::{join::Join, saveload::MarkerAllocator, Entity as EcsEntity, WorldExt
use tracing::error; use tracing::error;
use vek::Vec3; use vek::Vec3;
pub fn handle_damage(server: &Server, uid: Uid, change: HealthChange) { pub fn handle_damage(server: &Server, entity: EcsEntity, change: HealthChange) {
let ecs = &server.state.ecs(); let ecs = &server.state.ecs();
if let Some(entity) = ecs.entity_from_uid(uid.into()) { if let Some(health) = ecs.write_storage::<Health>().get_mut(entity) {
if let Some(health) = ecs.write_storage::<Health>().get_mut(entity) { health.change_by(change);
health.change_by(change);
}
} }
} }
@ -570,7 +568,13 @@ pub fn handle_explosion(
} }
} }
let mut damage = if let Some(damage) = damages.get_damage(same_group) { let target_group = if same_group {
GroupTarget::InGroup
} else {
GroupTarget::OutOfGroup
};
let mut damage = if let Some(damage) = damages.get_damage(target_group) {
damage damage
} else { } else {
continue; continue;
@ -667,13 +671,29 @@ pub fn handle_explosion(
.cast(); .cast();
} }
}, },
RadiusEffect::EntityEffect(effect) => { RadiusEffect::Entity(target_group, effect) => {
for (entity, pos_entity) in for (entity_b, pos_b) in (&ecs.entities(), &ecs.read_storage::<comp::Pos>()).join()
(&ecs.entities(), &ecs.read_storage::<comp::Pos>()).join()
{ {
let distance_squared = pos.distance_squared(pos_entity.0); let distance_squared = pos.distance_squared(pos_b.0);
if distance_squared < explosion.radius.powi(2) { // See if entities are in the same group
server.state().apply_effect(entity, effect); let mut same_group = owner_entity
.and_then(|e| groups.get(e))
.map_or(false, |group_a| Some(group_a) == groups.get(entity_b));
if let Some(entity) = owner_entity {
if entity == entity_b {
same_group = true;
}
}
let hit_group = if same_group {
GroupTarget::InGroup
} else {
GroupTarget::OutOfGroup
};
if distance_squared < explosion.radius.powi(2)
&& target_group.map_or(true, |g| g == hit_group)
{
server.state().apply_effect(entity_b, effect);
} }
} }
}, },
@ -754,11 +774,9 @@ pub fn handle_buff(server: &mut Server, entity: EcsEntity, buff_change: buff::Bu
} }
} }
pub fn handle_energy_change(server: &Server, uid: Uid, change: EnergyChange) { pub fn handle_energy_change(server: &Server, entity: EcsEntity, change: EnergyChange) {
let ecs = &server.state.ecs(); let ecs = &server.state.ecs();
if let Some(entity) = ecs.entity_from_uid(uid.into()) { if let Some(energy) = ecs.write_storage::<Energy>().get_mut(entity) {
if let Some(energy) = ecs.write_storage::<Energy>().get_mut(entity) { energy.change_by(change);
energy.change_by(change);
}
} }
} }

View File

@ -82,7 +82,7 @@ impl Server {
ServerEvent::Knockback { entity, impulse } => { ServerEvent::Knockback { entity, impulse } => {
handle_knockback(&self, entity, impulse) handle_knockback(&self, entity, impulse)
}, },
ServerEvent::Damage { uid, change } => handle_damage(&self, uid, change), ServerEvent::Damage { entity, change } => handle_damage(&self, entity, change),
ServerEvent::Destroy { entity, cause } => handle_destroy(self, entity, cause), ServerEvent::Destroy { entity, cause } => handle_destroy(self, entity, cause),
ServerEvent::InventoryManip(entity, manip) => handle_inventory(self, entity, manip), ServerEvent::InventoryManip(entity, manip) => handle_inventory(self, entity, manip),
ServerEvent::GroupManip(entity, manip) => handle_group(self, entity, manip), ServerEvent::GroupManip(entity, manip) => handle_group(self, entity, manip),
@ -137,8 +137,8 @@ impl Server {
entity, entity,
buff_change, buff_change,
} => handle_buff(self, entity, buff_change), } => handle_buff(self, entity, buff_change),
ServerEvent::EnergyChange { uid, change } => { ServerEvent::EnergyChange { entity, change } => {
handle_energy_change(&self, uid, change) handle_energy_change(&self, entity, change)
}, },
} }
} }

View File

@ -242,6 +242,10 @@ impl StateExt for State {
z_max: body.height(), z_max: body.height(),
}); });
self.write_component(entity, body); self.write_component(entity, body);
self.write_component(
entity,
comp::Health::new(stats.body_type, stats.level.level()),
);
self.write_component(entity, stats); self.write_component(entity, stats);
self.write_component(entity, inventory); self.write_component(entity, inventory);
self.write_component(entity, loadout); self.write_component(entity, loadout);

View File

@ -50,10 +50,13 @@ impl<'a> System<'a> for Sys {
pos: pos.0, pos: pos.0,
explosion: Explosion { explosion: Explosion {
effects: vec![ effects: vec![
RadiusEffect::EntityEffect(Effect::Health(HealthChange { RadiusEffect::Entity(
amount: -500, None,
cause: HealthSource::Explosion { owner: *owner }, Effect::Health(HealthChange {
})), amount: -500,
cause: HealthSource::Explosion { owner: *owner },
}),
),
RadiusEffect::TerrainDestruction(4.0), RadiusEffect::TerrainDestruction(4.0),
], ],
radius: 12.0, radius: 12.0,
@ -74,10 +77,13 @@ impl<'a> System<'a> for Sys {
pos: pos.0, pos: pos.0,
explosion: Explosion { explosion: Explosion {
effects: vec![ effects: vec![
RadiusEffect::EntityEffect(Effect::Health(HealthChange { RadiusEffect::Entity(
amount: -50, None,
cause: HealthSource::Explosion { owner: *owner }, Effect::Health(HealthChange {
})), amount: -50,
cause: HealthSource::Explosion { owner: *owner },
}),
),
RadiusEffect::TerrainDestruction(4.0), RadiusEffect::TerrainDestruction(4.0),
], ],
radius: 12.0, radius: 12.0,