diff --git a/assets/common/abilities/sword/heavy_combo.ron b/assets/common/abilities/sword/heavy_combo.ron
index d311941ad4..e8767b351b 100644
--- a/assets/common/abilities/sword/heavy_combo.ron
+++ b/assets/common/abilities/sword/heavy_combo.ron
@@ -1,25 +1,47 @@
-// TODO: Make actual ability, just for testing right now
-BasicMelee(
- energy_cost: 50,
- buildup_duration: 0.3,
- swing_duration: 0.1,
- recover_duration: 0.2,
- melee_constructor: (
- kind: Stab(
- damage: 10,
- poise: 0,
- knockback: 0,
- energy_regen: 0,
+ComboMelee2(
+ strikes: [
+ (
+ melee_constructor: (
+ kind: Slash(
+ damage: 7,
+ poise: 0,
+ knockback: 0,
+ energy_regen: 5,
+ ),
+ range: 3.0,
+ angle: 45.0,
+ ),
+ buildup_duration: 0.4,
+ swing_duration: 0.1,
+ hit_timing: 0.5,
+ recover_duration: 0.7,
+ ori_modifier: 0.6,
),
- range: 5.0,
- angle: 10.0,
- ),
- ori_modifier: 1.0,
+ (
+ melee_constructor: (
+ kind: Slash(
+ damage: 10,
+ poise: 0,
+ knockback: 0,
+ energy_regen: 10,
+ ),
+ range: 3.0,
+ angle: 45.0,
+ ),
+ buildup_duration: 0.5,
+ swing_duration: 0.1,
+ hit_timing: 0.5,
+ recover_duration: 0.6,
+ ori_modifier: 0.6,
+ ),
+ ],
+ is_stance: true,
+ energy_cost_per_strike: 5,
meta: (
- kind: Some(Sword(Balanced)),
+ kind: Some(Sword(Heavy)),
capabilities: (
- // Block
- bits: 0b00000010,
+ // Poise resistant during attack
+ bits: 0b00001000,
),
),
-)
+)
\ No newline at end of file
diff --git a/assets/common/abilities/sword/heavy_finisher.ron b/assets/common/abilities/sword/heavy_finisher.ron
index d311941ad4..27bbf2c7ca 100644
--- a/assets/common/abilities/sword/heavy_finisher.ron
+++ b/assets/common/abilities/sword/heavy_finisher.ron
@@ -1,25 +1,30 @@
-// TODO: Make actual ability, just for testing right now
-BasicMelee(
- energy_cost: 50,
- buildup_duration: 0.3,
+FinisherMelee(
+ energy_cost: 40,
+ buildup_duration: 0.4,
swing_duration: 0.1,
- recover_duration: 0.2,
+ recover_duration: 0.4,
melee_constructor: (
- kind: Stab(
- damage: 10,
- poise: 0,
+ kind: Slash(
+ damage: 20,
+ poise: 30,
+ knockback: 0,
+ energy_regen: 10,
+ ),
+ scaled: Some(Slash(
+ damage: 0,
+ poise: 20,
knockback: 0,
energy_regen: 0,
- ),
- range: 5.0,
- angle: 10.0,
+ )),
+ range: 3.0,
+ angle: 15.0,
),
- ori_modifier: 1.0,
+ scaling: Some((
+ target: Attack,
+ kind: Linear,
+ )),
+ minimum_combo: 10,
meta: (
- kind: Some(Sword(Balanced)),
- capabilities: (
- // Block
- bits: 0b00000010,
- ),
+ kind: Some(Sword(Heavy)),
),
-)
+)
\ No newline at end of file
diff --git a/assets/common/abilities/sword/heavy_fortitude.ron b/assets/common/abilities/sword/heavy_fortitude.ron
index d311941ad4..9170b40712 100644
--- a/assets/common/abilities/sword/heavy_fortitude.ron
+++ b/assets/common/abilities/sword/heavy_fortitude.ron
@@ -1,25 +1,12 @@
-// TODO: Make actual ability, just for testing right now
-BasicMelee(
- energy_cost: 50,
- buildup_duration: 0.3,
- swing_duration: 0.1,
- recover_duration: 0.2,
- melee_constructor: (
- kind: Stab(
- damage: 10,
- poise: 0,
- knockback: 0,
- energy_regen: 0,
- ),
- range: 5.0,
- angle: 10.0,
- ),
- ori_modifier: 1.0,
+SelfBuff(
+ buildup_duration: 0.2,
+ cast_duration: 0.2,
+ recover_duration: 0.6,
+ buff_kind: Fortitude,
+ buff_strength: 1.0,
+ buff_duration: Some(5.0),
+ energy_cost: 40,
meta: (
- kind: Some(Sword(Balanced)),
- capabilities: (
- // Block
- bits: 0b00000010,
- ),
+ kind: Some(Sword(Heavy)),
),
-)
+)
\ No newline at end of file
diff --git a/assets/common/abilities/sword/heavy_pommelstrike.ron b/assets/common/abilities/sword/heavy_pommelstrike.ron
index d311941ad4..57ac8ab658 100644
--- a/assets/common/abilities/sword/heavy_pommelstrike.ron
+++ b/assets/common/abilities/sword/heavy_pommelstrike.ron
@@ -1,25 +1,26 @@
-// TODO: Make actual ability, just for testing right now
-BasicMelee(
- energy_cost: 50,
- buildup_duration: 0.3,
- swing_duration: 0.1,
- recover_duration: 0.2,
- melee_constructor: (
- kind: Stab(
- damage: 10,
- poise: 0,
- knockback: 0,
- energy_regen: 0,
+ComboMelee2(
+ strikes: [
+ (
+ melee_constructor: (
+ kind: Slash(
+ damage: 10,
+ poise: 20,
+ knockback: 0,
+ energy_regen: 10,
+ ),
+ range: 4.0,
+ angle: 5.0,
+ ),
+ buildup_duration: 0.2,
+ swing_duration: 0.1,
+ hit_timing: 0.6,
+ recover_duration: 0.4,
+ ori_modifier: 0.6,
),
- range: 5.0,
- angle: 10.0,
- ),
- ori_modifier: 1.0,
+ ],
+ is_stance: false,
+ energy_cost_per_strike: 10,
meta: (
- kind: Some(Sword(Balanced)),
- capabilities: (
- // Block
- bits: 0b00000010,
- ),
+ kind: Some(Sword(Heavy)),
),
-)
+)
\ No newline at end of file
diff --git a/assets/voxygen/i18n/en/buff.ftl b/assets/voxygen/i18n/en/buff.ftl
index 3cd5c8464d..c4d1d9e1eb 100644
--- a/assets/voxygen/i18n/en/buff.ftl
+++ b/assets/voxygen/i18n/en/buff.ftl
@@ -61,6 +61,9 @@ buff-desc-wet = The ground rejects your feet, making it hard to stop.
## Ensnared
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.
## Util
buff-text-over_seconds = over { $dur_secs } seconds
buff-text-for_seconds = for { $dur_secs } seconds
diff --git a/common/src/cmd.rs b/common/src/cmd.rs
index bd9e772a84..9af913f81f 100644
--- a/common/src/cmd.rs
+++ b/common/src/cmd.rs
@@ -153,6 +153,7 @@ lazy_static! {
BuffKind::Ensnared => "ensnared",
BuffKind::Poisoned => "poisoned",
BuffKind::Hastened => "hastened",
+ BuffKind::Fortitude => "fortitude",
};
let mut buff_parser = HashMap::new();
for kind in BuffKind::iter() {
diff --git a/common/src/combat.rs b/common/src/combat.rs
index 5b18087aa7..f15c8ee1d7 100644
--- a/common/src/combat.rs
+++ b/common/src/combat.rs
@@ -286,7 +286,13 @@ impl Attack {
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, msm);
+ let change = -Poise::apply_poise_reduction(
+ poise,
+ target.inventory,
+ msm,
+ target.char_state,
+ target.stats,
+ );
let poise_change = PoiseChange {
amount: change,
impulse: *dir,
@@ -377,8 +383,13 @@ impl Attack {
}
},
CombatEffect::Poise(p) => {
- let change = -Poise::apply_poise_reduction(*p, target.inventory, msm)
- * strength_modifier;
+ let change = -Poise::apply_poise_reduction(
+ *p,
+ target.inventory,
+ msm,
+ target.char_state,
+ target.stats,
+ ) * strength_modifier;
if change.abs() > Poise::POISE_EPSILON {
let poise_change = PoiseChange {
amount: change,
@@ -536,8 +547,13 @@ impl Attack {
}
},
CombatEffect::Poise(p) => {
- let change = -Poise::apply_poise_reduction(p, target.inventory, msm)
- * strength_modifier;
+ let change = -Poise::apply_poise_reduction(
+ p,
+ target.inventory,
+ msm,
+ target.char_state,
+ target.stats,
+ ) * strength_modifier;
if change.abs() > Poise::POISE_EPSILON {
let poise_change = PoiseChange {
amount: change,
@@ -1146,7 +1162,8 @@ pub fn combat_rating(
// Normalized with a standard max poise of 100
let poise_rating = poise.base_max() as f32
/ 100.0
- / (1.0 - Poise::compute_poise_damage_reduction(inventory, msm)).max(0.00001);
+ / (1.0 - Poise::compute_poise_damage_reduction(Some(inventory), msm, None, None))
+ .max(0.00001);
// Normalized with a standard crit multiplier of 1.2
let crit_rating = compute_crit_mult(Some(inventory), msm) / 1.2;
diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs
index 10c088014e..ea4e104880 100644
--- a/common/src/comp/ability.rs
+++ b/common/src/comp/ability.rs
@@ -2544,5 +2544,6 @@ bitflags::bitflags! {
const ROLL_INTERRUPT = 0b00000001;
const BLOCK_INTERRUPT = 0b00000010;
const BUILDUP_PARRIES = 0b00000100;
+ const POISE_RESISTANT = 0b00001000;
}
}
diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs
index 1b19446da2..26088496df 100644
--- a/common/src/comp/buff.rs
+++ b/common/src/comp/buff.rs
@@ -51,6 +51,11 @@ 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 incomin poise over time
+ /// Strength scales the resistance linearly, values over 1 will usually do
+ /// nothing. 0.5 is 50%, 1.0 is 100%.
+ Fortitude,
// Debuffs
/// Does damage to a creature over time
/// Strength should be the DPS of the debuff
@@ -99,7 +104,8 @@ impl BuffKind {
| BuffKind::IncreaseMaxHealth
| BuffKind::Invulnerability
| BuffKind::ProtectingWard
- | BuffKind::Hastened => true,
+ | BuffKind::Hastened
+ | BuffKind::Fortitude => true,
BuffKind::Bleeding
| BuffKind::Cursed
| BuffKind::Burning
@@ -181,6 +187,8 @@ pub enum BuffEffect {
AttackSpeed(f32),
/// Modifies ground friction of target
GroundFriction(f32),
+ /// Reduces poise damage taken after armor is accounted for by this fraction
+ PoiseReduction(f32),
}
/// Actual de/buff.
@@ -378,6 +386,10 @@ impl Buff {
],
data.duration,
),
+ BuffKind::Fortitude => (
+ vec![BuffEffect::PoiseReduction(data.strength)],
+ data.duration,
+ ),
};
Buff {
kind,
diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs
index 8f30484fb0..b5bdad148b 100644
--- a/common/src/comp/character_state.rs
+++ b/common/src/comp/character_state.rs
@@ -1,7 +1,7 @@
use crate::{
comp::{
- ability::Capability, inventory::item::armor::Friction, item::ConsumableKind, ControlAction, Density, Energy, InputAttr,
- InputKind, Ori, Pos, Vel,
+ ability::Capability, inventory::item::armor::Friction, item::ConsumableKind, ControlAction,
+ Density, Energy, InputAttr, InputKind, Ori, Pos, Vel,
},
event::{LocalEvent, ServerEvent},
states::{
diff --git a/common/src/comp/poise.rs b/common/src/comp/poise.rs
index 09556c59d0..c4f55b6c3c 100644
--- a/common/src/comp/poise.rs
+++ b/common/src/comp/poise.rs
@@ -2,8 +2,9 @@ use crate::{
combat::{DamageContributor, DamageSource},
comp::{
self,
+ ability::Capability,
inventory::item::{armor::Protection, ItemKind, MaterialStatManifest},
- CharacterState, Inventory,
+ CharacterState, Inventory, Stats,
},
resources::Time,
states,
@@ -234,39 +235,58 @@ impl Poise {
/// Returns the total poise damage reduction provided by all equipped items
pub fn compute_poise_damage_reduction(
- inventory: &Inventory,
+ inventory: Option<&Inventory>,
msm: &MaterialStatManifest,
+ char_state: Option<&CharacterState>,
+ stats: Option<&Stats>,
) -> f32 {
- let protection = inventory
- .equipped_items()
- .filter_map(|item| {
- if let ItemKind::Armor(armor) = &*item.kind() {
- armor.stats(msm).poise_resilience
- } else {
- None
- }
- })
- .map(|protection| match protection {
- Protection::Normal(protection) => Some(protection),
- Protection::Invincible => None,
- })
- .sum::