mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Removed Damages struct. Added GroupTarget enum. Changed RadiusEffect to use Effect instead of Daamges. Added Damage variant to Effect Eenum.
This commit is contained in:
parent
d38f1d319c
commit
bda7fefdc0
@ -6,34 +6,6 @@ use crate::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
pub const BLOCK_EFFICIENCY: f32 = 0.9;
|
||||
|
||||
/// Each section of this struct determines what damage is applied to a
|
||||
/// particular target, using some identifier
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Damages {
|
||||
/// Targets enemies, and all other creatures not in your group
|
||||
pub enemy: Option<Damage>,
|
||||
/// Targets people in the same group as you, and any pets you have
|
||||
pub group: Option<Damage>,
|
||||
}
|
||||
|
||||
impl Damages {
|
||||
pub fn new(enemy: Option<Damage>, group: Option<Damage>) -> Self { Damages { enemy, group } }
|
||||
|
||||
pub fn get_damage(self, group_target: GroupTarget) -> Option<Damage> {
|
||||
match group_target {
|
||||
GroupTarget::InGroup => self.group,
|
||||
GroupTarget::OutOfGroup => self.enemy,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_damage(self, source: DamageSource) -> bool {
|
||||
self.enemy.map_or(false, |e| e.source == source)
|
||||
|| self.group.map_or(false, |g| g.source == source)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GroupTarget {
|
||||
InGroup,
|
||||
@ -58,12 +30,7 @@ pub struct Damage {
|
||||
}
|
||||
|
||||
impl Damage {
|
||||
pub fn modify_damage(
|
||||
self,
|
||||
block: bool,
|
||||
loadout: Option<&Loadout>,
|
||||
uid: Option<Uid>,
|
||||
) -> HealthChange {
|
||||
pub fn modify_damage(self, loadout: Option<&Loadout>, uid: Option<Uid>) -> HealthChange {
|
||||
let mut damage = self.value;
|
||||
match self.source {
|
||||
DamageSource::Melee => {
|
||||
@ -72,10 +39,6 @@ impl Damage {
|
||||
if rand::random() {
|
||||
critdamage = damage * 0.3;
|
||||
}
|
||||
// Block
|
||||
if block {
|
||||
damage *= 1.0 - BLOCK_EFFICIENCY
|
||||
}
|
||||
// Armor
|
||||
let damage_reduction = loadout.map_or(0.0, |l| l.get_damage_reduction());
|
||||
damage *= 1.0 - damage_reduction;
|
||||
@ -95,10 +58,6 @@ impl Damage {
|
||||
if rand::random() {
|
||||
damage *= 1.2;
|
||||
}
|
||||
// Block
|
||||
if block {
|
||||
damage *= 1.0 - BLOCK_EFFICIENCY
|
||||
}
|
||||
// Armor
|
||||
let damage_reduction = loadout.map_or(0.0, |l| l.get_damage_reduction());
|
||||
damage *= 1.0 - damage_reduction;
|
||||
@ -109,10 +68,6 @@ impl Damage {
|
||||
}
|
||||
},
|
||||
DamageSource::Explosion => {
|
||||
// Block
|
||||
if block {
|
||||
damage *= 1.0 - BLOCK_EFFICIENCY
|
||||
}
|
||||
// Armor
|
||||
let damage_reduction = loadout.map_or(0.0, |l| l.get_damage_reduction());
|
||||
damage *= 1.0 - damage_reduction;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{sync::Uid, Damages};
|
||||
use crate::{sync::Uid, Damage, GroupTarget};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
@ -8,7 +8,7 @@ use std::time::Duration;
|
||||
pub struct Properties {
|
||||
pub angle: f32,
|
||||
pub speed: f32,
|
||||
pub damages: Damages,
|
||||
pub damages: Vec<(Option<GroupTarget>, Damage)>,
|
||||
pub lifesteal_eff: f32,
|
||||
pub energy_regen: u32,
|
||||
pub energy_cost: u32,
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
event::{LocalEvent, ServerEvent},
|
||||
states::*,
|
||||
sys::character_behavior::JoinData,
|
||||
Damages, Knockback,
|
||||
Damage, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, FlaggedStorage, VecStorage};
|
||||
@ -155,9 +155,9 @@ impl Component for CharacterState {
|
||||
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Attacking {
|
||||
pub damages: Damages,
|
||||
pub damages: Vec<(Option<GroupTarget>, Damage)>,
|
||||
pub range: f32,
|
||||
pub max_angle: f32,
|
||||
pub applied: bool,
|
||||
|
@ -7,8 +7,9 @@ use crate::{
|
||||
buff::{Buff, BuffCategory, BuffData, BuffKind, BuffSource},
|
||||
projectile, Body, CharacterAbility, Gravity, LightEmitter, Projectile,
|
||||
},
|
||||
effect::Effect,
|
||||
states::combo_melee,
|
||||
Damage, DamageSource, Damages, Explosion, Knockback, RadiusEffect,
|
||||
Damage, DamageSource, Explosion, GroupTarget, Knockback, RadiusEffect,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -302,13 +303,10 @@ impl Tool {
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damages(Damages::new(
|
||||
Some(Damage {
|
||||
source: DamageSource::Projectile,
|
||||
value: 40.0 * self.base_power(),
|
||||
}),
|
||||
None,
|
||||
)),
|
||||
projectile::Effect::Damage(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Projectile,
|
||||
value: 40.0 * self.base_power(),
|
||||
}),
|
||||
projectile::Effect::Knockback(Knockback::Away(10.0)),
|
||||
projectile::Effect::RewardEnergy(50),
|
||||
projectile::Effect::Vanish,
|
||||
@ -360,13 +358,10 @@ impl Tool {
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damages(Damages::new(
|
||||
Some(Damage {
|
||||
source: DamageSource::Projectile,
|
||||
value: 40.0 * self.base_power(),
|
||||
}),
|
||||
None,
|
||||
)),
|
||||
projectile::Effect::Damage(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Projectile,
|
||||
value: 40.0 * self.base_power(),
|
||||
}),
|
||||
projectile::Effect::Knockback(Knockback::Away(10.0)),
|
||||
projectile::Effect::Vanish,
|
||||
projectile::Effect::Buff {
|
||||
@ -425,16 +420,22 @@ impl Tool {
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![
|
||||
projectile::Effect::Explode(Explosion {
|
||||
effects: vec![RadiusEffect::Damages(Damages::new(
|
||||
Some(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 50.0 * self.base_power(),
|
||||
}),
|
||||
Some(Damage {
|
||||
source: DamageSource::Healing,
|
||||
value: 140.0 * self.base_power(),
|
||||
}),
|
||||
))],
|
||||
effects: vec![
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 50.0 * self.base_power(),
|
||||
}),
|
||||
),
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::InGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Healing,
|
||||
value: 140.0 * self.base_power(),
|
||||
}),
|
||||
),
|
||||
],
|
||||
radius: 3.0 + 2.5 * self.base_power(),
|
||||
energy_regen: 0,
|
||||
}),
|
||||
@ -442,16 +443,22 @@ impl Tool {
|
||||
],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Explode(Explosion {
|
||||
effects: vec![RadiusEffect::Damages(Damages::new(
|
||||
Some(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 50.0 * self.base_power(),
|
||||
}),
|
||||
Some(Damage {
|
||||
source: DamageSource::Healing,
|
||||
value: 140.0 * self.base_power(),
|
||||
}),
|
||||
))],
|
||||
effects: vec![
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 50.0 * self.base_power(),
|
||||
}),
|
||||
),
|
||||
RadiusEffect::Entity(
|
||||
Some(GroupTarget::InGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Healing,
|
||||
value: 140.0 * self.base_power(),
|
||||
}),
|
||||
),
|
||||
],
|
||||
radius: 3.0 + 2.5 * self.base_power(),
|
||||
energy_regen: 0,
|
||||
}),
|
||||
@ -478,13 +485,13 @@ impl Tool {
|
||||
projectile: Projectile {
|
||||
hit_solid: vec![
|
||||
projectile::Effect::Explode(Explosion {
|
||||
effects: vec![RadiusEffect::Damages(Damages::new(
|
||||
Some(Damage {
|
||||
effects: vec![RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 100.0 * self.base_power(),
|
||||
}),
|
||||
None,
|
||||
))],
|
||||
)],
|
||||
radius: 5.0,
|
||||
energy_regen: 50,
|
||||
}),
|
||||
@ -492,13 +499,13 @@ impl Tool {
|
||||
],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Explode(Explosion {
|
||||
effects: vec![RadiusEffect::Damages(Damages::new(
|
||||
Some(Damage {
|
||||
effects: vec![RadiusEffect::Entity(
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
Effect::Damage(Damage {
|
||||
source: DamageSource::Explosion,
|
||||
value: 100.0 * self.base_power(),
|
||||
}),
|
||||
None,
|
||||
))],
|
||||
)],
|
||||
radius: 5.0,
|
||||
energy_regen: 50,
|
||||
}),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{comp::Buff, sync::Uid, Damages, Explosion, Knockback};
|
||||
use crate::{comp::Buff, sync::Uid, Damage, Explosion, GroupTarget, Knockback};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
@ -6,7 +6,7 @@ use std::time::Duration;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Effect {
|
||||
Damages(Damages),
|
||||
Damage(Option<GroupTarget>, Damage),
|
||||
Knockback(Knockback),
|
||||
RewardEnergy(u32),
|
||||
Explode(Explosion),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{sync::Uid, Damages, Knockback};
|
||||
use crate::{sync::Uid, Damage, GroupTarget, Knockback};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, FlaggedStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
@ -9,7 +9,7 @@ pub struct Properties {
|
||||
pub angle: f32,
|
||||
pub vertical_angle: f32,
|
||||
pub speed: f32,
|
||||
pub damages: Damages,
|
||||
pub damages: Vec<(Option<GroupTarget>, Damage)>,
|
||||
pub knockback: Knockback,
|
||||
pub requires_ground: bool,
|
||||
pub duration: Duration,
|
||||
|
@ -1,11 +1,12 @@
|
||||
use crate::comp;
|
||||
use crate::{combat, comp};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// An effect that may be applied to an entity
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Effect {
|
||||
Health(comp::HealthChange),
|
||||
Xp(i64),
|
||||
Damage(combat::Damage),
|
||||
}
|
||||
|
||||
impl Effect {
|
||||
@ -13,6 +14,21 @@ impl Effect {
|
||||
match self {
|
||||
Effect::Health(c) => format!("{:+} health", c.amount),
|
||||
Effect::Xp(n) => format!("{:+} exp", n),
|
||||
Effect::Damage(d) => format!("{:+}", d.value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify_strength(&mut self, modifier: f32) {
|
||||
match self {
|
||||
Effect::Health(change) => {
|
||||
change.amount = (change.amount as f32 * modifier) as i32;
|
||||
},
|
||||
Effect::Xp(amount) => {
|
||||
*amount = (*amount as f32 * modifier) as i64;
|
||||
},
|
||||
Effect::Damage(damage) => {
|
||||
damage.interpolate_damage(modifier, 0.0);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
use crate::{
|
||||
combat::{Damages, GroupTarget},
|
||||
effect::Effect,
|
||||
};
|
||||
use crate::{combat::GroupTarget, effect::Effect};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -13,7 +10,6 @@ pub struct Explosion {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum RadiusEffect {
|
||||
Damages(Damages),
|
||||
TerrainDestruction(f32),
|
||||
Entity(Option<GroupTarget>, Effect),
|
||||
}
|
||||
|
@ -53,6 +53,6 @@ pub mod util;
|
||||
pub mod vol;
|
||||
pub mod volumes;
|
||||
|
||||
pub use combat::{Damage, DamageSource, Damages, GroupTarget, Knockback};
|
||||
pub use combat::{Damage, DamageSource, GroupTarget, Knockback};
|
||||
pub use explosion::{Explosion, RadiusEffect};
|
||||
pub use loadout_builder::LoadoutBuilder;
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
states::utils::*,
|
||||
sync::Uid,
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
Damage, DamageSource, Damages,
|
||||
Damage, DamageSource, GroupTarget,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -126,7 +126,10 @@ impl CharacterBehavior for Data {
|
||||
let properties = beam::Properties {
|
||||
angle: self.static_data.max_angle.to_radians(),
|
||||
speed,
|
||||
damages: Damages::new(Some(damage), Some(heal)),
|
||||
damages: vec![
|
||||
(Some(GroupTarget::OutOfGroup), damage),
|
||||
(Some(GroupTarget::InGroup), heal),
|
||||
],
|
||||
lifesteal_eff: self.static_data.lifesteal_eff,
|
||||
energy_regen,
|
||||
energy_cost,
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
comp::{Attacking, CharacterState, EnergyChange, EnergySource, StateUpdate},
|
||||
states::utils::*,
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
Damage, DamageSource, Damages, Knockback,
|
||||
Damage, DamageSource, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -76,13 +76,10 @@ impl CharacterBehavior for Data {
|
||||
|
||||
// Hit attempt
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
damages: Damages::new(
|
||||
Some(Damage {
|
||||
source: DamageSource::Melee,
|
||||
value: self.static_data.base_damage as f32,
|
||||
}),
|
||||
None,
|
||||
),
|
||||
damages: vec![(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Melee,
|
||||
value: self.static_data.base_damage as f32,
|
||||
})],
|
||||
range: self.static_data.range,
|
||||
max_angle: 180_f32.to_radians(),
|
||||
applied: false,
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
comp::{Attacking, CharacterState, EnergyChange, EnergySource, StateUpdate},
|
||||
states::utils::{StageSection, *},
|
||||
sys::character_behavior::*,
|
||||
Damage, DamageSource, Damages, Knockback,
|
||||
Damage, DamageSource, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -125,7 +125,7 @@ impl CharacterBehavior for Data {
|
||||
|
||||
// Hit attempt
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
damages: Damages::new(Some(damage), None),
|
||||
damages: vec![(Some(GroupTarget::OutOfGroup), damage)],
|
||||
range: self.static_data.range,
|
||||
max_angle: self.static_data.max_angle.to_radians(),
|
||||
applied: false,
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
event::ServerEvent,
|
||||
states::utils::*,
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
Damage, DamageSource, Damages, Knockback,
|
||||
Damage, DamageSource, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -99,7 +99,7 @@ impl CharacterBehavior for Data {
|
||||
let mut projectile = Projectile {
|
||||
hit_solid: vec![projectile::Effect::Stick],
|
||||
hit_entity: vec![
|
||||
projectile::Effect::Damages(Damages::new(Some(damage), None)),
|
||||
projectile::Effect::Damage(Some(GroupTarget::OutOfGroup), damage),
|
||||
projectile::Effect::Knockback(Knockback::Away(knockback)),
|
||||
projectile::Effect::Vanish,
|
||||
projectile::Effect::Buff {
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
comp::{Attacking, CharacterState, EnergyChange, EnergySource, StateUpdate},
|
||||
states::utils::*,
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
Damage, DamageSource, Damages, Knockback,
|
||||
Damage, DamageSource, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -131,13 +131,10 @@ impl CharacterBehavior for Data {
|
||||
* self.static_data.stage_data[stage_index].damage_increase,
|
||||
);
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
damages: Damages::new(
|
||||
Some(Damage {
|
||||
source: DamageSource::Melee,
|
||||
value: damage as f32,
|
||||
}),
|
||||
None,
|
||||
),
|
||||
damages: vec![(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Melee,
|
||||
value: damage as f32,
|
||||
})],
|
||||
range: self.static_data.stage_data[stage_index].range,
|
||||
max_angle: self.static_data.stage_data[stage_index].angle.to_radians(),
|
||||
applied: false,
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
comp::{Attacking, CharacterState, EnergyChange, EnergySource, StateUpdate},
|
||||
states::utils::*,
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
Damage, DamageSource, Damages, Knockback,
|
||||
Damage, DamageSource, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -139,7 +139,7 @@ impl CharacterBehavior for Data {
|
||||
* charge_frac
|
||||
+ self.static_data.base_knockback;
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
damages: Damages::new(Some(damage), None),
|
||||
damages: vec![(Some(GroupTarget::OutOfGroup), damage)],
|
||||
range: self.static_data.range,
|
||||
max_angle: self.static_data.angle.to_radians(),
|
||||
applied: false,
|
||||
|
@ -2,7 +2,7 @@ use crate::{
|
||||
comp::{Attacking, CharacterState, StateUpdate},
|
||||
states::utils::{StageSection, *},
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
Damage, DamageSource, Damages, Knockback,
|
||||
Damage, DamageSource, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -133,13 +133,10 @@ impl CharacterBehavior for Data {
|
||||
if !self.exhausted {
|
||||
// Hit attempt, when animation plays
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
damages: Damages::new(
|
||||
Some(Damage {
|
||||
source: DamageSource::Melee,
|
||||
value: self.static_data.base_damage as f32,
|
||||
}),
|
||||
None,
|
||||
),
|
||||
damages: vec![(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Melee,
|
||||
value: self.static_data.base_damage as f32,
|
||||
})],
|
||||
range: self.static_data.range,
|
||||
max_angle: self.static_data.max_angle.to_radians(),
|
||||
applied: false,
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
event::ServerEvent,
|
||||
states::utils::*,
|
||||
sys::character_behavior::{CharacterBehavior, JoinData},
|
||||
Damage, DamageSource, Damages, Knockback,
|
||||
Damage, DamageSource, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -70,13 +70,10 @@ impl CharacterBehavior for Data {
|
||||
vertical_angle: self.static_data.shockwave_vertical_angle,
|
||||
speed: self.static_data.shockwave_speed,
|
||||
duration: self.static_data.shockwave_duration,
|
||||
damages: Damages::new(
|
||||
Some(Damage {
|
||||
source: DamageSource::Shockwave,
|
||||
value: self.static_data.damage as f32,
|
||||
}),
|
||||
None,
|
||||
),
|
||||
damages: vec![(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Shockwave,
|
||||
value: self.static_data.damage as f32,
|
||||
})],
|
||||
knockback: self.static_data.knockback,
|
||||
requires_ground: self.static_data.requires_ground,
|
||||
owner: Some(*data.uid),
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
character_behavior::{CharacterBehavior, JoinData},
|
||||
phys::GRAVITY,
|
||||
},
|
||||
Damage, DamageSource, Damages, Knockback,
|
||||
Damage, DamageSource, GroupTarget, Knockback,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@ -108,13 +108,10 @@ impl CharacterBehavior for Data {
|
||||
});
|
||||
// Hit attempt
|
||||
data.updater.insert(data.entity, Attacking {
|
||||
damages: Damages::new(
|
||||
Some(Damage {
|
||||
source: DamageSource::Melee,
|
||||
value: self.static_data.base_damage as f32,
|
||||
}),
|
||||
None,
|
||||
),
|
||||
damages: vec![(Some(GroupTarget::OutOfGroup), Damage {
|
||||
source: DamageSource::Melee,
|
||||
value: self.static_data.base_damage as f32,
|
||||
})],
|
||||
range: self.static_data.range,
|
||||
max_angle: 180_f32.to_radians(),
|
||||
applied: false,
|
||||
|
@ -1,19 +1,17 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
group, Beam, BeamSegment, Body, CharacterState, Energy, EnergyChange, EnergySource, Health,
|
||||
HealthChange, HealthSource, Last, Loadout, Ori, Pos, Scale,
|
||||
group, Beam, BeamSegment, Body, Energy, EnergyChange, EnergySource, Health, HealthChange,
|
||||
HealthSource, Last, Loadout, Ori, Pos, Scale,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
state::{DeltaTime, Time},
|
||||
sync::{Uid, UidAllocator},
|
||||
DamageSource, GroupTarget,
|
||||
GroupTarget,
|
||||
};
|
||||
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
|
||||
pub const BLOCK_ANGLE: f32 = 180.0;
|
||||
|
||||
/// This system is responsible for handling beams that heal or do damage
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
@ -33,7 +31,6 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Health>,
|
||||
ReadStorage<'a, Loadout>,
|
||||
ReadStorage<'a, group::Group>,
|
||||
ReadStorage<'a, CharacterState>,
|
||||
ReadStorage<'a, Energy>,
|
||||
WriteStorage<'a, BeamSegment>,
|
||||
WriteStorage<'a, Beam>,
|
||||
@ -56,7 +53,6 @@ impl<'a> System<'a> for Sys {
|
||||
healths,
|
||||
loadouts,
|
||||
groups,
|
||||
character_states,
|
||||
energies,
|
||||
mut beam_segments,
|
||||
mut beams,
|
||||
@ -116,25 +112,13 @@ impl<'a> System<'a> for Sys {
|
||||
};
|
||||
|
||||
// Go through all other effectable entities
|
||||
for (
|
||||
b,
|
||||
uid_b,
|
||||
pos_b,
|
||||
last_pos_b_maybe,
|
||||
ori_b,
|
||||
scale_b_maybe,
|
||||
character_b,
|
||||
health_b,
|
||||
body_b,
|
||||
) in (
|
||||
for (b, uid_b, pos_b, last_pos_b_maybe, scale_b_maybe, health_b, body_b) in (
|
||||
&entities,
|
||||
&uids,
|
||||
&positions,
|
||||
// TODO: make sure that these are maintained on the client and remove `.maybe()`
|
||||
last_positions.maybe(),
|
||||
&orientations,
|
||||
scales.maybe(),
|
||||
character_states.maybe(),
|
||||
&healths,
|
||||
&bodies,
|
||||
)
|
||||
@ -174,58 +158,63 @@ impl<'a> System<'a> for Sys {
|
||||
continue;
|
||||
}
|
||||
|
||||
let damage = if let Some(damage) = beam_segment.damages.get_damage(target_group)
|
||||
{
|
||||
damage
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let block = character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
|
||||
// TODO: investigate whether this calculation is proper for beams
|
||||
&& ori_b.0.angle_between(pos.0 - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0;
|
||||
|
||||
let change = damage.modify_damage(block, loadouts.get(b), beam_segment.owner);
|
||||
|
||||
if !matches!(damage.source, DamageSource::Healing) {
|
||||
server_emitter.emit(ServerEvent::Damage { entity: b, change });
|
||||
if let Some(entity) = beam_owner {
|
||||
if beam_segment.lifesteal_eff > 0.0 {
|
||||
server_emitter.emit(ServerEvent::Damage {
|
||||
entity,
|
||||
change: HealthChange {
|
||||
amount: (-change.amount as f32 * beam_segment.lifesteal_eff)
|
||||
as i32,
|
||||
cause: HealthSource::Healing {
|
||||
by: beam_segment.owner,
|
||||
},
|
||||
},
|
||||
});
|
||||
for (target, damage) in beam_segment.damages.iter() {
|
||||
if let Some(target) = target {
|
||||
if *target != target_group {
|
||||
continue;
|
||||
}
|
||||
server_emitter.emit(ServerEvent::EnergyChange {
|
||||
entity,
|
||||
change: EnergyChange {
|
||||
amount: beam_segment.energy_regen as i32,
|
||||
source: EnergySource::HitEnemy,
|
||||
},
|
||||
});
|
||||
}
|
||||
} else if let Some(energy) = beam_owner.and_then(|o| energies.get(o)) {
|
||||
if energy.current() > beam_segment.energy_cost {
|
||||
server_emitter.emit(ServerEvent::EnergyChange {
|
||||
entity: beam_owner.unwrap(), /* If it's able to get an energy
|
||||
* component, the entity exists */
|
||||
change: EnergyChange {
|
||||
amount: -(beam_segment.energy_cost as i32), // Stamina use
|
||||
source: EnergySource::Ability,
|
||||
},
|
||||
});
|
||||
server_emitter.emit(ServerEvent::Damage { entity: b, change });
|
||||
|
||||
// Modify damage
|
||||
let change = damage.modify_damage(loadouts.get(b), beam_segment.owner);
|
||||
|
||||
match target {
|
||||
Some(GroupTarget::OutOfGroup) => {
|
||||
server_emitter.emit(ServerEvent::Damage { entity: b, change });
|
||||
if let Some(entity) = beam_owner {
|
||||
server_emitter.emit(ServerEvent::Damage {
|
||||
entity,
|
||||
change: HealthChange {
|
||||
amount: (-change.amount as f32
|
||||
* beam_segment.lifesteal_eff)
|
||||
as i32,
|
||||
cause: HealthSource::Healing {
|
||||
by: beam_segment.owner,
|
||||
},
|
||||
},
|
||||
});
|
||||
server_emitter.emit(ServerEvent::EnergyChange {
|
||||
entity,
|
||||
change: EnergyChange {
|
||||
amount: beam_segment.energy_regen as i32,
|
||||
source: EnergySource::HitEnemy,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
Some(GroupTarget::InGroup) => {
|
||||
if let Some(energy) = beam_owner.and_then(|o| energies.get(o)) {
|
||||
if energy.current() > beam_segment.energy_cost {
|
||||
server_emitter.emit(ServerEvent::EnergyChange {
|
||||
entity: beam_owner.unwrap(), /* If it's able to get an energy
|
||||
* component, the entity exists */
|
||||
change: EnergyChange {
|
||||
amount: -(beam_segment.energy_cost as i32), // Stamina use
|
||||
source: EnergySource::Ability,
|
||||
},
|
||||
});
|
||||
server_emitter
|
||||
.emit(ServerEvent::Damage { entity: b, change });
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
|
||||
// Adds entities that were hit to the hit_entities list on the beam, sees if
|
||||
// it needs to purge the hit_entities list
|
||||
hit_entities.push(*uid_b);
|
||||
}
|
||||
// Adds entities that were hit to the hit_entities list on the beam, sees if it
|
||||
// needs to purge the hit_entities list
|
||||
hit_entities.push(*uid_b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
comp::{buff, group, Attacking, Body, CharacterState, Health, Loadout, Ori, Pos, Scale},
|
||||
comp::{buff, group, Attacking, Body, Health, Loadout, Ori, Pos, Scale},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
span,
|
||||
@ -12,8 +12,6 @@ use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage}
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
|
||||
pub const BLOCK_ANGLE: f32 = 180.0;
|
||||
|
||||
/// This system is responsible for handling accepted inputs like moving or
|
||||
/// attacking
|
||||
pub struct Sys;
|
||||
@ -32,7 +30,6 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Health>,
|
||||
ReadStorage<'a, Loadout>,
|
||||
ReadStorage<'a, group::Group>,
|
||||
ReadStorage<'a, CharacterState>,
|
||||
WriteStorage<'a, Attacking>,
|
||||
);
|
||||
|
||||
@ -51,7 +48,6 @@ impl<'a> System<'a> for Sys {
|
||||
healths,
|
||||
loadouts,
|
||||
groups,
|
||||
character_states,
|
||||
mut attacking_storage,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
@ -76,16 +72,8 @@ impl<'a> System<'a> for Sys {
|
||||
attack.applied = true;
|
||||
|
||||
// Go through all other entities
|
||||
for (b, pos_b, ori_b, scale_b_maybe, character_b, health_b, body_b) in (
|
||||
&entities,
|
||||
&positions,
|
||||
&orientations,
|
||||
scales.maybe(),
|
||||
character_states.maybe(),
|
||||
&healths,
|
||||
&bodies,
|
||||
)
|
||||
.join()
|
||||
for (b, pos_b, scale_b_maybe, health_b, body_b) in
|
||||
(&entities, &positions, scales.maybe(), &healths, &bodies).join()
|
||||
{
|
||||
// 2D versions
|
||||
let pos2 = Vec2::from(pos.0);
|
||||
@ -116,20 +104,16 @@ impl<'a> System<'a> for Sys {
|
||||
GroupTarget::OutOfGroup
|
||||
};
|
||||
|
||||
let damage = if let Some(damage) = attack.damages.get_damage(target_group) {
|
||||
damage
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
for (target, damage) in attack.damages.iter() {
|
||||
if let Some(target) = target {
|
||||
if *target != target_group {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let block = character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
|
||||
&& ori_b.0.angle_between(pos.0 - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0;
|
||||
let change = damage.modify_damage(loadouts.get(b), Some(*uid));
|
||||
|
||||
let change = damage.modify_damage(block, loadouts.get(b), Some(*uid));
|
||||
|
||||
if change.amount != 0 {
|
||||
server_emitter.emit(ServerEvent::Damage { entity: b, change });
|
||||
|
||||
// Apply bleeding buff on melee hits with 10% chance
|
||||
// TODO: Don't have buff uniformly applied on all melee attacks
|
||||
if change.amount < 0 && thread_rng().gen::<f32>() < 0.1 {
|
||||
@ -147,15 +131,13 @@ impl<'a> System<'a> for Sys {
|
||||
)),
|
||||
});
|
||||
}
|
||||
attack.hit_count += 1;
|
||||
}
|
||||
|
||||
if change.amount != 0 {
|
||||
let kb_dir = Dir::new((pos_b.0 - pos.0).try_normalized().unwrap_or(*ori.0));
|
||||
let impulse = attack.knockback.calculate_impulse(kb_dir);
|
||||
if !impulse.is_approx_zero() {
|
||||
server_emitter.emit(ServerEvent::Knockback { entity: b, impulse });
|
||||
}
|
||||
|
||||
attack.hit_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,31 +104,27 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
for effect in projectile.hit_entity.drain(..) {
|
||||
match effect {
|
||||
projectile::Effect::Damages(damages) => {
|
||||
projectile::Effect::Damage(target, damage) => {
|
||||
if Some(other) == projectile.owner {
|
||||
continue;
|
||||
}
|
||||
let damage = if let Some(damage) = damages.get_damage(target_group) {
|
||||
damage
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Some(target) = target {
|
||||
if target != target_group {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(other_entity) =
|
||||
uid_allocator.retrieve_entity_internal(other.into())
|
||||
{
|
||||
let other_entity_loadout = loadouts.get(other_entity);
|
||||
let change = damage.modify_damage(
|
||||
false,
|
||||
other_entity_loadout,
|
||||
projectile.owner,
|
||||
);
|
||||
|
||||
if change.amount != 0 {
|
||||
server_emitter.emit(ServerEvent::Damage {
|
||||
entity: other_entity,
|
||||
change,
|
||||
});
|
||||
}
|
||||
let change =
|
||||
damage.modify_damage(other_entity_loadout, projectile.owner);
|
||||
server_emitter.emit(ServerEvent::Damage {
|
||||
entity: other_entity,
|
||||
change,
|
||||
});
|
||||
}
|
||||
},
|
||||
projectile::Effect::Knockback(knockback) => {
|
||||
@ -177,6 +173,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
},
|
||||
// TODO: Change to effect after !1472 merges
|
||||
projectile::Effect::Buff { buff, chance } => {
|
||||
if let Some(entity) =
|
||||
uid_allocator.retrieve_entity_internal(other.into())
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp::{
|
||||
group, Body, CharacterState, Health, HealthSource, Last, Loadout, Ori, PhysicsState, Pos,
|
||||
Scale, Shockwave, ShockwaveHitEntities,
|
||||
group, Body, Health, HealthSource, Last, Loadout, Ori, PhysicsState, Pos, Scale, Shockwave,
|
||||
ShockwaveHitEntities,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
state::{DeltaTime, Time},
|
||||
@ -12,8 +12,6 @@ use crate::{
|
||||
use specs::{saveload::MarkerAllocator, Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
pub const BLOCK_ANGLE: f32 = 180.0;
|
||||
|
||||
/// This system is responsible for handling accepted inputs like moving or
|
||||
/// attacking
|
||||
pub struct Sys;
|
||||
@ -35,7 +33,6 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Health>,
|
||||
ReadStorage<'a, Loadout>,
|
||||
ReadStorage<'a, group::Group>,
|
||||
ReadStorage<'a, CharacterState>,
|
||||
ReadStorage<'a, PhysicsState>,
|
||||
WriteStorage<'a, Shockwave>,
|
||||
WriteStorage<'a, ShockwaveHitEntities>,
|
||||
@ -59,7 +56,6 @@ impl<'a> System<'a> for Sys {
|
||||
healths,
|
||||
loadouts,
|
||||
groups,
|
||||
character_states,
|
||||
physics_states,
|
||||
mut shockwaves,
|
||||
mut shockwave_hit_lists,
|
||||
@ -131,9 +127,7 @@ impl<'a> System<'a> for Sys {
|
||||
uid_b,
|
||||
pos_b,
|
||||
last_pos_b_maybe,
|
||||
ori_b,
|
||||
scale_b_maybe,
|
||||
character_b,
|
||||
health_b,
|
||||
body_b,
|
||||
physics_state_b,
|
||||
@ -143,9 +137,7 @@ impl<'a> System<'a> for Sys {
|
||||
&positions,
|
||||
// TODO: make sure that these are maintained on the client and remove `.maybe()`
|
||||
last_positions.maybe(),
|
||||
&orientations,
|
||||
scales.maybe(),
|
||||
character_states.maybe(),
|
||||
&healths,
|
||||
&bodies,
|
||||
&physics_states,
|
||||
@ -199,21 +191,19 @@ impl<'a> System<'a> for Sys {
|
||||
&& (!shockwave.requires_ground || physics_state_b.on_ground);
|
||||
|
||||
if hit {
|
||||
let damage = if let Some(damage) = shockwave.damages.get_damage(target_group) {
|
||||
damage
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
for (target, damage) in shockwave.damages.iter() {
|
||||
if let Some(target) = target {
|
||||
if *target != target_group {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let block = character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
|
||||
&& ori_b.0.angle_between(pos.0 - pos_b.0) < BLOCK_ANGLE.to_radians() / 2.0;
|
||||
let owner_uid = shockwave.owner.unwrap_or(*uid);
|
||||
let change = damage.modify_damage(loadouts.get(b), Some(owner_uid));
|
||||
|
||||
let owner_uid = shockwave.owner.unwrap_or(*uid);
|
||||
let change = damage.modify_damage(block, loadouts.get(b), Some(owner_uid));
|
||||
|
||||
if change.amount != 0 {
|
||||
server_emitter.emit(ServerEvent::Damage { entity: b, change });
|
||||
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 impulse = shockwave.knockback.calculate_impulse(kb_dir);
|
||||
if !impulse.is_approx_zero() {
|
||||
|
@ -11,12 +11,12 @@ use common::{
|
||||
object, Alignment, Body, Energy, EnergyChange, Group, Health, HealthChange, HealthSource,
|
||||
Item, Player, Pos, Stats,
|
||||
},
|
||||
effect::Effect,
|
||||
lottery::Lottery,
|
||||
msg::{PlayerListUpdate, ServerGeneral},
|
||||
outcome::Outcome,
|
||||
state::BlockChange,
|
||||
sync::{Uid, UidAllocator, WorldSyncExt},
|
||||
sys::melee::BLOCK_ANGLE,
|
||||
terrain::{Block, TerrainGrid},
|
||||
vol::ReadVol,
|
||||
Damage, DamageSource, Explosion, GroupTarget, RadiusEffect,
|
||||
@ -457,7 +457,7 @@ pub fn handle_land_on_ground(server: &Server, entity: EcsEntity, vel: Vec3<f32>)
|
||||
value: falldmg,
|
||||
};
|
||||
let loadouts = state.ecs().read_storage::<comp::Loadout>();
|
||||
let change = damage.modify_damage(false, loadouts.get(entity), None);
|
||||
let change = damage.modify_damage(loadouts.get(entity), None);
|
||||
health.change_by(change);
|
||||
}
|
||||
}
|
||||
@ -516,7 +516,7 @@ pub fn handle_explosion(
|
||||
// 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::Damages(d) if d.contains_damage(DamageSource::Healing)),
|
||||
|e| matches!(e, RadiusEffect::Entity(_, e) if matches!(e, Effect::Damage(d) if matches!(d.source, DamageSource::Healing))),
|
||||
) {
|
||||
-1.0
|
||||
} else {
|
||||
@ -530,7 +530,7 @@ pub fn handle_explosion(
|
||||
is_attack: explosion
|
||||
.effects
|
||||
.iter()
|
||||
.any(|e| matches!(e, RadiusEffect::Damages(_))),
|
||||
.any(|e| matches!(e, RadiusEffect::Entity(_, e) if matches!(e, Effect::Damage(_)))),
|
||||
reagent,
|
||||
});
|
||||
let owner_entity = owner.and_then(|uid| {
|
||||
@ -541,70 +541,6 @@ pub fn handle_explosion(
|
||||
|
||||
for effect in explosion.effects {
|
||||
match effect {
|
||||
RadiusEffect::Damages(damages) => {
|
||||
for (entity_b, pos_b, ori_b, character_b, health_b, loadout_b) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::Pos>(),
|
||||
&ecs.read_storage::<comp::Ori>(),
|
||||
ecs.read_storage::<comp::CharacterState>().maybe(),
|
||||
&mut ecs.write_storage::<comp::Health>(),
|
||||
ecs.read_storage::<comp::Loadout>().maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let distance_squared = pos.distance_squared(pos_b.0);
|
||||
// Check if it is a hit
|
||||
if !health_b.is_dead
|
||||
// RADIUS
|
||||
&& distance_squared < explosion.radius.powi(2)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
let target_group = if same_group {
|
||||
GroupTarget::InGroup
|
||||
} else {
|
||||
GroupTarget::OutOfGroup
|
||||
};
|
||||
|
||||
let mut damage = if let Some(damage) = damages.get_damage(target_group) {
|
||||
damage
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let strength = 1.0 - distance_squared / explosion.radius.powi(2);
|
||||
damage.interpolate_damage(strength, 0.0);
|
||||
|
||||
let block = character_b.map(|c_b| c_b.is_block()).unwrap_or(false)
|
||||
&& ori_b.0.angle_between(pos - pos_b.0)
|
||||
< BLOCK_ANGLE.to_radians() / 2.0;
|
||||
|
||||
let change = damage.modify_damage(block, loadout_b, owner);
|
||||
|
||||
if change.amount != 0 {
|
||||
health_b.change_by(change);
|
||||
if let Some(owner) = owner_entity {
|
||||
if let Some(energy) =
|
||||
ecs.write_storage::<comp::Energy>().get_mut(owner)
|
||||
{
|
||||
energy.change_by(EnergyChange {
|
||||
amount: explosion.energy_regen as i32,
|
||||
source: comp::EnergySource::HitEnemy,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
RadiusEffect::TerrainDestruction(power) => {
|
||||
const RAYS: usize = 500;
|
||||
|
||||
@ -671,10 +607,14 @@ pub fn handle_explosion(
|
||||
.cast();
|
||||
}
|
||||
},
|
||||
RadiusEffect::Entity(target_group, effect) => {
|
||||
for (entity_b, pos_b) in (&ecs.entities(), &ecs.read_storage::<comp::Pos>()).join()
|
||||
RadiusEffect::Entity(target, mut effect) => {
|
||||
for (entity_b, pos_b, health_b) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::Pos>(),
|
||||
&ecs.read_storage::<comp::Health>(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let distance_squared = pos.distance_squared(pos_b.0);
|
||||
// See if entities are in the same group
|
||||
let mut same_group = owner_entity
|
||||
.and_then(|e| groups.get(e))
|
||||
@ -684,16 +624,34 @@ pub fn handle_explosion(
|
||||
same_group = true;
|
||||
}
|
||||
}
|
||||
let hit_group = if same_group {
|
||||
let target_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);
|
||||
if let Some(target) = target {
|
||||
if target != target_group {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let distance_squared = pos.distance_squared(pos_b.0);
|
||||
let strength = 1.0 - distance_squared / explosion.radius.powi(2);
|
||||
|
||||
if strength > 0.0 && !health_b.is_dead {
|
||||
effect.modify_strength(strength);
|
||||
server.state().apply_effect(entity_b, effect, owner);
|
||||
// Apply energy change
|
||||
if let Some(owner) = owner_entity {
|
||||
if let Some(energy) = ecs.write_storage::<comp::Energy>().get_mut(owner)
|
||||
{
|
||||
energy.change_by(EnergyChange {
|
||||
amount: explosion.energy_regen as i32,
|
||||
source: comp::EnergySource::HitEnemy,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -349,7 +349,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
|
||||
|
||||
drop(inventories);
|
||||
if let Some(effect) = maybe_effect {
|
||||
state.apply_effect(entity, effect);
|
||||
state.apply_effect(entity, effect, None);
|
||||
}
|
||||
if let Some(event) = event {
|
||||
state.write_component(entity, comp::InventoryUpdate::new(event));
|
||||
|
@ -20,7 +20,7 @@ use vek::*;
|
||||
|
||||
pub trait StateExt {
|
||||
/// Updates a component associated with the entity based on the `Effect`
|
||||
fn apply_effect(&self, entity: EcsEntity, effect: Effect);
|
||||
fn apply_effect(&self, entity: EcsEntity, effect: Effect, source: Option<Uid>);
|
||||
/// Build a non-player character
|
||||
fn create_npc(
|
||||
&mut self,
|
||||
@ -71,7 +71,7 @@ pub trait StateExt {
|
||||
}
|
||||
|
||||
impl StateExt for State {
|
||||
fn apply_effect(&self, entity: EcsEntity, effect: Effect) {
|
||||
fn apply_effect(&self, entity: EcsEntity, effect: Effect, source: Option<Uid>) {
|
||||
match effect {
|
||||
Effect::Health(change) => {
|
||||
self.ecs()
|
||||
@ -85,6 +85,16 @@ impl StateExt for State {
|
||||
.get_mut(entity)
|
||||
.map(|stats| stats.exp.change_by(xp));
|
||||
},
|
||||
Effect::Damage(damage) => {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let loadout = self.ecs().read_storage::<comp::Loadout>().get(entity) {
|
||||
let change = damage.modify_damage(loadout, source);
|
||||
self.ecs()
|
||||
.write_storage::<comp::Health>()
|
||||
.get_mut(entity)
|
||||
.map(|health| health.change_by(change));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user