fix(physics): L.2.3i — use FloorZ (not LandingZ) for OnWalkable test
Two parallel research agents converged on this bug. acdream's
ValidateTransition was setting OnWalkable based on `Normal.Z >= LandingZ`
(0.087, ~85° permissive) instead of `Normal.Z >= FloorZ` (0.664, ~49°
strict). Effect: a 60° roof slope (normal.Z = 0.5) was being marked
OnWalkable, letting the player walk freely up surfaces retail blocks.
Per retail PhysicsObj::is_valid_walkable
(acclient_2013_pseudo_c.txt:277180-277193) and ACE
PhysicsObj.cs:2861, the canonical "walkable" predicate is FloorZ.
LandingZ is the more permissive threshold used only in airborne→ground
transitions (Path 6 Collide handler) where we want to accept a brief
landing before the next frame's strict FloorZ check rejects the surface
and CliffSlide kicks in.
Three sites fixed:
1. Step-down branch's `zVal` initial value (was unconditional LandingZ;
now `oi.GetWalkableZ()` returns FloorZ when OnWalkable, LandingZ
otherwise — matches retail's transitional_insert step-down OK
branch at acclient_2013_pseudo_c.txt:273258-273265).
2. ValidateTransition's live-contact OnWalkable test (LandingZ → FloorZ).
3. ValidateTransition's LastKnown-fallback OnWalkable test (LandingZ →
FloorZ).
After this commit:
- Walking horizontally INTO a 60° slope: step-up's WalkableAllowance
is FloorZ (when OnWalkable), find_walkable rejects the slope's
polygon, step-up fails, StepUpSlide. Player blocked from climbing.
- Jumping ONTO a 60° roof: Path 6 still uses LandingZ (correct, we
want to land), so the player lands. Next frame: ValidateTransition
sees Normal.Z=0.5 < FloorZ → OnWalkable cleared. Player is Contact
but not OnWalkable. Currently this leaves them STUCK on the roof
(no CliffSlide yet to push them off). That's still better than
walking up the roof.
Full slide-off-roof + edge-slide-along-balcony behaviors require
porting CliffSlide + PrecipiceSlide + adding Walkable polygon
reference — that's Phase L.4 (~12-20h, sketched out by both research
agents). This commit unblocks the worst of the steep-walk-up behavior
while the bigger port is being designed.
Test count 825/825 still pass. Build clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4cbfe0a5f8
commit
e44d24cec6
1 changed files with 19 additions and 3 deletions
|
|
@ -623,7 +623,15 @@ public sealed class Transition
|
|||
if (!ci.ContactPlaneValid && oi.Contact && !sp.StepDown
|
||||
&& sp.CheckCellId != 0 && oi.StepDown)
|
||||
{
|
||||
float zVal = PhysicsGlobals.LandingZ;
|
||||
// L.2.3i (2026-04-29): retail uses FloorZ when OnWalkable,
|
||||
// LandingZ when not. acdream was unconditionally LandingZ —
|
||||
// which let the step-down probe accept steep polygons
|
||||
// (~85° permissive instead of ~49° strict) as the player's
|
||||
// new contact, contributing to the "walks up steep roofs"
|
||||
// bug. Per CTransition::transitional_insert step-down OK
|
||||
// branch (acclient_2013_pseudo_c.txt:273258-273265) and
|
||||
// ACE Transition.cs:849-856.
|
||||
float zVal = oi.GetWalkableZ();
|
||||
float stepDownHeight = oi.StepDownHeight;
|
||||
sp.WalkableAllowance = zVal;
|
||||
sp.SaveCheckPos();
|
||||
|
|
@ -1638,7 +1646,14 @@ public sealed class Transition
|
|||
ci.LastKnownContactPlaneIsWater = ci.ContactPlaneIsWater;
|
||||
|
||||
oi.State |= ObjectInfoState.Contact;
|
||||
if (ci.ContactPlane.Normal.Z >= PhysicsGlobals.LandingZ)
|
||||
// L.2.3i (2026-04-29): use FloorZ (~49°) NOT LandingZ (~85°)
|
||||
// for the OnWalkable test. The previous LandingZ check was
|
||||
// far too permissive — a 60° roof (normal.Z=0.5) was being
|
||||
// marked OnWalkable, letting the player walk up steep slopes
|
||||
// they shouldn't reach. Retail's PhysicsObj::is_valid_walkable
|
||||
// uses FloorZ unconditionally (acclient_2013_pseudo_c.txt:277180-277193,
|
||||
// ACE PhysicsObj.cs:2861).
|
||||
if (ci.ContactPlane.Normal.Z >= PhysicsGlobals.FloorZ)
|
||||
oi.State |= ObjectInfoState.OnWalkable;
|
||||
else
|
||||
oi.State &= ~ObjectInfoState.OnWalkable;
|
||||
|
|
@ -1651,7 +1666,8 @@ public sealed class Transition
|
|||
// last-known plane. Without this, every wall bump dropped the
|
||||
// player into the falling animation for one frame.
|
||||
oi.State |= ObjectInfoState.Contact;
|
||||
if (ci.LastKnownContactPlane.Normal.Z >= PhysicsGlobals.LandingZ)
|
||||
// L.2.3i: same FloorZ correction as the live-contact branch.
|
||||
if (ci.LastKnownContactPlane.Normal.Z >= PhysicsGlobals.FloorZ)
|
||||
oi.State |= ObjectInfoState.OnWalkable;
|
||||
else
|
||||
oi.State &= ~ObjectInfoState.OnWalkable;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue