Files
TeslaRel410/restoration/source410/BT/MECHSUB.NOTES.md
T
CydandClaude Fable 5 d4f0aef6e1 BT410 Phase 5.3.17: the destruction cascade -- zone deaths DESTROY things
Mech::DamageZone::TakeDamage is the full binary cascade (@0049c690): LOD
artifact router with same-attacker clustering (@0049c40c, hysteresis 0.33),
artifact parent level = mean of children, Energy-hit generator shorts
through the crit plug binding (novice-exempt), weighted CriticalHit
(@0049ccc4), zone-death allotment push (SendSubsystemDamage @0049c9a8) and
the segment-table destruction descent (RecurseSegmentTable @0049cad4 --
SIBS + DESCEND via the engine EntitySegment iterators).

Supporting bricks: Mech's OWN handler table with the TakeDamage override
(latches lastInflictingID @0x43c; gyro feed staged; cylinder table
deferred); friend class Mech__DamageZone (authentic); subsystem private
zones ARMED (structureReference + armorByFacing[5] normalized -- crits are
measurable); ApplyDamageAndMeasure; ForceCriticalFailure sets
DestroyedState so the weapon FSMs' GetSimulationState()==1 hard gate went
live; Generator::ForceShort + PoweredSubsystem::ForceShortRecovery.

Fight-verified (mutual BT_SPAWN_ENEMY + BT_FORCE_ZONE=8 concentrated fire):
arm zone to 1.0 -> sibling searchlight zone dies (Searchlight2/ThermalSight
crits destroyed, HUD degrading) -> DESCEND kills the gun zone -> PPC_2 +
ERMLaser_2 + Condenser6 DESTROYED and FALL SILENT (0 shots after death;
undamaged PPC_1 keeps firing); vital-zone hit = MECH KILL; PPC hit shorted
GeneratorD. This art has zero artifact zones (redirect=0 across all 20 --
router verified dormant-correct). Smoke + novice regressions clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 11:13:28 -05:00

194 lines
11 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.
# MECHSUB — reconstruction notes (phase 2 kickoff, 2026-07-19)
**Status: base-class ANALYSIS done; the reconstruction must be done FRESH against
the 4.10 structure, NOT backdated from BT411 (its base class + damage model
diverge). Key findings below de-risk the actual code.**
MechSubsystem is the base of the ~30-class subsystem roster (sensor, gyro, torso,
hud, generator, myomers, weapons…) the Mech ctor's segment-table walk
instantiates. The staged MECHSUB.HPP is interface-only (one `Mech *owner`
member, no bodies). Reconstructing the base is phase-2 step 1.
## Dependencies (all survive in the 4.10 archive)
- `Subsystem` (CODE/RP/MUNGA/SUBSYSTM.HPP) — the base.
- `DamageZone` (CODE/RP/MUNGA/DAMAGE.HPP/.CPP) — the engine damage zone.
- `Mech__DamageZone : public DamageZone` (CODE/BT/BT/MECHDMG.HPP) + the BT damage
model (MechCriticalSubsystem, redirect tables, critical hits).
- `AlarmIndicator` (just reconstructed, MUNGA/ALARM.HPP) — statusAlarm.
## Finding 1 — the base Subsystem DECLARES the zone but does NOT create it (RESOLVED)
SUBSYSTM.HPP:181 declares `DamageZone *damageZone;` in the **base** Subsystem and
its TakeDamage (SUBSYSTM.HPP:177-178) delegates `damageZone->TakeDamage(damage)`.
The base ctors ARE reconstructed — **staged source410/MUNGA/SUBSYSTM.CPP** (built,
in munga.lib; 38 Subsystem:: syms in the map). Both base ctors set
`damageZone = NULL` (resource ctor line 63) — the base does **not** allocate the
zone. So the DERIVED MechSubsystem creates the `Mech__DamageZone` (BT411's
zone-creation is structurally right here) — but the ARMOUR it seeds must follow
Finding 2 (per-type streamed), not BT411's per-facing hand-seed.
## Finding 2 — CRITICAL: the damage model diverged
The 4.10 base DamageZone (DAMAGE.HPP/CPP) is a **per-damage-TYPE** model:
- members: `defaultArmorPoints` (Scalar) + `damageScale[Damage::DamageTypeCount]`
where DamageTypeCount = 5 = {Collision, Ballistic, Explosive, Laser, Energy}.
- TakeDamage: `damageLevel += damage.damageAmount * damageScale[damage.damageType]`
(DAMAGE.CPP:413); the zone STREAMS its own armour (`*stream >> defaultArmorPoints;
*stream >> damageScale[ii]`, DAMAGE.CPP:335,340).
BT411's reconstruction is a **per-FACING** model: `armorByFacing[5]` (front/back/
left/right/top) + `structureReference`, **manually seeded** by MechSubsystem's
resource ctor with an armour→absorption-coefficient inversion. Those field names
(`armour[5]`, `structureReference`) exist only in BT411's `ReconDamageZone`
proxy — NOT in the surviving 4.10 DamageZone/Mech__DamageZone. The staged
`MechSubsystem__SubsystemResource` (armorByFacing[5]+structureReference) was
copied from BT411 and is likewise suspect for 4.10.
**Consequence:** BT411's MechSubsystem ctor (heat.cpp/mechsub.cpp) CANNOT be
backdated verbatim — it would install a damage model the 4.10 engine's DamageZone
doesn't implement, corrupting every subsystem's damage behaviour. The 4.10
MechSubsystem must let the base Subsystem + DamageZone stream ctor handle armour
(per-type), not hand-seed per-facing values.
## Corrected reconstruction approach (fully scoped — ready to write)
1. ~~Pin the base Subsystem ctor~~ **DONE (Finding 1)** — staged SUBSYSTM.CPP sets
`damageZone = NULL`; MechSubsystem creates the `Mech__DamageZone`.
2. Reconstruct MechSubsystem: chain the base Subsystem, `new Mech__DamageZone(this,
index)`, add the mech-specific members (statusAlarm = AlarmIndicator, vital
flag, alarmModel, criticalReference, collisionCriticalHitWeight,
printSimulationState, configureActivePress) and the TakeDamage override, using
the 4.10 **per-type** damage model — let the zone stream its own armour
(defaultArmorPoints + damageScale[5]); do NOT hand-seed BT411's per-facing
armorByFacing[5]/structureReference.
3. Re-derive `MechSubsystem__SubsystemResource` against the 4.10 DamageZone stream
format (the staged struct's per-facing fields are BT411-copied and suspect).
4. Then the roster (GAUSS/PPC/SENSOR source + .TCP partials + decomp).
Analysis complete; step 2 is the next code to write. This worksheet is the
deliverable that keeps the subsystem foundation on the 4.10 damage model rather
than BT411's divergent one.
## Progress + roster hierarchy findings (2026-07-19)
**DONE:** `MechSubsystem` base (MECHSUB.HPP/.CPP) and `HeatableSubsystem`
(HEAT.HPP/.CPP) reconstructed + compile-verified. Verified vertical slice so far:
`Subsystem → MechSubsystem → HeatableSubsystem`.
**The subsystem hierarchy is DEEPER than the staged headers show.** From BT411:
```
MechSubsystem (done)
└ HeatableSubsystem (done; ctor chains MechSubsystem + ResetToInitialState
-> currentTemperature=300, heatLoad=0)
└ HeatSink (MISSING from the staged tree -- not in source410 nor
CODE; VDATA HeatSinkClassID=0xBC5. Must be added.)
└ PoweredSubsystem (staged POWERSUB.HPP wrongly derives it from
HeatableSubsystem -- real base is HeatSink; FIX the
staged header. Also its ctor has embedded AlarmIndicators
(electricalStateAlarm 5-level, modeAlarm 3-level) and a
voltageSource SlotOf.)
└ Sensor (surviving header CODE/BT/BT/SENSOR.HPP; leaf)
└ Generator, ... (other leaves)
```
**PoweredSubsystem has inter-subsystem wiring** — its ctor resolves a voltage
source (generator) by indexing the OWNER MECH's subsystem roster
(`owner->GetSubsystem(res->voltageSourceIndex)`), not the skeleton. So powered
subsystems must be created AFTER the generator in the segment-walk order, and the
Mech must expose GetSubsystemCount()/GetSubsystem(). This ordering constraint is
a segment-walk (phase-4 ctor) concern; note it there.
## Complete subsystem family tree (mapped 2026-07-19) + build status
```
MechSubsystem DONE (MECHSUB.HPP/.CPP)
├─ HeatableSubsystem DONE (HEAT)
│ └─ HeatSink DONE (HEAT)
│ ├─ PoweredSubsystem DONE (POWERSUB)
│ │ ├─ Sensor DONE (SENSOR; interface survives in CODE)
│ │ └─ Myomers todo (myomers.hpp)
│ ├─ Generator DONE (POWERSUB; source, GNRATOR.TCP partial)
│ └─ Condenser todo (heat.hpp)
└─ HeatWatcher (: MechSubsystem) todo -- sibling branch to HeatableSubsystem
└─ PowerWatcher (: HeatWatcher) todo
├─ Torso todo (torso.hpp) -- Mech sinkSourceSubsystem
├─ HUD todo (hud.hpp) -- Mech hudSubsystem
└─ Gyroscope todo (gyro.hpp) -- Mech gyroSubsystem
```
Plus the WEAPON family (separate subtree): MechWeapon → {PPC, Gauss, ProjectileWeapon
→ Missile/…}. PPC/GAUSS source survives in CODE/BT/BT; AMMOBIN/EMITTER/MISSILE/
PROJTILE/PROJWEAP have .TCP partials; the rest decomp-only.
**Pattern established** (6 classes verified): each = statics
(ClassDerivations(parent, "Name") + DefaultData reusing Subsystem::MessageHandlers/
AttributeIndex/StateCount), ctor chaining the parent + member init from the
resource, dtor, TestClass/TestInstance/ResetToInitialState real, per-frame
Simulation method + CreateStreamedSubsystem staged with Fail. Embedded alarms =
AlarmIndicator(N); filters = AverageOf<Scalar>; owner->GetInstance() !=
ReplicantInstance gates the master performance install.
## ROSTER CORE COMPLETE (2026-07-20) — 16 classes verified
All committed + compile-verified: MechSubsystem, HeatableSubsystem, HeatSink,
HeatWatcher, PowerWatcher, PoweredSubsystem, Generator, Condenser, Sensor,
Myomers, Gyroscope, HUD, Torso, MechWeapon, Emitter (+ surviving PPC/GaussRifle),
ProjectileWeapon, MissileLauncher, AmmoBin. Tree links clean.
## Phase-4 blueprint: the Mech-ctor segment-walk factory (mech.cpp:1146-1330)
The Mech ctor allocates `subsystemArray[subsystemCount]` (+GetSubsystem/Count),
then loops segments (from id 2) switching on `seg->classID` to `new <Class>(this,
id, seg)`, caching the key ones. **The VDATA ClassID enum names are MISLABELED vs
the real class** (BT411's mapping):
| ClassID | enum name | REAL class | built? |
|---|---|---|---|
| 0xBBD | CockpitClassID | Condenser | ✅ |
| 0xBBE | SensorClassID | HeatSink bank | ~ (HeatSink ✅; bank variant TODO) |
| 0xBC0 | CondenserClassID | **Reservoir** | ❌ TODO |
| 0xBC1 | GeneratorClassID | Generator | ✅ |
| 0xBC2 | PoweredSubsystemClassID | PoweredSubsystem | ✅ |
| 0xBC3 | MyomersClassID | Sensor | ✅ |
| 0xBC4 | GyroClassID | Gyroscope | ✅ (cache gyroSubsystem) |
| 0xBC5 | SinkSourceClassID | Torso | ✅ (cache sinkSourceSubsystem) |
| 0xBC6 | ActuatorClassID | Myomers | ✅ |
| 0xBC8 | WeaponEmitterClassID | Emitter | ✅ (weaponCount++) |
| 0xBCB | JumpJetClassID | AmmoBin | ✅ |
| 0xBCD | MechWeaponClassID | ProjectileWeapon | ✅ |
| 0xBCE | MissileWeaponClassID | GaussRifle | ✅ |
| 0xBD0 | BallisticWeaponClassID | MissileLauncher | ✅ |
| 0xBD3 | SubsystemMessageManagerID | **SubsystemMessageManager** | ❌ TODO |
| 0xBD4 | GaussWeaponClassID | Emitter (PPC) | ✅ |
| 0xBD6 | MechTechClassID | HUD | ✅ (cache hudSubsystem) |
| 0xBD8 | LegSubsystemClassID | **Searchlight** (: PowerWatcher) | ❌ TODO |
| 0xBDC | HeatableClassID | **MechTech** | ❌ TODO |
| 0xBDE | DisplayClassID | **ThermalSight** (: PowerWatcher) | ❌ TODO |
Remaining subsystem classes for a full walk: Reservoir, HeatSink-bank variant,
Searchlight, MechTech, ThermalSight, SubsystemMessageManager, Actuator (fallback).
Then the Mech member layout (subsystemArray/subsystemCount + the capability chains
controllable/heatable/weaponRoster/damageable + the alarms/reticle/state-indicators
/SequenceControllers/NameFilter/CStrings embedded members) must be named in
MECH.HPP for the ctor to set them.
## 5.3.17 — the subsystem side of the damage cascade
- The subsystem's PRIVATE zone is now ARMED (binary @4abf28): owned by the
SUBSYSTEM (`new DamageZone(this, 0)` — Joint.cpp:512 proves subsystems are
valid zone owners), named, `defaultArmorPoints = structureReference`,
`damageScale[5] = armorByFacing[]` normalized with the hull-zone rule
(1/(raw×points); guard: structureReference<=0 leaves the zone inert).
This makes crits MEASURABLE.
- `ApplyDamageAndMeasure` (@4ac07c): TakeDamage + return the zone-level
delta (the crit accountant charges it).
- `ForceCriticalFailure` now also sets `SetSimulationState(DestroyedState)` —
the subsystem SIMULATION state enum (Destroyed=1/Exploding=2, from the
binary PrintState string pool) added to MECHSUB.HPP; both weapon FSMs'
`GetSimulationState() == 1` hard gate is now live (destroyed weapons stop
firing — fight-verified).
- `IsVitalSubsystem()` accessor (vital crit death = mech kill in
SendSubsystemDamage).