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