diff --git a/src/AcDream.Core/Physics/TransitionTypes.cs b/src/AcDream.Core/Physics/TransitionTypes.cs index 048d2c4..08c8050 100644 --- a/src/AcDream.Core/Physics/TransitionTypes.cs +++ b/src/AcDream.Core/Physics/TransitionTypes.cs @@ -2498,8 +2498,29 @@ public sealed class Transition return true; // Placement validation: can we actually stand here? + // + // A6.P3 slice 4 (2026-05-22) — reset WalkInterp to 1.0 before + // the placement_insert. The prior TransitionalInsert(5) probe + // above may have consumed WalkInterp down to 0 (e.g. on a + // step-up onto a sloped ramp — AdjustSphereToPlane lifted the + // sphere by step_down_amt and ate all the interp). With + // WalkInterp=0, subsequent AdjustSphereToPlane calls' `interp + // >= path.WalkInterp` check fires immediately (0 >= 0) and + // rejects any push-back — so any geometric overlap that needs + // push-out resolution returns false → placement fails → step-up + // returns failure → step_up_slide loop → player stuck. + // + // Retail's CTransition::step_down (acclient_2013_pseudo_c.txt:272952) + // resets walk_interp = 1 at function entry. The placement_insert + // (line 272989-272990) runs after that initial reset; we believe + // placement-insert mode doesn't consume walk_interp the same way + // because it's a "can we fit here" check, not a movement sweep. + // + // This fix is the cellar-up target (issue #98). May also help + // other "step-up onto sloped surface" scenarios. var savedInsert = sp.InsertType; sp.InsertType = InsertType.Placement; + sp.WalkInterp = 1.0f; var placeState = TransitionalInsert(1, engine);