fix(physics): AD-55 retired — Sledding fast-sled constant is cos(10 deg)

Per docs/research/2026-07-30-ts4-116-oracle-plan.md Addendum (byte-proven
2026-07-30). Raw bytes of CPhysicsObj::calc_friction @ 0x0050ee70's
Sledding fast-sled branch (0x0050ef52-0x0050ef6a):

  d9 86 38 01 00 00   fld  dword [esi+0x138]    ; contact_plane.Normal.Z
  dd 05 28 6b 7c 00   fld  qword [0x007c6b28]   ; = 0.17453292519943295 (10 deg RADIANS)
  d9 ff               fcos                       ; st0 = cos(10 deg) = 0.984807753
  de d9               fcompp

confirm a genuine fcos opcode over a real 10-degrees-in-radians double
literal -- not a BN misdecompile of a raw float load. Retail truly
computes cos(10 deg) ~ 0.9848078 at runtime; ACE's 0.99999536f equals
cos(0.1745 DEGREES) -- the same radian literal evaluated in degree mode,
a proven ACE porting error carried into this port provisionally.

PhysicsBody.calc_friction's Sledding near-flat override now compares
GroundNormal.Z > 0.98480775f (cos 10 deg). Feel impact: retail's 0.2f
fast-sled friction override engages on any ground within 10 degrees of
flat; the old constant engaged only within ~0.175 degrees (never, in
practice).

Tests: two new boundary pins
(calc_friction_sledding_fast_override_engages_at_5_degrees_from_flat /
..._does_not_engage_at_15_degrees_from_flat) construct a tilted
GroundNormal with velocity purely orthogonal to the tilt plane (dot=0
exactly, isolating the Sledding-band friction value from the outer 0.25f
gate and the normal-removal step) and assert the exact pow(1-friction, dt)
decay on each side of the new 10-degree boundary.

Register: AD-55 retired (struck through, retirement note with the byte
decode).

Full AcDream.Core.Tests suite: 4063 passed / 1 skipped, no regressions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-30 12:56:26 +02:00
parent 0149220506
commit 252e806804
3 changed files with 75 additions and 14 deletions

View file

@ -555,6 +555,60 @@ public sealed class PhysicsBodyTests
$"got speed {body.Velocity.Length()}");
}
// ════════════════════════════════════════════════════════════════════
// AD-55 (Campaign P final physics slice, 2026-07-30): Sledding
// fast-sled slope-flatness constant is cos(10 deg) ~ 0.98480775f
// (byte-confirmed, docs/research/2026-07-30-ts4-116-oracle-plan.md
// Addendum), NOT the ACE-derived 0.99999536f this port carried
// provisionally (cos(0.1745 DEGREES) -- a radians/degrees porting
// bug). Both boundary tests put Velocity purely along Y and
// GroundNormal's tilt purely in the X-Z plane, so
// dot(velocity, groundNormal) is EXACTLY zero -- the outer 0.25f gate
// and the normal-component-removal step are inert, isolating the
// Sledding-band friction value itself.
// ════════════════════════════════════════════════════════════════════
[Fact]
public void calc_friction_sledding_fast_override_engages_at_5_degrees_from_flat()
{
float cos5 = MathF.Cos(5f * MathF.PI / 180f);
float sin5 = MathF.Sin(5f * MathF.PI / 180f);
var body = MakeGrounded();
body.GroundNormal = new Vector3(sin5, 0f, cos5); // 5 deg tilt -- within retail's real 10 deg band
body.State |= PhysicsStateFlags.Sledding;
body.Velocity = new Vector3(0f, 3f, 0f);
float mag2 = body.Velocity.LengthSquared();
const float dt = 1f / 60f;
body.calc_friction(dt, mag2);
// friction = 0.2f (light) expected: scalar = (1 - 0.2)^dt.
float expectedSpeed = 3f * MathF.Pow(0.8f, dt);
Assert.Equal(expectedSpeed, body.Velocity.Length(), precision: 3);
}
[Fact]
public void calc_friction_sledding_fast_override_does_not_engage_at_15_degrees_from_flat()
{
float cos15 = MathF.Cos(15f * MathF.PI / 180f);
float sin15 = MathF.Sin(15f * MathF.PI / 180f);
var body = MakeGrounded();
body.GroundNormal = new Vector3(sin15, 0f, cos15); // 15 deg tilt -- past retail's real 10 deg threshold
body.State |= PhysicsStateFlags.Sledding;
body.Velocity = new Vector3(0f, 3f, 0f);
float mag2 = body.Velocity.LengthSquared();
const float dt = 1f / 60f;
body.calc_friction(dt, mag2);
// friction stays the default 0.95f (heavy): the fast-sled override
// must NOT engage past retail's real 10 deg threshold, unlike the
// old (buggy) 0.99999536f/~0.175 deg constant which would also
// have rejected this case for the wrong reason.
float expectedSpeed = 3f * MathF.Pow(1f - PhysicsBody.DefaultFriction, dt);
Assert.Equal(expectedSpeed, body.Velocity.Length(), precision: 3);
}
// ════════════════════════════════════════════════════════════════════
// update_object — per-frame driver
// ════════════════════════════════════════════════════════════════════