Files
BT412/context/open-questions.md
T
arcattackandClaude Fable 5 3c34ae6de6 KB: full staleness audit + sweep -- 35 verified corrections across 16 topics, 15 new glossary terms
Adversarially-verified audit (18 agents) against the task #46-#56 landings:
MP/current-state understatements, superseded punch readings, retired env
gates, dead paths, line-cite drift; env-gate hub table completed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 10:56:51 -05:00

230 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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).
- **✅ 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. Firing needs a target but NOT a manual
lock/pinpoint — the target is AUTO-acquired (task #40, binary-verified: FireWeapon doubly-gated
on mech+0x388, but 0x388 has 11 reads / 0 direct stores across CODE → set indirectly). Residue:
(a) the binary's own per-frame reticle→mech copy + the AUTO-TARGET SELECTOR are still in an
un-exported gap (a message/selector; our port auto-targets the single living enemy — for MP,
reconstruct the real multi-target selection: nearest/most-aligned/cycle); (b) the eyepoint now
rides the parent DCS (task #55 authentic eye), so torso pose reaches the view; on a
TWIST-CAPABLE mech (selectable via `BT_FORCE_MODEL`) the crosshair should deflect with the
torso twist (`BTTwistToReticleX` is wired for it) AND the torso should visibly lead the legs —
verify the reticle deflection on a twist mech (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 +
ALL the instrument dynamics are LIVE (the Execute @004cdcf0 gap was RECOVERED via capstone
disasm, task #37; the authentic Lock producer + the simple-X mode landed in #38 — see
[[gauges-hud]] for the full instrument map). Remaining: (a) the **`*_cop` canopy shell** —
SOLVED for all 8 (task #55): authentic eye + the PUNCH stencil-cut kit + double-sided cop
geometry + unlit constant frame colour (`BT_COP_FRAME`) — see [[cockpit-view]] Rendering/FINAL;
shows by DEFAULT now (`BT_HIDE_COCKPIT=1` hides). NOTE the old claim here ("canopy windows are
punch texels") was WRONG — the shell has no texture; the openings are geometry. ✅ RESOLVED
(2026-07-11): PUNCH = a 3-chunk STENCIL-CUT kit (mask/hull/twin, i860-firmware-decoded)
executed as a D24S8 stencil cut; visible canopy = hull-minus-apertures ([[cockpit-view]]
§FINAL). All 8 mechs render connected dark frames with clear viewports (the intermediate
"frameless bhk1/loki/vulture/avatar" reading was wrong); thor matches the pod footage exactly.
Eye placement verified exact per-mech incl. Thor's +1.13 offset cockpit ([[cockpit-view]]). (b) the **3D marker
chain** ([0x31c]/[0x320] dpl objects + the PNAME1-8.bgf player-name meshes over the locked
target — matters for MP). (c) the compass rotation SIGN is derived-not-verified [T3] (turn
left → the stem should swing right; flip the sin sign in Draw if footage disagrees).
- **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) — RE-ENABLED LIVE (task #56, 2026-07-10).** The NaN revert's root causes
are fixed byte-exact (ctor field map @004b3778 — springConstant@0x1E8/dampingConstant@0x1F4
were mislabelled, the 0x254-0x2B3 block was missing, clamps/accumulators uninitialised; the
integrators' state-minus-target/componentwise-damping-overwrite/X-Z-crossing semantics; the
writers' one-node-two-channels form; dispatch from the MECH performance tail, not the gyro
Performance). Layout locked (sizeof==0x3D0); runtime clean (joints type 5, finite state, no
NaN). Empirical: spring targets are SYMMETRIC → eye equilibrium (0,0,0) → the gyro is a
±0.1-0.15u BOUNCE mechanism, NOT a steady offset (the earlier hypothesis is disproven).
**FAN-OUT LANDED (2026-07-11):** FUN_004b2980 re-disassembled from raw bytes and reconstructed
(`Gyroscope::ApplyDamageResponse`) + wired at the take-damage hub, the crushable crunch and the
firing recoil — the hit-BOUNCE is live and verified (damped eye oscillation, no NaN).
REMAINING (task #56 tail): (a) the alternate-gait engage jolt + engaged-gait rumble
(@4aa158-4aa365 — [T3] gate naming, mutates the #49/#50-stabilized gait machine; byte recipe in
the wf_6880e605 synthesis); (b) the mech+0x3F0 overspeed sway model (swayBias fed 0); (c) the
per-frame `EyepointRotation.pitch = torso pitch` writer (FUN_004b66b4) + mapper glance-look
states (FUN_004afd10 — yaw/pitch from mech+0x564..0x570); (d) senders filling
`Damage::damageForce` for directional bounce (random-fallback is binary-legal meanwhile).
Also: `deathAnimationLatched`/`legResetLatch` were never ctor-initialised (0xCDCDCDCD gate bug,
fixed in mech.cpp ctor). See [[cockpit-view]].
- **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.
- **Weapon groups / per-button fire channels (decomp-anchored 2026-07-09)** — MechWeapon message
handlers id 9 **`ConfigureMappables`** (`FUN_004b9550`) and id 10 **`ChooseButton`**
(`FUN_004b95b8`), table @0x511860 region: ConfigureMappables binds the weapon's
`fireImpulse`@0x31C to mapper fire-channel #N (msg value 1-based; <1 unbinds; mapper = roster
slot 0, vtable +0x38 register / +0x3c unregister; weapon+0x110 = the bound-state), ChooseButton
re-binds (vtable +0x44) — the pod's in-cockpit weapon→button GROUPING. Weapons sharing a button
fire together; grouping was a PILOT choice (heat management: alpha vs split). The port's
SPACE=all-energy / CTRL=missiles split is a stand-in default; the authentic system needs the
mapper channel registration + who SENDS the default ConfigureMappables (mission/player setup —
not yet traced). Payoff: authentic weapon groups + a path to chain-fire.
- **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
`<mech>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 — DONE (tasks #46/#47: replicant targeting + damage rerouted to the owning
master, full cross-pod kill verified). ✅ Replicant GAIT animation — DONE (task #50: replicant
derives speedDemand from the replicated velocity, full stand→walk→run lifecycle verified).
See [[multiplayer]] — the entries here were stale (swept 2026-07-11).
- **Mech-level update records (@0x4a0c2c) untranscribed — the biggest remaining MP fidelity gap:**
only the base Mover record replicates, so a peer's death SINK/burial, knockdown, heat, alarm and
movementMode states don't reach the other pod (the wreck SWAP does appear). The writer's disasm is
recovered + 9 record types decoded (`reference/decomp/mech_writeupdate_004a0c2c.disasm.txt`);
the read-side leg-state branches at mech.cpp:1511/:1613 are the dead Wword comparisons.
- The WinSock2 stack (L4NET.CPP) is 2-node verified end-to-end (cross-pod kills, beams,
replicant gait — tasks #46-#51); remaining = the real pod-LAN config (real IPs, bare-IP
pilot entries).
## 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).