From d1e1de3b1465b74ac50f8f6426b16b49ae460631 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 7 Jan 2022 00:30:28 -0500 Subject: [PATCH] Slashing damage now decreases target's energy if available, and if target has no remaining energy will do additional damage. Piercing damage now ignores an amount of protection equal to the piercing damage value. Crushing damage now does poise damage equal to the amount of mitigated damage. When poise damage is dealt while in a poise state, poise damage is instead converted to damage. --- assets/common/abilities/axe/doublestrike.ron | 123 +++++++------ .../common/abilities/hammer/singlestrike.ron | 65 ++++--- .../common/abilities/sword/triplestrike.ron | 167 ++++++++++-------- common/src/combat.rs | 122 +++++++++++-- common/src/comp/mod.rs | 2 +- common/src/comp/poise.rs | 21 ++- common/src/event.rs | 3 +- common/systems/src/beam.rs | 1 + common/systems/src/buff.rs | 2 +- common/systems/src/melee.rs | 1 + common/systems/src/projectile.rs | 1 + common/systems/src/shockwave.rs | 1 + common/systems/src/stats.rs | 12 +- server/src/events/entity_manipulation.rs | 32 +++- server/src/events/mod.rs | 6 +- server/src/state_ext.rs | 16 +- voxygen/src/hud/bag.rs | 2 +- 17 files changed, 377 insertions(+), 200 deletions(-) diff --git a/assets/common/abilities/axe/doublestrike.ron b/assets/common/abilities/axe/doublestrike.ron index 59172a0787..fa72fdc605 100644 --- a/assets/common/abilities/axe/doublestrike.ron +++ b/assets/common/abilities/axe/doublestrike.ron @@ -1,56 +1,69 @@ -ComboMelee( - stage_data: [ - ( - stage: 1, - base_damage: 11.0, - base_poise_damage: 12, - damage_increase: 1.0, - poise_damage_increase: 0, - knockback: 5.0, - range: 3.5, - angle: 50.0, - base_buildup_duration: 0.15, - base_swing_duration: 0.075, - hit_timing: 0.6, - base_recover_duration: 0.35, - forward_movement: 0.5, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), - ), - ( - stage: 2, - base_damage: 13.0, - base_poise_damage: 20, - damage_increase: 1.5, - poise_damage_increase: 0, - knockback: 6.0, - range: 3.5, - angle: 30.0, - base_buildup_duration: 0.2, - base_swing_duration: 0.1, - hit_timing: 0.6, - base_recover_duration: 0.35, - forward_movement: 0.25, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), - ), - ], - initial_energy_gain: 2.5, - max_energy_gain: 17.5, - energy_increase: 3.0, - speed_increase: 0.1, - max_speed_increase: 0.6, - scales_from_combo: 2, - is_interruptible: false, - ori_modifier: 1.0, +// ComboMelee( +// stage_data: [ +// ( +// stage: 1, +// base_damage: 11.0, +// base_poise_damage: 12, +// damage_increase: 1.0, +// poise_damage_increase: 0, +// knockback: 5.0, +// range: 3.5, +// angle: 50.0, +// base_buildup_duration: 0.15, +// base_swing_duration: 0.075, +// hit_timing: 0.6, +// base_recover_duration: 0.35, +// forward_movement: 0.5, +// damage_kind: Slashing, +// damage_effect: Some(Buff(( +// kind: Bleeding, +// dur_secs: 10.0, +// strength: DamageFraction(0.1), +// chance: 0.1, +// ))), +// ), +// ( +// stage: 2, +// base_damage: 13.0, +// base_poise_damage: 20, +// damage_increase: 1.5, +// poise_damage_increase: 0, +// knockback: 6.0, +// range: 3.5, +// angle: 30.0, +// base_buildup_duration: 0.2, +// base_swing_duration: 0.1, +// hit_timing: 0.6, +// base_recover_duration: 0.35, +// forward_movement: 0.25, +// damage_kind: Slashing, +// damage_effect: Some(Buff(( +// kind: Bleeding, +// dur_secs: 10.0, +// strength: DamageFraction(0.1), +// chance: 0.1, +// ))), +// ), +// ], +// initial_energy_gain: 2.5, +// max_energy_gain: 17.5, +// energy_increase: 3.0, +// speed_increase: 0.1, +// max_speed_increase: 0.6, +// scales_from_combo: 2, +// is_interruptible: false, +// ori_modifier: 1.0, +// ) +BasicMelee( + energy_cost: 0, + buildup_duration: 0.1, + swing_duration: 0.05, + recover_duration: 0.1, + base_damage: 10.0, + base_poise_damage: 0, + knockback: ( strength: 0.0, direction: Away), + range: 5.0, + max_angle: 45.0, + damage_effect: None, + damage_kind: Slashing, ) diff --git a/assets/common/abilities/hammer/singlestrike.ron b/assets/common/abilities/hammer/singlestrike.ron index b5b0d54b84..c5d207a06d 100644 --- a/assets/common/abilities/hammer/singlestrike.ron +++ b/assets/common/abilities/hammer/singlestrike.ron @@ -1,26 +1,39 @@ -ComboMelee( - stage_data: [( - stage: 1, - base_damage: 15.0, - damage_increase: 1.0, - base_poise_damage: 20, - poise_damage_increase: 0, - knockback: 3.5, - range: 4.5, - angle: 50.0, - base_buildup_duration: 0.2, - base_swing_duration: 0.1, - hit_timing: 0.5, - base_recover_duration: 0.45, - forward_movement: 0.0, - damage_kind: Crushing, - )], - initial_energy_gain: 5.0, - max_energy_gain: 15.0, - energy_increase: 5.0, - speed_increase: 0.1, - max_speed_increase: 0.4, - scales_from_combo: 2, - is_interruptible: false, - ori_modifier: 1.0, -) +// ComboMelee( +// stage_data: [( +// stage: 1, +// base_damage: 15.0, +// damage_increase: 1.0, +// base_poise_damage: 20, +// poise_damage_increase: 0, +// knockback: 3.5, +// range: 4.5, +// angle: 50.0, +// base_buildup_duration: 0.2, +// base_swing_duration: 0.1, +// hit_timing: 0.5, +// base_recover_duration: 0.45, +// forward_movement: 0.0, +// damage_kind: Crushing, +// )], +// initial_energy_gain: 5.0, +// max_energy_gain: 15.0, +// energy_increase: 5.0, +// speed_increase: 0.1, +// max_speed_increase: 0.4, +// scales_from_combo: 2, +// is_interruptible: false, +// ori_modifier: 1.0, +// ) +BasicMelee( + energy_cost: 0, + buildup_duration: 0.1, + swing_duration: 0.05, + recover_duration: 0.1, + base_damage: 10.0, + base_poise_damage: 0, + knockback: ( strength: 0.0, direction: Away), + range: 5.0, + max_angle: 45.0, + damage_effect: None, + damage_kind: Crushing, +) \ No newline at end of file diff --git a/assets/common/abilities/sword/triplestrike.ron b/assets/common/abilities/sword/triplestrike.ron index 84a55425d2..0a35bec8d2 100644 --- a/assets/common/abilities/sword/triplestrike.ron +++ b/assets/common/abilities/sword/triplestrike.ron @@ -1,78 +1,91 @@ -ComboMelee( - stage_data: [ - ( - stage: 1, - base_damage: 10.0, - damage_increase: 1.0, - base_poise_damage: 10, - poise_damage_increase: 0, - knockback: 0.0, - range: 4.0, - angle: 30.0, - base_buildup_duration: 0.1, - base_swing_duration: 0.075, - hit_timing: 0.5, - base_recover_duration: 0.15, - forward_movement: 0.5, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), - ), - ( - stage: 2, - base_damage: 8.0, - damage_increase: 1.5, - base_poise_damage: 13, - poise_damage_increase: 0, - knockback: 2.0, - range: 3.5, - angle: 40.0, - base_buildup_duration: 0.1, - base_swing_duration: 0.1, - hit_timing: 0.5, - base_recover_duration: 0.3, - forward_movement: 0.0, - damage_kind: Slashing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), - ), - ( - stage: 3, - base_damage: 13, - damage_increase: 2, - base_poise_damage: 15, - poise_damage_increase: 0, - knockback: 2.0, - range: 6.0, - angle: 10.0, - base_buildup_duration: 0.15, - base_swing_duration: 0.1, - hit_timing: 0.2, - base_recover_duration: 0.35, - forward_movement: 1.2, - damage_kind: Piercing, - damage_effect: Some(Buff(( - kind: Bleeding, - dur_secs: 10.0, - strength: DamageFraction(0.1), - chance: 0.1, - ))), - ), - ], - initial_energy_gain: 0, - max_energy_gain: 20.0, - energy_increase: 2.5, - speed_increase: 0.1, - max_speed_increase: 0.8, - scales_from_combo: 2, - is_interruptible: true, - ori_modifier: 1.0, +// ComboMelee( +// stage_data: [ +// ( +// stage: 1, +// base_damage: 10.0, +// damage_increase: 1.0, +// base_poise_damage: 10, +// poise_damage_increase: 0, +// knockback: 0.0, +// range: 4.0, +// angle: 30.0, +// base_buildup_duration: 0.1, +// base_swing_duration: 0.075, +// hit_timing: 0.5, +// base_recover_duration: 0.15, +// forward_movement: 0.5, +// damage_kind: Slashing, +// damage_effect: Some(Buff(( +// kind: Bleeding, +// dur_secs: 10.0, +// strength: DamageFraction(0.1), +// chance: 0.1, +// ))), +// ), +// ( +// stage: 2, +// base_damage: 8.0, +// damage_increase: 1.5, +// base_poise_damage: 13, +// poise_damage_increase: 0, +// knockback: 2.0, +// range: 3.5, +// angle: 40.0, +// base_buildup_duration: 0.1, +// base_swing_duration: 0.1, +// hit_timing: 0.5, +// base_recover_duration: 0.3, +// forward_movement: 0.0, +// damage_kind: Slashing, +// damage_effect: Some(Buff(( +// kind: Bleeding, +// dur_secs: 10.0, +// strength: DamageFraction(0.1), +// chance: 0.1, +// ))), +// ), +// ( +// stage: 3, +// base_damage: 13, +// damage_increase: 2, +// base_poise_damage: 15, +// poise_damage_increase: 0, +// knockback: 2.0, +// range: 6.0, +// angle: 10.0, +// base_buildup_duration: 0.15, +// base_swing_duration: 0.1, +// hit_timing: 0.2, +// base_recover_duration: 0.35, +// forward_movement: 1.2, +// damage_kind: Piercing, +// damage_effect: Some(Buff(( +// kind: Bleeding, +// dur_secs: 10.0, +// strength: DamageFraction(0.1), +// chance: 0.1, +// ))), +// ), +// ], +// initial_energy_gain: 0, +// max_energy_gain: 20.0, +// energy_increase: 2.5, +// speed_increase: 0.1, +// max_speed_increase: 0.8, +// scales_from_combo: 2, +// is_interruptible: true, +// ori_modifier: 1.0, +// ) +BasicMelee( + energy_cost: 0, + buildup_duration: 0.1, + swing_duration: 0.05, + recover_duration: 0.1, + base_damage: 10.0, + base_poise_damage: 0, + knockback: ( strength: 0.0, direction: Away), + range: 5.0, + max_angle: 45.0, + damage_effect: None, + damage_kind: Piercing, ) diff --git a/common/src/combat.rs b/common/src/combat.rs index 51a12c133b..80ee62ac3a 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -12,7 +12,7 @@ use crate::{ }, skillset::SkillGroupKind, Alignment, Body, CharacterState, Combo, Energy, Health, HealthChange, Inventory, Ori, - Player, Poise, SkillSet, Stats, + Player, Poise, PoiseChange, SkillSet, Stats, }, event::ServerEvent, outcome::Outcome, @@ -70,6 +70,7 @@ pub struct TargetInfo<'a> { pub pos: Vec3, pub ori: Option<&'a Ori>, pub char_state: Option<&'a CharacterState>, + pub energy: Option<&'a Energy>, } #[derive(Clone, Copy)] @@ -135,12 +136,12 @@ impl Attack { target: &TargetInfo, source: AttackSource, dir: Dir, - kind: DamageKind, + damage: Damage, mut emit: impl FnMut(ServerEvent), mut emit_outcome: impl FnMut(Outcome), ) -> f32 { let damage_reduction = - Damage::compute_damage_reduction(target.inventory, target.stats, Some(kind)); + Damage::compute_damage_reduction(Some(damage), target.inventory, target.stats); let block_reduction = match source { AttackSource::Melee => { if let (Some(CharacterState::BasicBlock(data)), Some(ori)) = @@ -223,7 +224,7 @@ impl Attack { &target, attack_source, dir, - damage.damage.kind, + damage.damage, &mut emit, &mut emit_outcome, ); @@ -243,6 +244,57 @@ impl Attack { entity: target.entity, change, }); + match damage.damage.kind { + DamageKind::Slashing => { + // For slashing damage, reduce target energy by some fraction of applied + // damage. When target would lose more energy than they have, deal an + // equivalent amount of damage + if let Some(target_energy) = target.energy { + let energy_change = applied_damage * SLASHING_ENERGY_FRACTION; + if energy_change > target_energy.current() { + let health_change = HealthChange { + amount: -(energy_change - target_energy.current()), + by: attacker.map(|x| x.into()), + cause: Some(damage.damage.source), + time, + }; + emit(ServerEvent::HealthChange { + entity: target.entity, + change: health_change, + }); + } + emit(ServerEvent::EnergyChange { + entity: target.entity, + change: -energy_change, + }); + } + }, + DamageKind::Crushing => { + // For crushing damage, reduce target poise by some fraction of the amount + // of damage that was reduced by target's protection + // Damage reduction should never equal 1 here as otherwise the check above + // that health change amount is greater than 0 would fail. + let reduced_damage = + applied_damage * damage_reduction / (1.0 - damage_reduction); + let poise = reduced_damage * CRUSHING_POISE_FRACTION; + let change = Poise::apply_poise_reduction(poise, target.inventory); + let poise_change = PoiseChange { + amount: change, + impulse: *dir, + by: attacker.map(|x| x.into()), + cause: Some(damage.damage.source), + }; + if change.abs() > Poise::POISE_EPSILON { + emit(ServerEvent::PoiseChange { + entity: target.entity, + change: poise_change, + }); + } + }, + // Piercing damage ignores some penetration, and is handled when damage + // reduction is computed Energy is a placeholder damage type + DamageKind::Piercing | DamageKind::Energy => {}, + } for effect in damage.effects.iter() { match effect { CombatEffect::Knockback(kb) => { @@ -297,10 +349,15 @@ impl Attack { let change = -Poise::apply_poise_reduction(*p, target.inventory) * strength_modifier; if change.abs() > Poise::POISE_EPSILON { + let poise_change = PoiseChange { + amount: change, + impulse: *dir, + by: attacker.map(|x| x.into()), + cause: Some(damage.damage.source), + }; emit(ServerEvent::PoiseChange { entity: target.entity, - change, - kb_dir: *dir, + change: poise_change, }); } }, @@ -434,10 +491,15 @@ impl Attack { let change = -Poise::apply_poise_reduction(p, target.inventory) * strength_modifier; if change.abs() > Poise::POISE_EPSILON { + let poise_change = PoiseChange { + amount: change, + impulse: *dir, + by: attacker.map(|x| x.into()), + cause: Some(attack_source.into()), + }; emit(ServerEvent::PoiseChange { entity: target.entity, - change, - kb_dir: *dir, + change: poise_change, }); } }, @@ -649,20 +711,37 @@ pub enum DamageSource { Other, } +impl From for DamageSource { + fn from(attack: AttackSource) -> Self { + match attack { + AttackSource::Melee => DamageSource::Melee, + AttackSource::Projectile => DamageSource::Projectile, + AttackSource::Explosion => DamageSource::Explosion, + AttackSource::Shockwave => DamageSource::Shockwave, + AttackSource::Beam => DamageSource::Energy, + } + } +} + /// DamageKind for the purpose of differentiating damage reduction #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] pub enum DamageKind { - /// Arrows/Sword dash + /// Bypasses some protection from armor Piercing, - /// Swords/axes + /// Reduces energy of target, dealing additional damage when target energy + /// is 0 Slashing, - /// Hammers + /// Deals additional poise damage the more armored the target is Crushing, - /// Staves/sceptres (TODO: differentiate further once there are more magic - /// weapons) + /// Catch all for remaining damage kinds (TODO: differentiate further with + /// staff/sceptre reworks Energy, } +const PIERCING_PENETRATION_FRACTION: f32 = 1.0; +const SLASHING_ENERGY_FRACTION: f32 = 1.0; +const CRUSHING_POISE_FRACTION: f32 = 1.0; + #[cfg(not(target_arch = "wasm32"))] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Damage { @@ -675,9 +754,9 @@ pub struct Damage { impl Damage { /// Returns the total damage reduction provided by all equipped items pub fn compute_damage_reduction( + damage: Option, inventory: Option<&Inventory>, stats: Option<&Stats>, - kind: Option, ) -> f32 { let inventory_dr = if let Some(inventory) = inventory { let protection = inventory @@ -696,12 +775,17 @@ impl Damage { }) .sum::>(); - let kind_modifier = if matches!(kind, Some(DamageKind::Piercing)) { - 0.75 + let penetration = if let Some(damage) = damage { + if let DamageKind::Piercing = damage.kind { + damage.value * PIERCING_PENETRATION_FRACTION + } else { + 0.0 + } } else { - 1.0 + 0.0 }; - let protection = protection.map(|dr| dr * kind_modifier); + + let protection = protection.map(|p| p - penetration); const FIFTY_PERCENT_DR_THRESHOLD: f32 = 60.0; @@ -971,7 +1055,7 @@ pub fn combat_rating( // Normalized with a standard max health of 100 let health_rating = health.base_max() / 100.0 - / (1.0 - Damage::compute_damage_reduction(Some(inventory), None, None)).max(0.00001); + / (1.0 - Damage::compute_damage_reduction(None, Some(inventory), None)).max(0.00001); // Normalized with a standard max energy of 100 and energy reward multiplier of // x1 diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index be2c405d12..9476eb598f 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -96,7 +96,7 @@ pub use self::{ }, player::DisconnectReason, player::{AliasError, Player, MAX_ALIAS_LEN}, - poise::{Poise, PoiseState}, + poise::{Poise, PoiseChange, PoiseState}, projectile::{Projectile, ProjectileConstructor}, shockwave::{Shockwave, ShockwaveHitEntities}, skillset::{ diff --git a/common/src/comp/poise.rs b/common/src/comp/poise.rs index 9f235e2564..184fab66f0 100644 --- a/common/src/comp/poise.rs +++ b/common/src/comp/poise.rs @@ -1,4 +1,5 @@ use crate::{ + combat::{DamageContributor, DamageSource}, comp::{ self, inventory::item::{armor::Protection, ItemKind}, @@ -13,6 +14,20 @@ use specs_idvs::IdvStorage; use std::{ops::Mul, time::Duration}; use vek::*; +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct PoiseChange { + /// The amount of the poise change + pub amount: f32, + /// The direction that the poise change came from, used for when the target + /// is knocked down + pub impulse: Vec3, + /// The the individual or group who caused the poise change (None if the + /// damage wasn't caused by an entity) + pub by: Option, + /// The category of action that resulted in the poise change + pub cause: Option, +} + #[derive(Clone, Copy, Debug, Serialize, Deserialize)] /// Poise is represented by u32s within the module, but treated as a float by /// the rest of the game. @@ -149,11 +164,11 @@ impl Poise { } } - pub fn change_by(&mut self, change: f32, impulse: Vec3) { - self.current = (((self.current() + change).clamp(0.0, f32::from(Self::MAX_POISE)) + pub fn change(&mut self, change: PoiseChange) { + self.current = (((self.current() + change.amount).clamp(0.0, f32::from(Self::MAX_POISE)) * Self::SCALING_FACTOR_FLOAT) as u32) .min(self.maximum); - self.last_change = Dir::from_unnormalized(impulse).unwrap_or_default(); + self.last_change = Dir::from_unnormalized(change.impulse).unwrap_or_default(); } pub fn reset(&mut self) { self.current = self.maximum; } diff --git a/common/src/event.rs b/common/src/event.rs index 0c551ed39d..d1e8215a11 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -53,8 +53,7 @@ pub enum ServerEvent { }, PoiseChange { entity: EcsEntity, - change: f32, - kb_dir: Vec3, + change: comp::PoiseChange, }, Delete(EcsEntity), Destroy { diff --git a/common/systems/src/beam.rs b/common/systems/src/beam.rs index cb5aabc8c9..1ff263796b 100644 --- a/common/systems/src/beam.rs +++ b/common/systems/src/beam.rs @@ -226,6 +226,7 @@ impl<'a> System<'a> for Sys { pos: pos_b.0, ori: read_data.orientations.get(target), char_state: read_data.character_states.get(target), + energy: read_data.energies.get(target), }; // PvP check diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index 559b6a5fea..4bd3516a7b 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -165,9 +165,9 @@ impl<'a> System<'a> for Sys { } let damage_reduction = Damage::compute_damage_reduction( + None, read_data.inventories.get(entity), Some(&stat), - None, ); if (damage_reduction - 1.0).abs() < f32::EPSILON { for (id, buff) in buff_comp.buffs.iter() { diff --git a/common/systems/src/melee.rs b/common/systems/src/melee.rs index d8f0a9ca9d..ebc5d750ae 100644 --- a/common/systems/src/melee.rs +++ b/common/systems/src/melee.rs @@ -164,6 +164,7 @@ impl<'a> System<'a> for Sys { pos: pos_b.0, ori: read_data.orientations.get(target), char_state: read_data.char_states.get(target), + energy: read_data.energies.get(target), }; // PvP check diff --git a/common/systems/src/projectile.rs b/common/systems/src/projectile.rs index 1f0013d669..3c3f204902 100644 --- a/common/systems/src/projectile.rs +++ b/common/systems/src/projectile.rs @@ -279,6 +279,7 @@ fn dispatch_hit( pos: target_pos, ori: projectile_target_info.ori, char_state: read_data.character_states.get(target), + energy: read_data.energies.get(target), }; // TODO: Is it possible to have projectile without body?? diff --git a/common/systems/src/shockwave.rs b/common/systems/src/shockwave.rs index 2074d74aa7..259756ea72 100644 --- a/common/systems/src/shockwave.rs +++ b/common/systems/src/shockwave.rs @@ -207,6 +207,7 @@ impl<'a> System<'a> for Sys { pos: pos_b.0, ori: read_data.orientations.get(target), char_state: read_data.character_states.get(target), + energy: read_data.energies.get(target), }; // PvP check diff --git a/common/systems/src/stats.rs b/common/systems/src/stats.rs index 2b38d30698..5097710ad0 100644 --- a/common/systems/src/stats.rs +++ b/common/systems/src/stats.rs @@ -3,8 +3,8 @@ use common::{ comp::{ self, skills::{GeneralSkill, Skill}, - Body, CharacterState, Combo, Energy, Health, Inventory, Poise, Pos, SkillSet, Stats, - StatsModifier, + Body, CharacterState, Combo, Energy, Health, Inventory, Poise, PoiseChange, Pos, SkillSet, + Stats, StatsModifier, }, event::{EventBus, ServerEvent}, resources::{DeltaTime, EntitiesDiedLastTick, Time}, @@ -173,7 +173,13 @@ impl<'a> System<'a> for Sys { if res_poise { let poise = &mut *poise; - poise.change_by(poise.regen_rate * dt, Vec3::zero()); + let poise_change = PoiseChange { + amount: poise.regen_rate * dt, + impulse: Vec3::zero(), + by: None, + cause: None, + }; + poise.change(poise_change); poise.regen_rate = (poise.regen_rate + POISE_REGEN_ACCEL * dt).min(10.0); } }, diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 67b4c2ce4c..fc57857cf1 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -48,14 +48,29 @@ enum DamageContrib { NotFound, } -pub fn handle_poise(server: &Server, entity: EcsEntity, change: f32, knockback_dir: Vec3) { +pub fn handle_poise(server: &Server, entity: EcsEntity, change: comp::PoiseChange) { let ecs = &server.state.ecs(); if let Some(character_state) = ecs.read_storage::().get(entity) { - // Entity is invincible to poise change during stunned/staggered character state + // Entity is invincible to poise change during stunned/staggered character + // state, but the mitigated poise damage is converted to health damage instead if !character_state.is_stunned() { if let Some(mut poise) = ecs.write_storage::().get_mut(entity) { - poise.change_by(change, knockback_dir); + poise.change(change); } + } else { + // TODO: Look into multiplying health by some fraction dependent on poise state + let time = ecs.read_resource::