Files
TeslaRel410/restoration/source410/BT/MECHWEAP.NOTES.md
T
CydandClaude Fable 5 896bbbed4d BT410 Phase 5.3.8: weapon fire path -- authentic attribute table + fire state machine
The energy weapons now run a live fire cycle, and the REAL trigger wiring is in
place: the 1995 MechWeapon attribute table (binary @0x511890) is published with
PINNED IDs, so the streamed per-mech fire-button mappings bind TriggerState
(0x13) -> fireImpulse and the controls push writes the trigger into the weapon.

- MECHWEAP: attribute enum + table (PercentDone 0x12, TriggerState 0x13,
  DistanceToTarget 0x14, TargetWithinRange 0x15, WeaponRange 0x16,
  EstimatedReadyTime 0x1A, RearFiring 0x1B, WeaponState 0x1C). Pads bridge the
  chain gap 2..0x11 -- LOAD-BEARING: AttributeIndexSet::Build leaves uncovered
  gap slots as uninitialized garbage, so every ID up to the max must be covered
  (they shrink to the authentic 0x0F..0x11 when the parent attribute waves land;
  SENSOR.HPP pins PoweredSubsystem::NextAttributeID at 0x0F).
- MECHWEAP: fire-machine members (fireImpulse/previousFireImpulse,
  rechargeLevel, rangeToTarget, effectiveRange, estimatedReadyTime, recoil,
  weaponAlarm 0/2/3/4); CheckFireEdge (@004b9608, BIT-PATTERN int compare --
  TriggerState carries raw ControlsButton ints whose release value is a float
  NaN; IEEE compare would latch the detector shut); ComputeOutputVoltage
  (@004b9c9c recharge dial).
- EMITTER: EmitterSimulation (PARTIAL @004baa88) -- Firing/Loaded/Loading FSM
  on the weapon alarm, viewFireEnable gate at Loaded->Firing, recoil-decay
  recharge over the authored RechargeRate seconds; FireWeapon (PARTIAL
  @004bace8) discharge bookkeeping; ChargeLevel re-pinned to the authentic
  0x1D; index re-chained to MechWeapon's. Deferred: electrical charge model
  (TrackSeekVoltage), heat dump, HasActiveTarget gate, beam/damage submission.
- BT_FORCE_FIRE dev hook: trigger pulse whenever Loaded (auto-fire cadence).

VERIFIED headlessly: forward view -- PPC_1/2 + ERMLaser_1 cycle FIRED->LOADED
at the authored 0.6s/1s cadence, rear lasers silent; BT_FORCE_LOOK=3 -- ONLY
the rear lasers (ERMLaser_2/3) fire. The view-fire x fire-FSM interlock holds
both directions. Zero Fail. (SRM6 ballistic FSM = a later increment.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 23:01:57 -05:00

87 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MECHWEAP.CPP / .HPP — reconstruction notes
`MechWeapon` (: PoweredSubsystem) is the weapon base: PPC/GaussRifle bind it via
Emitter, the SRMs via ProjectileWeapon/MissileLauncher. The resource streams
rechargeRate / weaponRange / damage / heatCostToFire (+ pip fields).
## Reconstructed
- Statics (ClassDerivations, DefaultData on Subsystem::MessageHandlers/
AttributeIndex), ctor streaming the tuning fields, damageData prime.
- **View-fire gating (2026-07-21, the look-commit wave):** real `rearFiring` /
`viewFireEnable` members (1995 binary @0x334/@0x3E0) + `IsRearFiring()` /
`GetViewFireEnable()` / `SetViewFireEnable()`. The ctor resolves REAR-FIRING
authentically (binary ctor tail @004b99a8): the mount SEGMENT site name
(`owner->GetSegment(GetSegmentIndex())`) is tested for the 'b' (back) marker —
only the back gun ports (`sitelbgunport`/`siterbgunport`) carry it. Spawn
state = armed for the forward view. `Mech::CommitLookState` re-arms on every
view change (see MECH.NOTES.md increment 7). Verified: the TEST.EGG mech's
two rear lasers (ERMLaser_2/3) arm only in LOOK-BACK.
## Fire path (2026-07-21, Phase 5.3.8)
- **The authentic attribute table IS published** (binary @0x511890, IDs pinned):
PercentDone 0x12 → rechargeLevel, **TriggerState 0x13 → fireImpulse** (the
streamed per-mech fire-button mappings bind this ID — the real trigger
wiring), DistanceToTarget 0x14, TargetWithinRange 0x15, WeaponRange 0x16 →
effectiveRange, EstimatedReadyTime 0x1A, RearFiring 0x1B, WeaponState 0x1C →
weaponAlarm. Pads bridge our chain gap 2..0x11 (parents publish nothing yet;
they shrink to the authentic 0x0F..0x11 when the mechsub/heat/powersub
attribute waves land — SENSOR.HPP pins PoweredSubsystem::NextAttributeID at
0x0F). **Pads are LOAD-BEARING**: AttributeIndexSet::Build leaves uncovered
gap slots as UNINITIALIZED GARBAGE (`new IndexEntry[entryCount]`, only
inherited + listed entries written), so every ID up to the max must be
covered or Find() on a gap ID returns a wild pointer. Pip* (0x17-0x19) are
pads → rechargeLevel until the pip members are reconstructed.
- **Fire state machine members**: fireImpulse/previousFireImpulse (the trigger
sample pair), rechargeLevel, rangeToTarget, effectiveRange,
estimatedReadyTime, recoil, weaponAlarm (the state carrier: 0 Firing /
2 Loaded / 3 Loading / 4 trigger-during-load). Spawn = charged + Loaded.
- **CheckFireEdge** (@004b9608): rising-edge on fireImpulse comparing BIT
PATTERNS as signed ints — TriggerState carries raw ControlsButton ints
(+(button+1) press / (button+1) release); the release bit-pattern is a
negative NaN as float, and an IEEE float compare would latch the detector
shut after the first release (BT411 task #8). Int compare reproduces the
binary's x87 semantics exactly.
- **ComputeOutputVoltage** (@004b9c9c): `rechargeLevel = (rechargeRate
recoil) / rechargeRate` — the recharge dial.
- **Emitter::EmitterSimulation** (PARTIAL, @004baa88) installed on every
non-replicant energy weapon: Firing → discharge countdown →
ResetFiringState(Loading); Loaded + trigger edge → viewFireEnable gate →
FireWeapon; Loading → recoil decays over the authored RechargeRate seconds →
Loaded. Deferred within it: the leading PoweredSubsystemSimulation electrical
step, the destroyed/heat-failure/dead-mech hard gates, the TrackSeekVoltage
generator charge integration (the partial uses the authored seconds
directly), and the HasActiveTarget gate (targeting wave).
- **Emitter::FireWeapon** (PARTIAL, @004bace8): discharge bookkeeping (beam
countdown re-arm, charge spent, recoil loaded). Deferred: the 0.5·V²·EC
energy/damage/heat closed forms (need the electrical model), the heat dump
(heat wave), the beam build + Damage submission (targeting + renderer).
- Emitter's index re-chained to MechWeapon's (ChargeLevel at the authentic
0x1D past the table end); Emitter::DefaultData now binds
MechWeapon::MessageHandlers.
- DEV hook `BT_FORCE_FIRE=1`: pulses the trigger whenever a weapon is Loaded →
every armed weapon auto-fires at its authored cadence.
**VERIFIED headlessly**: forward view — PPC_1/2 + ERMLaser_1 cycle
FIRED→LOADED→FIRED at the authored 0.6 s discharge / 1 s recharge, rear lasers
silent; `BT_FORCE_LOOK=3` (look-behind) — ONLY ERMLaser_2/3 fire. The full
view-fire × fire-FSM interlock holds in both directions. Zero Fail. (SRM6s are
MissileLaunchers — the ballistic ProjectileWeaponSimulation is a later
increment.)
## Still staged
- The ballistic fire path (ProjectileWeaponSimulation @004bbd04, missile
launch/seeker), `SendDamage` (damage/networking), `CreateStreamedSubsystem`
(tool-side model build).
- ~~`MechWeapon::MessageHandlers` declared but not defined~~ — **FIXED
2026-07-21**: it is now a real defined set (`(0, NULL,
Subsystem::MessageHandlers)` — no own handlers yet, inherits the chain), and
`MechWeapon::DefaultData` binds it. This mattered because the surviving CODE
PPC.CPP binds the inherited name (`PPC::MessageHandlers`) into
PPC::DefaultData, and a declared-but-undefined static links as a zero-filled
common block — the same silent-NULL trap as the Emitter::AttributeIndex
crash. Real weapon handlers (fire/damage messages) come with the combat wave
(grow the table in place).