fix(physics): #150 — skip ethereal targets in the step-down pass (open doors fully passable)
An OPEN door (ETHEREAL_PS 0x4 set on Use) still stopped the player with a residual threshold block after the collision sweep, despite swinging open visually. The resolver runs two collision passes per step: the main sweep and a step-down (foot-sphere "is there floor?") sub-pass. acdream tested the ethereal door in BOTH; the main pass cleared it (BSPQuery Path 1 + the Layer-2 override) but the step-down pass had no escape, leaving a Collided result at the sill -- the "can-sized cylinder on the ground threshold". Retail's CPhysicsObj::FindObjCollisions (pc:276795-276806) SKIPS an ethereal target when sphere_path.step_down != 0 -- it only tests it in the main pass. So an open door is fully passable everywhere; the swung panel's position is irrelevant (ethereal = no collision; the swing animation is purely visual). Port that branch verbatim: an ethereal-for-this-test target (target state & 0x4, OR mover-ethereal vs a non-static target) is `continue`d when sp.StepDown is set. Live-verified (user confirmed): the door now blocks 0x while open (0x1000C), still blocks while closed (0x10008); pre-fix it blocked 217x while open. Core suite green (1595/0). (An earlier "animate the door collision" theory was wrong and dropped -- if collision tracked the swung panel you'd bump the panel in its open position, which retail does not do. The user caught it.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2ac7ea776f
commit
aa7c0b5c31
2 changed files with 47 additions and 9 deletions
|
|
@ -5482,6 +5482,27 @@ outdoors at the angle that previously erased it.
|
|||
|
||||
# Recently closed
|
||||
|
||||
## #150 — Open doors still blocked at the threshold (ethereal target not skipped in the step-down pass)
|
||||
|
||||
**Status:** DONE (2026-06-25) — after the retail collision sweep, an OPEN door
|
||||
(ETHEREAL_PS 0x4 set on Use) still stopped the player with a small residual block at
|
||||
the sill ("can-sized cylinder on the ground threshold"), even though the door swings
|
||||
open visually. Root: the resolver runs two collision passes per step — the main
|
||||
sweep and a step-down (foot-sphere "is there floor?") sub-pass. acdream tested the
|
||||
ethereal door in BOTH; the main pass cleared it (Layer-1 Path-1 + the Layer-2
|
||||
override) but the **step-down pass had no escape** and its `Collided` result survived
|
||||
as the threshold block. Retail's `CPhysicsObj::FindObjCollisions` (pc:276795-276806)
|
||||
SKIPS an ethereal target entirely when `sphere_path.step_down != 0` — it only tests
|
||||
it in the main pass — so an open door is fully passable everywhere (the swung panel's
|
||||
position is irrelevant; ethereal = no collision, the animation is purely visual).
|
||||
Fix: port that exact branch — `if ((state & 0x4) || (mover.Ethereal && (state & 0x1)
|
||||
== 0)) && sp.StepDown → continue`. `TransitionTypes.cs` per-object loop. Live-verified
|
||||
(user "Yes it works"; the door now blocks 0× while open [0x1000C], still blocks while
|
||||
closed [0x10008]; pre-fix it blocked 217× while open). Core suite green (1595/0). The
|
||||
earlier "animate the door collision" theory was WRONG and dropped — the user correctly
|
||||
noted that if collision followed the swung panel you'd bump the panel in its open
|
||||
position, which retail does not do. Likely also advances the door half of #137.
|
||||
|
||||
## #149 — BSP-less landblock statics (torches/braziers/lamp-posts) were walk-through
|
||||
|
||||
**Status:** DONE (2026-06-25, `4cf6eeb`) — town props placed as landblock stabs
|
||||
|
|
|
|||
|
|
@ -2599,15 +2599,32 @@ public sealed class Transition
|
|||
if (CollisionExemption.ShouldSkip(obj.State, obj.Flags, ObjectInfo.State))
|
||||
continue;
|
||||
|
||||
// Task 3 (2026-06-24): set obstruction_ethereal on SpherePath before
|
||||
// the shape dispatch. Retail: CPhysicsObj::FindObjCollisions pc:276806 /
|
||||
// 0x0050f0c9 — `ebx->sphere_path.obstruction_ethereal = var_c` where
|
||||
// var_c=1 when the target has ETHEREAL_PS (0x4). The flag is consumed by
|
||||
// BSPQuery Path 1 (BSPTREE::find_collisions pc:323742) to route through
|
||||
// sphere_intersects_solid instead of the blocking paths, making the player
|
||||
// passable through the open door's BSP (no solid leaf at the opening).
|
||||
// Cleared after each per-object test below (retail pc:276989 / 0x0050f31e).
|
||||
sp.ObstructionEthereal = (obj.State & 0x4u) != 0;
|
||||
// Retail CPhysicsObj::FindObjCollisions ethereal branch
|
||||
// (pc:276795-276806 / 0x0050f0a2-0x0050f0c9). A target counts as
|
||||
// "ethereal for this test" when it has ETHEREAL_PS (0x4) OR the mover
|
||||
// is ethereal against a NON-static target ((state & 1) == 0):
|
||||
//
|
||||
// if ((state & 4) || (mover.ethereal && (state & 1) == 0)) {
|
||||
// var_c = 1;
|
||||
// if (sphere_path.step_down == 0) goto do_test; // main pass
|
||||
// // step_down != 0 → fall through = SKIP this target entirely
|
||||
// } else { var_c = 0; do_test: obstruction_ethereal = var_c; ...test... }
|
||||
//
|
||||
// The step-down SKIP (pc:276799 — no `goto` when step_down != 0) is what
|
||||
// makes an OPEN DOOR fully passable: the main pass tests it with
|
||||
// obstruction_ethereal=1 (BSPQuery Path 1 + the Layer-2 override below
|
||||
// force it to OK), and the foot-sphere step-down sub-pass NEVER TESTS IT
|
||||
// at all. acdream previously tested ethereal targets in BOTH passes with
|
||||
// no step-down escape, so the step-down pass left a residual threshold
|
||||
// block ("can" at the open door's sill) that retail does not have
|
||||
// (#137 / live capture 2026-06-25: 217 blocks all while door state=0x1000C).
|
||||
// obstruction_ethereal (= retail var_c) is consumed by BSPQuery Path 1
|
||||
// (BSPTREE::find_collisions pc:323742); cleared after each test (pc:276989).
|
||||
bool etherealForTest = (obj.State & 0x4u) != 0
|
||||
|| (ObjectInfo.Ethereal && (obj.State & 0x1u) == 0);
|
||||
if (etherealForTest && sp.StepDown)
|
||||
continue; // retail pc:276799 — ethereal target not tested in step-down
|
||||
sp.ObstructionEthereal = etherealForTest;
|
||||
|
||||
// L.2a slice 3 (2026-05-12): snapshot collision-normal state so
|
||||
// we can tell whether THIS object's BSP/CylSphere test produced a
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue