mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'srpapinha/parried-debuff-rework' into 'master'
Parried debuff rework See merge request veloren/veloren!4416
This commit is contained in:
commit
9264c10289
@ -63,6 +63,7 @@ pub const MAX_BLOCK_POISE_COST: f32 = 25.0;
|
||||
pub const PARRY_BONUS_MULTIPLIER: f32 = 2.0;
|
||||
pub const FALLBACK_BLOCK_STRENGTH: f32 = 5.0;
|
||||
pub const BEHIND_TARGET_ANGLE: f32 = 45.0;
|
||||
pub const BASE_PARRIED_POISE_PUNISHMENT: f32 = 100.0 / 3.5;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AttackerInfo<'a> {
|
||||
@ -76,6 +77,7 @@ pub struct AttackerInfo<'a> {
|
||||
pub mass: Option<&'a Mass>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TargetInfo<'a> {
|
||||
pub entity: EcsEntity,
|
||||
pub uid: Uid,
|
||||
@ -187,6 +189,7 @@ impl Attack {
|
||||
defender: target.entity,
|
||||
attacker: attacker.map(|a| a.entity),
|
||||
source,
|
||||
poise_multiplier: 2.0 - (damage_value / block_strength).min(1.0),
|
||||
});
|
||||
}
|
||||
|
||||
@ -301,10 +304,22 @@ impl Attack {
|
||||
(matches!(attack_effect.target, Some(GroupTarget::OutOfGroup)) && !allow_friendly_fire)
|
||||
&& (target_dodging || !permit_pvp)
|
||||
};
|
||||
let precision_mult = attacker
|
||||
|
||||
let from_precision_mult = attacker
|
||||
.and_then(|a| a.stats)
|
||||
.and_then(|s| s.precision_multiplier_override)
|
||||
.or(precision_mult);
|
||||
|
||||
let from_precision_vulnerability_mult = target
|
||||
.stats
|
||||
.and_then(|s| s.precision_vulnerability_multiplier_override);
|
||||
|
||||
let precision_mult = match (from_precision_mult, from_precision_vulnerability_mult) {
|
||||
(Some(a), Some(b)) => Some(a.max(b)),
|
||||
(Some(a), None) | (None, Some(a)) => Some(a),
|
||||
(None, None) => None,
|
||||
};
|
||||
|
||||
let mut is_applied = false;
|
||||
let mut accumulated_damage = 0.0;
|
||||
let damage_modifier = attacker
|
||||
|
@ -2402,6 +2402,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState {
|
||||
},
|
||||
timer: Duration::default(),
|
||||
stage_section: StageSection::Buildup,
|
||||
is_parry: false,
|
||||
}),
|
||||
CharacterAbility::Roll {
|
||||
energy_cost: _,
|
||||
|
@ -436,7 +436,10 @@ impl BuffKind {
|
||||
BuffEffect::PoiseReduction(nn_scaling(data.strength)),
|
||||
BuffEffect::PoiseDamageFromLostHealth(data.strength),
|
||||
],
|
||||
BuffKind::Parried => vec![BuffEffect::AttackSpeed(0.5)],
|
||||
BuffKind::Parried => vec![
|
||||
BuffEffect::RecoverySpeed(0.25),
|
||||
BuffEffect::PrecisionVulnerabilityOverride(1.0),
|
||||
],
|
||||
//TODO: Handle potion sickness in a more general way.
|
||||
BuffKind::PotionSickness => vec![
|
||||
BuffEffect::HealReduction(data.strength),
|
||||
@ -672,6 +675,8 @@ pub enum BuffEffect {
|
||||
MovementSpeed(f32),
|
||||
/// Modifies attack speed of target
|
||||
AttackSpeed(f32),
|
||||
/// Modifies recovery speed of target
|
||||
RecoverySpeed(f32),
|
||||
/// Modifies ground friction of target
|
||||
GroundFriction(f32),
|
||||
/// Reduces poise damage taken after armor is accounted for by this fraction
|
||||
@ -686,6 +691,8 @@ pub enum BuffEffect {
|
||||
AttackDamage(f32),
|
||||
/// Overrides the precision multiplier applied to an attack
|
||||
PrecisionOverride(f32),
|
||||
/// Overrides the precision multiplier applied to an incoming attack
|
||||
PrecisionVulnerabilityOverride(f32),
|
||||
/// Changes body.
|
||||
BodyChange(Body),
|
||||
BuffImmunity(BuffKind),
|
||||
|
@ -61,11 +61,13 @@ pub struct Stats {
|
||||
pub move_speed_modifier: f32,
|
||||
pub jump_modifier: f32,
|
||||
pub attack_speed_modifier: f32,
|
||||
pub recovery_speed_modifier: f32,
|
||||
pub friction_modifier: f32,
|
||||
pub max_energy_modifiers: StatsModifier,
|
||||
pub poise_damage_modifier: f32,
|
||||
pub attack_damage_modifier: f32,
|
||||
pub precision_multiplier_override: Option<f32>,
|
||||
pub precision_vulnerability_multiplier_override: Option<f32>,
|
||||
pub swim_speed_modifier: f32,
|
||||
/// This adds effects to any attacks that the entity makes
|
||||
pub effects_on_attack: Vec<AttackEffect>,
|
||||
@ -93,11 +95,13 @@ impl Stats {
|
||||
move_speed_modifier: 1.0,
|
||||
jump_modifier: 1.0,
|
||||
attack_speed_modifier: 1.0,
|
||||
recovery_speed_modifier: 1.0,
|
||||
friction_modifier: 1.0,
|
||||
max_energy_modifiers: StatsModifier::default(),
|
||||
poise_damage_modifier: 1.0,
|
||||
attack_damage_modifier: 1.0,
|
||||
precision_multiplier_override: None,
|
||||
precision_vulnerability_multiplier_override: None,
|
||||
swim_speed_modifier: 1.0,
|
||||
effects_on_attack: Vec::new(),
|
||||
mitigations_penetration: 0.0,
|
||||
|
@ -332,6 +332,7 @@ pub struct ParryHookEvent {
|
||||
pub defender: EcsEntity,
|
||||
pub attacker: Option<EcsEntity>,
|
||||
pub source: AttackSource,
|
||||
pub poise_multiplier: f32,
|
||||
}
|
||||
|
||||
pub struct RequestSiteInfoEvent {
|
||||
|
@ -134,7 +134,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
update.character = CharacterState::BasicAura(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -216,7 +216,11 @@ impl CharacterBehavior for Data {
|
||||
StageSection::Recover => {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
update.character = CharacterState::BasicBeam(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -51,6 +51,8 @@ pub struct Data {
|
||||
pub timer: Duration,
|
||||
/// What section the character stage is in
|
||||
pub stage_section: StageSection,
|
||||
// Whether there was parry
|
||||
pub is_parry: bool,
|
||||
}
|
||||
|
||||
impl CharacterBehavior for Data {
|
||||
@ -100,10 +102,16 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
},
|
||||
StageSection::Recover => {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
if (self.static_data.parry_window.recover || !self.is_parry)
|
||||
&& self.timer < self.static_data.recover_duration
|
||||
{
|
||||
// Recovery
|
||||
update.character = CharacterState::BasicBlock(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -133,7 +133,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovery
|
||||
update.character = CharacterState::BasicMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -154,7 +154,11 @@ impl CharacterBehavior for Data {
|
||||
} else if self.timer < self.static_data.recover_duration {
|
||||
// Recovers
|
||||
update.character = CharacterState::BasicRanged(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -249,7 +249,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovery
|
||||
update.character = CharacterState::BasicSummon(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -78,7 +78,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovery
|
||||
update.character = CharacterState::Blink(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -206,7 +206,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovers
|
||||
update.character = CharacterState::ChargedMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -171,7 +171,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovers
|
||||
update.character = CharacterState::ChargedRanged(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -234,7 +234,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < strike_data.recover_duration {
|
||||
// Recovery
|
||||
if let CharacterState::ComboMelee2(c) = &mut update.character {
|
||||
c.timer = tick_attack_or_default(data, self.timer, None);
|
||||
c.timer = tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Return to wielding
|
||||
|
@ -170,7 +170,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recover
|
||||
update.character = CharacterState::DashMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -131,7 +131,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Complete recovery delay before finishing state
|
||||
if let CharacterState::DiveMelee(c) = &mut update.character {
|
||||
c.timer = tick_attack_or_default(data, self.timer, None);
|
||||
c.timer = tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Done
|
||||
|
@ -128,7 +128,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovery
|
||||
if let CharacterState::FinisherMelee(c) = &mut update.character {
|
||||
c.timer = tick_attack_or_default(data, self.timer, None);
|
||||
c.timer = tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Done
|
||||
|
@ -139,14 +139,22 @@ impl CharacterBehavior for Data {
|
||||
);
|
||||
|
||||
update.character = CharacterState::LeapMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
exhausted: true,
|
||||
..*self
|
||||
});
|
||||
} else if self.timer < self.static_data.recover_duration {
|
||||
// Complete recovery delay before finishing state
|
||||
update.character = CharacterState::LeapMelee(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -248,7 +248,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovers
|
||||
update.character = CharacterState::LeapShockwave(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -127,7 +127,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recover
|
||||
if let CharacterState::RapidMelee(c) = &mut update.character {
|
||||
c.timer = tick_attack_or_default(data, self.timer, None);
|
||||
c.timer = tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Done
|
||||
|
@ -187,7 +187,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recover from attack
|
||||
update.character = CharacterState::RepeaterRanged(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -94,7 +94,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovery
|
||||
if let CharacterState::RiposteMelee(c) = &mut update.character {
|
||||
c.timer = tick_attack_or_default(data, self.timer, None);
|
||||
c.timer = tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Done
|
||||
|
@ -119,7 +119,11 @@ impl CharacterBehavior for Data {
|
||||
{
|
||||
// Recover
|
||||
update.character = CharacterState::Roll(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -170,7 +170,11 @@ impl CharacterBehavior for Data {
|
||||
StageSection::Recover => {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
update.character = CharacterState::SelfBuff(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -174,7 +174,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovers
|
||||
update.character = CharacterState::Shockwave(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -95,7 +95,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovery
|
||||
if let CharacterState::SpriteInteract(c) = &mut update.character {
|
||||
c.timer = tick_attack_or_default(data, self.timer, None);
|
||||
c.timer = tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Create inventory manipulation event
|
||||
|
@ -183,7 +183,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovery
|
||||
update.character = CharacterState::SpriteSummon(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -140,7 +140,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
update.character = CharacterState::StaticAura(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -66,7 +66,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
// Recovery
|
||||
update.character = CharacterState::Stunned(Data {
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -114,7 +114,11 @@ impl CharacterBehavior for Data {
|
||||
if self.timer < self.static_data.recover_duration {
|
||||
update.character = CharacterState::Transform(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -120,7 +120,11 @@ impl CharacterBehavior for Data {
|
||||
// Recovery
|
||||
update.character = CharacterState::UseItem(Data {
|
||||
static_data: self.static_data.clone(),
|
||||
timer: tick_attack_or_default(data, self.timer, None),
|
||||
timer: tick_attack_or_default(
|
||||
data,
|
||||
self.timer,
|
||||
Some(data.stats.recovery_speed_modifier),
|
||||
),
|
||||
..*self
|
||||
});
|
||||
} else {
|
||||
|
@ -755,6 +755,9 @@ fn execute_effect(
|
||||
BuffEffect::AttackSpeed(speed) => {
|
||||
stat.attack_speed_modifier *= *speed;
|
||||
},
|
||||
BuffEffect::RecoverySpeed(speed) => {
|
||||
stat.recovery_speed_modifier *= *speed;
|
||||
},
|
||||
BuffEffect::GroundFriction(gf) => {
|
||||
stat.friction_modifier *= *gf;
|
||||
},
|
||||
@ -781,6 +784,13 @@ fn execute_effect(
|
||||
.map(|mult| mult.min(*val))
|
||||
.or(Some(*val));
|
||||
},
|
||||
BuffEffect::PrecisionVulnerabilityOverride(val) => {
|
||||
// Use higher of precision multiplier overrides
|
||||
stat.precision_vulnerability_multiplier_override = stat
|
||||
.precision_vulnerability_multiplier_override
|
||||
.map(|mult| mult.max(*val))
|
||||
.or(Some(*val));
|
||||
},
|
||||
BuffEffect::BodyChange(b) => {
|
||||
// For when an entity is under the effects of multiple de/buffs that change the
|
||||
// body, to avoid flickering between many bodies only change the body if the
|
||||
|
@ -18,7 +18,7 @@ use crate::{
|
||||
#[cfg(feature = "worldgen")]
|
||||
use common::rtsim::{Actor, RtSimEntity};
|
||||
use common::{
|
||||
combat::{self, AttackSource, DamageContributor, DeathEffect},
|
||||
combat::{self, AttackSource, DamageContributor, DeathEffect, BASE_PARRIED_POISE_PUNISHMENT},
|
||||
comp::{
|
||||
self,
|
||||
aura::{self, EnteredAuras},
|
||||
@ -28,7 +28,7 @@ use common::{
|
||||
item::flatten_counted_items,
|
||||
loot_owner::LootOwnerKind,
|
||||
Alignment, Auras, Body, CharacterState, Energy, Group, Health, Inventory, Object,
|
||||
PickupItem, Player, Poise, Pos, Presence, PresenceKind, SkillSet, Stats,
|
||||
PickupItem, Player, Poise, PoiseChange, Pos, Presence, PresenceKind, SkillSet, Stats,
|
||||
BASE_ABILITY_LIMIT,
|
||||
},
|
||||
consts::TELEPORTER_RADIUS,
|
||||
@ -1746,18 +1746,31 @@ impl ServerEvent for ParryHookEvent {
|
||||
type SystemData<'a> = (
|
||||
Read<'a, Time>,
|
||||
Read<'a, EventBus<EnergyChangeEvent>>,
|
||||
Read<'a, EventBus<PoiseChangeEvent>>,
|
||||
Read<'a, EventBus<BuffEvent>>,
|
||||
WriteStorage<'a, CharacterState>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Stats>,
|
||||
ReadStorage<'a, comp::Mass>,
|
||||
ReadStorage<'a, Inventory>,
|
||||
);
|
||||
|
||||
fn handle(
|
||||
events: impl ExactSizeIterator<Item = Self>,
|
||||
(time, energy_change_events, buff_events, mut character_states, uids, stats, masses): Self::SystemData<'_>,
|
||||
(
|
||||
time,
|
||||
energy_change_events,
|
||||
poise_change_events,
|
||||
buff_events,
|
||||
mut character_states,
|
||||
uids,
|
||||
stats,
|
||||
masses,
|
||||
inventories,
|
||||
): Self::SystemData<'_>,
|
||||
) {
|
||||
let mut energy_change_emitter = energy_change_events.emitter();
|
||||
let mut poise_change_emitter = poise_change_events.emitter();
|
||||
let mut buff_emitter = buff_events.emitter();
|
||||
for ev in events {
|
||||
if let Some(mut char_state) = character_states.get_mut(ev.defender) {
|
||||
@ -1773,6 +1786,7 @@ impl ServerEvent for ParryHookEvent {
|
||||
entity: ev.defender,
|
||||
change: c.static_data.energy_regen,
|
||||
});
|
||||
c.is_parry = true;
|
||||
false
|
||||
},
|
||||
_ => false,
|
||||
@ -1787,8 +1801,8 @@ impl ServerEvent for ParryHookEvent {
|
||||
if let Some(attacker) = ev.attacker
|
||||
&& matches!(ev.source, AttackSource::Melee)
|
||||
{
|
||||
// When attacker is parried, add the parried debuff for 2 seconds, which slows
|
||||
// them
|
||||
// When attacker is parried, the debuff lasts 2 seconds, the attacker takes
|
||||
// poise damage, get precision vulnerability and get slower recovery speed
|
||||
let data = buff::BuffData::new(1.0, Some(Secs(2.0)));
|
||||
let source = if let Some(uid) = uids.get(ev.defender) {
|
||||
BuffSource::Character { by: *uid }
|
||||
@ -1812,6 +1826,27 @@ impl ServerEvent for ParryHookEvent {
|
||||
entity: attacker,
|
||||
buff_change: buff::BuffChange::Add(buff),
|
||||
});
|
||||
|
||||
let attacker_poise_change = Poise::apply_poise_reduction(
|
||||
ev.poise_multiplier.clamp(1.0, 2.0) * BASE_PARRIED_POISE_PUNISHMENT,
|
||||
inventories.get(attacker),
|
||||
&MaterialStatManifest::load().read(),
|
||||
character_states.get(attacker),
|
||||
stats.get(attacker),
|
||||
);
|
||||
|
||||
poise_change_emitter.emit(PoiseChangeEvent {
|
||||
entity: attacker,
|
||||
change: PoiseChange {
|
||||
amount: -attacker_poise_change,
|
||||
impulse: Vec3::zero(),
|
||||
by: uids
|
||||
.get(ev.defender)
|
||||
.map(|d| DamageContributor::new(*d, None)),
|
||||
cause: Some(DamageSource::Melee),
|
||||
time: *time,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user