Reticle Execute @004cdcf0 RECOVERED: every HUD instrument now live (task #37)

The one un-exported gap in the reticle chain, read via capstone
(tools/disas2.py; the annotated disasm preserved at
reference/decomp/reticle_execute_004cdcf0.disasm.txt). Draw() is now a
transcription of the real per-frame logic, and the HUD attr-table names
(hud.hpp ids 4/5/6/8/A/B/C/D) are CONFIRMED by their Execute usage:

- Range ladder: BAR from ladder-top to the caret + caret translate.
- The bottom 21-tick tape is the TORSO-TWIST indicator (NOT heading):
  deflection = -/+(span/2) x (RotationOfTorsoHorizontal / twist limit),
  attrs 4/5/6. Fixed-torso BLH reads centred -- authentic static.
- The circle-with-stem is the COMPASS (attr 0xD, rad->deg rotation) at
  (botX, botY - 3*tickMajor - 0.03), with the THREAT trail (attr 0xC)
  in its rotated frame: 0.05-unit attack-direction marks, fresh < 2s
  red, expiring at 6s. Port feed: player TakeDamage pushes the impact
  direction (dormant vs the passive test dummy).
- Pips (composed into subB6): hidden when destroyed (attr 1 == 1), LIT
  when the fire cycle is LOADED (attr 0x1c == 2; port source
  rechargeLevel >= 1) else the dark charging ring; filtered by the
  weapon-GROUP bits (weaponMode & elementMask&0xF). Range plays NO part
  (the stored TargetWithinRange slots are never read by Execute).
- Lock ring: subB9 at frame centre SPINNING 4 deg/frame while locked
  ([0x9d] is the spin matrix, not a heading list).
- Target HOTBOX: a rectangle hugging the projected extents (x+-4 around
  the top-centre hotbox point, +1/-11.5 vertical; baked K=2.8145 -- the
  port projects through the live per-axis projection), switching to the
  edge arrows past +-1.6 or behind (BTProjectHotBox, L4VIDEO).
- Reticle state Off/On + PrimaryHudOn full-HUD/simple-X switch, aim
  translate on slew move, 3D marker + PNAME player-name mesh identified
  (chain still deferred).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-08 22:38:50 -05:00
co-authored by Claude Fable 5
parent cf9f56044e
commit 18d49491b7
10 changed files with 1677 additions and 108 deletions
+39
View File
@@ -231,6 +231,45 @@ int BTProjectToReticle(const float world[3], float *rx, float *ry)
return 1;
}
//
// The target HOTBOX projection (the recovered reticle Execute @4cdff7-4ce0f9
// [T1]): project the box hugging the target's extents -- x +-4 around the
// hotbox point (the target's top-centre), +1 above / -11.5 below it (the
// authored pod mech envelope; constants @4cee7c/4ceea0/4ceeac). Returns 1
// with the reticle-frame edges when the box is displayable; 0 when the target
// is BEHIND or both x-edges pass +-1.6 (constants @4cee88/90) -- then *side
// carries the arrow side (-1 left / +1 right).
//
int BTProjectHotBox(const float top[3], float *xl, float *xr,
float *yt, float *yb, int *side)
{
*side = 0;
if (!gBTAimCamValid || gBTAimP11 <= 0.0f || gBTAimP22 <= 0.0f
|| gBTAimVpH <= 0.0f)
return 0;
float rel[3];
for (int i = 0; i < 3; ++i)
rel[i] = top[i] - gBTAimCamPos[i];
const float xc = rel[0]*gBTAimCamX[0] + rel[1]*gBTAimCamX[1] + rel[2]*gBTAimCamX[2];
const float yc = rel[0]*gBTAimCamY[0] + rel[1]*gBTAimCamY[1] + rel[2]*gBTAimCamY[2];
const float zc = rel[0]*gBTAimCamZ[0] + rel[1]*gBTAimCamZ[1] + rel[2]*gBTAimCamZ[2];
const float depth = -zc; // camera looks down -Z
if (depth < 0.1f)
{
*side = (xc >= 0.0f) ? 1 : -1;
return 0;
}
const float xs = (gBTAimP11 / depth) * (gBTAimVpW / gBTAimVpH);
const float ys = gBTAimP22 / depth;
*xl = (xc - 4.0f) * xs;
*xr = (xc + 4.0f) * xs;
*yt = -(yc + 1.0f) * ys; // 1 above the hotbox point
*yb = -(yc - 11.5f) * ys; // 11.5 below it
if (*xl > 1.6f && *xr > 1.6f) { *side = 1; return 0; }
if (*xl < -1.6f && *xr < -1.6f) { *side = -1; return 0; }
return 1;
}
void BTPushBeamKind(float fx, float fy, float fz, float tx, float ty, float tz,
unsigned color, float ttl, float width, int kind)
{