From 1ed8b051602de084ebb48afd544d5ee4d08751d1 Mon Sep 17 00:00:00 2001 From: arcattack Date: Fri, 17 Jul 2026 15:24:52 -0500 Subject: [PATCH] Radar view-wedge tracks the torso twist (Gitea issue #1) The SECTOR radar's view cone read viewHorizontalRotation, wired by the MapDisplay ctor from the mech's Torso -- but FindSubObject and GetHorizontalRotation were NULL stubs, so the connection was never created and the wedge sat at heading 0 regardless of twist. Reconstructed from the binary: - FindSubObject (FUN_0041f98c): a subsystem-ROSTER walk (count @+0x124, array @+0x128) matching the streamed subsystem name (sub+0xd4) with a tolower-strcmp (FUN_004d4b58) -- the 'Torso' sub-object IS the roster Torso subsystem. - GetHorizontalRotation: torso+0x1D8 == Torso::currentTwist (layout-locked), via the existing task-#56 bridge BTGetTorsoTwistAddr (Radian is layout- identical to Scalar). Verified live (MadCat, Standard mode Q/E): the wedge tracks the twist in lockstep (rot 0 -> -2.21 rad), and the semantic test passes -- body turned away, torso twisted back onto the enemy: reticle green + wedge pointing at the enemy's blip on the body-fixed scope. NB the Blackhawk's torso is FIXED (+/-0.01 deg limits) -- its wedge authentically never moves; test with a twisting mech. Diag env: BT_RADAR_LOG. Co-Authored-By: Claude Opus 4.8 (1M context) --- context/gauges-hud.md | 16 ++++++++++ game/reconstructed/btl4rdr.cpp | 55 +++++++++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/context/gauges-hud.md b/context/gauges-hud.md index 2b13a77..a862a46 100644 --- a/context/gauges-hud.md +++ b/context/gauges-hud.md @@ -131,6 +131,22 @@ At the authentic 1e7-unit economy (tasks #9-#10) the Heat MFD is fully dynamic: 77→2000 (the authored failure threshold), condensers/generators run 100-1400 under sustained fire, and the bank plateaus ~600 — temperatures, heatLoad and the heat alarms all animate. [T2] +## Radar view-wedge tracks the torso twist (Gitea issue #1 — FIXED 2026-07-17) [T2] +The SECTOR radar's view cone (`MapDisplay::DrawViewWedge` @004c2484, btl4rdr.cpp) reads +`viewHorizontalRotation@0x31C`, fed by a per-frame `GaugeConnectionDirectOf` the ctor +wires from the mech's Torso. The two helpers were NULL stubs, so the connection was never +created and the wedge sat at heading 0 (the reported "cone does not track the twist"). +Reconstructed from the binary: `FindSubObject` (FUN_0041f98c) = a SUBSYSTEM-ROSTER walk +(count @+0x124 / array @+0x128) matching the streamed name (sub+0xd4) case-insensitively +(FUN_004d4b58 = tolower-strcmp) — the "Torso" sub-object IS the roster Torso subsystem; +`GetHorizontalRotation` = torso+0x1D8 = `Torso::currentTwist` (layout-locked), reached via the +existing task-#56 bridge `BTGetTorsoTwistAddr` (Radian ≡ {Scalar angle}, exact reinterpret). +VERIFIED live (MadCat, Standard mode Q/E): wedge rot tracks twist 0→−2.21 rad in lockstep, and +the SEMANTIC test passes — body turned away, torso twisted back onto the enemy → reticle goes +green AND the wedge points at the enemy's blip while the scope stays body-fixed. ⚠ Test with a +TWISTING mech: the Blackhawk's torso is FIXED (limits ±0.01°) — its wedge authentically never +moves. Diag: `BT_RADAR_LOG` ([radar] ctor probe + 1 Hz [radar-wedge] rot trace). [T2] + ## Remaining = DATA FEEDS, not widgets (deferred systems) **✅ The condenser valve CONTROL is LIVE (task #13, 2026-07-11) [T2]:** `MoveValve` (id 4, the Condenser handler table @0x50E52C — exactly one entry) registered + guarded by the REAL diff --git a/game/reconstructed/btl4rdr.cpp b/game/reconstructed/btl4rdr.cpp index 4d2c360..ac061d9 100644 --- a/game/reconstructed/btl4rdr.cpp +++ b/game/reconstructed/btl4rdr.cpp @@ -201,11 +201,13 @@ static Entity * // // Mech sub-object lookup ("Torso") + its horizontal rotation feed. +// (The "sub-object" IS a roster SUBSYSTEM -- FUN_0041f98c walks the entity's +// subsystem roster by NAME; see the bodies at the end of this file.) // -static Entity * +static Subsystem * FindSubObject(Entity *entity, const char *name); static Radian * - GetHorizontalRotation(Entity *entity); + GetHorizontalRotation(Subsystem *torso); //########################################################################### @@ -471,7 +473,11 @@ MapDisplay::MapDisplay( // if (entity->GetClassID() == 0xBB9) { - Entity *torso = FindSubObject(entity, "Torso"); // FUN_0041f98c + Subsystem *torso = FindSubObject(entity, "Torso"); // FUN_0041f98c (roster walk) + if (getenv("BT_RADAR_LOG")) + DEBUG_STREAM << "[radar] ctor: torso sub " + << (torso ? "FOUND" : "NOT FOUND (roster names?)") + << " on mech " << (void *)entity << "\n" << std::flush; if (torso != NULL) { AddConnection( @@ -791,6 +797,19 @@ void Radian leftEdge = viewHorizontalRotation - viewHalfHorizontalWidth; Radian rightEdge = viewHorizontalRotation + viewHalfHorizontalWidth; + // DIAG (issue #1): 1 Hz wedge-heading trace. + if (getenv("BT_RADAR_LOG")) + { + static unsigned long sLast = 0; + unsigned long now = GetTickCount(); + if (now - sLast >= 1000) + { + sLast = now; + DEBUG_STREAM << "[radar-wedge] rot=" << (Scalar)viewHorizontalRotation + << "\n" << std::flush; + } + } + localView.SetColor(staticColor); // (this+0x48 vtbl+0x18) Radian edges[2]; @@ -1176,20 +1195,40 @@ static Entity * // // FUN_0041f98c -- Entity::FindSubObject(name) (locates "Torso"). +// The binary walks the entity's SUBSYSTEM ROSTER (count @+0x124, array +// @+0x128) and returns the first subsystem whose streamed NAME (sub+0xd4 == +// Subsystem::subsystemName) matches case-insensitively (FUN_004d4b58 is a +// tolower-strcmp). Gitea issue #1 fix (2026-07-17): this and the feed below +// were NULL stubs, so the torso-twist -> radar view-wedge connection was +// never created and the wedge sat at heading 0 forever. // -static Entity * - FindSubObject(Entity * /*entity*/, const char * /*name*/) +static Subsystem * + FindSubObject(Entity *entity, const char *name) { + if (entity == NULL || name == NULL) + return NULL; + for (int i = 0; i < entity->GetSubsystemCount(); ++i) + { + Subsystem *sub = entity->GetSubsystem(i); + if (sub != NULL && sub->GetName() != NULL + && _stricmp(sub->GetName(), name) == 0) + return sub; + } return NULL; } // -// torso+0x1D8 -- the sub-object's horizontal (yaw) rotation feed. +// torso+0x1D8 -- the sub-object's horizontal (yaw) rotation feed: +// Torso::currentTwist (layout-locked @0x1D8, torso.hpp). Reached via the +// torso.cpp complete-type bridge (task #56's BTGetTorsoTwistAddr -- the same +// pointer the gyro's external-pitch link uses). Radian is layout-identical +// to Scalar ({ Scalar angle }, ANGLE.h), so the reinterpret is exact. // static Radian * - GetHorizontalRotation(Entity * /*entity*/) + GetHorizontalRotation(Subsystem *torso) { - return NULL; + extern Scalar *BTGetTorsoTwistAddr(Subsystem *torso); + return (Radian *)BTGetTorsoTwistAddr(torso); }