BallisticWeaponCluster's two round counters pointed at UnboundIntegerSource
because ProjectileWeapon::ammoBinLink is protected -- the documented inert
gap in the ctor ledger. ProjectileWeapon now exposes GetAmmoCount() (the
resolved bin's rounds, -1 with no bin) and the cluster copies it into a live
cell each Execute, the same pattern it already uses for jammed and
reloadSeconds. The binary pointed its NumericDisplayInteger straight at the
resolved bin's count.
The STREAK 6 panel now reads 0024 against the shipped binary's 0024, in the
same font, stencilled into the fire-ready disc the same way.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MissileLauncher::DefaultData passed Subsystem::MessageHandlers and
Subsystem::AttributeIndex where every sibling weapon passes MechWeapon's --
and a launcher publishes no tables of its own, so it must chain MechWeapon's
exactly as ProjectileWeapon (its own base) does. Wired to Subsystem's, EVERY
weapon attribute on a missile launcher resolved to nothing and the gauge read
the unbound zero cell: PercentDone, TriggerState, WeaponState,
DistanceToTarget, RearFiring.
The cockpit is what found it. The shipped binary lights a fire-ready disc on
the STREAK 6 panel (WeaponCluster gates it on PercentDone >= 0.99) and ours
never did -- while the launcher itself reported state=Loaded recoil=0 level=1
bin=24. A healthy weapon behind a dead binding.
head missing before -> after extra
Mfd1 8807 -> 4991 4063 -> 4003
Mfd3 6935 -> 3174 2659 -> 2608
Mfd2 6882 -> 6870 (unchanged -- it hosts no missile panel)
~7.6K missing pixels recovered. The disc, its rays and the stencilled ammo
cells now draw; the digits themselves stay blank pending the ammo feed, which
is the documented inert gap in the BallisticWeaponCluster ledger.
Traces added, all env-gated on BT_VIS_LOG and kept as tooling: [warn]
(cluster percentDone/warn state) and [proj-state] (launcher state, recoil,
recharge rate, bin count) -- the pair that separated "broken weapon" from
"broken binding" in one run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Scoring roles bound (binary ctor tail @004c0bc8): the mission role dict ->
Player::scenarioRole; TEST.EGG's Role::Default = the baked dfltrole
(lives=1000, killBonus=500) -- authored data flowing. The three score
handlers are live per the decomp derivations (@004c02e4 / @004c0200 /
@004c02a8 + CalcInflictedScore @004c052c; tonnage/bias staged); the
producers post damage scores per delivered hit and the kill credit from
the death transition with the latched killing-blow magnitude. First live
kill: award=3.43, kills=1, score=123.6.
Out of lives -> the mission END: the binary's +10s review post sits in the
one decomp gap, so the staged stand-in enters the engine's own cascade
(StopMissionMessage +10s) -- EndingMission -> the 3s fade -> the second
Stop -> Application::Stop -> RunMissions exits. The BTL4/L4 stop layers
run authentically (plasma score display off, egress lamps).
VERIFIED END-TO-END: a 2-lives egg (role-page return=2 override) -- death
#1 debits and respawns healed; death #2 is OUT OF LIVES; +10s later the
mission ends and BTL4OPT.EXE exits CLEANLY to DOS (GAME-RC prints). The
full 1995 pod mission loop -- egg, boot, spawn, fight, score, die,
respawn, die, mission end, exit -- now runs from reconstructed source.
Zero faults; fight/smoke/novice regressions green. Dev knob:
BT_PLAYER_PASSIVE=1 (piloted mechs hold force-fire).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The full circuit, workflow-researched (5 parallel dossiers over BT411 + the
engine) and adversarially reviewed (3 lenses) before landing:
Mech side: the once-per-death transition in Simulate (freeze, motion kill,
DeathShutdown sweep, MASTER-only VehicleDead(-1) to the player link);
Mech::Reset @0049fb74 (reposition + heal every hull zone + the roster
DeathReset sweep + PreRun -- the reset-based respawn that REUSES the entity);
dead-owner terms in both weapon hard gates (wrecks fall silent).
Player side: the VehicleDead(-1) branch (deathPending dedup, deathCount
bump+stamp, scenario-role life debit, +5s re-post -> the engine drop-zone
hunt) and the DropZoneReply respawn branch (reset the dead mech at the
replied drop zone; probes on a live mech are moot).
Subsystem side: the engine base virtual DeathReset implemented across the
family -- MechSubsystem (zone heal + DestroyedState clear), MechWeapon (full
powered/thermal restore + fresh Loading cycle), AmmoBin (restock from the
ctor-cached count), HeatSink/HeatWatcher/PowerWatcher/Generator/Sensor/
MissileLauncher.
Review catches fixed before commit: AmmoBin restocked through the FREED
padBuffer pointer (use-after-free -> initialAmmoCount; MechSubsystem::
resource is now documented as never-deref-post-ctor); died-hot weapons
respawned at FailureHeat (now full thermal re-init); Generator tap counts
desynced across reset (preserved); Sensor skipped the base heal; PowerWatcher
inherited a statically-bound reset; cooling toggle + connect mode restored.
Verified: kill -> wreck (0 shots while dead) -> +5s -> drop-zone hunt ->
HEALED + placed at a real drop zone -> 134 shots after respawn incl. 12 SRM
(restock proof); unowned enemy wreck settles silently; fight/smoke/novice
regressions green, zero faults.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The simulation is now a FIGHT. Mech target slot (+0x388), authentic
Loaded->Firing gate (viewFireEnable && HasActiveTarget), UpdateTargeting
range refresh, and SendDamage via the engine TakeDamageMessage.
MECHDMG.CPP is BORN against the AUTHENTIC surviving CODE/BT/BT/MECHDMG.HPP:
the Mech ctor's Pass-3 hull zone fill constructs Mech__DamageZone per zone
(the Entity base only allocates the raw pointer array -- unfilled slots were
crash #1; a base-class fill parses each record short and skews the stream --
crash #2). Streamed ctor parses the full BT tail (flags / Scalar-weighted
criticals with the Master+Dynamic plug gate / LOD redirect table) and
normalizes the armor economy: scale[type]=1/(raw x armorPoints), legs
halved -- BT411-verified @0049ce50.
Live two-mech verification (BT_SPAWN_ENEMY harness in DropZoneReply):
20 named hull zones stream on both mechs; PPC lands 11.77/hit (12 x
chargeRatio^2, type 4), ER-M laser 3.43 (type 3), SRM6 salvos 5.83 x 6
rounds on independent zones (type 2, one message per missile -- burstCount
is NOT in the zone formula); repeat hits climb linearly, leg zones absorb
at half scale, zones reach 1.0 Burning/Destroyed. No-target and novice
regressions hold (weapons load but never fire without a target).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
The heat economy now bites back, verified under sustained fire:
- Ballistic gate 1 (@4bbd36): destroyed-state or own-sink FailureHeat pins
full recoil + the unavailable alarm (the NoAmmo roach-motel re-asserts).
- CheckForJam (@4bbfcc): p = 0.41*T/failT clamped [minJamChance, 1.0], rolled
per granted shot against the MUNGA uniform Random. Interim heat-degraded
gate stands in for the deferred LiveFireEnabled novice switch (the exact
spurious-cold-jam trap the BT411 port documented). VERIFIED: SRM6s jam at
T~1200-1320 after riding past the authored 1000-degree threshold, and stay
jammed (mission-reset recovery only) -- authentic.
- Emitter hard gate (@4baab9): FailureHeat drops the beam state + charge each
frame; SELF-RECOVERING once conduction cools the sink below failure.
VERIFIED: the PPC settles into an emergent thermal duty cycle -- fire at
~1930K, spike to 2562K, shutdown, cool, refire -- firing exactly as fast as
its sink sheds heat; the lasers oscillate around ~2200K.
Zero Fail. Deferred: LiveFireEnabled/HeatModelOff experience gates,
mech-disabled gate halves, coolant depletion, jam recovery via mission reset.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
The SRM6 MissileLaunchers now run the authentic ballistic fire cycle against
their linked AmmoBins, wire-verified end to end.
- PROJWEAP ProjectileWeaponSimulation (PARTIAL, binary @004bbd04 -- fully
recovered in the BT411 RE): one trigger-edge sample; the dry-bin gate pins
NoAmmo(7) every frame; Loaded(2) -- the AMMO PULL LIVES IN THE CALLER (a
denied shot does the 4->2 denial blip with NO ammo pulled -- early-returning
gates from FireWeapon while the caller cycles the alarm is the 1995 "denied
shot fakes a full firing cycle" defect class); granted -> Firing ->
FireWeapon -> Loading (or NoAmmo on the emptying pull), recoil=rechargeRate;
Loading bleeds recoil -> Loaded when a round is chambered, dial animates;
Jammed(5) held; NoAmmo(7) = the roach-motel (re-asserts unconditionally).
Deferred: electrical step, gate 1, eject, jam roll, HasActiveTarget.
- AMMOBIN: FeedAmmo() + GetAmmoState() (1 round-ready / 2 EMPTY).
- ammoBinLink wired from the resource's ammoBinIndex (the bin's roster slot).
- WIRE-VERIFIED RESOURCE ALIGNMENT: a raw-stream dump pinned the
ProjectileWeapon field block +3 ints past our staged struct (the MechWeapon
resource ancestry runs 3 ints short -- the pip-family fields). Fixed with
resourceAlignPad[3]; phantom muzzleVelocity/missileCount tail dropped.
Confirmed on-wire: ammoBinIndex=27/29 (the exact bin slots), tracerInterval=1,
minTOF=0.5, minVolt%=0.3, minJam=0.05, missileCount=6 (an SRM6!).
- MECHWEAP: weapon-state enum extended to the full 1995 set (DryTrigger 1,
Jammed 5, TriggerDuringJam 6, NoAmmo 7; count 8).
- MISLANCH FireWeapon PARTIAL (@004bcc60: heat + salvo spawn only -- spawn
needs the entity/targeting waves).
VERIFIED headlessly (BT_FORCE_FIRE): bins resolve with the authored 24 rounds;
SRM6s fire 6-missile salvos at the authored 1s cadence, rounds 24->0; after
the 24th salvo the launcher goes DRY and stays silent across ~3,000 subsequent
fire events while the energy weapons keep cycling. Zero Fail.
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>