Commit Graph
17 Commits
Author SHA1 Message Date
CydandClaude Fable 5 e1e5a9a6db BT410 Phase 5.3.12: experience gates + coolant system -- novice/expert modes REAL
The player-experience system now gates the entire heat/jam economy, verified in
BOTH directions with a one-token egg edit (TESTNOV.EGG, experience=novice):
NOVICE = 212 fire cycles all pinned at T=77, zero jams, zero shutdowns (the
heat model authentically absent); EXPERT = the full economy (duty cycles, 119
shutdowns + 2 authentic jams under forced fire). Zero Fail in both.

- BTPLAYER: the flag block renamed to its TRUE semantics (simLive @0x25c,
  heatModelOn @0x260 -- the FUN_004ad7d4 master switch, advancedDamageOn pair,
  levelFlag26c/270, experienceLevel); the ctor rows were already
  binary-accurate (nov 0000 / std 1011 / vet 1111 / exp 1101); accessors +
  [exp] sentinel.
- HeatSink::HeatModelActive() + ProjectileWeapon::LiveFireEnabled(): owner
  mech -> Entity::GetPlayerLink() -> the BTPlayer flags, NULL-permissive.
  Gates: both HeatSinkSimulation phases, every weapon fire-heat dump, and
  CheckForJam is now the AUTHENTIC form (LiveFireEnabled + heatLoad<=0
  early-outs + the minJamChance floor; the interim heat-degraded gate retired).

- THE LOAD-BEARING FIX: Mech ctor SetValidFlag(). Every 1995 entity ctor tail
  marks itself valid; ours didn't -- Entity::Dispatch routes messages to an
  INVALID entity into the deferred event queue, so the PlayerLink bind (and
  every directly-dispatched mech message) silently never landed and the gates
  read a NULL player forever.

- THE COOLANT SYSTEM (authentic bodies, byte-verified constants: HeatLoadScale
  0.002 -> heatLoad now in [0,1]; equalize eps 1e-4; draw floor/ON
  0.0025/0.003): UpdateCoolant (damage-scaled draw -- an undamaged mech leaks
  nothing), BalanceCoolant (full clamp chain from ConductHeat), DrawCoolant
  base=0 with the RESERVOIR override as THE SOURCE; Reservoir reconstructed
  (capacity overlays thermalCapacity, CoolantSimulation + the full
  InjectCoolant flush distribution, BT_FORCE_FLUSH dev hook); Condenser
  RefrigerationSimulation (massScale = (1-damage)*refrigerationFactor >= 1 --
  the heat pump that chills the bank; valveState inits 1; digit-suffix number
  fix). Deferred: AggregateHeatSink family, cockpit-button handlers
  (MoveValve/ToggleCooling/InjectCoolant), TrackSeekVoltage charge model.

Research driven by a 4-agent workflow dossier over the BT411 RE (verbatim
bodies for every function above + the egg experience plumbing).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 22:15:07 -05:00
CydandClaude Fable 5 57507cb15c BT410 Phase 5.3.10: power/heat wave -- the thermal + electrical economy is LIVE
Weapons dump firing heat into their own sinks, sinks conduct through the
Condenser bank into the central HeatSink, temperatures drive the degradation/
failure alarms, and every powered subsystem tracks its generator through the
electrical state machine. Verified: the authentic fire-discipline game -- a PPC
spikes 77->709K per shot, relaxes to 441K across its 5s reload, and sustained
fire climbs 441->674->838->960K, brushing the authored 1000K degradation
threshold. All calibration values match the BT411 audit exactly (central bank
1.39e6, PPC sink 174000, thresholds 77/1000/2000).

- HEAT: HeatSinkSimulation (@004ad924 absorb->T->load->conduct->alarm),
  ConductHeat/ComputeHeatFlow (@004ad8ac/@004ad9ec two-body equilibrium
  relaxation; flow==0 exactly at uniform T), UpdateHeatLoad (15-sample filter);
  heat-state enum + accessors; installed by the HeatSink ctor.
- WIRE-VERIFIED: HeatSink resource gains linkedSinkIndex -- THE missing
  ancestry int that shifted every descendant block +1 (voltageSourceIndex had
  been reading the linked-sink index: "power sources" appeared to be
  Condensers). Conduction topology wired from it at construction:
  weapons->Condensers1-6->central; Generators->Condensers; Reservoir->central.
- MECHWEAP resource: authentic pip tail (pipPosition int + pipColor 3 floats +
  pipExtendedRange int) per the BT411 verified overlay; with linkedSinkIndex
  this closes the whole +3 alignment mystery (ProjectileWeapon pad deleted).
  True bhk1 reads: PPC recharge 5.0s (not 1.0), discharge 0.99s, range 900.
- POWERSUB: ctor resolves voltageSourceIndex -> GeneratorA-D (wire-verified),
  taps via Generator::TapVoltageSource (-1 when full); PoweredSubsystemSimulation
  (@004b0bd0) electrical FSM (Starting/NoVoltage/Shorted/GeneratorOff/Ready);
  GeneratorSimulation partial (start/short-recovery timers).
- Weapons: power step at sim head; Loading recharge gated on electrical Ready
  (authentic @4bbdf5); FireWeapon dumps firing heat. HEAT UNITS: the chain is
  1e7-native with TWO authoring conventions -- energy weapons store small
  (PPC=11, x1e7 from the energy algebra), ballistics store native (SRM6=5.06e7,
  dumped raw; double-scaling it was the bring-up runaway-temperature bug).
- SENSOR: authentic gating (@004b1c4c) -- power step, electrical-Ready gate,
  heat-state switch (Degradation x0.5 / Failure 0). Verified Ready + 100%.

Deferred: coolant depletion/venting, the novice HeatModelOff gate, the charge
model (TrackSeekVoltage/voltage sag/I2R), weapon gate 1 + jam roll, the central
sink's forward-linked drain. Zero Fail across fire + neutral runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 23:55:48 -05:00
CydandClaude Fable 5 d422dfffc0 BT410 Phase 5.3.7: weapon view-fire gating + build header-stamp hardening
Completes the weapon-side half of the look commit:

- MECHWEAP: real rearFiring/viewFireEnable members (binary @0x334/@0x3E0) +
  accessors. Ctor resolves REAR-FIRING authentically (@004b99a8 tail): the
  mount SEGMENT site name is tested for the 'b' (back) marker -- only the back
  gun ports (sitelbgunport/siterbgunport) carry it. Spawn = forward-armed.
- MECH CommitLookState: re-arms every roster weapon per view (forward =
  non-rear, LOOK-BACK = rear-mounted, side/down = none) and flips the HUD
  reticle pip group with the authentic Reticle::Front/RearFiringWeaponsOn flags
  (BT411's raw "bits 1/2" resolved to their 1995 names).
- MECHWEAP: defined MechWeapon::MessageHandlers (0-entry set inheriting the
  Subsystem chain) -- it was declared-but-undefined, and the surviving CODE
  PPC.CPP binds the inherited name into PPC::DefaultData; the zero-filled
  common block was a latent NULL deref (same trap as Emitter::AttributeIndex).

Discovery: the TEST.EGG mech genuinely mounts TWO REAR LASERS (ERMLaser_2/3 on
the b-ports). Verified on a full-clean baseline (engine 181 + bt 42, 0 fail):
look-behind arms exactly the rear lasers, disarms the other five,
pipMask=0xfffffffe; neutral run holds forward-armed; zero Fail.

build410.sh HARDENED against the stale-obj layout-skew trap this wave exposed:
cc() skipped recompiles on obj-vs-.cpp timestamps only, so the MECHWEAP.HPP
member additions left emitter.obj on the OLD MechWeapon layout -- its
chargeLevel=0.0f write landed exactly on the new rearFiring (a silent cross-TU
struct skew, heisenbug-grade). cc() now honors header stamps: a source410
engine-header edit invalidates every bucket, a BT/BT_L4 header edit
additionally invalidates the game buckets. CODE/ is immutable, no stamp needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 22:43:38 -05:00
CydandClaude Fable 5 eb8bba3195 BT410 Phase 5.3.6: look-button state machine -- full eyepoint composition
Reconstructs the binary's five-state LOOK machine (controls mapper tail,
part_013.c:396-459) as proper members/methods:

- MECHMPPR: LookState enum (None/Left/Right/Behind/Down) + lookState/
  previousLookState (out of reserved[24] -> [22]). InterpretControls picks the
  state from the look buttons each frame and on a CHANGE calls
  Mech::CommitLookState. BT_FORCE_LOOK=<1..4> dev hook.
- MECH: authored look angles lookLeft/Right/Front/BackAngle (deg->rad from the
  GameModel resource, guarded) + lookPitch/lookYaw + CommitLookState(int):
  side looks yaw by the authored angle, look-behind = yaw pi + lookBackAngle
  pitch, look-down = lookFrontAngle pitch, forward = identity. The per-frame
  eyepoint compose in Simulate adds the live Torso elevation on top.
  (reservedState [208] -> [202].)
- Deferred inside the commit (needs MechWeapon viewFireEnable/rearFiring):
  per-view weapon fire re-arm + HUD pip group-mask flip.

Verified headlessly: model reads clean authored angles (L=60 R=-60 F=-10 B=0
deg -- ModelResource layout confirmed again); BT_FORCE_LOOK=3 fires ONE commit
([look] state=3 yaw=3.14159 pitch=0) and the per-frame compose holds eyeYaw=pi
with eyePitch=0.349066 (lookBackAngle + the 20deg-clamped elevation). Zero Fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 22:08:50 -05:00
CydandClaude Fable 5 87b1c048cf BT410 Phase 5.3.5: eyepointRotation -- torso elevation pitches the eye/aim-ray, not a joint
Investigated the next planned binding (elevation -> gun joints jointlgun/
jointrgun) before implementing it, and found it was the wrong target: BT411's
own reverse-engineering history records that NO gun/arm elevation joint exists
in the authentic engine. The pod's stick-Y aim pitches the COCKPIT EYE and the
weapon boresight directly (mech4.cpp @~5219, pixel-calibrated against real
screenshots) -- the torso geometry never tilts for elevation on this mech
family. Reconstructing a gun-joint binding would have been invented behavior.

- MECH.HPP: EulerAngles eyepointRotation member (out of reservedState, now
  [208]) + GetEyepointRotation() accessor.
- MECH.CPP: composed each frame in Simulate -- eyepointRotation =
  EulerAngles(Radian(Normalize(lookPitch+elevation)), Radian(Normalize(lookYaw)),
  Radian(0)), reading Torso::CurrentElevation() via sinkSourceSubsystem.
  lookPitch/lookYaw are 0 until the look-button wave (BTCommitLookState) lands.

Verified: BT_FORCE_ELEV=0.8 -> torsoElev and eyePitch both read 0.349066 (the
authentic 20 degree resource limit) every frame, exact match; neutral -> 0.
Zero Fail. Corrected TORSO.NOTES.md's prior (wrong) "next: gun joints" note.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 21:51:28 -05:00
CydandClaude Fable 5 9fff0e969e BT410 Phase 5.3.4: Mech::ResolveJoint + skeleton-joint binding (torso twist)
Reconstructs the shared skeleton-joint resolver and binds the first subsystem
(Torso) to the live skeleton.

- Mech::ResolveJoint(name) (mech.cpp @00424b60): GetSegment(name) -> segment
  joint index -> GetJointSubsystem()->GetJoint(idx).
- Verified the JointedMover base streams the full skeleton headlessly:
  jointCount=19, 40 named segments (gun joints jointlgun/jointrgun, shoulders,
  hip, leg joints jointlthigh..jointrankle). BT_MECH_LOG [skel] summary;
  BT_SKEL_DUMP lists every segment/jointIdx.
- Torso resolves + binds its twist joint (ResolveJoint(torsoHorizontalJoint))
  and pushes currentTwist onto it via Joint::SetRotation (hinge->Radian,
  ball->EulerAngles yaw). The TEST.EGG mech has a fixed torso (horizJoint='',
  enabled=0) so its twist path is inert -- correct + guarded, zero Fail.

Next joint piece: elevation -> gun joints (jointlgun/jointrgun, the fixed-torso
aim mechanism) via weapon-joint binding; then gait leg animation. Both are
VISIBLE only under the renderer; headlessly the joint transforms are loggable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 16:17:37 -05:00
CydandClaude Fable 5 0cc7713865 BT410 Phase 5.3.2e: source authentic per-mech locomotion params from GameModel resource
The Mech ctor now reads walkingTurnRate / runningTurnRate / maxAcceleration /
throttleAdjustment from the GameModel resource (SearchList(GameModelResourceType)
-> ModelResource), replacing the bring-up-default constants for those fields.

Each read is sanity-guarded (out-of-band -> keep default) since BT411 flags parts
of the ModelResource layout as mis-decoded -- but the live values came back clean
and authentic: walkTR=75deg/s, runTR=50deg/s, maxAcc=30 u/s^2, throttleAdj=1.0
(walking turns faster than running; maxAcc matches the madcat note), confirming
our reconstructed struct layout is correct for these fields.

Verified: at walk speed the authentic 75deg/s tightens the turn circle to r~6.9
(=speed/turnRate); zero Fail. Still on defaults (pending LoadLocomotionClips):
reverseStrideLength (top speed) / walkStrideLength / reverseSpeedMax -- measured
from the walk/run animation clips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 15:52:20 -05:00
CydandClaude Fable 5 ebf0d8c23f BT410 Phase 5.3.2: DRIVABLE mech -- authentic control interpretation + locomotion
The mech now drives from the authentic control chain (faithful route). Verified
headlessly: full throttle -> walks straight at top speed (30 u/s) along heading;
throttle+turn -> walks a circle (radius = speed/turnRate); neutral -> holds pose;
zero Fail.

MechControlsMapper::InterpretControls (mechmppr.cpp @004afd10) -- installed as the
mapper's per-frame Performance (roster slot 0, ticks before the mech):
- speedDemand = topSpeed*throttle*fwdScale (reverse inverts); soft stick (square)
  / pedal (cube) response; Basic=stick turn, Std/Vet=pedal turn; speed clamped
  while turning hard. Reads owner stride via Mech accessors.
- BT_FORCE_THROTTLE/BT_FORCE_TURN dev hooks for headless verification.

Mech::Simulate drive -- consumes the mapper demands:
- accelerate currentBodySpeed toward speedDemand (maxBodyAcceleration);
- authTurnRate = lerp(walkingTurnRate, runningTurnRate) by ground speed + over-run
  falloff (mech4.cpp master-perf @0x4aa3d3);
- integrate heading via Quaternion::Add(prevPose, (0,turn*rate*dt,0));
- facing = world -Z basis (GetFromAxis(Z_Axis)); worldLinearVelocity = facing*spd;
- integrate position (increment-1 core).

MECH.HPP: 9 named locomotion members out of reservedState (now [211]) --
walking/runningTurnRate, reverse/walkStrideLength, reverseSpeedMax,
forwardThrottleScale, maxBodyAcceleration, body/currentBodySpeed. BRING-UP
DEFAULTS (authentic values come from the model resource + LoadLocomotionClips --
next refinement).

Deferred: gait-clip-exact advance + leg anim (needs animation subsystem/renderer),
model-resource sourcing, terrain drop, torso/free-look aim, telemetry filters.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 14:46:30 -05:00
CydandClaude Fable 5 3364b65ae8 BT410 Phase 5.3.1: Mech::Simulate motion core -- mech integrates motion per-frame
Installs Mech::Simulate as the mech's per-frame Performance (was DoNothingOnce).
Reconstructs the load-bearing spine of the 1995 Simulate (mech4.cpp @004ab430):
integrate the body velocity into localOrigin (linearPosition.AddScaled(..,
worldLinearVelocity, dt)) and commit the Origin to the world transform with the
engine idiom (localToWorld = localOrigin, per ENTITY.cpp:988 / MOVER.cpp:850).

Uses the NAMED engine base Mover fields (localOrigin/localToWorld/
worldLinearVelocity) -- BT411's MechBaseLayoutCheck proved the WinTesla decomp's
raw this+0x100/0x260 offsets actually stomp those base fields; the clean 1995
build addresses them by name.

- MECH.HPP: Mech Performance typedef + SetPerformance + Simulate() decl.
- MECH.CPP: SetPerformance(&Mech::Simulate) at ctor tail; Simulate body.

Verified headlessly (BT_MECH_LOG "[sim] mech pos=" 1Hz): BT_DRIVE="5,0,10"
advances the mech +5.0/s x, +10.0/s z (y fixed) = exactly the injected world
velocity; no BT_DRIVE -> worldLinearVelocity is 0, mech holds spawn pose. Zero
Fail/Exception either way. BT_DRIVE is a retained dev hook for headless motion.

Deferred (locomotion wave): gait-cycle self-propulsion feeding worldLinearVelocity
(IntegrateMotion->AdvanceBodyAnimation, steered by mapper throttle/turn), heading
integration, terrain-height drop, cockpit telemetry filters.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 13:45:24 -05:00
CydandClaude Fable 5 b8f5928887 Mech ctor PROVEN: constructs 33 subsystems + 7 weapons from real model data
Live trace (BT_MECH_LOG) on the pod TEST.EGG mech: '[mech] segment walk done:
subsystemCount=33 weaponCount=7' -- the segment walk instantiates the ENTIRE real
subsystem roster (31 subsystems + 2 sentinels, 7 weapons) from the actual streamed
model, no crash. The structural reconstruction is proven end-to-end on real data.

The crash is AFTER full construction, in MakeAndLinkViewpointEntity's attribute-
watcher setup (an AttributeWatcher resolving a subsystem attribute via
GetAttributePointer). Phase-5 frontier confirmed = per-subsystem AttributeIndex
tables + watcher wiring. Trace gated behind BT_MECH_LOG.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 08:55:42 -05:00
CydandClaude Fable 5 b93c5d4bdd Mech phase 4: non-NULL default roster slots -- boot reaches the attribute binding
Unrecognised subsystem classIDs now get a base MechSubsystem (Laser/ParticleCannon
-> Emitter) so control/damage bindings that resolve a subsystemID find a real
subsystem, not a NULL plug. This moved the boot PAST the first Link::AddToPlug
NULL-deref; it now runs to Simulation::GetAttributePointer -- the subsystem
ATTRIBUTE system. Each reconstructed subsystem currently reuses the base
Subsystem::AttributeIndex, but the streamed control-mapping / gauge bindings
reference subsystem-specific published attributes (Sensor RadarPercent, Generator
OutputVoltage, Emitter ChargeLevel, ...) that aren't in the base index -> the
attribute lookup walks off the end. Reconstructing each subsystem's AttributeIndex
(+ plug/capability-chain wiring) is the phase-5 integration. BT: 42 ok.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 07:15:00 -05:00
CydandClaude Fable 5 77041a1539 Mech phase 4: SetMappingSubsystem + MechControlsMapper ctor -- mech links as viewpoint
SetMappingSubsystem installs the control mapper into roster slot 0 (the streamed
control-mapping binds DirectMappings to subsystemID 0). MechControlsMapper ctor
constructs (per-frame InterpretControls deferred to phase 5). With RIO controls,
MakeViewpointEntity now builds the MechRIOMapper, installs it, and gets PAST the
controls check -- the mech constructs AND links as the viewpoint entity. Boot now
advances into the mission-startup / control-binding path (next: a real NULL-deref
there, deeper than the staged Fails). BT: 42 ok.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 07:11:41 -05:00
CydandClaude Fable 5 c9aff18191 Mech phase 4: the Mech constructor + segment walk WORKS -- roster instantiates live
The Mech ctor now finds the model's subsystem-model-stream resource
(SearchList by SubsystemModelStreamResourceType), wraps it in a MemoryStream,
and walks the segments -- switching on seg->classID to  into the base Entity's subsystemArray, caching sensor/gyro/sinkSource/hud
and counting weapons.

KEY FINDING: the source410 VDATA ClassID values MATCH the 4.10 binary for the
core subsystems (0xBBD=Condenser, 0xBC3=Sensor, 0xBC5=Torso, 0xBD6=HUD, ...) --
BT411's 'mislabels' were its OWN wrong enum names. So the walk switches on the
real VDATA names cleanly. Unrecognised classIDs leave a NULL slot (roster stays
aligned) rather than aborting.

LIVE: boot now runs the full Mech ctor -- segment walk instantiates the roster,
no crash -- and advances PAST it to BTL4Application::MakeViewpointEntity, which
halts at 'Mech has no controls mapping!' (the slot-0 control mapper /
SetMappingSubsystem is the next brick). The largest function in the game
executes. BT: 42 ok; tree links clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 07:07:39 -05:00
CydandClaude Fable 5 4d175c959a Mech phase 3: named member layout + embedded-member construction
Replaced MECH.HPP reserved[331] with the named Mech-own members: cached subsystem
pointers (sensor/gyro/sinkSource/hud) + messageManager + weaponCount, the 5
capability chains (ChainOf<Subsystem*>), and the embedded status/animation state
(4 AlarmIndicators, Reticle, 3 StateIndicators, 2 SequenceControllers, NameFilter,
telemetryFilter[5]=AverageOf<Scalar>, 3 CStrings) + a reservedState pad for the
phase-5 per-frame fields. The subsystem ROSTER (subsystemArray/subsystemCount)
lives in the base Entity (GetSubsystem/GetSubsystemCount), so the Mech only caches
back-pointers.

The Mech ctor now CONSTRUCTS all embedded members (alarms Initialize'd, reticle
armed, state indicators sized, telemetry filters sized, sequence controllers
Init'd) -- compile-verified -- then halts at the segment walk (the remaining
piece). BT: 42 ok; tree links clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 07:00:51 -05:00
CydandClaude Fable 5 e610a2a3aa 4.10 reconstruction: real spawn factory path -> Mech ctor frontier
BTPlayer::CreatePlayerVehicle reconstructed (faithful; BT411's BT_SPAWN_XZ/
BT_SPAWN_ENEMY bring-up scaffolding dropped): builds the Mech::MakeMessage from
the mission game-model resource and hands it to MakeAndLinkViewpointEntity.
Mech::Make = new Mech(creation_message); a staged Mech ctor chains the real
JointedMover base (so the model skeleton/segments stream from BTL4.RES) then
Fails.

This validates the entire spawn factory chain live: CreatePlayerVehicle ->
MakeAndLinkViewpointEntity -> registry -> Mech::Make -> new Mech -> JointedMover
base ctor (streams the mech model) -> halts at the Mech ctor (mech.cpp:66).

The Mech ctor (@004a1674, 5690 bytes -- the largest function in the game) plus
the subsystem roster is the next MAJOR milestone, not a brick: it needs the full
1995 Mech member layout derived first (MECH.HPP is still reserved[331]; BT411's
decomp uses raw offset pokes that can't compile fresh), the subsystem class
hierarchy (only GAUSS/PPC/SENSOR survive in the 4.10 archive; the rest are the
measured "917 missing functions"), and the segment-table walk. Plan + scope in
MECH.NOTES.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 20:33:15 -05:00
CydandClaude Fable 5 5b35eb973c 4.10 reconstruction: BTL4OPT.EXE links clean and BOOTS to the first staged brick
The reconstructed tree now produces a runnable binary with the authentic
1995 toolchain (BC4.52 / tlink32 / DPMI32):

- BTL4.CPP main TU reconstructed from the 4.11 Ghidra decomp (FUN_0040109c)
  + the 4.10 binary's own string pool + surviving RPL4TOOL.CPP house style;
  probe_main.cpp scaffold retired (BTL4.NOTES.md documents every decoded call)
- L4NET.CPP staged: L4NetworkManager ctor/dtor + 10 vtable-pulled virtuals
  (standalone-benign ones no-op, network ones Fail loudly) + NetNub client
  globals (Net_Common_Ptr=NULL routes L4File to its plain-DOS path)
- build410.sh: libs now built in the AUTHENTIC makefile member order
  (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK). Order is load-bearing:
  tlink emits static-init records in module pull order, and alphabetical
  order booted into a null-vptr crash (IcomManager::ClassDerivations
  constructing before parent NetworkClient::ClassDerivations). Also fixed
  stage_link to the proven 32-bit lib set (SOSDBXC+SOSMBXC, no WATTCPLG)
- BOXTREE.HPP MemoryBlock unify, BTL4GRND notify stubs, remaining engine
  backfills (audio/gauge/resource/stream TUs) that closed the deep ledger

Smoke test (DOSBox-X + 32RTM, copy of the pod BT tree, our exe swapped in):
  BattleTech v4.10
  BTL4Application::BTL4Application
  l4net.cpp(22): L4NetworkManager -- l4net.cpp not yet reconstructed
Static init, main, -egg parse, BTL4.RES load (version 1.0.6 check passes),
ApplicationManager and the BTL4Application ctor chain all execute real
reconstructed code; boot halts at the first staged Fail() as designed.
Next brick: the real l4net.cpp body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:05:53 -05:00
CydandClaude Fable 5 af80d52e22 source410: engine COMPLETE (165/165) - link reaches PE emission; deep ledger cut
The tlink32 campaign after the checkpoint: eleven engine bodies back-dated
from BT412 (rotation player team explode dropzone terrain cultural receiver
subsystm app l4gauge - the Application core included), the WinTesla-ectomy
handled by backdate.py's new unwrap rules (accessor-fn statics -> 1995 static
objects, decl rewrites, pointer->reference Derivation ctor, 2007 windowed-
gauge/console-marshal/idle-pump excisions), staged statics TUs opened for the
game classes (MECH/BTPLAYER/BTDIRECT/PROJTILE/MISSILE/BTL4MPPR .CPP + L4APP/
NETWORK engine statics).

State: every compiled symbol short of the shallow graph RESOLVED (the 52- and
17-symbol ledgers burned to zero); with 32stub.exe in place the linker reaches
full vtable closure and emits the deep ledger (~210 symbols, UNRESOLVED-
LEDGER.txt): remaining engine bodies (objstrm cstr gauge/gaugrend graphics
pixelmap palette resfile ray scnrole explosion-table), the DOS driver extern
layer (_SVGA*/_PCSerial*/_PCSPAK*/joystick/netnub/sosMIDI), the full L4App
body, and the real game-TU frontier (Mech::Make et al.). Recipe proven for
every category.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 11:25:49 -05:00