HUD ironing (task #38): authentic Lock producer + simple-X mode

- LOCK rules transcribed from the exported HudSimulation
  (part_013.c:5619-5634): lock requires a target AND your own HUD host
  zone damage < 0.75 (_DAT_004b7ec4 -- a shot-up targeting computer
  drops lock) AND the targeted zone damage < 1.0 (_DAT_004b7ec8;
  whole-mech target checks zone 0 -- a wreck's dead zone can't
  re-lock). Box and ring are now separate signals like the binary:
  gBTHudLockState 1 = target held (hotbox draws), 2 = LOCKED (+ the
  spinning ring).
- SIMPLE-X mode: the ctor's [0x99] minimal-reticle list transcribed
  (@4689-4705: green +-0.02..0.08 cross on the aim translate); Draw
  switches master <-> simple X on the PrimaryHudOn element bit (0x20),
  completing the recovered Execute's state-list logic.
- Canopy diagnosis sharpened (open-questions): blx_cop is the torso
  segment's inside-skeleton mesh enclosing the eye; the black box =
  the skeleton render branch missing its texture + PUNCH cutout (the
  canopy windows are punch texels). A rendering-branch task; stays
  hidden by default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-08 23:12:58 -05:00
co-authored by Claude Fable 5
parent 18d49491b7
commit 24ea7f13af
5 changed files with 82 additions and 14 deletions
+32 -2
View File
@@ -1049,6 +1049,7 @@ BTReticleRenderable::BTReticleRenderable(Entity *entity, Scalar *range_attr)
lockSpinDeg= 0.0f;
masterList = dpl2d_NewDisplayList();
simpleXList = dpl2d_NewDisplayList();
aimDotList = dpl2d_NewDisplayList();
rangeCaretR = dpl2d_NewDisplayList();
rangeCaretB = dpl2d_NewDisplayList();
@@ -1207,6 +1208,30 @@ BTReticleRenderable::BTReticleRenderable(Entity *entity, Scalar *range_attr)
dpl2d_SetLineWidth(rightArrow, 1.0f);
dpl2d_End(rightArrow); dpl2d_Compile(rightArrow);
//
// The SIMPLE X [0x99] (ctor @4689-4705 [T1]): the minimal reticle used
// when PrimaryHudOn is OFF -- a small green cross (arms +-0.02..0.08)
// riding the same aim translate. Draw switches master <-> this on the
// element-mask bit (the recovered Execute's state-list logic @4cdd9d).
//
dpl2d_Begin(simpleXList, 1);
dpl2d_SetLineWidth(simpleXList, 1.0f);
dpl2d_FullScreenClip(simpleXList);
dpl2d_SetColor(simpleXList, 0.0f, 0.75f, 0.0f);
dpl2d_CallList(simpleXList, aimDotList); // slews with the crosshair
dpl2d_OpenLines(simpleXList);
dpl2d_AddPoint(simpleXList, -0.08f, 0.0f);
dpl2d_AddPoint(simpleXList, -0.02f, 0.0f);
dpl2d_AddPoint(simpleXList, 0.02f, 0.0f);
dpl2d_AddPoint(simpleXList, 0.08f, 0.0f);
dpl2d_AddPoint(simpleXList, 0.0f, -0.08f);
dpl2d_AddPoint(simpleXList, 0.0f, -0.02f);
dpl2d_AddPoint(simpleXList, 0.0f, 0.02f);
dpl2d_AddPoint(simpleXList, 0.0f, 0.08f);
dpl2d_CloseLines(simpleXList);
dpl2d_End(simpleXList);
dpl2d_Compile(simpleXList);
// empty placeholders (filled per frame / on lock)
dpl2d_Begin(crossList, 1); dpl2d_End(crossList); dpl2d_Compile(crossList);
dpl2d_Begin(aimDotList, 1); dpl2d_End(aimDotList); dpl2d_Compile(aimDotList);
@@ -1393,7 +1418,7 @@ void
// -- the 3D marker chain remains deferred.)
{
extern int gBTHudLockState;
const int locked = (gBTHudLockState != 0);
const int locked = (gBTHudLockState == 2); // the Lock attr rule, not just a target
if (locked != lockShown)
{
lockShown = locked;
@@ -1449,7 +1474,12 @@ void
dpl2d_Compile(crossList);
}
dpl2d_ExecuteList(masterList, device);
// the STATE-list switch (Execute @4cdd9d [T1]): PrimaryHudOn (element mask
// 0x20) selects the full HUD; off = just the simple aim cross.
{
extern int gBTHudPrimary;
dpl2d_ExecuteList(gBTHudPrimary ? masterList : simpleXList, device);
}
}
//
+1
View File
@@ -547,6 +547,7 @@ class BTReticleRenderable:
//
Scalar *rangeAttr2; // [0x89] the target-range source
dpl2d_DISPLAY *masterList; // [0x98] the composed reticle
dpl2d_DISPLAY *simpleXList; // [0x99] the minimal cross (PrimaryHudOn off)
dpl2d_DISPLAY *aimDotList; // [0x9a] centre aim dot
dpl2d_DISPLAY *rangeCaretR; // [0x9b] right-ladder caret
dpl2d_DISPLAY *rangeCaretB; // [0x9c] bottom-ladder carets
+29 -1
View File
@@ -563,6 +563,7 @@ float gBTHudHeading = 0.0f;
float gBTHudTwist = 0.0f;
float gBTHudTwistLimit = 0.0f;
int gBTHudGroupMask = 0xF;
int gBTHudPrimary = 1; // PrimaryHudOn (element mask 0x20): full HUD vs simple X
// BT_GOTO beeline harness outputs (consumed by the mapper bridge, mechmppr.cpp)
int gBTGotoActive = 0;
float gBTGotoTurn = 0.0f;
@@ -2383,10 +2384,36 @@ void
float hddx = dp.x - localOrigin.linearPosition.x;
float hddz = dp.z - localOrigin.linearPosition.z;
BTSetHudTargetRange((Scalar)sqrtf(hddx*hddx + hddz*hddz));
gBTHudLockState = 2; // locked == crosshair on it
gBTHudLockWorld[0] = dp.x; // the HOTBOX point: top-centre
gBTHudLockWorld[1] = dp.y + (float)dm->CylinderReferenceHeight();
gBTHudLockWorld[2] = dp.z;
// AUTHENTIC LOCK (HudSimulation, part_013.c:5619-5634 [T1]):
// the fire-control LOCK needs (a) a working targeting computer
// -- your own HUD's host zone below 75% damage -- and (b) a
// live targeted zone -- its damage below 1.0 (a whole-mech
// target checks zone 0). So a shot-up cockpit loses the lock
// light, and a destroyed wreck's dead zone can't be re-locked.
int lock = 1;
{
MechSubsystem *hud = (MechSubsystem *)GetHudSubsystem();
if (hud != 0 && hud->GetDamageZoneProxy() != 0)
{
Mech__DamageZone *hz =
(Mech__DamageZone *)hud->GetDamageZoneProxy();
if (hz->damageLevel >= 0.75f) // _DAT_004b7ec4
lock = 0;
}
int tz = MECH_TARGET_SUBIDX(this);
if (tz < 0) tz = 0; // whole-mech -> zone 0
if (lock && tz < dm->damageZoneCount && dm->Zone(tz) != 0
&& dm->Zone(tz)->damageLevel >= 1.0f) // _DAT_004b7ec8
lock = 0;
}
// 1 = target held (hotbox draws); 2 = LOCKED (box + spin ring).
// The binary keeps these separate: the box follows HotBoxVector,
// the ring follows the Lock attr.
gBTHudLockState = lock ? 2 : 1;
}
else
{
@@ -2398,6 +2425,7 @@ void
gBTHudTwist = (float)TorsoHeading(); // RotationOfTorsoHorizontal (attr 4)
gBTHudTwistLimit = (float)GetHorizontalFiringReach();// HorizontalTorsoLimit (attrs 5/6)
gBTHudGroupMask = (int)targetReticle.reticleElementMask & 0xF;
gBTHudPrimary = ((int)targetReticle.reticleElementMask & 0x20) != 0;
}
if (gEnemyMech != 0)