The whole critical-hit pipeline was dark, three layers deep, and one of those
layers had fooled us into a false conclusion about the 1995 binary itself.
LAYER 1 -- the trigger, recovered from the un-exported gap. The Mech MESSAGE
TABLE at 0x50bdf8 ({id, name, handler} rows) names the real
Mech::TakeDamageMessageHandler at 0x4a0230 -- message 0x12 "TakeDamage" --
plus seven sibling handlers (PlayerLink, RealMaxSpeed, BalanceCoolant,
Set/ClearBurningState, EjectPilot, DuckRequest). Inside it, the crit chance
at 0x4a0164: p = clamp(0.7 * damageLevel^2 + 0.01, 0..1), gated on the
player's simLive flag (+0x25c -- novice never crits), rolled PER BURST on the
current zone, skipping a zone already burning. Chance is ~1% on fresh armour,
~18% at half-stripped, ~58% at 90% -- crits arrive exactly as armour fails.
The handler's application loop replaces the engine base's single call, which
ignored burstCount entirely (multi-burst damage under-applied (burst-1)x).
Faithful shape: per burst, crit-roll -> CriticalHit @0049ccc4 (which routes
half the amount through the armour internally and picks ONE critical
subsystem by criticalWeight) else zone->TakeDamage -- then RE-RUN the
cylinder lottery from the impact point for the next burst, stopping early
once the mech is disabled. Multi-burst damage sprays across zones by design.
LAYER 2 -- the sink. MechSubsystem::TakeDamage was an empty btstubs stand-in;
the real body is at 0x4ac0bc (CLASSMAP had that address mislabeled
"HandleMessage"): zone damage, then on level >= 1.0 the Destroyed alarm, the
PrintState gate, the 1.0 pin, and -- for a vital subsystem -- the owner
mech's graphicAlarm to level 9, the same fall/death level the leg path
raises. That is the #28 vital-subsystem kill machinery, now real.
LAYER 3 -- the one that rewrites yesterday. The subsystem ctor DID copy
armour points + per-type scales into the private zone -- through the
ReconDamageZone PROXY, whose fields sit at struct offsets +4/+8, not the
binary's +0x140/+0x144. The floats landed on the engine object's header and
the real damageScale[] stayed zero. The 2026-07-28 experiment that "proved"
subsystem zones cannot be damaged -- and that the Myomers un-powered
self-repair was dead code in the original -- was measuring exactly this port
bug. Both verdicts reversed: the binary ctor (0x4ac7bb) initializes the zone
from the resource keys WeaponDamagePoints (required) + CriticalHitScoreBonus
(required) + Collision/Ballistic/Explosive/Laser/EnergyDamagePoints, none of
which the CSS parsed. Now parsed (with the binary's own error strings), and
the ctor writes the engine's NAMED members -- layout-parity holds, so they
land on +0x140/+0x144 faithfully. The Myomers repair branch is LIVE, in 1995
and here. KB corrected and swept (combat-damage, subsystems WAVE 6,
myomers.cpp, CLASSMAP).
Live-verified twice: [subarmor] prints real parsed scales for every subsystem
at spawn (HeatSink pts=10 scale=0.1x5, Condensers pts=5 scale=0.2x5, ...);
[critroll] landed full-chain crits in both runs (zone -> weighted pick ->
subsystem's own zone driven to 1.0 -> Destroyed); mech death/respawn and the
ammo gates un-regressed; zero crashes/asserts. Honest gaps: burst>1 spraying
is transcribed but not yet exercised live (self-damage fires burst=1), the
damageType==0 COLLISION divert (@0x49ffcc) is documented-not-reconstructed,
and the id-0x16 damage/kill report messages to the players (the authentic
stats plumbing, decoded to field level in the KB) are deferred to the #45
work.
Diags: BT_CRIT_LOG ([subarmor] + [critroll]), the existing BT_DMG_LOG.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
377 lines
18 KiB
C++
377 lines
18 KiB
C++
//===========================================================================//
|
|
// File: mechsub.hpp //
|
|
// Project: BattleTech Brick: Entity Manager //
|
|
// Contents: MechSubsystem -- BT damage-coupled base for all mech subsystems //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// --/--/95 ?? Initial coding. //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
//
|
|
// RECONSTRUCTED from the shipped binary. No mechsub.hpp survived, but the
|
|
// surviving MECHTECH.HPP `#include <mechsub.hpp>` and references
|
|
// `MechSubsystem::TechStatusTypeCount`, `MechSubsystem *monitoredSubsystem`,
|
|
// confirming a distinct BT class named MechSubsystem.
|
|
//
|
|
// RECONCILIATION VERDICT: MechSubsystem IS a distinct base class -- it is NOT
|
|
// an alias for the MUNGA `Subsystem` (RP/MUNGA/SUBSYSTM.HPP, which has no
|
|
// "Tech" status and no DamageZone coupling). It sits between MUNGA Subsystem
|
|
// and HeatableSubsystem:
|
|
//
|
|
// Simulation (MUNGA)
|
|
// Subsystem (MUNGA, SUBSYSTM.HPP -- we have it)
|
|
// MechSubsystem <-- THIS FILE (classID 0xBBB, vtable 0x50e210)
|
|
// HeatableSubsystem (heat.cpp -- string @0x50e700, classID 0xBBC?)
|
|
// HeatSink ... (heat.cpp / heatfamily_reslice.cpp)
|
|
// MechTech (mechtech.cpp -- : MechSubsystem? see note)
|
|
// <non-heatable mech subsystems>
|
|
//
|
|
// *** CLASSMAP CORRECTION (for the next reconciler) ***
|
|
// The heat.cpp / heat.hpp reconstruction attributed the cluster
|
|
// @0x4ac07c..@0x4ac9ec (vtable 0x50e210, dtor 0x4ac868) to its
|
|
// "Subsystem/HeatableSubsystem base". The string and behavioural evidence say
|
|
// that cluster is actually MechSubsystem:
|
|
// * CreateStreamedSubsystem @0x4ac9ec stamps classID 0xBBB and model size
|
|
// 0xE4, and parses ONLY damage/critical fields (PrintSimulationState,
|
|
// CollisionCriticalHitWeight, VideoObjectName, VitalSubsystem) -- NO
|
|
// thermal fields. (Thermal init is HeatSink's @0x4ae150.)
|
|
// * The ClassDerivations name string is "MechSubsystem" (@0x50def5,
|
|
// @0x50e2fd), distinct from "HeatableSubsystem" (@0x50e700).
|
|
// * The class couples the subsystem to a DamageZone (this+0xE0) and exposes
|
|
// the subsystem status/alarm with state names @0x50df17:
|
|
// Destroyed / Damaged / CoolantLeaking / Overheating / AmmoBurning /
|
|
// Jammed / BadPower (TechStatusTypeCount of these), plus the
|
|
// PrintSimulationState names DefaultState / Destroyed / Exploding.
|
|
// heat.cpp's `HeatableSubsystem(currentTemperature@0x114)` ctor @0x4ac644 does
|
|
// NOT write 0x114 -- it is in fact a MechSubsystem ctor. HeatableSubsystem is
|
|
// a (near-empty) layer above MechSubsystem; the temperature/heat fields belong
|
|
// to HeatSink (@0x4adda0).
|
|
//
|
|
// This reconstruction is BEST-EFFORT and overlaps heat.cpp; names of the
|
|
// MechSubsystem data members are inferred from usage. See mechsub.cpp for the
|
|
// per-method @ADDR evidence.
|
|
//
|
|
|
|
#if !defined(MECHSUB_HPP)
|
|
# define MECHSUB_HPP
|
|
|
|
#if !defined(SUBSYSTM_HPP)
|
|
# include <subsystm.hpp>
|
|
#endif
|
|
#if !defined(DAMAGE_HPP)
|
|
# include <damage.hpp>
|
|
#endif
|
|
#include <affnmtrx.hpp> // AffineMatrix
|
|
#include <average.hpp> // AverageOf<T>
|
|
#include <scalar.hpp> // Scalar
|
|
#include <alarm.hpp> // GaugeAlarm
|
|
|
|
#include "mechrecon.hpp" // reconstruction shim (proxies, artifact globals, type aliases)
|
|
|
|
//##################### Reconstruction type aliases #####################
|
|
#if !defined(BT_RECON_TYPE_ALIASES)
|
|
# define BT_RECON_TYPE_ALIASES
|
|
typedef AffineMatrix Matrix34; // 3x4 affine (AFFNMTRX.h)
|
|
typedef GaugeAlarm AlarmIndicator; // GAUGALRM.h
|
|
typedef AverageOf<Scalar> FilteredScalar; // 15-sample running average (AVERAGE.h)
|
|
#endif
|
|
|
|
//##################### Forward Class Declarations #######################
|
|
class Mech;
|
|
class NotationFile;
|
|
class Damage;
|
|
|
|
//###########################################################################
|
|
//##################### MechSubsystem Model Resource ####################
|
|
//###########################################################################
|
|
//
|
|
// Extends the base Subsystem resource. The mech-specific fields begin at +0x30
|
|
// in the parsed resource record (see MechSubsystem::CreateStreamedSubsystem
|
|
// @0x4ac9ec). Resource record size = 0xE4.
|
|
//
|
|
struct MechSubsystem__SubsystemResource:
|
|
public Subsystem::SubsystemResource
|
|
{
|
|
// task #80 RENAME (binary key strings @0x50e109..0x50e15d): these five are
|
|
// per-DAMAGE-TYPE points in Damage enum order -- "CollisionDamagePoints" /
|
|
// "Ballistic" / "Explosive" / "Laser" / "EnergyDamagePoints" -- NOT
|
|
// per-facing armour (the old name was a guess).
|
|
Scalar damageTypePoints[5]; // +0x30 per-damage-TYPE points (default -1.0f)
|
|
// "WeaponDamagePoints" (@0x50e09d) -- REQUIRED (" Must have a
|
|
// WeaponDamagePoints", @0x50e0b0) -- the subsystem's armour points,
|
|
// copied to its private zone's defaultArmorPoints@0x140 by the ctor.
|
|
Scalar weaponDamagePoints; // +0x44 "WeaponDamagePoints" (default -1.0f)
|
|
int vitalSubsystemIndex; // +0x48 "VitalSubsystem" segment (default -1)
|
|
char videoObjectName[128]; // +0x4C "VideoObjectName" (default "None")
|
|
ResourceDescription::ResourceID
|
|
alarmModel; // +0xCC (resolved id; the RECORD reserves a
|
|
// 12-byte field here -- @004ac9ec parses
|
|
// it via FUN_00408944 as 3 floats. The
|
|
// reconstruction only consumes the leading
|
|
// id, but the 12-byte footprint MUST be
|
|
// preserved or every field below slides
|
|
// 8 bytes low and the heat resource --
|
|
// which begins at +0xE4 -- misaligns.)
|
|
int _alarmModelReserved[2]; // +0xD0 remainder of the 12-byte 0xCC field
|
|
int printSimulationState; // +0xD8 "PrintSimulationState"
|
|
Scalar collisionCriticalHitWeight; // +0xDC "CollisionCriticalHitWeight"
|
|
Scalar criticalReference; // +0xE0 "CriticalHitScoreBonus" (@0x50e0d0,
|
|
// REQUIRED) -- the damage-tally value a
|
|
// crit on this subsystem is worth
|
|
};
|
|
|
|
//###########################################################################
|
|
//########################## MechSubsystem #############################
|
|
//###########################################################################
|
|
//
|
|
// Abstract BT base for every subsystem mounted in a mech. Owns a DamageZone
|
|
// (this+0xE0) representing its armour facings and structural integrity, a
|
|
// 3+-level status alarm (this+0x2C) reported by the cockpit MechTech, and the
|
|
// critical-hit / damage-distribution machinery.
|
|
// (vtable @0x50e210, ctors @0x4ac530 / @0x4ac644, dtor @0x4ac868,
|
|
// classID 0xBBB, resource model size 0xE4.)
|
|
//
|
|
class MechSubsystem:
|
|
public Subsystem
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
public:
|
|
static Derivation ClassDerivations; // name string "MechSubsystem"
|
|
static SharedData DefaultData;
|
|
static Recon MessageHandlers; // SharedData ctor operand
|
|
enum { StateCount = 7 }; // TechStatusTypeCount
|
|
|
|
// Attribute Support (AUDIO_FIDELITY.md F15): the binary registers
|
|
// ConfigureActivePress as a MechSubsystem-BASE attribute (id 2,
|
|
// descriptor @0x50de5c -> subsystem+0x110) -- the configure-session
|
|
// flag every weapon's ConfigureMappables handler drives (0 open /
|
|
// -1 idle) and the authored configure-ticker audio watches at
|
|
// thresh=-1. Publishing here makes it resolve on EVERY subsystem
|
|
// (each reads its own +0x110) and restores the binary-authentic
|
|
// dense id numbering (children start at 3, not 2).
|
|
enum {
|
|
ConfigureActivePressAttributeID = Simulation::NextAttributeID, // 2
|
|
NextAttributeID // 3
|
|
};
|
|
static const IndexEntry AttributePointers[];
|
|
static AttributeIndexSet& GetAttributeIndex();
|
|
|
|
// alarm-changed callback (vtable slot +0x34) + host back-pointer
|
|
void OnAlarmChanged();
|
|
Mech *owner; // owning mech (== hostEntity)
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Status model
|
|
//
|
|
public:
|
|
// Damage/condition status states (alarm @this+0x2C). Parsed from the
|
|
// state-name table @0x50df17 by ConfigureActivePress (@0x4ac194).
|
|
enum TechStatusType {
|
|
Destroyed = 0,
|
|
Damaged = 1,
|
|
CoolantLeaking = 2,
|
|
Overheating = 3,
|
|
AmmoBurning = 4,
|
|
Jammed = 5,
|
|
BadPower = 6,
|
|
TechStatusTypeCount // = 7 (referenced by MECHTECH.HPP)
|
|
};
|
|
|
|
// Simulation-state values stored at this+0x40 (printed by PrintState).
|
|
enum SimulationState {
|
|
DefaultState = 0,
|
|
DestroyedState = 1,
|
|
ExplodingState = 2
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Test Class Support
|
|
//
|
|
public:
|
|
static Logical
|
|
TestClass(Mech&);
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction and Destruction
|
|
//
|
|
public:
|
|
typedef MechSubsystem__SubsystemResource SubsystemResource;
|
|
|
|
// @0x4ac530 -- light ctor (name + classID); DamageZone named "None".
|
|
MechSubsystem(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
const char *subsystem_name,
|
|
RegisteredClass::ClassID class_id,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
|
|
// @0x4ac644 -- resource ctor; copies armorByFacing[5] -> DamageZone+0x144,
|
|
// structureReference -> DamageZone+0x140, and pre-inverts the armour
|
|
// scalars (1.0 / (armour * reference)) where above epsilon.
|
|
// (heat.cpp mislabels this as "HeatableSubsystem".)
|
|
MechSubsystem(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
|
|
~MechSubsystem(); // @0x4ac868
|
|
|
|
static int
|
|
CreateStreamedSubsystem( // @0x4ac9ec
|
|
NotationFile *model_file,
|
|
const char *model_name,
|
|
const char *subsystem_name,
|
|
SubsystemResource *subsystem_resource,
|
|
NotationFile *subsystem_file,
|
|
const ResourceDirectories *directories,
|
|
int passes = 1
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Subsystem virtual overrides (slots on vtable @0x50e210)
|
|
//
|
|
public:
|
|
// VIRTUAL (#47): the binary dispatches slot 12 through the vtable --
|
|
// MechTech's TechnicalAssistance scan calls (*sub_vtbl+0x30) on every
|
|
// monitored subsystem. Non-virtual here made a MechSubsystem* call bind
|
|
// statically to this base tier, so ProjectileWeapon's Jammed/AmmoBurning
|
|
// bits (@004bbf88) never reached the scan. (HeatableSubsystem already
|
|
// declared its own virtual; this unifies the root.)
|
|
virtual LWord
|
|
GetStatusFlags(); // slot 12, @0x4ac144
|
|
void
|
|
ResetToInitialState(Logical powered); // slot 8, @0x4ac1d4
|
|
void
|
|
PrintState(); // slot 13, @0x4ac8c0
|
|
Logical
|
|
HandleMessage(int message); // (address unknown -- the old @0x4ac0bc
|
|
// claim was the CLASSMAP mislabel; that
|
|
// address is TakeDamage, see below)
|
|
// @0x4ac0bc -- vtable slot +0x24 [T1, raw disasm 2026-07-29]. Routes the
|
|
// Damage into the subsystem's PRIVATE zone (zone vtbl+0x18), then on
|
|
// damageLevel >= 1.0: statusAlarm=Destroyed, the PrintState gate, pin 1.0,
|
|
// and -- if vitalSubsystem -- the owner mech's graphicAlarm to level 9 (the
|
|
// vital-subsystem KILL, issue #28). Was an empty btstubs stand-in, which is
|
|
// half of why crits never registered (#80). Defined in mechsub.cpp.
|
|
virtual void
|
|
TakeDamage(Damage &damage); // @0x4ac0bc (vtable +0x24)
|
|
Logical
|
|
IsDamaged(); // @0x4ac9c8 -- NOVICE-experience lockout predicate (player+0x274 == 0), NOT a damage query (issue #2); see mechsub.cpp
|
|
|
|
// Critical-state readouts for ColorMapperCritical (CriticalConnection):
|
|
// the raw simulation state (DefaultState=0 / Destroyed=1 / Exploding=2) and
|
|
// the subsystem's own damage zone (a real DamageZone behind the proxy type;
|
|
// set in the ctor via `new DamageZone(...)`, mechsub.cpp).
|
|
int
|
|
GetSimulationState() const { return simulationState; }
|
|
ReconDamageZone *
|
|
GetDamageZoneProxy() const { return damageZone; }
|
|
|
|
// gauge-complete wave: this subsystem's OWN structural damage [0,1] (0=intact,
|
|
// 1=destroyed) -- the engine DamageZone::damageLevel of the zone the ctor built
|
|
// (new DamageZone(this,0) @0xE0). Read via the ENGINE type's NAMED member (not
|
|
// the ReconDamageZone proxy, whose offset-0 structureLevel aliases the vtable
|
|
// ptr as a float = garbage). The binary reads *(this[0x38]+0x158) here (== the
|
|
// same anchor UpdateCoolant/SensorSimulation use). Defined in mechsub.cpp.
|
|
Scalar GetSubsystemDamageLevel() const;
|
|
void SetSubsystemDamageLevel(Scalar level);
|
|
|
|
// #80: the crit-tally worth of this subsystem ("CriticalHitScoreBonus",
|
|
// member @0x108) -- the TakeDamage handler adds it per landed crit
|
|
// (binary @0x4a0473: tally += critted->+0x108).
|
|
Scalar CriticalScoreBonus() const { return criticalReference; }
|
|
|
|
// task #2 (crit propagation): the zone-side crit paths
|
|
// (Mech__DamageZone::CriticalHit @0049ccc4 / SendSubsystemDamage
|
|
// @0049c9a8) reach these subsystem facets.
|
|
int IsVitalSubsystem() const { return vitalSubsystem; }
|
|
// @0x4ac07c -- run the virtual TakeDamage and return the resulting
|
|
// rise in the subsystem's own damageLevel (the crit allotment used).
|
|
Scalar ApplyDamageAndMeasure(Damage &damage);
|
|
// Apply a Damage straight to this subsystem's OWN zone -- the engine
|
|
// DamageZone::TakeDamage virtual (zone vtable +0x18), NOT the subsystem's
|
|
// own TakeDamage (this vtable +0x24, which is what ApplyDamageAndMeasure
|
|
// runs and which additionally cascades crits/vital checks). Myomers'
|
|
// Performance @004b8c16 calls the ZONE virtual directly, so it gets the
|
|
// plain `damageLevel += amount * damageScale[type]` and nothing else.
|
|
// Lives here because only a complete-DamageZone TU may deref the proxy.
|
|
void ApplyZoneDamage(Damage &damage);
|
|
// The destroyed-side effects SendSubsystemDamage applies when the
|
|
// subsystem's own zone hits 1.0: statusAlarm Destroyed(1) + the
|
|
// PrintState debug gate + the zone's state valve. [T1 @0049c9a8]
|
|
void ForceCriticalFailure();
|
|
// issue #22 (PORT, fresh-mech respawn emulation): undo everything
|
|
// ForceCriticalFailure/TakeDamage did to the subsystem's own private
|
|
// damage zone + status -- the binary respawn built a NEW mech, so a
|
|
// respawned subsystem was always pristine.
|
|
void RespawnRepair();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Internal helpers
|
|
//
|
|
protected:
|
|
|
|
// @0x4ac22c -- clear structure & both alarms to the inactive level.
|
|
void ClearStatus();
|
|
|
|
// @0x4ac274 -- distribute a critical hit across the contained critical
|
|
// subsystems, scaling damage by 1/criticalCount and logging
|
|
// "ammo explosion damaging ".
|
|
void DistributeCriticalHit(Damage &damage);
|
|
|
|
// @0x4ac194 -- map a status-state name string -> TechStatusType value
|
|
// using the name table @0x50de74. PUBLIC (was protected): the binary
|
|
// calls it cross-TU from BTL4GaugeAlarmManager::CreateGaugeAlarmStreamItem
|
|
// (@004cc294) to parse "gaugeAlarm Jammed = engEject"-style entries (#47).
|
|
public:
|
|
static Logical
|
|
LookupStatusType(const char *name, int *out_value);
|
|
protected:
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Local data (byte offsets into the shipped object)
|
|
//
|
|
protected:
|
|
AlarmIndicator statusAlarm; // @0x2C this+0xb (condition/status alarm)
|
|
int simulationState; // @0x40 DefaultState/Destroyed/Exploding
|
|
ReconDamageZone *damageZone; // @0xE0 this[0x38] (0x160-byte zone)
|
|
int vitalSubsystem; // @0xE4 this[0x39] -- destroying this
|
|
// subsystem KILLS the mech (ctor: res+0x48
|
|
// "VitalSubsystem"==1; was misnamed
|
|
// videoObjectFlag) [T1 part_012.c:15776]
|
|
// task #6 CORRECTION: these two are the CONTROLS feed, not identity --
|
|
// the binary ctor chain stores its destination/message ctor pass-throughs
|
|
// here (FUN_004ac644 part_012.c:15772-15773), and ConfigMapGauge::Execute
|
|
// @004c6f1c reads BOTH for buttonGroup GetMapState. MechWeapon's ctor
|
|
// defaults the destination to &fireImpulse (@004b99a8 part_013.c:6886-9).
|
|
// The old names hostEntity/subsystemId2 (populated with owner/subsystem_ID)
|
|
// were a mislabel -- any reader would have classified every weapon as
|
|
// "mappedByOthers". (No port reader existed; verified before the rename.)
|
|
void *controlDestination; // @0xE8 this[0x3a] (ControlsButton* the direct maps write)
|
|
int controlMessageID; // @0xEC this[0x3b] (event-mapping message id; weapons 0)
|
|
friend void BTSubsystemControlFeed(void *, void **, int *, void **); // gauge bridge (task #6)
|
|
SubsystemResource *resource; // @0xF0 this[0x3c]
|
|
void *refCount; // @0xF4 this[0x3d]
|
|
ResourceDescription::ResourceID
|
|
alarmModel; // @0xF8 this[0x3e]
|
|
int printSimulationState; // @0x104 this[0x41]
|
|
Scalar criticalReference; // @0x108 this[0x42]
|
|
Scalar collisionCriticalHitWeight; // @0x10C this[0x43]
|
|
int configureActivePress; // @0x110 this[0x44] (default -1) -- the
|
|
// configure-session flag (was misnamed
|
|
// vitalSubsystemIndex; the reader is the
|
|
// authored audio configure-ticker, F15)
|
|
};
|
|
|
|
#endif
|