--- id: open-questions title: "Open Questions — deferred systems, unknowns, get-from-Nick" status: living source_sections: "CLAUDE.md §9; docs/HARD_PROBLEMS.md; per-subsystem deferral notes" related_topics: [source-completeness, subsystems, multiplayer, combat-damage, locomotion] --- # Open Questions Known unknowns + deliberately-deferred systems. For each: what's known, what's missing, what would resolve it, status. Deferred ≠ broken — most are marked-and-guarded stand-ins with the authentic path scoped. ## From Nick (external — gating for some paths) - **[GATING] The BT game SOURCE CODE** — the missing implementation `.cpp` (mech, subsystems, mapper, HUD, app; see [[source-completeness]]). Without it, Route A (recompile original) is impossible; we reconstruct from the binary instead. Likely on a backup/dev drive. Status: OPEN. - Confirmation the PodPC image is the complete content master. (Low priority — the runtime `BTL4.RES` already has 8 maps + the full mech anim set.) Status: OPEN. - Pod specifics for Phase 8: the 7-monitor driver setup, the RIO cockpit I/O protocol, current Win10+wrapper pod config. Status: OPEN. ## Deferred subsystems / feeds (authentic path scoped, marked in code) - **0xBD3 SubsystemMessageManager (WAVE 8)** — a per-mech **damage/explosion consolidation hub** (`ConsolidateAndSendDamage` Performance @0049b784, `weaponExplosions` queue, `CommonDamageInformation`; messmgr.hpp). ctor `FUN_0049bca4` (vtable 0x50b954, installs a Performance → ticks). The factory caches it to **`Mech[0x10d]` = byte 0x434**. What wiring it needs: an untangle — our reconstruction MISLABELED `Mech[0x10d]` as `controlsMapper` and `mech4`'s live drive reads it as the mapper, so the real messmgr can't land there until the drive is re-pointed to the true mapper (**roster slot 0**, installed by `SetMappingSubsystem`/`MakeViewpointEntity`; a `MechRIOMapper`). Payoff = authentic damage/explosion consolidation (a COMBAT-fidelity improvement) + fixing the mapper/messmgr conflation. ⚠ **CORRECTION (verified 2026-07):** 0xBD3 does NOT gate the valve/Myomers/MessageBoard — those read a DIFFERENT object at **`mech+0x190`** (both `FUN_004ac9c8` the valve guard `→+0x274` and `FUN_004ad7d4` the Myomers gate `→+0x260` deref `owner+0x190`, which ≠ the 0x434 messmgr cache). The earlier "0xBD3 gates 4 things" note was wrong. - **✅ `mech+0x190` IDENTIFIED (2026-07): it is the owning `BTPlayer`** (`Mech::GetPlayerLink()`, `MECH_OWNING_PLAYER`; ENTITY.h:430). Set by `FUN_0049f624` (the mech↔player bind: `mech+0x190 = player` AND `player->playerVehicle(+0x1fc) = mech`), which resolves the player from the mission player registry (`app+0x2c+0x54`, `FUN_0041fd18`) by the pilot key. The valve/Myomers "gates" read the owning player's fields at `player+0x260` and `player+0x274` (the reconstruction maps this block as `showDamageReceived@0x25c / showKills@0x260 / showDamageInflicted@0x264 / roleClassIndex@0x274` in btplayer.hpp — from the SCORING work, so the names may NOT match the gate semantics; the true meaning + the WRITER of `player+0x260/0x274` are not yet pinned — part_013.c:4553-4660 is the TorsoSimulation, a different object, not the setter). So there is NO new subsystem to build. **The wiring (small):** point `MechSubsystem::IsDamaged()` (`FUN_004ac9c8`, valve guard) at `GetPlayerLink()->`(0x274) and `Myomers::OwnerAdvancedDamage()` (`FUN_004ad7d4`) at `GetPlayerLink()->`(0x260) — via NAMED members (databinding trap: our BTPlayer layout ≠ binary; do NOT raw-read `player+0x260`). ⚠ Resolve first: (a) a naming conflict — `FUN_004ad7d4` is labeled BOTH `HeatModelActive` (heat.hpp) AND `OwnerAdvancedDamage` (myomers.cpp); re-verify which body is which; (b) the true semantic of `player+0x260/0x274` vs the scoring-derived `showKills`/`roleClassIndex` names. NOTE: 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). - **StatusMessagePool (NULL stub, btstubs.cpp:62)** — the per-player status-message queue. BTPlayer+0x1dc is never populated → MessageBoard is empty (authentic for bring-up). What resolves it: wire the pool + decode `AddStatusMessage @0042e580` + the `Player__StatusMessage` record ({messageId@+0xc, nameEntity@+0x10}). - **Gyroscope (0xBC4)** — layout + joint-I/O reconstructed, but the ctor field-init + the two integrators (IntegrateEyeJoint @004b2ec0 / IntegrateBody @004b30ec) are incomplete → writes NaN to the root joint. Reverted to a stub. A full subsystem-sim reconstruction (bigger than Torso). - **MechControlsMapper look/eyepoint commit** — reconstructed but its offsets collide with declared members; arbitrate before enabling (no port consumer yet). The fire-trigger-through-mapper is still the `gBTWeaponTrigger` bring-up. - **Myomers authentic coupling** — the structural un-stub is INERT (mover feed + heat-gen no-op). Real coupling needs the advanced-damage gate (`OwnerAdvancedDamage`/`FUN_004ad7d4` → the owning **BTPlayer** `mech+0x190`+0x260, NOT 0xBD3 — see the mech+0x190 item above) + `MoverAttach` routing into the LIVE JointedMover (must be reconciled with the gait cutover first). - **SeekVoltageGraph** — 4 Seek* attrs unpublished (a cluster-child, not config-called; non-blocking). ## Locomotion / combat polish (non-gating) - Authentic per-mech TURN-RATE constant (currently a bring-up constant rate). - Body-callback gimp handlers (states 16-19, targets 0x70b2/0x7161 undecoded → fall back to stand); airborne callbacks (`FUN_004a6344`/`FUN_004a7970`). - Wall-block-vs-climb tuning. **✅ Collision DAMAGE application — DONE 2026-07-08 [T2].** The two deferred dispatches in `Mech::ProcessCollision` (mech4.cpp: mech-vs-mech `:15324-15358` + icon-crunch `:15369-15401`) now fire: on a collision with another Mech or a CulturalIcon, an `Entity::TakeDamageMessage{zone==−1}` is dispatched to the victim (via `BTDispatchCollisionDamage`, the engine ctor — same as the weapon path), and STEP 6's cylinder table resolves the impact point → a zone on the receiver. Terrain (walls/hills) matches neither branch → blocks without damage (faithful). Reachability is guaranteed (`Mover::ProcessCollisionList` calls the **virtual** `ProcessCollision` → `Mech::ProcessCollision`); built + stable. The live dispatch wasn't captured headlessly (the solo auto-walker never rammed a tree/mech), but the path is proven reachable and composed of runtime-verified pieces. **Note:** validated STEP 6's height ref along the way — `collisionTemplate->maxY ≈ 7.1` (a real mech height), confirming `CylinderReferenceHeight` reads a height, not the heat value the `mech+0x2ec` dual-labeling (heat-gauge sink vs groundRef, mech4.cpp:2697) hinted at. - **✅ Cylinder hit-location (STEP 6) — DONE + LIVE 2026-07-08 [T2].** Built + runtime-verified: the `dmgtable.cpp` classes now have real storage + a working `ResolveHit→zone`, the mech ctor loads the type-0x1d table by the DamageZoneStream name (`[cyl] table 'bhk1' layers=7`), and `Mech::TakeDamageMessageHandler` resolves unaimed (zone==−1) hits before base-routing. ⚠ The FIRST "verified" claim was PARTIAL: the table was cached via `Wword(0x111)` (the ABSORBER — stores nothing) so every unaimed hit silently no-op'd; fixed 2026-07-08 by promoting the cache to the named member `Mech::damageLookupTable` ([[reconstruction-gotchas]] §2). Now verified end-to-end (19 zones resolving, `BT_AUTOFIRE` harness). Full change list in [[combat-damage]] "STEP 6 COMPLETE". Historical investigation notes retained below for provenance. **Re-investigated 2026-07 (see [[combat-damage]] for the full algorithm):** the table (height×angle grid, resource type 0x1d) IS built (recon `StandingAnimation` @Mech[0x111], but with an EMPTY name → 0 rows, because `ResourceFindByName` is a **no-op template stub**). **CORRECTION to the earlier note:** the LOOKUP is **exported** [T1] — `FUN_0049eb54` (table height→row) + `FUN_0049e678` (row angle→cell), NOT unexported. Only the thin `Mech::TakeDamageMessageHandler` glue (zone==-1 → call the lookup → `damageZones[zone]->TakeDamage`) is unexported, and it's fully implied by pieces already reconstructed → no disassembly needed. Remaining: 6b real `FindByName` (name = the mech's type-0x14 DamageZoneStream name @ResourceDescription+0xc); 6c the 3 container ctors + the lookup as a `BTCylinderResolveZone` bridge (ground the cell zone-dict stream format vs the real .RES bytes); 6d register the handler + verify. Feasible; the only open risk is the cell stream format. The earlier-cited `FUN_004a0230`/`FUN_0049ed0c` don't exist. - **Death sequence — CORE DONE 2026-07-08 [T2]; effects+anim deferred.** `Mech::UpdateDeathState()` (mech4.cpp) reconstructs the death STATE machine (collapse `movementMode` → RP `VTV::DeathShutdown` subsystem loop → settle to disabled/frozen; wreck stays, no crash) — runtime-verified (`BT_DEATH_LOG`). Full map + citations in [[combat-damage]] "Death SEQUENCE". ✅ (b) `MechDeathHandler` DONE (mechdmg.cpp) + ✅ the render-side **RemakeEntity** destroyed-mesh swap DONE 2026-07-08 (btl4vid.cpp `RemakeEntityRenderables` + `BTRemakeMechModel` bridge; in-place `SetDrawObj` swap — the tree dtor does NOT cascade so never rebuild). ✅ (a) **RESOLVED — no collapse animation exists in BT 4.11** [T1]: the fall latch (modes 5-8 → table slots 0x1c-0x1f) is a vestige — no loader fills the slots, no fall clip ships, and firing it would bind resource 0 (an AUDIO stream) as keyframes. ✅ The authentic death VISUAL is the **WRECK-HULK SWAP** (death ModelList `blhdead` → effect 104 → the victim becomes its `dbr.bgf` burning hulk) — RECONSTRUCTED + verified (`SwapToWreck`, btl4vid.cpp; see [[combat-damage]] "Death SEQUENCE" for the full chain + proofs). ✅ The wreck **sinks** (the 1996 quadratic burial, `offsetY = -0.025·t²`, gone ~17s) with the `ldbr` debris field; at burial it goes **INERT** (collisionVolumeCount=0 + target lock dropped — no phantom blocking/hits). **Remaining**: (c) the whole-mech **DeathSplash** radius damage; wreck mesh FLAMES (flamesml/flamebig + sweep flicker, 1996 script case 4); the **full entity teardown at burial** (the authentic death-row removal — needs the mech render tree unhooked from the renderer first; the inert wreck is the safe stand-in until then). Do NOT issue DestroyEntityMessage on death (before the render-tree teardown lands). - **Critical-subsystem plugs UNBOUND (43 skips/mech) [T3].** `MechCriticalSubsystem::subsystemPlug` never gets WIRED to its live subsystem (the ctor's Resolve() at mechdmg.cpp:276 only READS; the binding write is elsewhere/unreconstructed), so `SendSubsystemDamage` skips every entry via the unbound-plug guard (mechdmg.cpp, added 2026-07-08 after a live NULL-deref AV in `SendSubsystemDamage+0x93` — the 1995 binary derefs unchecked because there every plug is bound). Consequence: zone destruction does NOT yet propagate damage into carried subsystems (generator/ gyro failures etc.). Also latent there: `SubProxy2` raw-offset reads (databinding trap) once s≠0. - **Two dead Wword comparison branches (multiplayer)**: `mech.cpp:1511` + `:1613` (replicant leg-state/stability sync in ReadUpdateRecord) — always-false BTVal comparisons ([[reconstruction-gotchas]] §2); needs slots 0xf/0x10 promoted to named members when P6 replication work resumes. ## Multiplayer (Phase 7 / P6) - Cross-pod COMBAT (target a replicant + route damage to the owning master). - Replicant GAIT animation (replicants don't animate joints yet — derive from replicated velocity). - The pod-LAN config (real IPs, bare-IP pilot entries). The WinSock2 TCP stack (L4NET.CPP) is reconstructed + smoke-tested on one box (two instances share a world, movement replicates). ## Rendering follow-ups (non-blocking) - **.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 `lastInflictingID`, now written by `Mech::TakeDamageMessageHandler`). Remaining nuances, all cosmetic: (a) `atten/attenv` distance attenuation not honoured; (b) the per-file texture name (`btfx:firesmoke1_scr_tex`) — all effects share the radial-masked grit sheet; decoding FIRE.BSL would give the authored sheet; (c) beams draw before particles, so a beam through thick smoke reads too bright (pass-ordering); (d) `colorWarp/alphaWarp` applied as `t^(1/warp)` [T4 convention]; (e) emission uses rate×releasePeriod batching [T4 convention vs the exact 1995 emitter]. - Replacement-LOD selection for NON-additive multi-LOD models (needs the board's hot-spot/ reference-point semantics; leads: `s_dplobject.lod_ranges[16]/lod_hot_spot`, 0x2047/0x2048). - Day/night MATERIAL path priority (BMF/IMG) — infrastructure done, gated `BT_MATPRI` (over-applies to shared terrain mats); needs the terrain-material model understood. - RGBA4444 alpha (TREE.BSL cutout) decoded but not alpha-tested outside punch batches; VTX/TGA paths. ## Content build sub-project (low priority) - Lab/other-build maps (`des`/`burnt`/`frstrm`) are source-only (`.map` in CONTENT/BT/MAPS/); would need compiling into a RES via the DOS `btl4tool.exe`. The 8 RES maps cover testing. ## Key Relationships - Feeds from: every subsystem/render topic (their deferral notes collect here). - Gating master: [[source-completeness]] (the missing BT source).