From 527ca3be75f2a00956eef84197005638b916be21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Rom=C3=A1n=20N=C3=BA=C3=B1ez?= Date: Sun, 27 Sep 2026 17:53:51 +0200 Subject: [PATCH 1/5] Fix airdodge being able to pass through platforms when holding down. --- src/fighter/collision.rs | 19 +++++++++++++++++-- src/fighter/state/air.rs | 3 ++- src/fighter/state/air_dodge.rs | 2 +- src/fighter/state/fall.rs | 1 + src/fighter/state/hitstun.rs | 2 +- src/fighter/state/jump.rs | 1 + src/fighter/state/mod.rs | 5 +++-- src/fighter/state/platform_pass.rs | 1 + 8 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/fighter/collision.rs b/src/fighter/collision.rs index 4ea1b55..f9eae3b 100644 --- a/src/fighter/collision.rs +++ b/src/fighter/collision.rs @@ -45,7 +45,7 @@ pub fn air_collide_with_stage( ecb: &FighterECB, stage_collision: &StageCollision, ignored_polys: &[usize], - ignore_soft_platforms: bool, + can_ignore_soft_platforms: bool, ) -> Option { let ray_segment = FGSegment2d::new( prev_translation.0 + prev_ecb.get_bottom_point(), @@ -58,7 +58,7 @@ pub fn air_collide_with_stage( .enumerate() .filter(|(poly_idx, poly)| { !ignored_polys.contains(poly_idx) - && !(ignore_soft_platforms && matches!(poly.poly_type, StagePolyType::Platform)) + && !(can_ignore_soft_platforms && matches!(poly.poly_type, StagePolyType::Platform)) }) .filter_map(|(poly_idx, poly)| { poly.intersect_ray(ray_segment).map(|intersect_result| { @@ -176,6 +176,21 @@ mod tests { true, ) .is_none()); + + assert_eq!( + air_collide_with_stage( + &previous_translation, + &translation, + &previous_ecb, + &ecb, + &stage_collision, + &[], + false, + ) + .expect("air dodges still collide with soft platforms") + .hit_position, + FGVec2::lit("0", "0") + ); } #[test] diff --git a/src/fighter/state/air.rs b/src/fighter/state/air.rs index a948a25..9f2b48f 100644 --- a/src/fighter/state/air.rs +++ b/src/fighter/state/air.rs @@ -115,8 +115,9 @@ pub fn update_standard_motion( pub fn collision_interrupt( ctx: &mut CollisionContext, landing_type: LandingType, + can_ignore_soft_platforms: bool, ) -> Option { - let res = ctx.air_collide_with_stage()?; + let res = ctx.air_collide_with_stage(can_ignore_soft_platforms)?; let diff = res.hit_position - ctx.translation.0; ctx.ecb.bottom -= diff; ctx.ecb.top -= diff; diff --git a/src/fighter/state/air_dodge.rs b/src/fighter/state/air_dodge.rs index 42165df..b894434 100644 --- a/src/fighter/state/air_dodge.rs +++ b/src/fighter/state/air_dodge.rs @@ -45,7 +45,7 @@ impl FighterStateImpl for AirDodgeState { &mut self, state_context: &mut CollisionContext, ) -> Option { - air::collision_interrupt(state_context, LandingType::Special) + air::collision_interrupt(state_context, LandingType::Special, false) } fn on_enter(&mut self, state_context: &mut EnterContext) { diff --git a/src/fighter/state/fall.rs b/src/fighter/state/fall.rs index 608ae82..e945184 100644 --- a/src/fighter/state/fall.rs +++ b/src/fighter/state/fall.rs @@ -38,6 +38,7 @@ impl FighterStateImpl for FallState { air::collision_interrupt( state_context, crate::fighter::state::land::LandingType::Normal, + true, ) } diff --git a/src/fighter/state/hitstun.rs b/src/fighter/state/hitstun.rs index 9849280..33cb905 100644 --- a/src/fighter/state/hitstun.rs +++ b/src/fighter/state/hitstun.rs @@ -114,7 +114,7 @@ impl FighterStateImpl for HitstunState { match &mut self.hitstop_kind { HitstopStateKind::Grounded => collision_interrupt(state_context, true), HitstopStateKind::Airborne => { - air::collision_interrupt(state_context, LandingType::Normal) + air::collision_interrupt(state_context, LandingType::Normal, false) } } } diff --git a/src/fighter/state/jump.rs b/src/fighter/state/jump.rs index 33e2119..77efb44 100644 --- a/src/fighter/state/jump.rs +++ b/src/fighter/state/jump.rs @@ -180,6 +180,7 @@ impl FighterStateImpl for JumpState { air::collision_interrupt( state_context, crate::fighter::state::land::LandingType::Normal, + true, ) } diff --git a/src/fighter/state/mod.rs b/src/fighter/state/mod.rs index 08bc6bf..64cd610 100644 --- a/src/fighter/state/mod.rs +++ b/src/fighter/state/mod.rs @@ -214,10 +214,11 @@ pub struct CollisionContext<'a> { impl CollisionContext<'_> { pub fn air_collide_with_stage( &self, + can_ignore_soft_platforms: bool, ) -> Option { let ignored_polys = self.surface.ignored_polygon_ids(); - let ignore_soft_platforms = - self.input.get_last_frame().movement.y <= -self.downward_stick_threshold; + let ignore_soft_platforms = can_ignore_soft_platforms + && self.input.get_last_frame().movement.y <= -self.downward_stick_threshold; crate::fighter::collision::air_collide_with_stage( self.prev_translation, self.translation, diff --git a/src/fighter/state/platform_pass.rs b/src/fighter/state/platform_pass.rs index ff172d1..81105ad 100644 --- a/src/fighter/state/platform_pass.rs +++ b/src/fighter/state/platform_pass.rs @@ -46,6 +46,7 @@ impl FighterStateImpl for PlatformPassState { air::collision_interrupt( state_context, crate::fighter::state::land::LandingType::Normal, + true, ) } -- 2.54.0 From 60ed07a247cc6955e3d0e89f4efa2e8c20c27147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Rom=C3=A1n=20N=C3=BA=C3=B1ez?= Date: Sun, 27 Sep 2026 17:54:00 +0200 Subject: [PATCH 2/5] Fix move compiler "angle" function --- src/scripting/move_compiler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/move_compiler.rs b/src/scripting/move_compiler.rs index 474234b..8cc1bab 100644 --- a/src/scripting/move_compiler.rs +++ b/src/scripting/move_compiler.rs @@ -117,7 +117,7 @@ pub fn register_common_types(engine: &mut rhai::Engine) { .register_fn("knockback_normal", KnockbackType::make_normal) .register_fn("knockback_fixed", KnockbackType::make_fixed) .register_type_with_name::("Angle") - .register_fn("angle", AttackAngle::make_normal) + .register_fn("angle", |str: &str| AttackAngle::make_normal(FGi32::lit(str))) .register_fn("angle_sakurai", AttackAngle::make_sakurai) .register_type_with_name::("Knockback") .register_fn("knockback", Knockback::lit) -- 2.54.0 From f63effb067b94ff4ad8c6485202e9ba8693aa5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Rom=C3=A1n=20N=C3=BA=C3=B1ez?= Date: Sun, 27 Sep 2026 17:55:11 +0200 Subject: [PATCH 3/5] Fix being hit not causing velocity to reset --- src/fighter/state/hitstun.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fighter/state/hitstun.rs b/src/fighter/state/hitstun.rs index 33cb905..cb7d9e8 100644 --- a/src/fighter/state/hitstun.rs +++ b/src/fighter/state/hitstun.rs @@ -11,8 +11,7 @@ use crate::{ land::LandingType, wait::WaitState, }, - }, - math::int::FGi32, + }, math::{int::FGi32, vec::FGVec2}, }; #[derive(Clone, Debug, Hash)] @@ -103,6 +102,7 @@ impl FighterStateImpl for HitstunState { HitstopStateKind::Airborne => AnimKind::FlinchAir, }; state_context.play_animation(animation, false); + state_context.velocity.0 = FGVec2::ZERO; } fn on_exit(&mut self, _state_context: &mut ExitContext) {} -- 2.54.0 From e57a0eeaad37e7fffaeb358979f0e4a169cc1bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Rom=C3=A1n=20N=C3=BA=C3=B1ez?= Date: Sun, 27 Sep 2026 17:56:56 +0200 Subject: [PATCH 4/5] Fix being unable to do forward tilts from a walk --- src/fighter/state/walk.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fighter/state/walk.rs b/src/fighter/state/walk.rs index 0403d99..383f47f 100644 --- a/src/fighter/state/walk.rs +++ b/src/fighter/state/walk.rs @@ -3,7 +3,7 @@ use super::{ ground, wait, }; use crate::fighter::animation::AnimKind; -use crate::fighter::state::FighterState; +use crate::fighter::state::{self, FighterState}; #[derive(Debug, Clone, Hash)] pub struct WalkState; @@ -14,7 +14,7 @@ impl FighterStateImpl for WalkState { if let Some(state) = ground::grounded_movement_common_interrupts(state_context) { return Some(state); } - wait::check_input(state_context).or_else(|| dash::check_input(state_context)) + wait::check_input(state_context).or_else(|| dash::check_input(state_context)).or_else(|| state::ground_attack::check_interrupt(state_context)) } fn on_enter(&mut self, state_context: &mut EnterContext) { -- 2.54.0 From 1a285cd08fd76b8c63d11de1020cb10612fa971e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Rom=C3=A1n=20N=C3=BA=C3=B1ez?= Date: Sun, 27 Sep 2026 21:32:56 +0200 Subject: [PATCH 5/5] Fix tests not building --- src/scripting/move_compiler.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripting/move_compiler.rs b/src/scripting/move_compiler.rs index 8cc1bab..65e1b98 100644 --- a/src/scripting/move_compiler.rs +++ b/src/scripting/move_compiler.rs @@ -261,18 +261,18 @@ pub fn compile_script(text: &str) -> Result { mod tests { use super::*; - const HITBOX: &str = "hitbox(0, \"hand_l\", damage(\"1\"), vec3(\"0\", \"0\", \"0\"), fg32(\"1\"), angle(fg32(\"0\")), knockback_normal(), knockback(\"1\"), fg32(\"1\"));"; + const HITBOX: &str = "hitbox(0, \"hand_l\", damage(\"1\"), vec3(\"0\", \"0\", \"0\"), fg32(\"1\"), angle(\"0\"), knockback_normal(), knockback(\"1\"), fg32(\"1\"));"; #[test] fn compiled_hitboxes_are_sorted_by_authored_id() { let script = compile_script( r#" frame(1); - hitbox(20, "hand_l", damage("1"), vec3("0", "0", "0"), fg32("1"), angle(fg32("0")), knockback_normal(), knockback("1"), fg32("1")); + hitbox(20, "hand_l", damage("1"), vec3("0", "0", "0"), fg32("1"), angle("0"), knockback_normal(), knockback("1"), fg32("1")); frame(2); - hitbox(3, "hand_l", damage("2"), vec3("0", "0", "0"), fg32("1"), angle(fg32("0")), knockback_normal(), knockback("1"), fg32("1")); + hitbox(3, "hand_l", damage("2"), vec3("0", "0", "0"), fg32("1"), angle("0"), knockback_normal(), knockback("1"), fg32("1")); frame(3); - hitbox(10, "hand_l", damage("3"), vec3("0", "0", "0"), fg32("1"), angle(fg32("0")), knockback_normal(), knockback("1"), fg32("1")); + hitbox(10, "hand_l", damage("3"), vec3("0", "0", "0"), fg32("1"), angle("0"), knockback_normal(), knockback("1"), fg32("1")); frame(4); "#, ) -- 2.54.0