Targeting correction: reticle = TORSO BORESIGHT, not a free mouse cursor (task #39)
Colleague flagged that targeting is torso-locked with no fine cursor. Correct: the pod stick's yaw drove the TORSO TWIST (MechControlsMapper -> HUD::SetFreeAimSlew(stick_x) @cockpit+0x28C, gated on torso-horizontal-enabled; hud.hpp:167) and reticlePosition @HUD+0x1FC is COMPUTED by HudSimulation from the mech pose quaternion + target geometry, zeroed to centre with no target (part_013.c:5680) -- never a free-floating cursor. The engine Reticle struct is general (shared with Red Planet); BT drives it from the torso boresight. Fix: - Removed the mouse-cursor slew (a mis-sourced stand-in from the RP-shared struct). The crosshair is now the torso boresight: BTTwistToReticleX(torsoTwist) = tan(twist) projected through the live per-axis projection. Dead-centre on the fixed-torso BLH (TorsoHorizontalEnabled=0); you aim by steering the whole mech. - BT_AIM="x y" retained as the headless test harness. Verified: face-to-face spawn -> HOT lock + aimed zone hits (36); BT_FORCE_TURN circling -> 31 no-target vs 1 HOT (steering off-target drops the lock, as it must). KB swept (combat-damage / gauges-hud / open-questions); checkctx CLEAN. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
24ea7f13af
commit
a8a56c57c9
+38
-35
@@ -32,41 +32,44 @@ player input). [T1]
|
||||
`mech+0x38c` = targeted sub-zone (−1=whole). Weapons cache hasTarget/targetPoint/muzzlePoint,
|
||||
refreshed each frame. [T1]
|
||||
|
||||
**The AUTHENTIC acquisition model (recovered 2026-07-08, `engine/MUNGA/RETICLE.h` [T0]):** the
|
||||
engine `Reticle` struct (the mech's **"TargetReticle" attribute** — the same one the reticle
|
||||
renderable ctor binds) carries `reticlePosition` (screen −1..+1, SLEWABLE — the mechmppr
|
||||
`freeAimSlew`), `pickPointingOn`, `rayIntersection` (Point3D), `targetEntity`, and
|
||||
`targetDamageZone`: the pilot slews the crosshair; the engine **pick-rays through it** into the
|
||||
3D world; the entity (and the specific DAMAGE ZONE) under the crosshair become the target. The
|
||||
mech's three slots are this pick's result: `0x37c` = rayIntersection, `0x388` = targetEntity,
|
||||
`0x38c` = targetDamageZone (so aimed shots hit the zone under the crosshair — the aimed-damage
|
||||
path). `Reticle::ReticleElements` has a `TargetDesignatorOn` box + direction-arrow bit (the HUD's
|
||||
lock box; the reticle's off-screen turn arrows point at it). Once locked, `Emitter::FireWeapon`
|
||||
converges on the target with NO aim/arc test (part_013.c:7758: `range <= weaponRange → damage
|
||||
*(mech+0x388)`) — convergence-on-lock IS authentic; the skill is keeping the crosshair on the
|
||||
enemy. `MechWeapon::UpdateTargetState` (`FUN_004b9bdc` [T1]): `targetWithinRange = dist <
|
||||
(1 − hostZoneDamage) × weaponRange` — damage DEGRADES weapon reach; that flag is the HUD pip's
|
||||
lit state. The 0x388 WRITER (the per-frame reticle→mech copy) is in an un-exported decomp gap.
|
||||
**Port status: RECONSTRUCTED + runtime-verified (task #36, 2026-07-08) [T2].** The chain:
|
||||
`Mech::targetReticle` (real `Reticle` member, bound to the TargetReticle attr 0x1d) ← slew from
|
||||
the MOUSE (dev-box stand-in for the pod stick free-aim; `BT_AIM="x y"` pins it headless) →
|
||||
`BTGetAimRay` (L4VIDEO; the ACTIVE eye publishes pos+LookAtRH basis via `BTSetAimCamera`, the
|
||||
render loop publishes proj._22) → `Mech::PickRayHit` (world ray → local frame →
|
||||
`BoundingBox::HitBy` slab test vs the collision template's ExtentBox → world hit point) → the
|
||||
entity target slots. The slots MIRROR the pick EACH FRAME: locked while the crosshair is ON the
|
||||
mech, no target otherwise — keeping the crosshair on the enemy IS the gunnery. (⚠ A first cut
|
||||
made the designation STICKY — once hovered, locked forever — which made aim irrelevant after the
|
||||
first acquisition; play-tested wrong, and the binary treats no-target as a FREQUENT live state:
|
||||
the fire path re-checks 0x388!=0 at every step, part_013.c:7689/7727, and the HUD range feed has
|
||||
a permanent no-target default, :5636. Corrected 2026-07-08.) While locked the impact point = the
|
||||
PICKED hull point → STEP-6 resolves the zone under the crosshair (verified: center-aim at the
|
||||
head band → zone 13 dominant). The HUD
|
||||
draws the aim group at the slewed position ([0x9a] translate list, contained by push/pop), the
|
||||
designator ring at the target's projected point (subB9 hot / subB8 designated,
|
||||
`BTProjectToReticle`), and the edge arrows when off-screen/behind. `BT_FIRE_ARC` is now an
|
||||
EXPLICIT OPT-IN presentation clamp (unset = authentic no-arc). The old hardwired lock, the
|
||||
±30°-default cone, and the projectile path's gEnemyMech fallback are all REMOVED. LMB fires
|
||||
lasers / RMB missiles (with SPACE/CTRL). ⚠ A view-selection bug was fixed en route: every
|
||||
**The AUTHENTIC acquisition model (recovered 2026-07-08; corrected 2026-07-08, task #39):** THERE
|
||||
IS NO FREE-AIM MOUSE CURSOR. The pod had a stick whose yaw drove the **torso twist**
|
||||
(`MechControlsMapper` writes `HUD::SetFreeAimSlew(stick_x)` → cockpit+0x28C, gated on the torso's
|
||||
horizontal-twist being enabled — `mechmppr.cpp:735/762`, hud.hpp:167 [T1]); the crosshair marks
|
||||
where the **torso guns boresight** relative to the body-mounted view. You aim by **steering the
|
||||
mech / twisting the torso**, not by moving a cursor. The engine `Reticle` struct
|
||||
(`engine/MUNGA/RETICLE.h`) carries `reticlePosition`, `pickPointingOn`, `rayIntersection`,
|
||||
`targetEntity`, `targetDamageZone` — a general struct shared with Red Planet — but in BT
|
||||
`reticlePosition`/HotBoxVector (@mech-HUD+0x1FC) is **COMPUTED by HudSimulation** from the mech
|
||||
pose quaternion (`FUN_0040954c` quat→euler of mech+0x10C) + the target geometry, and **zeroed to
|
||||
centre when there is no target** (part_013.c:5680, `FUN_00408440(...,&DAT_004e0f74)` [T1]) — it is
|
||||
NOT a free-floating cursor. The pick then hits whatever the guns point at; that entity + its
|
||||
DAMAGE ZONE become the target (`0x37c` rayIntersection, `0x388` targetEntity, `0x38c`
|
||||
targetDamageZone → aimed-zone damage). Fixed-torso mechs (the BLH: `TorsoHorizontalEnabled=0`)
|
||||
boresight dead-ahead — the crosshair sits centred and you point the whole mech. Once locked,
|
||||
`Emitter::FireWeapon` converges with NO aim/arc test (part_013.c:7758). `MechWeapon::
|
||||
UpdateTargetState` (`FUN_004b9bdc` [T1]): `targetWithinRange = dist < (1 − hostZoneDamage) ×
|
||||
weaponRange`. The 0x388 WRITER (the per-frame reticle→mech copy) is in an un-exported decomp gap.
|
||||
**Port status: RECONSTRUCTED + runtime-verified (tasks #36/#39, 2026-07-08) [T2].** The chain:
|
||||
the crosshair = **torso boresight** (`BTTwistToReticleX(torsoTwist)`, L4VIDEO — tan(twist)
|
||||
projected through the live per-axis projection; **0 = dead-centre on the fixed-torso BLH**;
|
||||
`BT_AIM="x y"` pins it for headless tests) → `BTGetAimRay` (the ACTIVE eye publishes pos+LookAtRH
|
||||
basis via `BTSetAimCamera`, the render loop publishes proj._11/_22 + backbuffer dims) →
|
||||
`Mech::PickRayHit` (world ray → local frame → `BoundingBox::HitBy` slab test vs the collision
|
||||
template's ExtentBox → world hit point) → the entity target slots. The slots MIRROR the pick EACH
|
||||
FRAME: locked while the boresight is ON the mech, no target otherwise — **steer to keep the enemy
|
||||
under the centred crosshair; that IS the gunnery** (verified: face-to-face spawn → HOT lock;
|
||||
`BT_FORCE_TURN` circling → 31 no-target vs 1 HOT). (⚠ Two earlier cuts were wrong and are
|
||||
corrected: a STICKY designation — locked forever after first hover, made aim irrelevant; and a
|
||||
MOUSE cursor slew — mis-sourced from the RP-shared struct, gave a free cursor the pod never had.
|
||||
Both removed.) While locked the impact point = the PICKED hull point → STEP-6 resolves the zone
|
||||
under the crosshair (verified: center-aim → head-band zone 13 dominant). The HUD draws the aim
|
||||
group at the boresight ([0x9a] translate), the designator hotbox at the target's projected point
|
||||
(subB9 hot / subB8 designated, `BTProjectHotBox`/`BTProjectToReticle`), and the edge arrows when
|
||||
off-screen/behind. `BT_FIRE_ARC` is now an EXPLICIT OPT-IN presentation clamp (unset = authentic
|
||||
no-arc). The old hardwired lock, the ±30°-default cone, and the projectile path's gEnemyMech
|
||||
fallback are all REMOVED. LMB fires lasers / RMB missiles (with SPACE/CTRL). ⚠ A view-selection
|
||||
bug was fixed en route: every
|
||||
renderable rebuild stomped `mCamera` back to the chase eye (btl4vid `mViewInside` now persists
|
||||
the chosen view — the aim camera feed and the V toggle both depend on it).
|
||||
|
||||
|
||||
@@ -126,7 +126,8 @@ and every instrument is now live [T2]:**
|
||||
around the hotbox point, +1/−11.5 vertical (K=2.8145 baked projection; the port uses the live
|
||||
per-axis projection) — switching to the left/right edge ARROW past ±1.6 or behind.
|
||||
- Reticle state Off/On + `PrimaryHudOn` (mask 0x20) picks full HUD vs the "simple X" list;
|
||||
the aim group translates by `reticlePosition` (SetMatrix, rebuilt on slew move).
|
||||
the aim group translates by `reticlePosition` = the TORSO BORESIGHT (SetMatrix; NOT a free
|
||||
cursor — see [[combat-damage]] Targeting: the stick twists the torso, no mouse-aim exists).
|
||||
This recovery also CONFIRMS the HUD attr-table ids 4/5/6/8/0xA/0xB/0xC/0xD name↔use pairings
|
||||
(hud.hpp had flagged them uncertain). Deferred: PNAME1-8.bgf 3D marker chain; the `blx_cop`
|
||||
canopy shell renders black and is hidden by name filter (`BT_INSIDE_COCKPIT=1` shows it) — see
|
||||
|
||||
@@ -51,13 +51,16 @@ authentic path scoped.
|
||||
these are MODE flags — in the basic test mission the inert Myomers / dormant valve is likely AUTHENTIC
|
||||
(advanced damage off); wiring makes them RESPOND when a mission enables the mode, not necessarily change
|
||||
the basic-mission behavior. The MessageBoard feed is separate (StatusMessagePool, below).
|
||||
- **✅ Authentic target acquisition RECONSTRUCTED (task #36, 2026-07-08)** — the `Reticle`
|
||||
pick-ray chain is LIVE (see [[combat-damage]] Targeting for the full port map): mouse slew →
|
||||
pick ray → per-frame lock (crosshair ON the mech = locked; off = none) → aimed zone damage +
|
||||
designator ring; `BT_FIRE_ARC` is opt-in-only now. Residue: (a) the binary's own per-frame reticle→mech copy is still in an
|
||||
un-exported gap (our writer follows RETICLE.h semantics [T3 dynamics]); (b) the pod's REAL slew
|
||||
device channel (stick free-aim via the controls mapper / `freeAimSlew` @HUD+0x28C) is bridged
|
||||
by the mouse — wire the real channel when pod hardware lands; (c) pre-burial, the pick still
|
||||
- **✅ Authentic target acquisition RECONSTRUCTED (tasks #36/#39, 2026-07-08)** — the `Reticle`
|
||||
pick-ray chain is LIVE (see [[combat-damage]] Targeting for the full port map): the crosshair =
|
||||
**torso boresight** (NO free-aim mouse — the pod stick twisted the torso; you steer to aim) →
|
||||
pick ray → per-frame lock (boresight ON the mech = locked; off = none) → aimed zone damage +
|
||||
designator hotbox; `BT_FIRE_ARC` is opt-in-only now. Residue: (a) the binary's own per-frame
|
||||
reticle→mech copy is still in an un-exported gap (our writer follows RETICLE.h + the
|
||||
HudSimulation pose derivation [T3 dynamics]); (b) our cockpit view is body-mounted, so on a
|
||||
TWIST-CAPABLE mech the crosshair should deflect with the torso twist (`BTTwistToReticleX` is
|
||||
wired for it) AND the torso should visibly lead the legs — verify on a twist mech when one is
|
||||
in play (the BLH is fixed-torso, boresight always centred); (c) pre-burial, the pick still
|
||||
tests the sinking wreck's collision box at its parked position (pre-existing wreck-targeting
|
||||
behavior).
|
||||
- **Cockpit HUD leftovers (tasks #35-#38 residue, 2026-07-08)** — the reticle + 7 weapon pips +
|
||||
|
||||
@@ -165,6 +165,20 @@ void BTClientToReticle(float mx, float my, float cw, float ch,
|
||||
*ry = y;
|
||||
}
|
||||
|
||||
//
|
||||
// Torso-twist angle (radians) -> reticle X (task #39): the crosshair marks
|
||||
// where the torso guns point relative to the body-mounted view. A boresight
|
||||
// ray at horizontal angle `twist` from forward hits camera-space
|
||||
// xc = d*tan(twist) at depth d, so ndc_x = tan(twist)*P11 and
|
||||
// rx = ndc_x * (vw/vh). Zero for a fixed torso (dead-centre boresight).
|
||||
//
|
||||
float BTTwistToReticleX(float twist_rad)
|
||||
{
|
||||
if (!gBTAimCamValid || gBTAimP11 <= 0.0f || gBTAimVpH <= 0.0f)
|
||||
return 0.0f;
|
||||
return (float)tan((double)twist_rad) * gBTAimP11 * (gBTAimVpW / gBTAimVpH);
|
||||
}
|
||||
|
||||
//
|
||||
// Crosshair (reticle coords) -> world pick ray. reticle -> NDC:
|
||||
// ndc_x = rx * vh/vw (the reticle x unit is half the viewport HEIGHT),
|
||||
|
||||
@@ -1241,12 +1241,18 @@ void
|
||||
}
|
||||
sPrevV = vNow;
|
||||
|
||||
// RETICLE SLEW (task #36): the pod slewed the target reticle
|
||||
// with the stick free-aim channel; the dev-box stand-in is the
|
||||
// MOUSE -- absolute cursor position mapped through the client
|
||||
// rect into reticle coordinates (centered, +y down, unit =
|
||||
// half the client height -- the dpl2d frame). BT_AIM="x y"
|
||||
// pins the crosshair for headless harness runs.
|
||||
// RETICLE = TORSO BORESIGHT (task #39 correction): the pod had
|
||||
// NO free-aim cursor -- the binary's HudSimulation computes
|
||||
// reticlePosition from the mech's POSE quaternions
|
||||
// (part_013.c:5652+, a rate-limited quat->euler of the torso
|
||||
// aim), i.e. the crosshair marks where the TORSO GUNS point
|
||||
// relative to the view, and you aim by steering the mech /
|
||||
// twisting the torso (the pod's right stick). The earlier
|
||||
// mouse-cursor slew was a mis-sourced stand-in and is
|
||||
// REMOVED. Our cockpit view is body-mounted, so the
|
||||
// crosshair deflection = the torso twist projected to screen
|
||||
// -- identically ZERO on the fixed-torso BLH (dead-centre
|
||||
// boresight). BT_AIM="x y" remains as the headless harness.
|
||||
{
|
||||
static int sAimEnv = -1;
|
||||
static float sAimEnvX = 0.0f, sAimEnvY = 0.0f;
|
||||
@@ -1261,39 +1267,13 @@ void
|
||||
gBTAimX = sAimEnvX;
|
||||
gBTAimY = sAimEnvY;
|
||||
}
|
||||
else if (focused && pFg != 0)
|
||||
else
|
||||
{
|
||||
typedef int (__stdcall *CurFn)(POINT *);
|
||||
typedef int (__stdcall *StcFn)(void *, POINT *);
|
||||
typedef int (__stdcall *CrFn)(void *, RECT *);
|
||||
static CurFn pCur = 0; static StcFn pStc = 0; static CrFn pCr = 0;
|
||||
if (pCur == 0)
|
||||
{
|
||||
HMODULE u = GetModuleHandleA("user32.dll");
|
||||
pCur = (CurFn)GetProcAddress(u, "GetCursorPos");
|
||||
pStc = (StcFn)GetProcAddress(u, "ScreenToClient");
|
||||
pCr = (CrFn)GetProcAddress(u, "GetClientRect");
|
||||
}
|
||||
void *wnd = pFg(); // focused == our window
|
||||
POINT cp; RECT rc;
|
||||
if (pCur && pStc && pCr && wnd != 0 &&
|
||||
pCur(&cp) && pStc(wnd, &cp) && pCr(wnd, &rc) &&
|
||||
rc.right > rc.left && rc.bottom > rc.top)
|
||||
{
|
||||
// client px -> reticle coords through the RENDERER
|
||||
// (it undoes the backbuffer->client present stretch;
|
||||
// a raw client-height mapping is only exact for a
|
||||
// backbuffer-shaped window and skews the pick
|
||||
// sideways otherwise).
|
||||
extern void BTClientToReticle(float mx, float my,
|
||||
float cw, float ch, float *rx, float *ry);
|
||||
float rx = 0.0f, ry = 0.0f;
|
||||
BTClientToReticle((float)cp.x, (float)cp.y,
|
||||
(float)(rc.right - rc.left),
|
||||
(float)(rc.bottom - rc.top), &rx, &ry);
|
||||
gBTAimX = rx;
|
||||
gBTAimY = ry;
|
||||
}
|
||||
// boresight = torso twist vs the body-mounted view,
|
||||
// projected through the live per-axis projection.
|
||||
extern float BTTwistToReticleX(float twist_rad);
|
||||
gBTAimX = BTTwistToReticleX(gBTHudTwist); // BLH: 0
|
||||
gBTAimY = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user