phase(N.1): per-helper conformance tests for WB substitutions (rotation excluded)

Phase N.1 step 3: prove our inline algorithms match WorldBuilder's
helpers for representative inputs including the 0xA9B1 edge-vertex case.

Four conformance tests pass: Displace, OnRoad, GetNormalZ, ScaleObj.
Our hand-ported algorithms match WB's helpers exactly for these.

Rotation is intentionally NOT conformance-tested. Investigation against
retail's Frame::set_heading (named-retail 0x00535e40) and
Frame::set_vector_heading (0x00535db0) showed our acdream port uses a
shortcut formula `yawDeg = -(450-degrees)%360` that diverges from
retail's atan2 round-trip by ~180°. WorldBuilder's SetHeading ports
the round-trip faithfully and matches retail. Our existing port is
wrong — undetectable visually because per-tree rotation noise masks
the offset. The migration to WB.SceneryHelpers.RotateObj fixes this
bug; adding a conformance test would lock in the wrong behavior.

Bumps IsOnRoad to internal so the OnRoad conformance test can call it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-08 09:53:00 +02:00
parent bbc618a40a
commit 4bfcb2b190
2 changed files with 177 additions and 1 deletions

View file

@ -282,7 +282,7 @@ public static class SceneryGenerator
/// based on which corners are road vertices. Road ribbons have a 5m
/// half-width (TileLength - RoadWidth = 19m).
/// </summary>
private static bool IsOnRoad(LandBlock block, float lx, float ly)
internal static bool IsOnRoad(LandBlock block, float lx, float ly)
{
int x = (int)MathF.Floor(lx / CellSize);
int y = (int)MathF.Floor(ly / CellSize);