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>
9.8 KiB
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)
Pin the base Subsystem ctorDONE (Finding 1) — staged SUBSYSTM.CPP setsdamageZone = NULL; MechSubsystem creates theMech__DamageZone.- 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. - Re-derive
MechSubsystem__SubsystemResourceagainst the 4.10 DamageZone stream format (the staged struct's per-facing fields are BT411-copied and suspect). - 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; 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.