Files
BT412/context/open-questions.md
T
arcattackandClaude Fable 5 bf87360c42 Buried wreck goes INERT: collision off + target lock dropped
Answers "it's still there but invisible": not normal -- the real game removes
the dead entity (death row).  Full entity teardown needs the mech render tree
unhooked from the renderer first (the remaining P5 follow-through), so until
then the burial transition makes the wreck behaviorally gone:
  - collisionVolumeCount = 0 (the collision gather skips volume-less movers;
    MoveCollisionVolume early-outs) -> no phantom blocking
  - the player's target lock drops -> beams stop converging on / hitting the
    empty spot, no phantom impact smoke
Verified: zero [damage] hits after burial; INERT fires one-shot at
"wreck buried".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 16:01:46 -05:00

163 lines
14 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).
- **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
`<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 (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).