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>
230 lines
20 KiB
Markdown
230 lines
20 KiB
Markdown
---
|
||
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).
|