diff --git a/CHANGELOG.md b/CHANGELOG.md index d42eaa89b9..2694d34f41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a skill tree for mining, which gains xp from mining ores and gems. ### Changed +- Entity-entity pushback is no longer applied in forced movement states like rolling and leaping. ### Removed diff --git a/assets/voxygen/i18n/en/_manifest.ron b/assets/voxygen/i18n/en/_manifest.ron index 737713c4dc..2be067818b 100644 --- a/assets/voxygen/i18n/en/_manifest.ron +++ b/assets/voxygen/i18n/en/_manifest.ron @@ -58,6 +58,7 @@ "You can toggle showing your amount of health on the healthbar in the settings.", "Sit near a campfire (with the 'K' key) to slowly recover from your injuries.", "Need more bags or better armor to continue your journey? Press 'C' to open the crafting menu!", + "Try jumping when rolling through creatures.", ], "npc.speech.villager": [ "Isn't it such a lovely day?", diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 4e40b2ac6c..b21d90008f 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -2,7 +2,7 @@ use crate::{ combat::Attack, comp::{tool::ToolKind, Density, Energy, InputAttr, InputKind, Ori, Pos, Vel}, event::{LocalEvent, ServerEvent}, - states::{behavior::JoinData, *}, + states::{behavior::JoinData, utils::StageSection, *}, }; use serde::{Deserialize, Serialize}; use specs::{Component, DerefFlaggedStorage, VecStorage}; @@ -196,6 +196,15 @@ impl CharacterState { pub fn is_stunned(&self) -> bool { matches!(self, CharacterState::Stunned(_)) } + pub fn is_forced_movement(&self) -> bool { + matches!(self, + CharacterState::ComboMelee(s) if s.stage_section == StageSection::Swing) + || matches!(self, CharacterState::DashMelee(s) if s.stage_section == StageSection::Charge) + || matches!(self, CharacterState::LeapMelee(s) if s.stage_section == StageSection::Movement) + || matches!(self, CharacterState::SpinMelee(s) if s.stage_section == StageSection::Swing) + || matches!(self, CharacterState::Roll(s) if s.stage_section == StageSection::Movement) + } + /// Compares for shallow equality (does not check internal struct equality) pub fn same_variant(&self, other: &Self) -> bool { // Check if state is the same without looking at the inner data diff --git a/common/systems/src/phys.rs b/common/systems/src/phys.rs index 48c36e506d..613431035c 100644 --- a/common/systems/src/phys.rs +++ b/common/systems/src/phys.rs @@ -425,16 +425,21 @@ impl<'a> PhysicsData<'a> { entity_entity_collisions += 1; } - // Don't apply repulsive force to projectiles or if - // we're - // colliding - // with a terrain-like entity, or if we are a - // terrain-like - // entity + // Don't apply e2e pushback to entities that are in a forced movement state + // (e.g. roll, leapmelee). This allows leaps to work properly (since you won't + // get pushed away before delivering the hit), and allows rolling through an + // enemy when trapped (e.g. with minotaur). This allows using e2e pushback to + // gain speed by jumping out of a roll while in the middle of a collider, this + // is an intentional combat mechanic. + let forced_movement = matches!(char_state_maybe, Some(cs) if cs.is_forced_movement()); + + // Don't apply repulsive force to projectiles or if we're colliding with a + // terrain-like entity, or if we are a terrain-like entity // // Don't apply force when entity is a sticky which is on the // ground (or on the wall) - if !(is_sticky && !is_mid_air) + if !forced_movement && + !(is_sticky && !is_mid_air) && diff.magnitude_squared() > 0.0 && !is_projectile && !matches!(