From a3d655970eb202ee77c63b1a04528fc84cfaa288 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 15 Dec 2022 21:51:03 -0500 Subject: [PATCH] Heavy stance required abilities --- .../abilities/sword/heavy_fortitude.ron | 48 +++---------- .../abilities/sword/heavy_pillar_thrust.ron | 63 +++++++---------- assets/voxygen/i18n/en/buff.ftl | 2 +- common/src/combat.rs | 25 +++++-- common/src/comp/ability.rs | 17 ++++- common/src/comp/buff.rs | 24 +++++-- common/src/comp/stats.rs | 12 ++-- common/src/states/behavior.rs | 3 - common/src/states/charged_melee.rs | 14 ++-- common/src/states/combo_melee2.rs | 7 +- common/src/states/dive_melee.rs | 24 +++++++ common/src/states/rapid_melee.rs | 6 +- common/src/states/self_buff.rs | 1 + common/src/states/utils.rs | 29 ++++++-- common/systems/src/aura.rs | 1 + common/systems/src/beam.rs | 1 + common/systems/src/buff.rs | 13 ++++ common/systems/src/character_behavior.rs | 5 +- common/systems/src/melee.rs | 1 + common/systems/src/projectile.rs | 1 + common/systems/src/shockwave.rs | 1 + server/src/cmd.rs | 2 + server/src/events/entity_manipulation.rs | 28 ++++---- server/src/state_ext.rs | 2 + voxygen/anim/src/character/divemelee.rs | 49 +++++++++++++ voxygen/anim/src/character/finishermelee.rs | 47 ------------- voxygen/anim/src/character/selfbuff.rs | 68 +++++++++---------- voxygen/anim/src/lib.rs | 2 +- 28 files changed, 277 insertions(+), 219 deletions(-) diff --git a/assets/common/abilities/sword/heavy_fortitude.ron b/assets/common/abilities/sword/heavy_fortitude.ron index dba2420527..15ccb63972 100644 --- a/assets/common/abilities/sword/heavy_fortitude.ron +++ b/assets/common/abilities/sword/heavy_fortitude.ron @@ -1,39 +1,9 @@ -ComboMelee2( - strikes: [ - ( - melee_constructor: ( - kind: Slash( - damage: 5, - poise: 0, - knockback: 0, - energy_regen: 5, - ), - range: 3.0, - angle: 45.0, - ), - buildup_duration: 0.15, - swing_duration: 0.05, - hit_timing: 0.5, - recover_duration: 0.1, - ori_modifier: 0.6, - ), - ( - melee_constructor: ( - kind: Slash( - damage: 10, - poise: 0, - knockback: 0, - energy_regen: 7.5, - ), - range: 3.0, - angle: 45.0, - ), - buildup_duration: 0.1, - swing_duration: 0.1, - hit_timing: 0.5, - recover_duration: 0.2, - ori_modifier: 0.6, - ), - ], - energy_cost_per_strike: 0, -) \ No newline at end of file +SelfBuff( + buildup_duration: 0.2, + cast_duration: 0.2, + recover_duration: 0.6, + buff_kind: Fortitude, + buff_strength: 1.0, + buff_duration: Some(30.0), + energy_cost: 25, +) diff --git a/assets/common/abilities/sword/heavy_pillar_thrust.ron b/assets/common/abilities/sword/heavy_pillar_thrust.ron index dba2420527..41636efdb2 100644 --- a/assets/common/abilities/sword/heavy_pillar_thrust.ron +++ b/assets/common/abilities/sword/heavy_pillar_thrust.ron @@ -1,39 +1,26 @@ -ComboMelee2( - strikes: [ - ( - melee_constructor: ( - kind: Slash( - damage: 5, - poise: 0, - knockback: 0, - energy_regen: 5, - ), - range: 3.0, - angle: 45.0, - ), - buildup_duration: 0.15, - swing_duration: 0.05, - hit_timing: 0.5, - recover_duration: 0.1, - ori_modifier: 0.6, +DiveMelee( + energy_cost: 25, + vertical_speed: 5, + buildup_duration: Some(0.2), + movement_duration: 5, + swing_duration: 0.1, + recover_duration: 0.3, + melee_constructor: ( + kind: Slash( + damage: 30, + poise: 40, + knockback: 0, + energy_regen: 0, ), - ( - melee_constructor: ( - kind: Slash( - damage: 10, - poise: 0, - knockback: 0, - energy_regen: 7.5, - ), - range: 3.0, - angle: 45.0, - ), - buildup_duration: 0.1, - swing_duration: 0.1, - hit_timing: 0.5, - recover_duration: 0.2, - ori_modifier: 0.6, - ), - ], - energy_cost_per_strike: 0, -) \ No newline at end of file + scaled: Some(Slash( + damage: 5, + poise: 10, + knockback: 0, + energy_regen: 0, + )), + range: 2.0, + angle: 45.0, + multi_target: Some(Normal), + ), + max_scaling: 6, +) diff --git a/assets/voxygen/i18n/en/buff.ftl b/assets/voxygen/i18n/en/buff.ftl index 36eb3480e2..41c4924bd9 100644 --- a/assets/voxygen/i18n/en/buff.ftl +++ b/assets/voxygen/i18n/en/buff.ftl @@ -63,7 +63,7 @@ buff-title-ensnared = Ensnared buff-desc-ensnared = Vines grasp at your legs, impeding your movement. ## Fortitude buff-title-fortitude = Fortitude -buff-desc-fortitude = You can withstand staggers. +buff-desc-fortitude = You can withstand staggers, and as you take more damage you stagger others more easily. ## Parried buff-title-parried = Parried buff-desc-parried = You were parried and now are slow to recover. diff --git a/common/src/combat.rs b/common/src/combat.rs index 3fe2c29c2c..0d98ef9e15 100644 --- a/common/src/combat.rs +++ b/common/src/combat.rs @@ -56,6 +56,7 @@ pub struct AttackerInfo<'a> { pub energy: Option<&'a Energy>, pub combo: Option<&'a Combo>, pub inventory: Option<&'a Inventory>, + pub stats: Option<&'a Stats>, } #[cfg(not(target_arch = "wasm32"))] @@ -294,7 +295,11 @@ impl Attack { // 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 poise = reduced_damage + * CRUSHING_POISE_FRACTION + * attacker + .and_then(|a| a.stats) + .map_or(1.0, |s| s.poise_damage_modifier); let change = -Poise::apply_poise_reduction( poise, target.inventory, @@ -369,6 +374,7 @@ impl Attack { time, attacker.map(|a| a.uid), target.stats, + target.health, applied_damage, strength_modifier, )), @@ -401,7 +407,10 @@ impl Attack { msm, target.char_state, target.stats, - ) * strength_modifier; + ) * strength_modifier + * attacker + .and_then(|a| a.stats) + .map_or(1.0, |s| s.poise_damage_modifier); if change.abs() > Poise::POISE_EPSILON { let poise_change = PoiseChange { amount: change, @@ -561,6 +570,7 @@ impl Attack { time, attacker.map(|a| a.uid), target.stats, + target.health, accumulated_damage, strength_modifier, )), @@ -593,7 +603,10 @@ impl Attack { msm, target.char_state, target.stats, - ) * strength_modifier; + ) * strength_modifier + * attacker + .and_then(|a| a.stats) + .map_or(1.0, |s| s.poise_damage_modifier); if change.abs() > Poise::POISE_EPSILON { let poise_change = PoiseChange { amount: change, @@ -1082,7 +1095,8 @@ impl CombatBuff { self, time: Time, uid: Option, - stats: Option<&Stats>, + tgt_stats: Option<&Stats>, + tgt_health: Option<&Health>, damage: f32, strength_modifier: f32, ) -> Buff { @@ -1102,7 +1116,8 @@ impl CombatBuff { Vec::new(), source, time, - stats, + tgt_stats, + tgt_health, ) } } diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 7b705180d6..857d47fc67 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -777,6 +777,7 @@ pub enum CharacterAbility { DiveMelee { energy_cost: f32, vertical_speed: f32, + buildup_duration: Option, movement_duration: f32, swing_duration: f32, recover_duration: f32, @@ -893,11 +894,15 @@ impl CharacterAbility { && update.energy.try_change_by(-*energy_cost).is_ok() }, CharacterAbility::DiveMelee { + buildup_duration, energy_cost, vertical_speed, .. } => { - data.vel.0.z < -*vertical_speed + // If either falling fast enough or is on ground and able to be activated from + // ground + (data.vel.0.z < -*vertical_speed + || (data.physics.on_ground.is_some() && buildup_duration.is_some())) && update.energy.try_change_by(-*energy_cost).is_ok() }, CharacterAbility::ComboMelee { .. } @@ -1425,12 +1430,14 @@ impl CharacterAbility { ref mut energy_cost, vertical_speed: _, movement_duration: _, + ref mut buildup_duration, ref mut swing_duration, ref mut recover_duration, ref mut melee_constructor, max_scaling: _, meta: _, } => { + *buildup_duration = buildup_duration.map(|b| b / stats.speed); *swing_duration /= stats.speed; *recover_duration /= stats.speed; *energy_cost /= stats.energy_efficiency; @@ -2744,6 +2751,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { exhausted: false, }), CharacterAbility::DiveMelee { + buildup_duration, movement_duration, swing_duration, recover_duration, @@ -2754,6 +2762,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { meta: _, } => CharacterState::DiveMelee(dive_melee::Data { static_data: dive_melee::StaticData { + buildup_duration: buildup_duration.map(|b| Duration::from_secs_f32(b)), movement_duration: Duration::from_secs_f32(*movement_duration), swing_duration: Duration::from_secs_f32(*swing_duration), recover_duration: Duration::from_secs_f32(*recover_duration), @@ -2763,7 +2772,11 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { ability_info, }, timer: Duration::default(), - stage_section: StageSection::Movement, + stage_section: if data.vel.0.z < 0.0 || buildup_duration.is_none() { + StageSection::Movement + } else { + StageSection::Buildup + }, exhausted: false, max_vertical_speed: 0.0, }), diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index c5c839a9c1..ab4d0a612c 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -1,6 +1,6 @@ #![allow(clippy::nonstandard_macro_braces)] //tmp as of false positive !? use crate::{ - comp::{aura::AuraKey, Stats}, + comp::{aura::AuraKey, Health, Stats}, resources::{Secs, Time}, uid::Uid, }; @@ -56,10 +56,13 @@ pub enum BuffKind { /// Strength scales strength of both effects linearly. 0.5 is a 50% /// increase, 1.0 is a 100% increase. Hastened, - // TODO: Consider non linear scaling? - /// Increases resistance to incoming poise over time - /// Strength scales the resistance linearly, values over 1 will usually do - /// nothing. 0.5 is 50%, 1.0 is 100%. + /// Increases resistance to incoming poise, and poise damage dealt as health + /// is lost from the time the buff activated + /// Strength scales the resistance non-linearly. 0.5 provides 50%, 1.0 + /// provides 67% + /// Strength scales the poise damage increase linearly, a strength of 1.0 + /// and n health less from activation will cause poise damage to increase by + /// n% Fortitude, // Debuffs /// Does damage to a creature over time @@ -214,6 +217,8 @@ pub enum BuffEffect { PoiseReduction(f32), /// Reduces amount healed by consumables HealReduction(f32), + /// Increases poise damage dealt when health is lost + PoiseDamageFromLostHealth { initial_health: f32, strength: f32 }, } /// Actual de/buff. @@ -272,6 +277,7 @@ impl Buff { source: BuffSource, time: Time, stats: Option<&Stats>, + health: Option<&Health>, ) -> Self { // Normalized nonlinear scaling let nn_scaling = |a| a / (a + 0.5); @@ -367,7 +373,13 @@ impl Buff { BuffEffect::MovementSpeed(1.0 + data.strength), BuffEffect::AttackSpeed(1.0 + data.strength), ], - BuffKind::Fortitude => vec![BuffEffect::PoiseReduction(data.strength)], + BuffKind::Fortitude => vec![ + BuffEffect::PoiseReduction(nn_scaling(data.strength)), + BuffEffect::PoiseDamageFromLostHealth { + initial_health: health.map_or(0.0, |h| h.current()), + strength: data.strength, + }, + ], BuffKind::Parried => vec![BuffEffect::AttackSpeed(0.5)], BuffKind::PotionSickness => vec![BuffEffect::HealReduction(data.strength)], }; diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index cf8321f7a5..e903780eb3 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -56,6 +56,7 @@ pub struct Stats { pub attack_speed_modifier: f32, pub friction_modifier: f32, pub max_energy_modifiers: StatsModifier, + pub poise_damage_modifier: f32, } impl Stats { @@ -70,6 +71,7 @@ impl Stats { attack_speed_modifier: 1.0, friction_modifier: 1.0, max_energy_modifiers: StatsModifier::default(), + poise_damage_modifier: 1.0, } } @@ -79,14 +81,8 @@ impl Stats { /// Resets temporary modifiers to default values pub fn reset_temp_modifiers(&mut self) { - self.damage_reduction = 0.0; - self.poise_reduction = 0.0; - self.heal_multiplier = 1.0; - self.max_health_modifiers = StatsModifier::default(); - self.move_speed_modifier = 1.0; - self.attack_speed_modifier = 1.0; - self.friction_modifier = 1.0; - self.max_energy_modifiers = StatsModifier::default(); + // TODO: Figure out how to avoid clone + *self = Self::new(self.name.clone()); } } diff --git a/common/src/states/behavior.rs b/common/src/states/behavior.rs index b3aa47f518..766a1738bc 100644 --- a/common/src/states/behavior.rs +++ b/common/src/states/behavior.rs @@ -146,7 +146,6 @@ pub struct JoinData<'a> { pub terrain: &'a TerrainGrid, pub mount_data: Option<&'a Is>, pub stance: Option<&'a Stance>, - pub time: &'a Time, } pub struct JoinStruct<'a> { @@ -174,7 +173,6 @@ pub struct JoinStruct<'a> { pub terrain: &'a TerrainGrid, pub mount_data: Option<&'a Is>, pub stance: Option<&'a Stance>, - pub time: &'a Time, } impl<'a> JoinData<'a> { @@ -216,7 +214,6 @@ impl<'a> JoinData<'a> { active_abilities: j.active_abilities, mount_data: j.mount_data, stance: j.stance, - time: j.time, } } } diff --git a/common/src/states/charged_melee.rs b/common/src/states/charged_melee.rs index e0842037c4..00fadd72ae 100644 --- a/common/src/states/charged_melee.rs +++ b/common/src/states/charged_melee.rs @@ -18,11 +18,9 @@ pub struct StaticData { pub energy_drain: f32, /// Energy cost per attack pub energy_cost: f32, - /// The state can optionally have a buildup strike that applies after buildup before charging - pub buildup_strike: Option<( - Duration, - MeleeConstructor, - )>, + /// The state can optionally have a buildup strike that applies after + /// buildup before charging + pub buildup_strike: Option<(Duration, MeleeConstructor)>, /// How long it takes to charge the weapon to max damage and knockback pub charge_duration: Duration, /// How long the weapon is swinging for @@ -74,10 +72,8 @@ impl CharacterBehavior for Data { } else { let crit_data = get_crit_data(data, self.static_data.ability_info); let buff_strength = get_buff_strength(data, self.static_data.ability_info); - data.updater.insert( - data.entity, - strike.create_melee(crit_data, buff_strength), - ); + data.updater + .insert(data.entity, strike.create_melee(crit_data, buff_strength)); if let CharacterState::ChargedMelee(c) = &mut update.character { c.stage_section = StageSection::Charge; diff --git a/common/src/states/combo_melee2.rs b/common/src/states/combo_melee2.rs index d72f8f8066..5bc9a3066a 100644 --- a/common/src/states/combo_melee2.rs +++ b/common/src/states/combo_melee2.rs @@ -76,7 +76,8 @@ pub struct StaticData { pub strikes: Vec>, /// The amount of energy consumed with each swing pub energy_cost_per_strike: f32, - /// Whether or not the state should progress through all strikes automatically once the state is entered + /// Whether or not the state should progress through all strikes + /// automatically once the state is entered pub auto_progress: bool, pub ability_info: AbilityInfo, } @@ -133,7 +134,9 @@ impl CharacterBehavior for Data { if let Some(movement) = strike_data.movement.swing { handle_forced_movement(data, &mut update, movement); } - if input_is_pressed(data, self.static_data.ability_info.input) || self.static_data.auto_progress { + if input_is_pressed(data, self.static_data.ability_info.input) + || self.static_data.auto_progress + { if let CharacterState::ComboMelee2(c) = &mut update.character { // Only have the next strike skip the recover period of this strike if not // every strike in the combo is complete yet diff --git a/common/src/states/dive_melee.rs b/common/src/states/dive_melee.rs index 6040cb4e1f..2982f1ad85 100644 --- a/common/src/states/dive_melee.rs +++ b/common/src/states/dive_melee.rs @@ -11,6 +11,8 @@ use std::time::Duration; /// Separated out to condense update portions of character state #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct StaticData { + /// If Some(_), the state can be activated on the ground + pub buildup_duration: Option, /// How long the state is moving pub movement_duration: Duration, /// How long the weapon swings @@ -51,6 +53,28 @@ impl CharacterBehavior for Data { } match self.stage_section { + StageSection::Buildup => { + handle_orientation(data, &mut update, 0.5, None); + handle_move(data, &mut update, 0.3); + + if let Some(buildup_duration) = self.static_data.buildup_duration { + if self.timer < buildup_duration { + if let CharacterState::DiveMelee(c) = &mut update.character { + c.timer = tick_attack_or_default(data, self.timer, None); + } + } else { + if let CharacterState::DiveMelee(c) = &mut update.character { + c.timer = Duration::default(); + c.stage_section = StageSection::Action; + } + } + } else { + if let CharacterState::DiveMelee(c) = &mut update.character { + c.timer = Duration::default(); + c.stage_section = StageSection::Action; + } + } + }, StageSection::Movement => { handle_move(data, &mut update, 1.0); if data.physics.on_ground.is_some() { diff --git a/common/src/states/rapid_melee.rs b/common/src/states/rapid_melee.rs index 3040a593af..9b8597ea74 100644 --- a/common/src/states/rapid_melee.rs +++ b/common/src/states/rapid_melee.rs @@ -92,9 +92,9 @@ impl CharacterBehavior for Data { Some(max) => self.current_strike < max, None => input_is_pressed(data, self.static_data.ability_info.input), } && update - .energy - .try_change_by(-self.static_data.energy_cost) - .is_ok() + .energy + .try_change_by(-self.static_data.energy_cost) + .is_ok() { if let CharacterState::RapidMelee(c) = &mut update.character { c.timer = Duration::default(); diff --git a/common/src/states/self_buff.rs b/common/src/states/self_buff.rs index c21fdb570f..43710b607b 100644 --- a/common/src/states/self_buff.rs +++ b/common/src/states/self_buff.rs @@ -72,6 +72,7 @@ impl CharacterBehavior for Data { BuffSource::Character { by: *data.uid }, *data.time, Some(data.stats), + data.health, ); output_events.emit_server(ServerEvent::Buff { entity: data.entity, diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index 5cca191e67..1b37d9767c 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -2,7 +2,7 @@ use crate::{ astar::Astar, combat, comp::{ - ability::{Ability, AbilityInput, AbilityMeta, Capability, AbilityInitEvent}, + ability::{Ability, AbilityInitEvent, AbilityInput, AbilityMeta, Capability}, arthropod, biped_large, biped_small, bird_medium, character_state::OutputEvents, controller::InventoryManip, @@ -471,7 +471,9 @@ pub fn handle_forced_movement( data.inputs.move_dir.reflected(Vec2::from(*data.ori)) } else { data.inputs.move_dir - }.try_normalized().unwrap_or_else(|| -Vec2::from(*data.ori)); + } + .try_normalized() + .unwrap_or_else(|| -Vec2::from(*data.ori)); update.vel.0 += direction * strength * accel * data.dt.0; } }, @@ -485,7 +487,9 @@ pub fn handle_forced_movement( data.inputs.move_dir.reflected(Vec2::from(*data.ori)) } else { data.inputs.move_dir - }.try_normalized().unwrap_or_else(|| Vec2::from(*data.ori)); + } + .try_normalized() + .unwrap_or_else(|| Vec2::from(*data.ori)); let direction = direction.reflected(Vec2::from(*data.ori).rotated_z(PI / 2.)); update.vel.0 += direction * strength * accel * data.dt.0; } @@ -1060,7 +1064,12 @@ pub fn handle_jump( .is_some() } -fn handle_ability(data: &JoinData<'_>, update: &mut StateUpdate, output_events: &mut OutputEvents, input: InputKind) -> bool { +fn handle_ability( + data: &JoinData<'_>, + update: &mut StateUpdate, + output_events: &mut OutputEvents, + input: InputKind, +) -> bool { let context = AbilityContext::from(data.stance); if let Some(ability_input) = input.into() { if let Some((ability, from_offhand)) = data @@ -1084,7 +1093,10 @@ fn handle_ability(data: &JoinData<'_>, update: &mut StateUpdate, output_events: if let Some(init_event) = ability.ability_meta().init_event { match init_event { AbilityInitEvent::EnterStance(stance) => { - output_events.emit_server(ServerEvent::ChangeStance { entity: data.entity, stance }); + output_events.emit_server(ServerEvent::ChangeStance { + entity: data.entity, + stance, + }); }, } } @@ -1428,7 +1440,12 @@ impl AbilityInfo { tool, hand, input, - input_attr: data.controller.queued_inputs.get(&input).map(|x| x.1).or_else(|| data.controller.held_inputs.get(&input).copied()), + input_attr: data + .controller + .queued_inputs + .get(&input) + .map(|x| x.1) + .or_else(|| data.controller.held_inputs.get(&input).copied()), ability_meta, ability, } diff --git a/common/systems/src/aura.rs b/common/systems/src/aura.rs index 74e7c38384..8037c693ac 100644 --- a/common/systems/src/aura.rs +++ b/common/systems/src/aura.rs @@ -241,6 +241,7 @@ fn activate_aura( source, *read_data.time, stats, + Some(health), )), }); } diff --git a/common/systems/src/beam.rs b/common/systems/src/beam.rs index 80aa0112d0..9025aba01b 100644 --- a/common/systems/src/beam.rs +++ b/common/systems/src/beam.rs @@ -215,6 +215,7 @@ impl<'a> System<'a> for Sys { energy: read_data.energies.get(entity), combo: read_data.combos.get(entity), inventory: read_data.inventories.get(entity), + stats: read_data.stats.get(entity), } }); diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index 92042cc23d..905416d2c9 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -151,6 +151,7 @@ impl<'a> System<'a> for Sys { BuffSource::World, *read_data.time, Some(&stat), + Some(&health), )), }); } @@ -168,6 +169,7 @@ impl<'a> System<'a> for Sys { BuffSource::World, *read_data.time, Some(&stat), + Some(&health), )), }); } @@ -185,6 +187,7 @@ impl<'a> System<'a> for Sys { BuffSource::World, *read_data.time, Some(&stat), + Some(&health), )), }); // When standing on IceSpike also apply Frozen @@ -197,6 +200,7 @@ impl<'a> System<'a> for Sys { BuffSource::World, *read_data.time, Some(&stat), + Some(&health), )), }); } @@ -217,6 +221,7 @@ impl<'a> System<'a> for Sys { BuffSource::World, *read_data.time, Some(&stat), + Some(&health), )), }); } else if matches!( @@ -296,6 +301,7 @@ impl<'a> System<'a> for Sys { buff.source, *read_data.time, Some(&stat), + Some(&health), )), }); } @@ -573,5 +579,12 @@ fn execute_effect( BuffEffect::HealReduction(red) => { stat.heal_multiplier *= 1.0 - *red; }, + BuffEffect::PoiseDamageFromLostHealth { + initial_health, + strength, + } => { + let lost_health = (*initial_health - health.current()).max(0.0); + stat.poise_damage_modifier *= lost_health / 100.0 * *strength; + }, }; } diff --git a/common/systems/src/character_behavior.rs b/common/systems/src/character_behavior.rs index 1a723dffa7..450aebfdda 100644 --- a/common/systems/src/character_behavior.rs +++ b/common/systems/src/character_behavior.rs @@ -201,7 +201,6 @@ impl<'a> System<'a> for Sys { terrain: &read_data.terrain, mount_data: read_data.is_riders.get(entity), stance: read_data.stances.get(entity), - time: &read_data.time, }; for action in actions { @@ -274,7 +273,7 @@ impl Sys { for (input, attr) in state_update.queued_inputs { join.controller .queued_inputs - .insert(input, (*join.time, attr)); + .insert(input, (Time(0.0), attr)); join.controller.held_inputs.insert(input, attr); } for input in state_update.used_inputs { @@ -283,7 +282,7 @@ impl Sys { for input in state_update.removed_inputs { join.controller.held_inputs.remove(&input); } - join.controller.cull_queued_inputs(*join.time); + join.controller.cull_queued_inputs(Time(0.0)); if state_update.swap_equipped_weapons { output_events.emit_server(ServerEvent::InventoryManip( join.entity, diff --git a/common/systems/src/melee.rs b/common/systems/src/melee.rs index 7b7446b282..b08576e145 100644 --- a/common/systems/src/melee.rs +++ b/common/systems/src/melee.rs @@ -191,6 +191,7 @@ impl<'a> System<'a> for Sys { energy: read_data.energies.get(attacker), combo: read_data.combos.get(attacker), inventory: read_data.inventories.get(attacker), + stats: read_data.stats.get(attacker), }); let target_info = TargetInfo { diff --git a/common/systems/src/projectile.rs b/common/systems/src/projectile.rs index 087a3e6818..2bf69a74e0 100644 --- a/common/systems/src/projectile.rs +++ b/common/systems/src/projectile.rs @@ -298,6 +298,7 @@ fn dispatch_hit( energy: read_data.energies.get(entity), combo: read_data.combos.get(entity), inventory: read_data.inventories.get(entity), + stats: read_data.stats.get(entity), }); let target_info = TargetInfo { diff --git a/common/systems/src/shockwave.rs b/common/systems/src/shockwave.rs index 3eb5e08ff1..993821ccf6 100644 --- a/common/systems/src/shockwave.rs +++ b/common/systems/src/shockwave.rs @@ -198,6 +198,7 @@ impl<'a> System<'a> for Sys { energy: read_data.energies.get(entity), combo: read_data.combos.get(entity), inventory: read_data.inventories.get(entity), + stats: read_data.stats.get(entity), }); let target_info = TargetInfo { diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 6289bb40fd..37efa70960 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -3541,6 +3541,7 @@ fn cast_buff(kind: &str, data: BuffData, server: &mut Server, target: EcsEntity) let ecs = &server.state.ecs(); let mut buffs_all = ecs.write_storage::(); let stats = ecs.read_storage::(); + let healths = ecs.read_storage::(); let time = ecs.read_resource::