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

14 KiB
Raw Blame History

id, title, status, source_sections, related_topics
id title status source_sections related_topics
open-questions Open Questions — deferred systems, unknowns, get-from-Nick living CLAUDE.md §9; docs/HARD_PROBLEMS.md; per-subsystem deferral notes
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 ProcessCollisionMech::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).