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>
Reconstructs Torso::TorsoSimulation (installed as the Torso's per-frame
Performance) and wires the torso aim into MechControlsMapper::InterpretControls,
so the control surface now covers aiming as well as locomotion.
- TORSO: analogElevationAxis/analogTwistAxis + SetAnalog* setters,
CurrentElevation()/GetHorizontalEnabled() accessors. TorsoSimulation slews
currentElevation += analogElevationAxis*baseElevationRate*dt clamped to the
vertical limits, and (if horizontalEnabled) currentTwist by the twist axis
clamped to the horizontal limits (authentic torso.cpp core; the skeleton-joint
application is deferred with the render wave).
- InterpretControls: routes stick pitch (stick_y, squared) into the torso
elevation every mode; Std/Vet route stick yaw into the twist. BT_FORCE_ELEV
dev hook.
Verified: BT_FORCE_ELEV=0.8 -> the elevation slews up and clamps at the authentic
verticalLimitTop = 0.349 rad = 20deg; neutral -> 0; zero Fail.
Deferred: skeleton-joint application (render wave), HUD free-aim slew,
look/eyepoint commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
The world now executes. Entity::Execute only PerformAndWatch's entities in
application state RunningMission, reached by two RunMissionMessages
(WaitingForLaunch->LaunchingMission->RunningMission). The 2nd is dispatched by
Player::ManageApplicationStatus when the launch fade expires -- but that only
runs inside PlayerSimulation, not the launch-phase HuntForDropZone. So the
player must switch Performance onto PlayerSimulation after it spawns.
- BTPLAYER.CPP DropZoneReplyMessageHandler: after CreatePlayerVehicle +
InitializePlayerLink, choose the per-vehicle Performance by class -- Mech ->
SetPerformance(PlayerSimulation)+SetScoringPlayerFlag; else CameraShipSimulation.
- BTPLAYER.CPP PlayerSimulation: chains the authentic base Player::PlayerSimulation
(CalcRanking + ManageApplicationStatus + vehicle-pos copy + status service);
console SCORE-delta flush deferred to the scoring wave.
- SENSOR.CPP SensorSimulation: minimal-safe partial (radarPercent = 1 -
GetSubsystemDamageLevel, sensor healthy) so the roster tick path can't Fail
once RunningMission engages. The heat/electrical gating awaits the power/heat
sim wave (PoweredSubsystem/Generator/HeatSink/HeatWatcher *Simulation staged).
Verified: BT_MECH_LOG run reaches "[tick] roster live (first Sensor frame)",
two RunMissionHandler transitions, zero Fail/Exception. The mech is executed
each frame; its BODY Performance is still DoNothingOnce (real Mech::Simulate =
Phase 5.3, now the frontier).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase-5.1 crash solved + two BTPlayer bricks reconstructed. The tree now
builds AND boots end-to-end with no staged Fail() reached, into the running
per-frame game loop.
- EMITTER.CPP: define Emitter::AttributePointers[]/AttributeIndex (ChargeLevel,
chained to Subsystem::AttributeIndex) and point Emitter::DefaultData at it.
EMITTER.HPP declared the index but the .cpp never defined it, so the surviving
PPC.CPP (PPC::DefaultData binds inherited Emitter::AttributeIndex) and
GAUSS.CPP (chains it) captured a NULL activeAttributeIndex -> GetAttributePointer
faulted on the first PPC (roster slot 22). Fix clears all 33 roster slots and
the control-mapping binding block.
- BTPLAYER.CPP InitializePlayerLink: real body -- dispatch PlayerLinkMessage
(our EntityID) to playerVehicle + replicants (mirrors engine
CameraDirector::CreateCameraShip). No staging.
- BTPLAYER.CPP VehicleDeadMessageHandler: non-death flavours (-2 drop-zone probe,
>=0 respawn re-post) delegate to the authentic Player base handler; only the
-1 death cycle stays staged (needs mech4 + scoring roles).
Verified: 516-line smoke run, zero Fail/Exception/abort; boot reaches
LBE4ControlsManager::Execute per-frame, waiting only on absent RIO hardware.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Trace confirms the MechControlsMapper (slot 0) publishes its control attributes
correctly: throttleAttr/controlModeAttr resolve to non-NULL pointers. So the
mapper's AttributeIndex works. The post-construction crash (GetAttributePointer
attr=0x13) is on a DIFFERENT object (EAX heap addr after the mapper) -- a streamed
watcher targeting another simulation, not the mapper. Localizing next. (BT_MECH_LOG
mapper trace retained.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reconstructed the MechControlsMapper attribute table (StickPosition..PilotArray,
IDs 3-0x16 chained from Subsystem::NextAttributeID==2) + the real members
(stickPosition ControlsJoystick, throttle/pedals/speed/turn Scalars, the look/
torso ControlsButtons, control/display/pilotArray ints) + AttributePointers[] +
AttributeIndex (chains Subsystem::AttributeIndex). Fixed the mapper hierarchy
statics in BTL4MPPR.CPP: L4/RIO/Thrustmaster ClassDerivations now chain correctly
(L4 defined first for static-init order) and all use MechControlsMapper::
AttributeIndex so the mapper instance publishes the control attributes the
streamed mappings bind to.
Mech still constructs (33 subsystems). The post-construction crash is UNCHANGED
(GetAttributePointer, attribute=0x13) -> so it's NOT the mapper; a streamed
AttributeWatcher (numeric ID 19) resolves on another object via GetSimulation.
Next diagnostic: which object/subsystemID the watcher targets. BT: 42 ok.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Mech ctor fully constructs (33 subsystems / 7 weapons on real TEST.EGG data,
trace-confirmed). The crash is the control-mapping resource binding in
MakeViewpointEntity resolving subsystem attribute IDs via GetAttributePointer --
the subsystems publish none (reuse base AttributeIndex). Documented the precise
phase-5 step-1 scope (per-subsystem AttributeIndex + the ID chain) in MECH.NOTES.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
Records that the Mech constructor works live (segment walk instantiates the full
roster, mech links as viewpoint, mapper installs) and the precise phase-5
frontier: Simulation::GetAttributePointer via PerformAndWatch, because the
reconstructed subsystems reuse the base AttributeIndex and publish none of their
real attributes. Phase-5 plan (per-subsystem AttributeIndex -> watcher/chain/plug
wiring -> mech2/3/4 per-frame sim -> rendering) in MECH.NOTES.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
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>
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>
Records the Mech-ctor segment-walk factory (mech.cpp:1146-1330) with the full
MISLABELED ClassID->real-class map (VDATA enum names differ from the real
classes). 16 roster classes done; 7 remain for a complete walk (Reservoir,
HeatSink-bank, Searchlight, MechTech, ThermalSight, SubsystemMessageManager,
Actuator). Blueprint in MECHSUB.NOTES.md guides phase 4.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ProjectileWeapon (: MechWeapon) -- ballistic (ammo-fed) base: ammo-bin link,
tracer/eject/jam/lead members. MissileLauncher (: ProjectileWeapon) -- salvo
launcher, using the surviving CODE MISLANCH.HPP (missileCount + per-salvo damage
split). AmmoBin (: HeatWatcher) -- ammo store with cook-off heat. All ctors chain
their parents + init from resource; fire paths staged.
Weapon family now COMPLETE: MechWeapon -> {Emitter -> PPC, GaussRifle;
ProjectileWeapon -> MissileLauncher} + AmmoBin. The surviving PPC.CPP/GAUSS.CPP
link against the reconstructed Emitter base. BT: 36 ok.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Emitter : MechWeapon -- energy-weapon (beam) base. Both surviving weapon leaves
(PPC.CPP, GAUSS.CPP/GaussRifle) derive from it and now compile against the real
base. Ctor chains MechWeapon + inits chargeLevel/dischargeTime; statics/dtor/test
real; FireWeapon (beam discharge) + CreateStreamedSubsystem staged. BT: 33 ok.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MechWeapon : PoweredSubsystem -- base of all weapons. Ctor chains PoweredSubsystem
+ copies resource (recharge/range/damage/heatCost) into members + damageData.
FireWeapon is the virtual abstract stub (Fail 'should not be here'; PPC/Gauss/
MissileLauncher override it); SendDamage + CreateStreamedSubsystem staged.
BT: 32 ok.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Eye/body stabilisation subsystem. Full resource struct + tuning members
(springs/damping/noise/percentages/damage multipliers) reconstructed; the
eye/body dynamics accumulators held in a reserved pad until the per-frame
GyroscopeSimulation is reconstructed (phase 5). Ctor chains PowerWatcher + copies
tuning; statics/dtor/test/reset real; sim staged. BT: 28 ok.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Base of the Torso/HUD/Gyroscope cockpit subsystems. Ctor chains HeatWatcher +
watchdogAlarm(5) + minVoltage; statics/dtor/test/reset real; Simulation staged.
BT: 27 ok.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Records the full mech-subsystem hierarchy discovered while reconstructing the
roster, with per-class build status. 6 classes done + verified (MechSubsystem,
HeatableSubsystem, HeatSink, PoweredSubsystem, Sensor, Generator); the tree shows
the remaining intermediates (HeatWatcher : MechSubsystem, PowerWatcher :
HeatWatcher) that unblock the Torso/HUD/Gyroscope branch (the Mech's directly-
referenced subsystems), plus Myomers/Condenser leaves and the separate weapon
subtree. The reconstruction pattern is now a proven template (documented). Enables
efficient continuation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generator : public HeatSink (classID 0xBC3) -- the voltage SOURCE that
PoweredSubsystems tap (currentTapCount = attached loads). Reconstructed from the
BT411 decomp + the surviving GNRATOR.TCP partial: ctor chains HeatSink, seeds
ratedVoltage/outputVoltage/maxTapCount/startTime/shortRecoveryTime + stateAlarm(5)
= AlarmIndicator, derives generatorNumber from the segment-name suffix. Statics,
dtor, TestClass/TestInstance/ResetToInitialState real (ResetToInitialState mirrors
the .TCP); GeneratorSimulation (per-frame voltage/short) staged. Master-instance
SetPerformance install deferred (per-frame sim staged anyway).
Power system pair now in place: Generator (source) + PoweredSubsystem (load).
Roster classes so far: MechSubsystem, HeatableSubsystem, HeatSink,
PoweredSubsystem, Sensor, Generator. BT: 27 ok; tree links clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sensor : public PoweredSubsystem -- the radar/targeting subsystem, using the
SURVIVING 4.10 interface (CODE/BT/BT/SENSOR.HPP) with a reconstructed SENSOR.CPP
body (from BT411 decomp). Ctor chains PoweredSubsystem, inits radarPercent/
selfTest/badVoltage, and installs the per-frame performance unless the owner is a
replicant (owner->GetInstance() != ReplicantInstance -- the clean form of the
binary's (flags & 0xC) != 4). Statics, dtor, TestClass/TestInstance,
ResetToInitialState, TakeDamage, DeathReset real; SensorSimulation (per-frame
radar) + CreateStreamedSubsystem staged.
Completes the first full vertical slice of the subsystem roster, all
compile-verified: MechSubsystem -> HeatableSubsystem -> HeatSink ->
PoweredSubsystem -> Sensor. The hierarchy backbone is proven; remaining leaves
(Generator, Gyro, Torso, HUD, Myomers, weapons) follow the same pattern.
BT: 27 ok; tree links clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes the staged POWERSUB.HPP base (HeatableSubsystem -> HeatSink, the real
hierarchy) and reconstructs PoweredSubsystem: a HeatSink that draws electrical
power. Added members (voltageSource = SubsystemConnection, electricalStateAlarm =
AlarmIndicator(5), modeAlarm = AlarmIndicator(3), input/output/ratedVoltage) and
corrected the resource struct (voltageSourceIndex + thermalResistivityCoefficient
+ startTime). Ctor chains HeatSink and primes the electrical state; statics, dtor,
ResetToInitialState, TestClass/TestInstance real.
The voltage-source resolution (indexing the owner mech's subsystem ROSTER for the
powering generator) + master-instance electrical sim + AttachToVoltageSource are
deferred to the segment-walk phase (phase 4) where the roster is populated -- the
subsystem constructs with no attached source until then. Verified slice now:
MechSubsystem -> HeatableSubsystem -> HeatSink -> PoweredSubsystem. Compile-verified
(BT: 26 ok); tree links clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HeatSink : public HeatableSubsystem (confirmed hierarchy) -- a thermal mass with
a coolant loop. Added to HEAT.HPP/.CPP: the class + its SubsystemConnection slot
helper + HeatSink__SubsystemResource. Ctor chains HeatableSubsystem and seeds the
thermal state from the resource (startingTemperature/degradation/failure/
thermalConductance/thermalMass), heatAlarm(3) = AlarmIndicator, heatFilter =
AverageOf<Scalar>(15). Statics, dtor, ResetToInitialState, TestClass/TestInstance
real; the per-frame thermal sim (HeatSinkSimulation/DrawCoolant) staged.
Also reconciled HeatableSubsystem to the 4.10 fields: its resource struct now
carries startingTemperature/degradationTemperature/failureTemperature/
thermalConductance/thermalMass (was the BT411-mislabeled thermalMass/degrade/fail/
coolingLoop set), and degradationTemperature/failureTemperature are base members
(HeatSink reads them). Verified slice now: MechSubsystem -> HeatableSubsystem ->
HeatSink. Compile-verified (BT: 25 ok); tree links clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HeatableSubsystem (HEAT.CPP) reconstructed + compile-verified (BT: 25 ok):
statics, ctor (chains MechSubsystem resource form + ResetToInitialState ->
currentTemperature=300, heatLoad=0), dtor, TestClass/TestInstance,
CreateStreamedSubsystem staged. Verified slice now: Subsystem -> MechSubsystem
-> HeatableSubsystem.
Also mapped the roster hierarchy from BT411, which is DEEPER than the staged
headers (recorded in MECHSUB.NOTES.md):
MechSubsystem -> HeatableSubsystem -> HeatSink -> PoweredSubsystem -> {Sensor,
Generator, ...}
Findings for the next steps: (1) HeatSink is MISSING entirely from the staged
tree and must be added between HeatableSubsystem and PoweredSubsystem;
(2) staged POWERSUB.HPP wrongly derives PoweredSubsystem from HeatableSubsystem
(real base = HeatSink) -- fix it; (3) PoweredSubsystem has inter-subsystem wiring
(resolves its voltage-source generator from the owner mech's subsystem roster),
imposing a segment-walk ordering constraint for the phase-4 ctor.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The base all ~30 mech subsystems derive from. Reconstructed against the 4.10
structure per the MECHSUB.NOTES analysis (NOT backdated from BT411's divergent
version):
- Header: expanded with the real mech-specific member set (statusAlarm =
AlarmIndicator, vitalSubsystem, alarmModel, criticalReference,
collisionCriticalHitWeight, printSimulationState, configureActivePress,
resource). Dropped the speculative MessageHandlers static -- MechSubsystem
reuses the base Subsystem sets (inherited Simulation handlers/attrs/statecount).
- CPP: statics (ClassDerivations/DefaultData), both ctors (light name+classID and
resource), dtor, TestClass/TestInstance, and the damage API on the 4.10
per-type model -- GetSubsystemDamageLevel/SetSubsystemDamageLevel read/write the
real DamageZone::damageLevel [0,1]; ForceCriticalFailure; TakeDamage delegates
to the zone. Both ctors build the damage zone the base leaves NULL.
Deferred (documented): the Mech__DamageZone per-type armour STREAM wiring (ctors
use a trivial armour-free base DamageZone placeholder for now) and
CreateStreamedSubsystem (model-load stream format). These are refinements above
the ctor frontier, not boot blockers.
Compile-verified (BT: 24 ok); full tree still links clean. Next: the subsystem
roster (GAUSS/PPC/SENSOR source + .TCP partials + decomp).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Begins phase 2 (MechSubsystem base + subsystem roster) with the base-class
analysis that keeps the reconstruction on the 4.10 damage model. Key findings:
- All base deps survive: Subsystem (SUBSYSTM.HPP + staged SUBSYSTM.CPP),
DamageZone (DAMAGE), Mech__DamageZone + BT damage model (MECHDMG.HPP),
AlarmIndicator (just built).
- Finding 1: the staged base Subsystem ctor sets damageZone=NULL, so the derived
MechSubsystem creates the Mech__DamageZone (BT411's zone-creation is right).
- Finding 2 (CRITICAL): the damage model DIVERGED. 4.10 is per-damage-TYPE --
DamageZone has defaultArmorPoints + damageScale[5] {collision/ballistic/
explosive/laser/energy} and STREAMS its own armour (DAMAGE.CPP:335,413).
BT411 reconstructed a per-FACING armorByFacing[5]/structureReference model that
MechSubsystem hand-seeds -- those fields exist only in BT411's ReconDamageZone
proxy, NOT in the 4.10 zone. So BT411's MechSubsystem ctor CANNOT be backdated
verbatim; doing so would install a damage model the 4.10 engine doesn't
implement, corrupting every subsystem.
Corrected approach (now fully scoped, ready to write): chain base Subsystem,
create Mech__DamageZone, add mech-specific members + TakeDamage override, let the
zone stream per-type armour. Full detail in MECHSUB.NOTES.md; the staged
MechSubsystem__SubsystemResource (per-facing, BT411-copied) is flagged for
re-derivation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NameFilter is the Mech's mechNameFilter (@0x36c), a small fixed debounce record
the ctor initialises. Reconstructed from FUN_00435a7c: a 10-word (0x28) struct,
Initialize() sets [2]=1 / [8]=[9]=-1 / rest 0 exactly. Header-only. Field
semantics unresolved (only caller is Initialize; reader is the unbuilt HUD) --
names best-effort, but size + init values are binary-exact, which is all the
Mech layout + ctor need.
All 3 missing embedded helper classes now reconstructed + compile-verified under
BC4.52 (AlarmIndicator, SequenceController struct+Init, NameFilter). MECH-LAYOUT.md
step 1 marked done. Next: MechSubsystem base + the subsystem roster, then finalize
MECH.HPP (probe sizeof==0x854), then the ctor + segment-table walk.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The BT keyframe-animation player embedded in the Mech as legAnimation/
bodyAnimation. Struct field layout (from BT411's binary-offset map), default
ctor, dtor, and Init(Mech*) reconstructed and compile-verified; Init is
ctor-time (Mech ctor calls legAnimation.Init(this)/bodyAnimation.Init(this)) so
it's real (binds owner + caches owner->GetJointSubsystem()). The per-frame gait
engine (SelectSequence/Advance/Reset) is staged with Fail bodies -- it fires
only once the mech is ticking, past the current ctor frontier.
BT stage 23 ok; full tree still links clean. Evidence + real/staged split in
SEQCTL.NOTES.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
First of the 3 missing Mech embedded-helper classes. AlarmIndicator is the
multi-level status indicator the Mech carries four of (master/heat/stability/
status). Reconstructed as a StateIndicator subclass: the shipped ctor
(@0041b9ec) is byte-for-byte the surviving StateIndicator(unsigned) ctor
(stateCount=oldState=currentState=count; 3 watcher sockets NULL) with a distinct
vtable, so a derived class reproduces it exactly and adds the level API
(SetLevel/GetLevel/GetLevelCount -> SetState/GetState/stateCount). Header-only
(StateIndicator's methods are in SIMULATE.CPP, already in munga.lib).
Compile-verified standalone under BC4.52 with the authentic build flags.
Evidence + placement in ALARM.NOTES.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Full-archive re-check: AverageOf DOES survive (AVERAGE.HPP, the SIGNATURED
lineage BT411 preserved), so telemetryFilter[5]'s type is available. The
genuinely-missing embedded helpers are just AlarmIndicator, SequenceController,
and NameFilter (confirmed absent from all of CODE; no alarm/filter/sequence
headers) -- to be reconstructed from BT411 decomp before the Mech layout finalizes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Begins the Mech reconstruction milestone (analysis phase). Extends the existing
MECH-LAYOUT.md worksheet with the findings needed to build MECH.HPP + the ctor:
- Resolved the BT411 mechrecon.hpp proxy layer to real 1995 types (ReconAlarm ->
AlarmIndicator, ReconSeq -> SequenceController, ReconFiltered -> AverageOf<
Scalar>/NameFilter, ReconChain -> ChainOf, ReconMatrix -> AffineMatrix;
StateIndicator/Reticle survive as-is; BTVal mostly base-class pose fields).
- CRITICAL: AlarmIndicator, SequenceController, NameFilter, AverageOf are ALSO
absent from the 4.10 archive -- additional helper classes the milestone must
reconstruct first (their sizes set the embedded-member offsets).
- Subsystem source availability mapped: full (GAUSS/PPC/SENSOR), .TCP partials
(AMMOBIN/EMITTER/GNRATOR/HEAT/MISSILE/PROJTILE/PROJWEAP), decomp-only (rest).
- Key tractability insight: StateIndicator is fixed-size (level count stored, not
arrayed), so a FUNCTIONAL fresh build needs only the right member set/types in
order -- byte-exact offset matching is a later refinement for network wire
format, not required to boot.
- Revised reconstruction order: helpers -> MechSubsystem+roster -> finalize
MECH.HPP (probe sizeof==0x854) -> ctor+segment walk -> per-frame path.
Everything below the Mech ctor runs real reconstructed code; the ctor is the
live frontier (spawn factory validated last commit).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
Fixes the incorrect DefaultData reuse of Player::MessageHandlers -- BTPlayer now
has its own handler table (DropZoneReply, VehicleDead, Score, ScoreInflicted,
ScoreUpdate; the last two add BT message IDs) chained onto the base set, matching
the .data table recovered in BT411. A mission-start DropZoneReply now routes to
BTPlayer::DropZoneReplyMessageHandler (the real spawn/respawn dispatch skeleton)
instead of the base "should not be handled by base player class" Fail stub.
Boot ladder now runs the full engine + app + network + mission + player path and
reaches the spawn handshake, halting at CreatePlayerVehicle -> Mech::Make -- the
Mech subsystem frontier (Mech ctor + mech2/3/4 + subsystems + weapons), the next
major reconstruction milestone. Scoring/death handlers, PlayerSimulation, and the
mech-placement tail staged with documented Fail bodies (BTPLAYER.NOTES.md).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Boot ladder advances past player creation. BTPlayer ctor/dtor/Make/
TestInstance/GetExperienceLevel reconstructed from BT411's Ghidra-recovered
body (@004c0bc8) backdated to 1995 idiom; the reserved[38] placeholder in
BTPLAYER.HPP replaced with the real BT-own members.
Key fidelity call: the game-mode flags are derived from
btMission->ExperienceLevel() (the egg's per-pilot experience key) with the
binary-accurate switch rows from the [T1] disassembly -- NOT from the scenario
role's returnFromDeath, which BT411's port uses as a [T3] stand-in. Mapping and
residual naming/[T4] uncertainty documented in BTPLAYER.NOTES.md.
Live boot now runs: banner -> resources -> app ctor -> network single-user ->
egg -> mission -> SetPlayerData -> BTRegistry::MakePlayer -> BTPlayer ctor
(resolves team, seeds experience flags) -> halts at the base
Player::DropZoneReplyMessageHandler stub (BTPlayer's own message-handler table
is the next brick -- DefaultData still reuses Player::MessageHandlers).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
All 10 surviving original TUs plus the reconstructed BTL4APP.CPP pilot build
clean with the authentic OPT.MAK flags (compile410.sh --sweep). First time
the 4.10 BattleTech source has compiled since 1996.
- layout_probe.cpp: the period compiler measures 1995 layouts from the
surviving headers; validated 3/3 against binary alloc sizes (BTMission
0xFC, BTL4ModeManager 0xC, BTRegistry 0x10). Base boundary: Simulation
0xD0 / Entity 0x1C4 / Mover 0x300 / JointedMover 0x328 => Mech-own region
0x328-0x854 (MECH-LAYOUT.md staging worksheet).
- 13 staged headers close the family ([T3] reserved[]-parked layouts;
interfaces PROVEN by the surviving consumers): MECH, MECHSUB, HEAT,
POWERSUB, MECHWEAP, EMITTER, MECHMPPR, BTPLAYER (BTPlayer__MakeMessage =
Player's 8 args + roleName/teamName [T1 via BTREG]), PROJTILE, MISSILE,
BTL4MPPR, BTL4VID + the round-2 BTCNSL/BTSCNRL.
- compile410.sh: PCH gate retired (bt.hpp/mungal4.hpp full include sets),
DPL SDK roots on the include line.
- BTL4APP.CPP: appmgr include + GetApplicationManager()->GetFrameRate() +
ResourceDescription:: scoping; Fail() held at its recorded line 400.
- Evidence ledgers: STAGED-HEADERS.NOTES.md, MECH-LAYOUT.md, BACKFILLS,
BTCNSL (binary-recovered console wire IDs), BTSCNRL.
Remaining for a linkable BTL4OPT: the ~40 missing TU bodies (917-function
manifest) - the header skeleton they grow into now exists and compiles.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>