Merge remote-tracking branch 'origin/master'

# Conflicts:
#	game/reconstructed/btl4gau2.cpp
This commit is contained in:
Cyd
2026-07-17 15:48:11 -05:00
17 changed files with 598 additions and 85 deletions
+16
View File
@@ -142,6 +142,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<Radian>` 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
+30
View File
@@ -29,6 +29,32 @@ authentic path scoped.
Remaining: bind the side/down look views to keys (only 'V' look-back is bound); pod look-button
mappings for Phase 8.
## Pod-hardware readiness gaps (Phase 8 assessment, 2026-07-17) [[pod-hardware]]
Everything below EXISTS in the tree but has NEVER run against real pod hardware. Mechanism
status vs the pod's 7-display / RGB-splitter / dual-sound-card rig:
- **CARRIED + plausibly functional (untested on hardware):**
- RIO serial controls: real Win32 COM (`L4SERIAL` CreateFileA/SetCommState), the full chain
RIO AnalogReply → Ranger → ControlsManager → streamed `.CTL` mappings → mapper traced [T1];
keyboard bridge disable = `BT_KEY_BRIDGE=0`. Pod look/config buttons are `.CTL` data-driven.
- RGB-splitter channel packing: `L4GraphicsPort::ChannelEnableID` (Red/Green/Blue/All +
transparent-zero variants) — each gauge draws into ONE color channel of the shared
640x480x16 surface, feeding one monochrome CRT per channel through the splitter. The gauge
CONTENT is complete (same `L4GaugeRenderer` verified daily in the `BT_DEV_GAUGES` window).
- Multi-output selection: `SVGA16::BuildWindows` (a fullscreen D3D9 device per gauge/MFD
surface), adapter env `PRIMGAUGE`/`SECGAUGE`/`MFDGAUGE`/`MFDGAUGE2`/`SPANDISABLE`, MFD span
= width x2 across two displays; `content/SETENV.BAT` = the authentic pod env preset.
- The `L4PLASMA.cpp` serial plasma-display driver (`L4PLASMA=com2`).
- **EXPECTED TO NEED REAL WORK on modern hardware:**
1. **Multi-head display management**: the original used TWO video cards; simultaneous
exclusive-fullscreen D3D9 devices on multiple heads of one modern GPU is fragile — likely
needs a borderless-window-per-head modernization of `BuildWindows`.
2. **The REAR sound card is folded away**: the pod ran `AWE_FRONT`/`AWE_REAR` as two physical
cards for the 4-speaker front/rear split; our OpenAL opens ONE device (front/rear collapses
to stereo). Feasible fix: OpenAL Soft quad output (surround config) or a second device.
3. Serial protocol timing/handshake vs a real RIO board (and the intercom path) — unverified.
4. `-platform pod` deliberately does NOT auto-enable `L4GAUGE` (each surface needs its own
device); the pod bring-up procedure itself is undocumented → the Nick items above.
## BINARY-COVERAGE AUDIT discoveries (2026-07-13, 6-agent decomp census) [T1 verified-uncited]
New unaccounted functionality no prior list knew (addresses verified absent from game/+context/+docs):
- **✅ `BTL4VideoRenderer::StartEntityEffectImplementation` @004d097c — DONE (2026-07-13) [T2].**
@@ -618,6 +644,10 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
LIVENESS audit (does a live call path reach each reconstructed fn?) would catch this class.
## Rendering follow-ups (non-blocking)
- ~~Per-pilot mech PAINT (color/badge/patch)~~ — **DONE 2026-07-17, verified live** (crimson MadCat +
yellow VGL emblems + hip hazard stripes). Mechanics + the vehicletable color/badge/patch name
tables in [[rendering]] §Per-pilot mech PAINT. Residual nit: eggs saying `color=Red` mean
**Crimson** (table has no Red; the binary Fail()ed on it, the port warns + drops).
- **.PFX effect-layer polish (deferred 2026-07-08; the layer itself is LIVE + verified).** The
reconstructed BT particle layer (L4VIDEO.cpp, see its banner) renders the authentic .PFX content
(fire + smoke, premultiplied blend, impact-frame oriented — weapon hits AND damage bands via
+35
View File
@@ -263,6 +263,11 @@ state transitions: charge/seek loops, snap comparisons, timers compared with `==
ucrtbased **abort() dialog** ("Debug Error!"), not an AV — `sxe av` won't break there; the box
blocks the event loop (a headless node just "stops logging"). cdb: run with a config that does
`g` then `kb 40` — the int3 lands ON the aborting thread. [T2]
- **Verify under the USER'S launch flags, not a bare run:** a "30 s regression: stable" check that
omits `BT_DEV_GAUGES=1` / `BT_START_INSIDE=1` (the `tools/mp_launch.sh` set) misses any bug on the
gauge/cockpit paths those flags gate. The task-#7 gauge crash was DORMANT for a day because every
post-commit check ran flagless; it surfaced the instant the pod launch config was used. Reproduce
with the real launcher's env, and drive (`-net` keyboard) — not just spawn-and-look. [T2]
---
@@ -358,6 +363,36 @@ hundreds of pixels off-scope (the radar looked simply "empty"; nothing crashed,
decompile) before assigning it an engine method — a wrong-but-plausible identity survives
every compile and every "it runs" test.
## 18. Uninitialized stack-built resource → garbage `simulationFlags` (the "worked for weeks then broke" trap)
**Symptom:** a subsystem installed from a HAND-BUILT (stack) `*__SubsystemResource` silently stops
ticking — `IsNonReplicantExecutable()` returns false because a stray `DontExecuteFlag` (0x2) bit is
set. Config-dependent and nondeterministic: it "works for weeks" then an UNRELATED commit that shifts
the stack layout before the install flips the garbage bit. Archetype (task #7, 2026-07-17): the RIO
controls mapper built on the stack in `btl4app.cpp MakeViewpointEntity``Subsystem::Subsystem`
copies `model->subsystemFlags` into `simulationFlags`, but the stack struct only set
`subsystemName`/`classID`/`subsystemModelSize`, leaving `subsystemFlags`+`segmentIndex` = stack
garbage. When the garbage carried 0x2 the mapper froze → `speedDemand` stuck at 0 → no forward motion
(MASKED in single-player when the garbage happened to be clean; surfaced in `-net` where the stack
differed; the July-16 audio commits shifted the stack and flipped it). **Cause:** partial init of a
struct the engine reads in full. **Fix:** `memset(&res, 0, sizeof(res))` before filling ANY
stack-built resource — flags 0 = `AlwaysExecute`, the faithful value for a mapper (it MUST tick every
frame). **Tell:** a subsystem present in the roster but absent from the executed set; instrument the
tick's `!IsNonReplicantExecutable()` branch to name the slot + dump `simulationFlags` (bit 0x2 =
DontExecute). **Rule:** zero every hand-built resource struct; never rely on a partially-filled one.
[T2]
**Related — raw numeric attribute index into a GROWING table (same root as gotcha 11):** the dev
gauges' `CoolingLoopConnection` reached the cooling master with a RAW `GetAttributePointer(3)` +
`*(master+0x1d4)` walk. The July-16 audio work inserted attribute rows (`ReportLeak` etc.), shifting
the chained ids — index 3 landed on a scalar, the resolve walked garbage, and the gauge background
pass AV'd (only with `BT_DEV_GAUGES=1`, the pod launch flag, ~15 s in when the gauge builds lazily —
the cdb stack pinned it to `CoolingLoopConnection::Update`). **Fix:** route through a complete-type
bridge reading NAMED members (`heat.cpp BTCoolingLoopFrame`: `linkedSinks.Resolve()` +
`Condenser::condenserNumber`) — the databinding rule (gotcha 8), never a raw numeric attribute index.
The name-keyed samplers (`PowerSourceConnection`/`GeneratorVoltageConnection`, which look up
`"InputVoltage"` by NAME) were unaffected — name lookup survives table growth. [T2]
---
## Diagnostic recipe (the standard loop)
+37 -2
View File
@@ -105,8 +105,43 @@ models is deferred (needs the board's hot-spot semantics). [T2]
`.BSL` is a bit-sliced container (6 grayscale sub-images per file); the BMF `0x18 BITSLICE` tag picks
the slice. Reading it as RGB overlaid 2-3 gray sheets = the "rainbow/graffiti" bug. Fixed:
`image.cpp decodeBSL` slice-decodes; `bgfload` threads the 0x18 channel; a cross-library RAMP registry
resolves the mech-skin `softer` ramp (defined in OTHER libs). Every mech renders authentic gray-metal
paint now. See [[asset-formats]]. [T2]
resolves the mech-skin `softer` ramp (defined in OTHER libs). Every mech renders the authentic BASE
gray-metal skin now. See [[asset-formats]]. [T2]
## Per-pilot mech PAINT (color/badge/patch substitution) — NOT WIRED (2026-07 audit)
The "missing warning stripes / coloration" report is the per-pilot paint layer, fully authored but
never engaged by the port. Mechanics (all [T1] from the BMF/BGF/vehicletable content + FUN_004d0cc0):
- Mech BGFs reference the BASE lib only (`blhskin:gen2_dz_rfoot_mtl` …). The binary rewrites lib
prefixes at load via the `vehicletable` resource `[substitute]` templates: `skin:``_%color%%serno%:`
(`blhskin:``blh_wht0:`) and `skin:lgo``<<<emblem%serno%:%badge%_%patch%>` (emblem pages →
`EMBLEM0.BMF` `lgoN_<patch>_dz_*` materials). Pilot egg values (color/badge/patch) map through the
`[color]/[badge]/[patch]` sections to the codes.
- The COLOR libs (e.g. `BLH_WHT0.BMF`) are byte-identical to the base lib EXCEPT they add tags
`0x23`(diffuse RGB) + `0x24`(ambient RGB) = the pilot color to the ~35 paintable `gen*/mech*_dz_*`
materials (base leaves them untinted). 7 colors: wht(.99,.99,.99) red(.90,.11,.10) grn(.63,.83,.52)
gry(.65,.60,.65) brn(.60,.44,.28) tan(.65,.55,.43) blk(0,0,0). All 8 sernos are byte-identical
(verified: 0 of 193 groups differ) — `%serno%` was future variety, never used. `<mech>SKIN.BMF`
(bare) == `<mech>SKIN0.BMF`.
- WARNING STRIPES are grayscale hazard-stripe art in the shared `GEN.BSL` pages (slice 1 = `gen2_tex`,
top-left), shown through the paintable-zone materials and tinted by the pilot color. `EMBLEM0.BMF`
carries `lgoN_<patchcolor>_dz_ld/rdleg` materials (8 patch tints incl. yellow .89,.73,0) over
`LGO.BSL` slices 0-5 (slice 5 = VGL winged logo).
- **WIRED 2026-07-17 (same-day fix), verified live**: MP MadCat renders crimson with hip hazard
stripes + yellow VGL leg emblems; Blackhawk white + emblems; replicants painted on both nodes.
The reconstruction: (a) `Mech::resourceNameA/B/C` are real `CString` members (the binary's exact
16-byte `CStringRepresentation` {size,len,text@+8,refs@+0xc}; ctor = part_012.c:9841-71, deep-copy
bind from the MakeMessage = `CString::operator=(const char*)` == FUN_00402a98 @10427-41, implicit
member dtors = 11388-403) with paint-name accessors; (b) `SetupMaterialSubstitutionList` reads them
(real egg names; `[paint]` log line); (c) `dpl_SetMaterialNameCallback` is REAL now
(L4VIDEO.cpp registry, cleared first in TearDown as FUN_004d11e8 does) and
`bgfload MaterialResolver::resolve()` runs every name through `dpl_ApplyMaterialNameCallback`;
no mesh-cache issue (LoadObject/LoadBgfFile don't cache — every load resolves fresh). [T2]
- DEVIATION (documented, btl4vid.cpp): on a vehicletable miss the binary Fail()ed ("Exiting"
@BTL4VID.CPP:0xbeb); the port warns + drops that placeholder (RP analogue). Real case: dev eggs
ship `color=Red` but the `[color]` table only has **Crimson** — MP_BHMC.EGG fixed to Crimson;
LAST.EGG pilot-2 still says Red (unused slot). The 7 valid egg colors:
Black/Brown/Crimson/Green/Grey/Tan/White; badges Davion/Kurita/Liao/Marik/None/Steiner/VGL;
patches Black/Blue/Green/Grey/Red/Violet/White/Yellow. [T1]
## The OLD-STYLE SPECIALFX layer (the weapon-impact action) — RECONSTRUCTED 2026-07-12 (firmware-decoded)
The per-weapon impact visuals are fully AUTHORED in `content/BTDPL.INI` `[effects_to_load]`: