Authentic target acquisition LIVE: reticle slew + pick-ray lock + aimed zone damage (task #36)

The engine Reticle model (MUNGA/RETICLE.h [T0]) reconstructed end to end:
- Mech::targetReticle is a real Reticle member bound to the TargetReticle
  attribute (0x1d), per the RP VTV analog (VTV.h targetReticle).
- Crosshair slew: mouse -> client rect -> reticle coords (the pod stick
  free-aim channel's dev-box stand-in); BT_AIM="x y" pins it headless.
  LMB fires lasers / RMB missiles (alongside SPACE/CTRL).
- Pick ray: the ACTIVE eye publishes pos + LookAtRH basis (BTSetAimCamera,
  L4VIDRND view-write site) + the render loop publishes proj._22;
  BTGetAimRay builds the world ray, Mech::PickRayHit slab-tests it against
  the collision template's ExtentBox via the engine's BoundingBox::HitBy
  (local frame; clips the Line at entry) -> world hull point.
- Designation: the mech under the crosshair designates (sticky; re-hover
  refreshes; cleared when the target leaves the roster at burial); the
  entity target slots 0x37c/0x388/0x38c feed the whole weapon path.
- Aimed fire: while HOT the impact point is the PICKED hull point -> the
  STEP-6 cylinder lookup resolves the zone under the crosshair (verified:
  center-aim -> head-band zone 13 dominant). Off-crosshair the sticky
  designation converges on center mass.
- HUD: the aim group draws at the slewed position ([0x9a] translate,
  contained by push/pop); the designator ring tracks the target's
  projected point (subB9 hot / subB8 designated, BTProjectToReticle);
  edge arrows when off-screen/behind.
- AUTHENTIC gating: no fire arc exists in the binary (FireWeapon fires
  whenever HasActiveTarget, part_013.c:7758) -> BT_FIRE_ARC is now an
  explicit OPT-IN presentation clamp; the hardwired gEnemyMech lock and
  the projectile path's gEnemyMech fallback are removed.
- Fixed en route: every renderable rebuild stomped mCamera back to the
  chase eye (start-inside silently lost the cockpit camera; the aim feed
  exposed it). BTL4VideoRenderer::mViewInside persists the chosen view.

Verified headless: BT_AIM="0 0" -> HOT lock, pick hits the hull face at
exact range, aimed zones resolve; BT_AIM="0.8 0.3" -> no lock, zero
damage, zero missile launches; kill chain completes to wreck + smoke.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-08 20:57:11 -05:00
co-authored by Claude Fable 5
parent 6988821525
commit d78bde066d
10 changed files with 541 additions and 185 deletions
+61 -2
View File
@@ -616,7 +616,11 @@ HierarchicalDrawComponent*
debugOffset(3,0) = camPx; debugOffset(3,1) = camPy; debugOffset(3,2) = camPz; // W row (pos)
mEyeChase = new DPLEyeRenderable(entity, debugOffset, this_root, NULL);
mCamera = mEyeChase; // default view: chase (V toggles cockpit)
// Respect the pilot's CHOSEN view across renderable rebuilds: this build
// used to stomp mCamera back to chase on every remake (damage swaps,
// start-inside), silently flipping the active eye out from under the V
// toggle (and the aim-ray camera feed with it).
mCamera = (mViewInside && mEyeCockpit != 0) ? mEyeCockpit : mEyeChase;
DEBUG_STREAM << "[BTrender] external debug chase camera installed at ("
<< camPx << "," << camPy << "," << camPz << ") looking at ("
<< tgtX << "," << tgtY << "," << tgtZ << ") -- V toggles the cockpit eyepoint"
@@ -1064,8 +1068,17 @@ BTReticleRenderable::BTReticleRenderable(Entity *entity, Scalar *range_attr)
dpl2d_SetLineWidth(m, 1.0f);
dpl2d_FullScreenClip(m);
dpl2d_SetColor(m, 0.75f, 0.0f, 0.0f);
dpl2d_CallList(m, crossList); // [0xa1] target-box slot (empty until lock)
dpl2d_CallList(m, crossList); // [0xa1] target-box slot (empty until lock;
// Draw rebuilds it: designator ring at the
// target's screen point / off-screen arrows)
dpl2d_SetColor(m, 0.0f, 0.75f, 0.0f);
// the AIM GROUP (task #36): [0x9a] is the aim TRANSLATE -- CallList state
// persists to the caller (the dpl2d inline-include semantic), so the slew
// translate it carries positions the dot + crosses that follow. The
// PushState/PopState pair contains it so the fixed frame (tick ladders,
// tapes) stays put. [T3 -- the binary Execute is un-exported; mechanism
// per the engine ReticleRenderable's position-list pattern, T0.]
dpl2d_PushState(m);
dpl2d_CallList(m, aimDotList); // [0x9a] the aim translate
dpl2d_OpenPolypoint(m); // centre dot
dpl2d_AddPoint(m, 0.0f, 0.0f);
@@ -1083,6 +1096,7 @@ BTReticleRenderable::BTReticleRenderable(Entity *entity, Scalar *range_attr)
dpl2d_AddPoint(m, 0.0f, 0.10f); dpl2d_AddPoint(m, 0.0f, 0.16f);
dpl2d_AddPoint(m, 0.0f, -0.10f); dpl2d_AddPoint(m, 0.0f, -0.16f);
dpl2d_CloseLines(m);
dpl2d_PopState(m); // contain the aim translate
dpl2d_SetLineWidth(m, 1.0f);
// the RIGHT range ladder (13 ticks up the right side, dir 3 = -y travel)
BTReticleTickLadder(m, kRetTicksR, 1, kRetScaleY,
@@ -1222,6 +1236,49 @@ void
dpl2d_End(rangeCaretR);
dpl2d_Compile(rangeCaretR);
// the AIM translate [0x9a] (task #36): the slewed crosshair position, in
// reticle coordinates (fed by the mouse / stick free-aim in mech4).
{
extern float gBTAimX, gBTAimY;
Scalar t6[6] = { 1, 0, 0, 1, gBTAimX, gBTAimY };
dpl2d_Begin(aimDotList, 1);
dpl2d_ConcatMatrix(aimDotList, t6);
dpl2d_End(aimDotList);
dpl2d_Compile(aimDotList);
}
// the TARGET DESIGNATOR slot [0xa1] (task #36, Reticle::TargetDesignatorOn
// [T0]): the designated target's projected screen point gets the lock ring
// (subB9 ring+cross while the crosshair is ON it, subB8 plain ring while
// designated); off-screen / behind, the edge turn ARROW points the way back.
{
extern int gBTHudLockState; // 0 none / 1 designated / 2 hot
extern float gBTHudLockWorld[3];
extern int BTProjectToReticle(const float world[3], float *rx, float *ry);
dpl2d_Begin(crossList, 1);
if (gBTHudLockState != 0)
{
float tx = 0.0f, ty = 0.0f;
const int onScreen = BTProjectToReticle(gBTHudLockWorld, &tx, &ty);
const float xLimit = 1.55f; // past the ladders = off-screen
if (onScreen && tx > -xLimit && tx < xLimit && ty > -1.0f && ty < 1.0f)
{
Scalar d6[6] = { 1, 0, 0, 1, tx, ty };
dpl2d_PushState(crossList);
dpl2d_ConcatMatrix(crossList, d6);
dpl2d_CallList(crossList, (gBTHudLockState == 2) ? subB9 : subB8);
dpl2d_PopState(crossList);
}
else
{
dpl2d_CallList(crossList, (tx < 0.0f) ? leftArrow : rightArrow);
}
}
dpl2d_End(crossList);
dpl2d_Compile(crossList);
}
dpl2d_ExecuteList(masterList, device);
for (int i = 0; i < weaponCount; ++i)
@@ -1623,6 +1680,7 @@ BTL4VideoRenderer::BTL4VideoRenderer(
Check_Pointer(this);
mEyeCockpit = 0;
mEyeChase = 0;
mViewInside = 0;
}
//
@@ -1633,6 +1691,7 @@ BTL4VideoRenderer::BTL4VideoRenderer(
void
BTL4VideoRenderer::SetViewInside(int inside)
{
mViewInside = inside; // persists across renderable rebuilds
if (inside && mEyeCockpit != 0)
mCamera = mEyeCockpit;
else if (!inside && mEyeChase != 0)