From c5dfb002f3bf6e10b9010576458d2b892d05dbd5 Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Mon, 3 Aug 2026 01:12:32 -0500 Subject: [PATCH] #124: hit-location ASPECT was rotated 180 degrees -- the resolver now speaks the 1995 frame Night-10's systematic targeting audit (rear panels unhittable from direct fire, Owens left torso hitting the RIGHT weapon pod and vice versa, missiles favoring the far side) measured down to one geometric fact: the authored wedge ring puts the Front* cells in the +Z arc (slice-name audit, bit-verified tables), i.e. the 1995 resolver frame has mech-forward = +Z -- while OUR engine's entity frame carries forward along -Z. Bench proof: a victim facing its attacker took frontal beams at local z = -4..-10, theta ~270 deg, resolving the REAR-named cells (zones 12/14/15) every time. The two frames differ by a pi ROTATION about Y -- rotation, not reflection, because the field flank observations CROSS (left->right) rather than persist. ResolveHit now rotates the local impact into the cylinder's frame (negate x and z; y untouched; handedness preserved so the SelectSlice torso-twist add keeps its sign). A/B (172 resolves, live missiles+beams on a facing victim): before theta~4.7 -> rear zones only; after theta~1.42-1.59 -> utorso/dtorso/ ltorso/rtorso/arm -- the front-authored cells, with the per-burst re-roll scatter intact. NOT this bug: the "one band LOW" Y-axis half of the night-10 table -- that is #16 (pick-ray boresight parallax, code-confirmed, still open). Co-Authored-By: Claude Fable 5 --- context/combat-damage.md | 10 ++++++++++ game/reconstructed/dmgtable.cpp | 20 +++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/context/combat-damage.md b/context/combat-damage.md index 1edf23c..13e40d9 100644 --- a/context/combat-damage.md +++ b/context/combat-damage.md @@ -1012,6 +1012,16 @@ code involved; grammar = the binary ctors @0x49ea48/@0x49e5e4). Results: "Right*", W1/W2 = "Front*" -- with theta = atan2(z,x) from +X toward +Z, the mech-local FRONT is the **+Z arc (theta 45-135 deg)** and dead-ahead is the W1|W2 SEAM. (Corrects the earlier #92 comment that put frontal hits in W6.) +* **⚠ PORT FRAME ADAPTER (#124, fixed 2026-08-03)**: that +Z-forward is the + **1995 resolver frame**. OUR engine's entity frame carries forward along + **−Z** (bench-measured: a victim facing its attacker took frontal beams at + local z=−4..−10, θ≈270°, resolving the REAR-named cells — which was the whole + night-10 field table: rear panels unhittable, Owens flanks CROSSED). The + frames differ by a **π rotation about Y** (rotation, not reflection — the + flank observations cross rather than persist), so `ResolveHit` negates + local x and z after `WorldToLocal` before the band/wedge math. A/B verified: + frontal fire θ≈1.5 → utorso/dtorso/ltorso/rtorso, zero rear zones. The + separate "one band LOW" Y-signature is #16 (pick-ray parallax), not this. Frontal unaimed foot-band hits therefore straddle the RightFoot/LeftFoot cells by impact-x sign, and the authored cross-bleed (20% opposite foot, 10+10% opposite leg) is a data-true source of "hit the opposite leg" reports. diff --git a/game/reconstructed/dmgtable.cpp b/game/reconstructed/dmgtable.cpp index fe637e8..f8ce4b0 100644 --- a/game/reconstructed/dmgtable.cpp +++ b/game/reconstructed/dmgtable.cpp @@ -277,6 +277,22 @@ int Scalar heightRef = owner->CylinderReferenceHeight(); // owner+0x2ec[+0xc] if (heightRef <= 0.0f) return -1; + // PORT FRAME ADAPTER (#124, measured 2026-08-03). The 1995 resolver frame + // carries the mech's FORWARD along +Z: the authored wedge ring puts the + // FrontChest-family cells in the +Z arc (slice-name audit [T1]) -- frontal + // hits MUST read z > 0 for the shipped tables to mean what they say. Our + // engine's entity frame carries forward along -Z (bench 2026-08-03: the + // dummy facing its attacker takes frontal beams at local z = -4..-10, + // theta ~270 deg, resolving the REAR-named cells; the night-10 field table + // -- rear panels unhittable, Owens left torso -> RIGHT pod -- is this same + // pi ROTATION at every aspect: rotation, not reflection, because the + // left/right flanks CROSS rather than persist). Express the impact in the + // cylinder's frame: rotate pi about Y. y (the band axis) is untouched, + // and the frames share handedness, so the torso-twist add in SelectSlice + // keeps its sign. + local.x = -local.x; + local.z = -local.z; + // --- height -> layer (penetration depth) --- Scalar depth = local.y; // binary local_2c int layerIndex = (int)floorf((Scalar)layerCount * (depth / heightRef)); @@ -305,7 +321,9 @@ int { static int s_rh = 0; if (s_rh++ < 400) - DEBUG_STREAM << "[dmgresolve] localY=" << local.y + DEBUG_STREAM << "[dmgresolve] impact=(" << impact.x << "," + << impact.y << "," << impact.z << ")" + << " local=(" << local.x << "," << local.y << "," << local.z << ")" << " heightRef=" << heightRef << " frac=" << (depth / heightRef) << " layer=" << layerIndex << "/" << layerCount