From 486de732fcbf96985814901e94ace6911bf328e3 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 30 Jan 2021 17:35:00 -0500 Subject: [PATCH] Explosions now use attacks. --- common/src/combat.rs | 7 +- common/src/comp/projectile.rs | 130 +++++++-------------- common/src/explosion.rs | 10 +- common/sys/src/shockwave.rs | 3 +- server/src/cmd.rs | 12 +- server/src/events/entity_manipulation.rs | 139 +++++++++++++---------- server/src/sys/object.rs | 46 +++----- 7 files changed, 147 insertions(+), 200 deletions(-) diff --git a/common/src/combat.rs b/common/src/combat.rs index 3d699c019c..d5ce0ad571 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -173,7 +173,7 @@ impl Attack { .filter(|e| !(matches!(e.target, Some(GroupTarget::OutOfGroup)) && target_dodging)) { if match &effect.requirement { - Some(CombatRequirement::AnyDamage) => accumulated_damage != 0.0, + Some(CombatRequirement::AnyDamage) => accumulated_damage > 0.0, Some(CombatRequirement::SufficientEnergy(r)) => { if attacker_energy.map_or(true, |e| e.current() >= *r) { server_events.push(ServerEvent::EnergyChange { @@ -322,7 +322,6 @@ pub enum CombatRequirement { pub enum DamageSource { Buff(BuffKind), Melee, - Healing, Projectile, Explosion, Falling, @@ -444,10 +443,6 @@ impl Damage { }, } }, - DamageSource::Healing => HealthChange { - amount: damage as i32, - cause: HealthSource::Heal { by: uid }, - }, DamageSource::Falling => { // Armor if (damage_reduction - 1.0).abs() < f32::EPSILON { diff --git a/common/src/comp/projectile.rs b/common/src/comp/projectile.rs index 06bb97f7e3..5cb2326593 100644 --- a/common/src/comp/projectile.rs +++ b/common/src/comp/projectile.rs @@ -3,7 +3,6 @@ use crate::{ Attack, AttackEffect, CombatBuff, CombatRequirement, Damage, DamageComponent, DamageSource, EffectComponent, GroupTarget, Knockback, KnockbackDir, }, - effect, uid::Uid, Explosion, RadiusEffect, }; @@ -109,41 +108,30 @@ impl ProjectileConstructor { damage, radius, energy_regen, - } => Projectile { - hit_solid: vec![ - Effect::Explode(Explosion { - effects: vec![ - RadiusEffect::Entity( - Some(GroupTarget::OutOfGroup), - effect::Effect::Damage(Damage { - source: DamageSource::Explosion, - value: damage, - }), - ), - RadiusEffect::TerrainDestruction(2.0), - ], - radius, - energy_regen, - }), - Effect::Vanish, - ], - hit_entity: vec![ - Effect::Explode(Explosion { - effects: vec![RadiusEffect::Entity( - Some(GroupTarget::OutOfGroup), - effect::Effect::Damage(Damage { - source: DamageSource::Explosion, - value: damage, - }), - )], - radius, - energy_regen, - }), - Effect::Vanish, - ], - time_left: Duration::from_secs(10), - owner, - ignore_group: true, + } => { + let damage = Damage { + source: DamageSource::Explosion, + value: damage, + }; + let energy = AttackEffect::EnergyReward(energy_regen); + let energy = EffectComponent::new(None, energy) + .with_requirement(CombatRequirement::AnyDamage); + let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup)); + let attack = Attack::default().with_damage(damage).with_effect(energy); + let explosion = Explosion { + effects: vec![ + RadiusEffect::Attack(attack), + RadiusEffect::TerrainDestruction(2.0), + ], + radius, + }; + Projectile { + hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish], + hit_entity: vec![Effect::Explode(explosion), Effect::Vanish], + time_left: Duration::from_secs(10), + owner, + ignore_group: true, + } }, Firebolt { damage, @@ -171,56 +159,26 @@ impl ProjectileConstructor { heal, damage, radius, - } => Projectile { - hit_solid: vec![ - Effect::Explode(Explosion { - effects: vec![ - RadiusEffect::Entity( - Some(GroupTarget::OutOfGroup), - effect::Effect::Damage(Damage { - source: DamageSource::Explosion, - value: damage, - }), - ), - RadiusEffect::Entity( - Some(GroupTarget::InGroup), - effect::Effect::Damage(Damage { - source: DamageSource::Healing, - value: heal, - }), - ), - ], - radius, - energy_regen: 0, - }), - Effect::Vanish, - ], - hit_entity: vec![ - Effect::Explode(Explosion { - effects: vec![ - RadiusEffect::Entity( - Some(GroupTarget::OutOfGroup), - effect::Effect::Damage(Damage { - source: DamageSource::Explosion, - value: damage, - }), - ), - RadiusEffect::Entity( - Some(GroupTarget::InGroup), - effect::Effect::Damage(Damage { - source: DamageSource::Healing, - value: heal, - }), - ), - ], - radius, - energy_regen: 0, - }), - Effect::Vanish, - ], - time_left: Duration::from_secs(10), - owner, - ignore_group: true, + } => { + let damage = Damage { + source: DamageSource::Explosion, + value: damage, + }; + let damage = DamageComponent::new(damage, Some(GroupTarget::OutOfGroup)); + let heal = AttackEffect::Heal(heal); + let heal = EffectComponent::new(Some(GroupTarget::InGroup), heal); + let attack = Attack::default().with_damage(damage).with_effect(heal); + let explosion = Explosion { + effects: vec![RadiusEffect::Attack(attack)], + radius, + }; + Projectile { + hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish], + hit_entity: vec![Effect::Explode(explosion), Effect::Vanish], + time_left: Duration::from_secs(10), + owner, + ignore_group: false, + } }, Possess => Projectile { hit_solid: vec![Effect::Stick], diff --git a/common/src/explosion.rs b/common/src/explosion.rs index 889602ecd2..04296a856b 100644 --- a/common/src/explosion.rs +++ b/common/src/explosion.rs @@ -1,15 +1,15 @@ -use crate::{combat::GroupTarget, effect::Effect}; +use crate::{combat::Attack, effect::Effect}; use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Explosion { pub effects: Vec, pub radius: f32, - pub energy_regen: u32, } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum RadiusEffect { TerrainDestruction(f32), - Entity(Option, Effect), + Entity(Effect), + Attack(Attack), } diff --git a/common/sys/src/shockwave.rs b/common/sys/src/shockwave.rs index fa66534cc1..d8608de45e 100644 --- a/common/sys/src/shockwave.rs +++ b/common/sys/src/shockwave.rs @@ -122,8 +122,7 @@ impl<'a> System<'a> for Sys { // Group to ignore collisions with // Might make this more nuanced if shockwaves are used for non damage effects - let group = shockwave_owner - .and_then(|e| groups.get(e)); + let group = shockwave_owner.and_then(|e| groups.get(e)); // Go through all other effectable entities for ( diff --git a/server/src/cmd.rs b/server/src/cmd.rs index baa017914a..3bd8ead2a9 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -1360,17 +1360,13 @@ fn handle_explosion( pos: pos.0, explosion: Explosion { effects: vec![ - RadiusEffect::Entity( - None, - Effect::Damage(Damage { - source: DamageSource::Explosion, - value: 100.0 * power, - }), - ), + RadiusEffect::Entity(Effect::Damage(Damage { + source: DamageSource::Explosion, + value: 100.0 * power, + })), RadiusEffect::TerrainDestruction(power), ], radius: 3.0 * power, - energy_regen: 0, }, owner: ecs.read_storage::().get(target).copied(), reagent: None, diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 15d5d4866c..39228ae9c2 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -16,12 +16,13 @@ use common::{ object, Alignment, Body, CharacterState, Energy, EnergyChange, Group, Health, HealthChange, HealthSource, Inventory, Item, Player, Poise, PoiseChange, PoiseSource, Pos, Stats, }, - effect::Effect, + event::{EventBus, ServerEvent}, lottery::Lottery, outcome::Outcome, rtsim::RtSimEntity, terrain::{Block, TerrainGrid}, uid::{Uid, UidAllocator}, + util::Dir, vol::ReadVol, Damage, DamageSource, Explosion, GroupTarget, RadiusEffect, }; @@ -576,32 +577,24 @@ pub fn handle_explosion( // Add an outcome // Uses radius as outcome power, makes negative if explosion has healing effect - let outcome_power = explosion.radius - * if explosion.effects.iter().any(|e| { - matches!( - e, - RadiusEffect::Entity( - _, - Effect::Damage(Damage { - source: DamageSource::Healing, - .. - }) - ) - ) - }) { - -1.0 - } else { - 1.0 - }; + let outcome_power = explosion.radius; + // + // * if explosion.effects.iter().any(|e| { matches!( e, RadiusEffect::Entity( _, + // Effect::Damage(Damage { source: DamageSource::Healing, .. }) ) ) + // }) { + // -1.0 + // } else { + // 1.0 + // }; ecs.write_resource::>() .push(Outcome::Explosion { pos, power: outcome_power, radius: explosion.radius, - is_attack: explosion - .effects - .iter() - .any(|e| matches!(e, RadiusEffect::Entity(_, Effect::Damage(_)))), + is_attack: false, /*explosion + .effects + .iter() + .any(|e| matches!(e, RadiusEffect::Entity(_, Effect::Damage(_))))*/ reagent, }); let owner_entity = owner.and_then(|uid| { @@ -685,54 +678,74 @@ pub fn handle_explosion( .cast(); } }, - RadiusEffect::Entity(target, mut effect) => { - for (entity_b, pos_b) in (&ecs.entities(), &ecs.read_storage::()).join() + RadiusEffect::Attack(attack) => { + // TODO: Before merging handle falloff + let energies = &ecs.read_storage::(); + for (entity_b, pos_b, _health_b, inventory_b_maybe) in ( + &ecs.entities(), + &ecs.read_storage::(), + &ecs.read_storage::(), + ecs.read_storage::().maybe(), + ) + .join() + .filter(|(_, _, h, _)| !h.is_dead) { - // See if entities are in the same group - 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; + // Check if it is a hit + let distance_squared = pos.distance_squared(pos_b.0); + let strength = 1.0 - distance_squared / explosion.radius.powi(2); + if strength > 0.0 { + // See if entities are in the same group + let same_group = owner_entity + .and_then(|e| groups.get(e)) + .map(|group_a| Some(group_a) == groups.get(entity_b)) + .unwrap_or(Some(entity_b) == owner_entity); + + let target_group = if same_group { + GroupTarget::InGroup + } else { + GroupTarget::OutOfGroup + }; + + let dir = Dir::new( + (pos_b.0 - pos) + .try_normalized() + .unwrap_or_else(Vec3::unit_z), + ); + + let server_events = attack.apply_attack( + target_group, + owner_entity.unwrap(), + entity_b, + inventory_b_maybe, + owner.unwrap(), + owner_entity.and_then(|e| energies.get(e)), + dir, + false, + ); + + let server_eventbus = ecs.read_resource::>(); + + for event in server_events { + server_eventbus.emit_now(event); } } - let target_group = if same_group { - GroupTarget::InGroup - } else { - GroupTarget::OutOfGroup - }; - - if let Some(target) = target { - if target != target_group { - continue; - } - } - + } + }, + RadiusEffect::Entity(mut effect) => { + for (entity_b, pos_b, _health_b) in ( + &ecs.entities(), + &ecs.read_storage::(), + &ecs.read_storage::(), + ) + .join() + .filter(|(_, _, h)| !h.is_dead) + { let distance_squared = pos.distance_squared(pos_b.0); let strength = 1.0 - distance_squared / explosion.radius.powi(2); if strength > 0.0 { - let is_alive = ecs - .read_storage::() - .get(entity_b) - .map_or(false, |h| !h.is_dead); - - if is_alive { - effect.modify_strength(strength); - server.state().apply_effect(entity_b, effect.clone(), owner); - // Apply energy change - if let Some(owner) = owner_entity { - if let Some(mut energy) = - ecs.write_storage::().get_mut(owner) - { - energy.change_by(EnergyChange { - amount: explosion.energy_regen as i32, - source: comp::EnergySource::HitEnemy, - }); - } - } - } + effect.modify_strength(strength); + server.state().apply_effect(entity_b, effect.clone(), owner); } } }, diff --git a/server/src/sys/object.rs b/server/src/sys/object.rs index ae577b40e0..afb3574a0f 100644 --- a/server/src/sys/object.rs +++ b/server/src/sys/object.rs @@ -49,24 +49,17 @@ impl<'a> System<'a> for Sys { pos: pos.0, explosion: Explosion { effects: vec![ - RadiusEffect::Entity( - None, - Effect::Damage(Damage { - source: DamageSource::Explosion, - value: 500.0, - }), - ), - RadiusEffect::Entity( - None, - Effect::PoiseChange(PoiseChange { - source: PoiseSource::Explosion, - amount: -100, - }), - ), + RadiusEffect::Entity(Effect::Damage(Damage { + source: DamageSource::Explosion, + value: 500.0, + })), + RadiusEffect::Entity(Effect::PoiseChange(PoiseChange { + source: PoiseSource::Explosion, + amount: -100, + })), RadiusEffect::TerrainDestruction(4.0), ], radius: 12.0, - energy_regen: 0, }, owner: *owner, reagent: None, @@ -83,24 +76,17 @@ impl<'a> System<'a> for Sys { pos: pos.0, explosion: Explosion { effects: vec![ - RadiusEffect::Entity( - None, - Effect::Damage(Damage { - source: DamageSource::Explosion, - value: 50.0, - }), - ), - RadiusEffect::Entity( - None, - Effect::PoiseChange(PoiseChange { - source: PoiseSource::Explosion, - amount: -40, - }), - ), + RadiusEffect::Entity(Effect::Damage(Damage { + source: DamageSource::Explosion, + value: 50.0, + })), + RadiusEffect::Entity(Effect::PoiseChange(PoiseChange { + source: PoiseSource::Explosion, + amount: -40, + })), RadiusEffect::TerrainDestruction(4.0), ], radius: 12.0, - energy_regen: 0, }, owner: *owner, reagent: Some(*reagent),