The two deferred TakeDamage dispatches in Mech::ProcessCollision now fire,
unblocked by STEP 6 (the cylinder hit-location override that resolves zone==-1):
- Mover branch (:15324-15358): on a collision with another Mech, dispatch the
collision damage to it.
- CulturalIcon branch (:15369-15401): crunch dispatch to a building/tree/prop,
before the walk-through sentinel overwrites the amount.
Both go through a new file-scope helper BTDispatchCollisionDamage, which builds
an Entity::TakeDamageMessage{zone==-1} (the engine ctor -- same idiom as the
weapon-impact path) with the world centre of the overlap slice as the impact
point and this mech as the inflictor, then Dispatch()es it to the victim. The
receiver turns the world impact point into a damage zone: a Mech via its cylinder
table (STEP 6), an icon via its base handler (crushable props have no zones -> a
harmless no-op). Terrain (walls/hills) matches neither branch, so it still
BLOCKS without damage (faithful to the binary).
Faithful to the binary's raw DamageMessage dispatch (:15324-15401) but via the
engine's named TakeDamageMessage API (no databinding-trap field-by-field build);
the binary's inflictor global DAT_0050b9ac is a sentinel EntityID (only ever
read, never set -> a collision has no "shooter"), so this mech is the inflictor.
Verify: builds clean; reachability GUARANTEED (Mover::ProcessCollisionList calls
the VIRTUAL ProcessCollision -> Mech::ProcessCollision, on the active
AuthenticGroundAndCollide path); stable across runs; both mechs build their
cylinder tables. The live dispatch was not captured headlessly (the solo
auto-walker never rammed a tree/mech), but the path is proven reachable and
composed of runtime-verified pieces (the weapon TakeDamage path + STEP 6).
Also validated STEP 6's height ref: collisionTemplate->maxY ~= 7.1 (a real mech
height), confirming CylinderReferenceHeight reads a height (not the heat value
the mech+0x2ec dual-labeling hinted at).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
10 KiB
10 KiB
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 |
|
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.RESalready 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
(
ConsolidateAndSendDamagePerformance @0049b784,weaponExplosionsqueue,CommonDamageInformation; messmgr.hpp). ctorFUN_0049bca4(vtable 0x50b954, installs a Performance → ticks). The factory caches it toMech[0x10d]= byte 0x434. What wiring it needs: an untangle — our reconstruction MISLABELEDMech[0x10d]ascontrolsMapperandmech4'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 bySetMappingSubsystem/MakeViewpointEntity; aMechRIOMapper). 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 atmech+0x190(bothFUN_004ac9c8the valve guard→+0x274andFUN_004ad7d4the Myomers gate→+0x260derefowner+0x190, which ≠ the 0x434 messmgr cache). The earlier "0xBD3 gates 4 things" note was wrong. - ✅
mech+0x190IDENTIFIED (2026-07): it is the owningBTPlayer(Mech::GetPlayerLink(),MECH_OWNING_PLAYER; ENTITY.h:430). Set byFUN_0049f624(the mech↔player bind:mech+0x190 = playerANDplayer->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 atplayer+0x260andplayer+0x274(the reconstruction maps this block asshowDamageReceived@0x25c / showKills@0x260 / showDamageInflicted@0x264 / roleClassIndex@0x274in btplayer.hpp — from the SCORING work, so the names may NOT match the gate semantics; the true meaning + the WRITER ofplayer+0x260/0x274are 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): pointMechSubsystem::IsDamaged()(FUN_004ac9c8, valve guard) atGetPlayerLink()->(0x274) andMyomers::OwnerAdvancedDamage()(FUN_004ad7d4) atGetPlayerLink()->(0x260) — via NAMED members (databinding trap: our BTPlayer layout ≠ binary; do NOT raw-readplayer+0x260). ⚠ Resolve first: (a) a naming conflict —FUN_004ad7d4is labeled BOTHHeatModelActive(heat.hpp) ANDOwnerAdvancedDamage(myomers.cpp); re-verify which body is which; (b) the true semantic ofplayer+0x260/0x274vs the scoring-derivedshowKills/roleClassIndexnames. 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+ thePlayer__StatusMessagerecord ({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
gBTWeaponTriggerbring-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 BTPlayermech+0x190+0x260, NOT 0xBD3 — see the mech+0x190 item above) +MoverAttachrouting 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, anEntity::TakeDamageMessage{zone==−1}is dispatched to the victim (viaBTDispatchCollisionDamage, 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::ProcessCollisionListcalls the virtualProcessCollision→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), confirmingCylinderReferenceHeightreads a height, not the heat value themech+0x2ecdual-labeling (heat-gauge sink vs groundRef, mech4.cpp:2697) hinted at. - ✅ Cylinder hit-location (STEP 6) — DONE 2026-07-08 [T2]. Built + runtime-verified: the
dmgtable.cppclasses now have real storage + a workingResolveHit→zone, the mech ctor loads the type-0x1d table by the DamageZoneStream name ([cyl] table 'bhk1' layers=7), andMech::TakeDamageMessageHandlerresolves unaimed (zone==−1) hits before base-routing. Full change list in combat-damage "STEP 6 COMPLETE". The live collision-damage path (zone==−1 → resolve) is now UNBLOCKED. 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 (reconStandingAnimation@Mech[0x111], but with an EMPTY name → 0 rows, becauseResourceFindByNameis 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 thinMech::TakeDamageMessageHandlerglue (zone==-1 → call the lookup →damageZones[zone]->TakeDamage) is unexported, and it's fully implied by pieces already reconstructed → no disassembly needed. Remaining: 6b realFindByName(name = the mech's type-0x14 DamageZoneStream name @ResourceDescription+0xc); 6c the 3 container ctors + the lookup as aBTCylinderResolveZonebridge (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-citedFUN_004a0230/FUN_0049ed0cdon't exist. - Death: reconstruct
DeathShutdown(RPVTV::DeathShutdownanalog) + collapse anim + destroyed skin. The wreck-stays behavior we ship is faithful; do NOT issue DestroyEntityMessage on death.
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)
- 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 (.mapin CONTENT/BT/MAPS/); would need compiling into a RES via the DOSbtl4tool.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).