Commit Graph
21 Commits
Author SHA1 Message Date
arcattackandClaude Fable 5 24ea7f13af HUD ironing (task #38): authentic Lock producer + simple-X mode
- LOCK rules transcribed from the exported HudSimulation
  (part_013.c:5619-5634): lock requires a target AND your own HUD host
  zone damage < 0.75 (_DAT_004b7ec4 -- a shot-up targeting computer
  drops lock) AND the targeted zone damage < 1.0 (_DAT_004b7ec8;
  whole-mech target checks zone 0 -- a wreck's dead zone can't
  re-lock). Box and ring are now separate signals like the binary:
  gBTHudLockState 1 = target held (hotbox draws), 2 = LOCKED (+ the
  spinning ring).
- SIMPLE-X mode: the ctor's [0x99] minimal-reticle list transcribed
  (@4689-4705: green +-0.02..0.08 cross on the aim translate); Draw
  switches master <-> simple X on the PrimaryHudOn element bit (0x20),
  completing the recovered Execute's state-list logic.
- Canopy diagnosis sharpened (open-questions): blx_cop is the torso
  segment's inside-skeleton mesh enclosing the eye; the black box =
  the skeleton render branch missing its texture + PUNCH cutout (the
  canopy windows are punch texels). A rendering-branch task; stays
  hidden by default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 23:12:58 -05:00
arcattackandClaude Fable 5 18d49491b7 Reticle Execute @004cdcf0 RECOVERED: every HUD instrument now live (task #37)
The one un-exported gap in the reticle chain, read via capstone
(tools/disas2.py; the annotated disasm preserved at
reference/decomp/reticle_execute_004cdcf0.disasm.txt). Draw() is now a
transcription of the real per-frame logic, and the HUD attr-table names
(hud.hpp ids 4/5/6/8/A/B/C/D) are CONFIRMED by their Execute usage:

- Range ladder: BAR from ladder-top to the caret + caret translate.
- The bottom 21-tick tape is the TORSO-TWIST indicator (NOT heading):
  deflection = -/+(span/2) x (RotationOfTorsoHorizontal / twist limit),
  attrs 4/5/6. Fixed-torso BLH reads centred -- authentic static.
- The circle-with-stem is the COMPASS (attr 0xD, rad->deg rotation) at
  (botX, botY - 3*tickMajor - 0.03), with the THREAT trail (attr 0xC)
  in its rotated frame: 0.05-unit attack-direction marks, fresh < 2s
  red, expiring at 6s. Port feed: player TakeDamage pushes the impact
  direction (dormant vs the passive test dummy).
- Pips (composed into subB6): hidden when destroyed (attr 1 == 1), LIT
  when the fire cycle is LOADED (attr 0x1c == 2; port source
  rechargeLevel >= 1) else the dark charging ring; filtered by the
  weapon-GROUP bits (weaponMode & elementMask&0xF). Range plays NO part
  (the stored TargetWithinRange slots are never read by Execute).
- Lock ring: subB9 at frame centre SPINNING 4 deg/frame while locked
  ([0x9d] is the spin matrix, not a heading list).
- Target HOTBOX: a rectangle hugging the projected extents (x+-4 around
  the top-centre hotbox point, +1/-11.5 vertical; baked K=2.8145 -- the
  port projects through the live per-axis projection), switching to the
  edge arrows past +-1.6 or behind (BTProjectHotBox, L4VIDEO).
- Reticle state Off/On + PrimaryHudOn full-HUD/simple-X switch, aim
  translate on slew move, 3D marker + PNAME player-name mesh identified
  (chain still deferred).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 22:38:50 -05:00
arcattackandClaude Fable 5 9666dc5b5e Targeting: lock mirrors the pick per frame (sticky designation removed)
The sticky lock made aim irrelevant after the first acquisition (the
crosshair starts on the face-to-face enemy, so it locked at spawn and
never let go -- played as auto-targeting). The binary treats no-target
as a frequent live state (fire path re-checks 0x388!=0 at every step,
part_013.c:7689/7727; HUD range feed has a permanent no-target default,
:5636), so the target slots now mirror the reticle pick each frame:
locked while the crosshair is ON the mech, no lock otherwise. Keeping
the crosshair on the enemy is the gunnery.

Verified headless: BT_AIM="0 0" -> HOT + aimed zone hits; BT_AIM="0.6
0.4" -> no lock, zero damage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 21:08:08 -05:00
arcattackandClaude Fable 5 d78bde066d Authentic target acquisition LIVE: reticle slew + pick-ray lock + aimed zone damage (task #36)
The engine Reticle model (MUNGA/RETICLE.h [T0]) reconstructed end to end:
- Mech::targetReticle is a real Reticle member bound to the TargetReticle
  attribute (0x1d), per the RP VTV analog (VTV.h targetReticle).
- Crosshair slew: mouse -> client rect -> reticle coords (the pod stick
  free-aim channel's dev-box stand-in); BT_AIM="x y" pins it headless.
  LMB fires lasers / RMB missiles (alongside SPACE/CTRL).
- Pick ray: the ACTIVE eye publishes pos + LookAtRH basis (BTSetAimCamera,
  L4VIDRND view-write site) + the render loop publishes proj._22;
  BTGetAimRay builds the world ray, Mech::PickRayHit slab-tests it against
  the collision template's ExtentBox via the engine's BoundingBox::HitBy
  (local frame; clips the Line at entry) -> world hull point.
- Designation: the mech under the crosshair designates (sticky; re-hover
  refreshes; cleared when the target leaves the roster at burial); the
  entity target slots 0x37c/0x388/0x38c feed the whole weapon path.
- Aimed fire: while HOT the impact point is the PICKED hull point -> the
  STEP-6 cylinder lookup resolves the zone under the crosshair (verified:
  center-aim -> head-band zone 13 dominant). Off-crosshair the sticky
  designation converges on center mass.
- HUD: the aim group draws at the slewed position ([0x9a] translate,
  contained by push/pop); the designator ring tracks the target's
  projected point (subB9 hot / subB8 designated, BTProjectToReticle);
  edge arrows when off-screen/behind.
- AUTHENTIC gating: no fire arc exists in the binary (FireWeapon fires
  whenever HasActiveTarget, part_013.c:7758) -> BT_FIRE_ARC is now an
  explicit OPT-IN presentation clamp; the hardwired gEnemyMech lock and
  the projectile path's gEnemyMech fallback are removed.
- Fixed en route: every renderable rebuild stomped mCamera back to the
  chase eye (start-inside silently lost the cockpit camera; the aim feed
  exposed it). BTL4VideoRenderer::mViewInside persists the chosen view.

Verified headless: BT_AIM="0 0" -> HOT lock, pick hits the hull face at
exact range, aimed zones resolve; BT_AIM="0.8 0.3" -> no lock, zero
damage, zero missile launches; kill chain completes to wreck + smoke.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 20:57:11 -05:00
arcattackandClaude Fable 5 6988821525 KB: authentic targeting model recovered (Reticle pick-ray, RETICLE.h [T0])
The engine Reticle struct (the mech's "TargetReticle" attribute) is the
acquisition chain: slewable screen-space crosshair -> pick-ray -> the
entity + damage zone under it become mech+0x388/0x38c, the intersection
point mech+0x37c. Convergence-on-lock is authentic (FireWeapon has no
aim test); targetWithinRange = dist < (1-damage) x weaponRange
(FUN_004b9bdc). Port acquisition is a bring-up stand-in (hardwired lock
+ BT_FIRE_ARC cone) -> tracked as the next combat-fidelity step.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 20:23:24 -05:00
arcattackandClaude Fable 5 48b17750e5 HUD reticle + weapon pips LIVE: dpl2d 2D display-list port (task #35)
- dpl2d API fully recovered from the binary recorders (@487f34-488630):
  opcode model (points/lines/polyline/circle/color/width/matrix/push-pop),
  CallList = INLINE include (state persists to caller), centered coordinate
  frame (unit = half viewport height). game/reconstructed/dpl2d.cpp rework.
- BTReticleRenderable ctor @004cc40c transcribed with the authentic
  calibration (originX .35, originY .25, scaleY .5, 0..1200m right range
  ladder, bottom heading tape, FUN_004cd938 tick ladders, lock rings,
  turn arrows); range caret slides from the live target range fed by the
  mech4 targeting step (BTSetHudTargetRange).
- Weapon pips: the binary gate is IsDerivedFrom(0x511830 =
  MechWeapon::ClassDerivations) [T1: part_014.c:5386 hard-aborts on missing
  weapon attrs; part_012 counts + roster ORs capabilityFlags@+0x334] so ALL
  7 BLH weapons register (3 lasers + 2 PPCs + 2 MissileLaunchers). Pip A
  (lit, authored PipColor) on TargetWithinRange, else dark ring B.
- AddWeapon @004cdac0 store map corrected to the verified order
  (part_014.c:4827-4837); both state attrs are literally named
  "SimulationState" (strings @51d526/51d577) -> weapon simulationState.
- Mech roster this[0x1ef] renamed poweredSubsystems -> weaponRoster
  (0x511830 is MechWeapon, not PoweredSubsystem=0x50f4bc); derivation-tag
  table added to context/decomp-reference.md.
- Draw hook BTDrawReticle after the 3D scene, cockpit view only. Binary
  Execute @004cdcf0 is an un-exported gap -> Draw dynamics [T3], tracked
  in context/open-questions.md with the blx_cop canopy + PNAME pip meshes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 20:05:44 -05:00
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
arcattackandClaude Fable 5 c0fa6bf21a Death = the burning WRECK-HULK swap (effect 104) -- the authentic chain, reconstructed
The user was right: a dead mech turns into a pile of wreckage.  The authentic
1995 chain, recovered end-to-end:

  kill -> the victim's per-mech DEATH ModelList ('blhdead'/'lokdead'/'owndead'/
  'thrdead', .RES ids 22-25) -> its authored effects: 104 (the WRECK script) +
  1007 (dnboom big explosion) + 1001 (ddthsmk rubble smoke plume) + a damage-
  smoke burst (3/4/5/15).

Effect 104 = ExplosionScripts case 4 (part_008.c:2663, LIVE in the 1996 binary;
the "disabled" warning is case 6): loads the destroyed hulk + flamesml/flamebig
flame meshes with sweep flicker.  Every mech ships its hulk (BLHDBR/MADDBR/
LOKDBR/... + GENDBR generic); the 1996 script hardcoded thrdbr.bgf (dev
shortcut) -- we use the victim's own.

Reconstructed as BTL4VideoRenderer::SwapToWreck: hide every segment mesh, hang
"<prefix>dbr.bgf" on the tree root (pending-swap if death precedes tree build);
routed from the engine's ExplosionClassID dispatch (effect 104 ->
BTSwapMechToWreck(explosion->GetEntityHit())).  The kill now fires the
authentic 'blhdead' resource (manual 7+1 pfx calls removed -- the list carries
1007/1001 itself).  Verified live:
  [death] firing authentic death list 'blhdead' id=22
     ** effect_number = 104
  [BTrender] wreck swap: victim -> 'blhdbr.bgf'

Follow-ups noted: mesh flames + hulk settle (cosmetic), DeathSplash.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 15:43:08 -05:00
arcattackandClaude Fable 5 d9254736ab Death is a FREEZE, not a collapse -- fall-latch vestige proven; band-effect impact frames
Task #32 (death collapse animation) resolved by decomp evidence -- BT 4.11 has
NO collapse animation; the movementMode 5-8 fall latch (clips 0x1c-0x1f) is an
engine-lineage vestige:
  (1) the clip-table loader FUN_004a80d4 fills slots 0x00-0x1b + 0x20 (bmp
      knockdown) and returns -- slots 0x1c-0x1f are never written;
  (2) mech+0x63c..0x648 appear in NO exported function;
  (3) no fall clip exists in the shipped 27-clip set;
  (4) firing the latch would bind resource id 0 -- a StaticAudioStream -- as
      keyframes.
Authentic death modes are the FREEZE modes (IsDestroyed == mode 2||9), so
UpdateDeathState now settles straight to 9 (was a [T3] mode-5 guess that would
trip the garbage latch in the binary).  The death READ = freeze + dnboom +
ddthsmk smoke plume + destroyed skins + shutdown; the wreck stands.

Also: damage-band effects orient toward the ATTACKER (impact frame) via
lastInflictingID -- which was declared but never written (recon gap); now
maintained by Mech::TakeDamageMessageHandler, unblocking the DamageZone LOD
same-attacker redirect too.

KB corrected + proofs recorded (combat-damage "Death SEQUENCE", open-questions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 14:50:12 -05:00
arcattackandClaude Fable 5 a3d67cc639 Combat visible + killable: Wword root-cause fix, .PFX effect layer, RemakeEntity swap
The 'can't kill the enemy / no visible damage' cluster, root-caused and fixed
faithfully:

- STEP-6 unaimed path was INERT: the cylinder table was 'cached' at Wword(0x111)
  -- the recon ABSORBER bank (stores nothing, reads 0) -- so every unaimed hit
  silently no-op'd.  Promoted to the named member Mech::damageLookupTable
  (binary this[0x111], was mislabeled ammoExpended).  New gotcha class recorded
  (reconstruction-gotchas §2) + sweep; 2 dead multiplayer branches logged.

- Fire path migrated off the stale vital-zone aim onto the completed STEP-6
  unaimed dispatch (zone=-1 + beam entry point -> cylinder resolves the
  exterior zone).  No more invisible 1-shot kills; death via the authentic
  cascade (~14 center-mass hits).  Wreck stays TARGETED on kill (beams stop on
  it); scoring latches off.

- SendSubsystemDamage AV fixed: unbound critical-subsystem plug guard (43
  unbound plugs/mech logged as an open question -- the binding itself is a gap).

- RemakeEntity (render damage swap): the 1996 render state machine's missing
  Remake state, reconstructed as an in-place SetDrawObj mesh swap keyed by each
  segment's damage-zone graphic state (tree dtor doesn't cascade -> never
  rebuild).  Destroyed arms/guns visibly wreck (the only variants the RES
  registers).

- BT .PFX particle layer (L4VIDEO.cpp): the 1995 explosion/damage effect layer,
  unported since 2007 (DPLIndependantEffect/ReadPSFX/ExplosionScripts all
  stubs).  Parses the authentic VIDEO/*.PFX definitions via the [pfx_day]
  psfxN mapping; premultiplied blending renders BOTH families from the same
  data (additive-style fire + occluding smoke -- DDAM2 is 30% grey, DDTHSMK
  ramps negative: impossible additively); depth-sorted billboards with a
  radial-masked grit sprite; impact-frame orientation (.PFX offsets are
  authored mech-local, -Z = out of the struck armor toward the shooter) for
  weapon hits AND damage bands (via lastInflictingID, now maintained -- was
  declared but never written).  Both effect-number encodings route (raw dpl
  <100 + WinTesla 1000+slot carried by the band resources).  Death fires the
  authentic dnboom (7) + ddthsmk smoke plume (1).

- Effects anchor at the impact point / damaged zone's segment, not the mech
  origin (no more fire at the feet).

- Dev force-input gates BT_AUTOFIRE / BT_AUTODRIVE for headless fire-chain
  verification; BT_PFX_ADD=1 flips the particle blend for A/B.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 14:43:32 -05:00
arcattackandClaude Opus 4.8 a9467481c5 Death-state sequence: collapse + subsystem shutdown + freeze (wreck stays)
Reconstructs the mech DEATH state machine — the un-exported master-perf death
branch (region 0x4a9770-0x4ab188) — from its EXPORTED consumers + the RP
VTV::DeathShutdown analog, wired into the active path (the bring-up drive
override bypasses the authentic Simulate where this normally lives).

Mech::UpdateDeathState() + IsMechDestroyed() (mech4.cpp), called for every mech
early in PerformAndWatch: on a vital kill (graphicAlarm >= 9, raised by the
damage side) it
  1. sets movementMode = 5 -> the collapse clip's one-shot latch in
     AdvanceBodyAnimation (fall direction 5-8 is un-exported -> 5 [T3]);
  2. loops the roster calling Subsystem::DeathShutdown(1) (RP VTV::DeathShutdown
     analog; the base is a no-op virtual, overrides act -- a SHUTDOWN not a
     teardown, so it frees nothing and never removes the entity: the wreck STAYS);
  3. next frame settles to movementMode = 9 -> IsDisabled -> locomotion frozen.
The drive's lone `movementMode = 1` write (mech4.cpp ~1309) is guarded on
!IsMechDestroyed so the death state is not clobbered back to a live gait.

Runtime-verified (forced kill, BT_DEATH_LOG=1):
  [death] mech destroyed -> collapse + subsystem shutdown (wreck stays)
  [death] mech settled -> disabled (IsDisabled=1, frozen wreck)
mech frozen in place, subsystem tick + renderer keep running, no crash, wreck
stays.

Also records the full death-sequence decomp map in combat-damage.md (the
exported consumers: AdvanceLeg/BodyAnimation collapse latch, IsDestroyed, the
MechDeathHandler effect engine; and the un-exported orchestration gap).

Deferred (honest): the visible collapse ANIMATION latch through the active path
(gait SM shows state=0 post-death; spawned mechs don't advance body anim);
MechDeathHandler (FUN_0042a984/FUN_0042aa2c -- the exported per-subsystem
destroyed-skin + explosion engine, still a stub) for death explosions; the
whole-mech DeathSplash radius damage (un-exported).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 09:30:34 -05:00
arcattackandClaude Opus 4.8 2af401eef8 Collision damage applied: mech-vs-mech + icon-crunch via the STEP-6 unaimed path
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>
2026-07-08 08:54:21 -05:00
arcattackandClaude Opus 4.8 d07ac7dd49 STEP 6 COMPLETE: cylinder hit-location LIVE — unaimed hits resolve to zones
The Mech per-impact hit-location resolver (the cylinder damage table) is now
functional, wired, and runtime-verified [T2].  Unaimed (zone==-1) hits — the
collision-damage path — now resolve an impact point to a damage zone via the
authentic height x angle grid + weighted dice roll, instead of dropping.

dmgtable.cpp/.hpp was a non-functional skeleton on no-op ReconTable/stream
shims; backed it with real std::vector storage and fixed 5 latent runtime bugs:
  - ReadEntries now consumes the leading cell name-string ([i32 len][len+1])
  - PieSlice ctor reads rotateWithTorso into the correct member
  - SelectSlice direct-indexes (was int lookup on a float-keyed table)
  - ResolveHit returns the zone (chains SelectSlice -> SelectZone)
  - real MemoryStream::ReadBytes (was a variadic no-op)

mech.cpp ctor: replaced the empty-name StandingAnimation stub with the real
load — FindResourceDescription(dzRes->resourceName, type 0x1d) -> stream ->
new DamageLookupTable, cached at mech[0x111]; ~Mech deletes it.

Mech::TakeDamageMessageHandler override registered (MESSAGE_ENTRY overlays
Entity's by ID): on invalidDamageZone, resolve via the table then base-route;
aimed reticle hits pass through unchanged.

Three named accessors (no databinding-trap raw reads): WorldToLocal
(localToWorld.MultiplyByInverse), CylinderReferenceHeight (standingTemplateMaxY
== collisionTemplate->maxY == binary mech+0x2ec[+0xc]), TorsoHeading via a
BTGetTorsoTwist bridge in torso.cpp (Torso::CurrentTwist == torso+0x1d8;
torso.hpp cannot be included into mech.cpp — subsystem-stub collision).

Stream format + geometry + roll + handler were all byte-verified against the
shipped BTL4.RES type-29 resources (18 tables, exact consumption) and the
disassembly (FUN_0049eb54/e678/de14, glue 0x49ed0c, handler @0x4a037a).

Runtime: boots clean, "[cyl] table 'bhk1' layers=7" (exact byte-verified layer
count, found by name), mech spawns + walks, no asserts/AV/0xCDCDCDCD.  Env gate
BT_CYL_LOG=1.  Unblocks collision-damage application.

KB updated (combat-damage.md STEP 6 COMPLETE, open-questions.md marked done).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 08:32:17 -05:00
arcattackandClaude Opus 4.8 33fee712e9 context: STEP-6 content confirmed — DamageLookupTableStream (type 29), 18 present, feasible
The cylinder table resource = type 29 DamageLookupTableStream, 18 in BTL4.RES (one per mech) ->
STEP 6 is FEASIBLE, not content-blocked. Name copied from a sibling resource (local_130+0xc).
RE phase complete; build (containers + handler + load + wire) is the next phase.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:24:43 -05:00
arcattackandClaude Opus 4.8 970d4fbad0 context: STEP-6 cylinder table FULLY reversed (height x angle grid) — build plan
De-risk + format-reversal pass complete. The CylinderDamageZoneTable is a passive nested-list
height x angle grid: TABLE (FUN_0049ea48) -> ROWS-by-height (FUN_0049e740, cell key i*2pi/count,
_DAT_0049e810=6.2831855) -> CELLS-by-angle (FUN_0049deb0) -> zone. All 3 vtables minimal (dtor +
2 Node slots, NO lookup method) -> the lookup is entirely in the unexported
Mech::TakeDamageMessageHandler (handler-set entry, not virtual) = the disassembly target.
Full ctor/dtor/vtable address map + the 4-step build plan recorded in combat-damage.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:20:44 -05:00
arcattackandClaude Opus 4.8 99c3d9d041 context: cylinder hit-location (STEP 6) investigated — accurate structure + addresses
Per the 'correct errors' convention: the cited FUN_004a0230/FUN_0049ed0c don't exist. The real
CylinderDamageZoneTable = a list of 0x30-byte entries (FUN_0049e740) from resource 0x1d; the recon
builds the table (FUN_0049ea48, mislabeled StandingAnimation @Mech[0x111]) with an EMPTY name -> 0
entries -> no-op. The lookup + Mech::TakeDamageMessageHandler override are NOT in the exported decomp
(need disassembly). Recorded in combat-damage + open-questions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:14:39 -05:00
arcattackandClaude Opus 4.8 5b7f3a1c40 context: sweep the 0xBD3/mech+0x190 correction across all topic files
Propagate the verified finding (0xBD3 = damage/explosion hub @0x434, NOT the valve/message
gate; the valve/Myomers gates read the owning BTPlayer @mech+0x190) into the topic files that
still carried the old claim: decomp-reference (ClassID row + both offset rows), gauges-hud,
subsystems, open-questions (Myomers coupling), + frontmatter. Graph validates clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:01:45 -05:00
arcattackandClaude Opus 4.8 40fdceaf65 context: mech+0x190 IDENTIFIED = the owning BTPlayer (Mech::GetPlayerLink)
The valve/Myomers 'gates' (FUN_004ac9c8 / FUN_004ad7d4) read the owning BTPlayer's
+0x274 / +0x260 (mech+0x190 = the player, bound by FUN_0049f624). So there's no new
subsystem to build -- the wiring is 2 gate accessors -> GetPlayerLink() named members.
Open: the true semantics of player+0x260/0x274 (scoring names showKills/roleClassIndex
may not match the gate use) + the FUN_004ad7d4 HeatModelActive-vs-OwnerAdvancedDamage
label conflict + these are likely MODE flags authentically-off in the basic mission.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 22:57:18 -05:00
arcattackandClaude Opus 4.8 16af8dbffb context: correct 0xBD3 — it's the damage/explosion hub (0x434), NOT the valve/Myomers gate
Risk-4 investigation (before wiring WAVE 8) found my earlier 'keystone unblocks 4 things'
claim was wrong. Verified from the binary:
- 0xBD3 SubsystemMessageManager = a damage/explosion consolidation hub (ConsolidateAndSendDamage,
  weaponExplosions), cached to Mech[0x10d]=0x434, mislabeled 'controlsMapper' in our recon (the
  live drive squats there; the real mapper is roster slot 0 via SetMappingSubsystem).
- The valve MoveValve guard (FUN_004ac9c8 ->owner+0x190+0x274) AND the Myomers gate
  (FUN_004ad7d4 ->owner+0x190+0x260) read a DIFFERENT object at mech+0x190 (!= 0x434). So 0xBD3
  does NOT gate the valve/Myomers/MessageBoard; mech+0x190 (unidentified, no decompiled writer yet)
  is the real keystone for those gauge-adjacent routes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 22:49:29 -05:00
arcattackandClaude Opus 4.8 f914fc040a context-system: complete migration -> CLAUDE.md is now a 160-line router (zero context lost)
Full migration of the 2236-line monolithic CLAUDE.md into the progressive-context
knowledge graph (per spark-lesson / expert-seed.md), so the deep RE knowledge loads
on-demand instead of every session.

ZERO CONTEXT LOST:
- docs/PROGRESS_LOG.md = the complete old CLAUDE.md, VERBATIM (byte-identical) -- the
  lossless safety net + the "full detail" quick-lookup fallback.
- 18 context/*.md topic files (1343 lines) digest every section (§1-3 -> project-overview,
  §4 -> content-archives, §5 -> asset-formats/bgf-format, §5a -> source-completeness,
  §5b/§8 -> wintesla-port, §7/§10 -> locomotion, §10a -> build-and-run, §10b ->
  reconstruction-method, §10c -> combat-damage + reconstruction-gotchas, §10d -> subsystems,
  render notes -> rendering, gauges -> gauges-hud, MP -> multiplayer, §9 -> open-questions).
- reference/glossary.yaml (53 terms). decomp-reference.md = the offsets/ClassIDs/addresses hub.

CLAUDE.md (160 lines) = router: identity, answer/reason protocols, quick-lookup table,
evidence tiers (T0 engine-truth / T1 decompiled+verified / T2 reconstructed+runtime /
T3 guarded / T4 hypothesis), conventions + DO-NOT (the systemic bug classes), structure.
Retains the load-bearing work directives (build recipe pointer, "keep current" mandate).

Knowledge graph validates CLEAN (scratchpad/checkctx.py -- all [[links]] + quick-lookup +
docs refs resolve; [[name]] -> topic file or glossary term). docs/*.md ledgers stay as the
detailed logs; context/*.md are the curated digests that route into them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 22:19:50 -05:00
arcattackandClaude Opus 4.8 1cd57ade85 context-system: bootstrap the progressive-context expert knowledge base (foundation)
Adapt the spark-lesson / expert-seed.md progressive-context pattern to the bt411 port:
a thin router + context/*.md knowledge graph so the 2236-line CLAUDE.md's deep knowledge
loads on-demand instead of every session.

NON-DESTRUCTIVE foundation pass (live CLAUDE.md unchanged; proposed router is a draft):
- reference/glossary.yaml        -- ~45 terms (engine/formats/scene/reconstruction)
- context/decomp-reference.md    -- the quantitative hub: resource types, ClassID map,
                                    mech offsets, damage delivery, weapon constants, env gates, tools
- context/reconstruction-gotchas.md -- the 12 systemic bug classes (conventions/DO-NOT hub)
- context/bgf-format.md          -- geometry format + CONN/PCONN + LOD-sqrt3 + ramp shading
- context/gauges-hud.md          -- the gauge/MFD system (the just-completed wave)
- context/open-questions.md      -- deferred systems + get-from-Nick
- context/_ROUTER-DRAFT.md       -- the proposed slim CLAUDE.md (identity, protocols,
                                    quick-lookup, evidence tiers T0-T4, conventions, structure)
- phases/phase-01-context-restructure.md -- design + migration plan + status

docs/*.md ledgers stay as the DETAILED logs; context/*.md are the curated digests that
route into them. Remaining: ~10 topic files (project-overview, subsystems, combat-damage,
rendering, locomotion, wintesla-port, build-and-run, ...) then the CLAUDE.md swap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 22:06:53 -05:00