vehicleSubSystems Phase 1: reconstruct + register the cluster-panel family

Reconstruct the whole engineering-screen (MFD) subsystem cluster-panel system in
btl4gau2 (from the Ghidra decomp of BTL4OPT.EXE) and register the vehicleSubSystems
config primitive:

- Sub-gauges: AnimatedSubsystemLamp/AnimatedSourceLamp (OneOfSeveral + cooling/
  power connections), ScalarBarGauge (BarGraphBitMapScalar + generator-voltage
  connection), ConfigMapGauge, plus the 3 file-private GaugeConnection classes
  (@004c3134/31ec/3288 samplers).
- SubsystemCluster base (ctor builds ~11 child gauges across the MFD + engineering
  ports; Execute/dtor/frame-draw/enable helpers) + the 5 subclasses HeatSink/
  Myomer/Weapon/Energy/Ballistic (ctors + Executes).
- VehicleSubSystems::Make dispatcher (@004cbaf0): per-subsystem factory keyed on
  classID (HeatSink 0xBC3 / Myomer 0xBC6 / Energy 0xBC8,0xBD4 / Ballistic
  0xBCD,0xBD0), placed via the 12-row aux-screen geometry table, + registered in
  BTL4MethodDescription[].

SAFE + gated: gauges only build under BT_DEV_GAUGES/pod, and until Phase 2
populates the subsystem aux-screen field (subsystem[0x1dc]) the Make hits its
"aux screen = zero" skip -> combat untouched.  Two minor children deferred as
marked NULLs (SegmentArc270 recharge dial + BitMapInverseWipeScalar eject wipe --
their ctors are btl4gaug placeholders).  Raw-offset subsystem reads (0x1dc/0x1e0/
0x1e4/0x31c/0x334/0x364/0x43c...) marked BEST-EFFORT pending Phase 2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-07 06:43:32 -05:00
co-authored by Claude Opus 4.8
parent a5fa9f1c79
commit 674c172cf8
3 changed files with 1205 additions and 35 deletions
File diff suppressed because it is too large Load Diff
+105 -12
View File
@@ -173,7 +173,7 @@
AnimatedSubsystemLamp( // @004c70a4
GaugeRate, ModeMask, L4GaugeRenderer *, int,
int x, int y, const char *image, int columns, int rows,
Entity *subsystem, const char *identification_string);
void *subsystem, const char *identification_string);
~AnimatedSubsystemLamp(); // @004c7134
protected:
int selected; // @0xAC this[0x2B] (connection dst)
@@ -186,7 +186,7 @@
AnimatedSourceLamp( // @004c7160
GaugeRate, ModeMask, L4GaugeRenderer *, int,
int x, int y, const char *image, int columns, int rows,
Entity *source, const char *identification_string);
void *source, const char *identification_string);
~AnimatedSourceLamp(); // @004c71f0
protected:
int selected; // @0xAC this[0x2B]
@@ -202,14 +202,25 @@
// Both share dtor FUN_004c733c (chains the bar dtor @00472fb4). Used with
// the strings "GeneratorVoltage(slotOf)" / "GeneratorVoltage(scalar)".
//#######################################################################
class ScalarBarGauge : // (best-effort)
public GraphicGauge // MUNGA L4 bar primitive (FUN_00472ef0); engine has no plain "BarGraph" class
// ScalarBarGauge chains the MUNGA L4 bar primitive @00472ef0 == the engine
// BarGraphBitMapScalar (WipeGaugeScalar). Its value slot @0xB4 (this[0x2D])
// IS the inherited WipeGaugeScalar::currentValue -- the connection writes it,
// so NO own field is declared (declaring one would shadow / mis-align).
class ScalarBarGauge :
public BarGraphBitMapScalar // @00472ef0 base (WipeGaugeScalar : GraphicGauge)
{
public:
ScalarBarGauge(/* ...bar geometry..., Scalar *value, id */); // @004c721c / @004c72ac
// @004c721c -- the "slotOf" variant: bar body then AddConnection(new
// GeneratorVoltageConnection @004c3288) feeding currentValue from a
// resolved voltage source. (The @004c72ac plain-Scalar variant is unused
// by the cluster path.)
ScalarBarGauge( // @004c721c
GaugeRate, ModeMask, L4GaugeRenderer *, int graphics_port_number,
int left, int bottom, int right, int top,
const char *tile_image, int foreground_color, int background_color,
WipeGaugeScalar::Direction direction, Scalar min, Scalar max,
void *voltage_source, const char *identification_string);
~ScalarBarGauge(); // @004c733c
protected:
Scalar value; // @0xB4 this[0x2D] (connection dst)
};
@@ -322,19 +333,24 @@
public GraphicGauge
{
public:
// @004c8140. Binary param order (rate/mode are hardcoded 0xFFFF/0xFFFFFFFF
// in the base GraphicGauge ctor; the panel's two bit-plane MODE masks are
// mfd_mode (MFD-port children) and eng_mode (engineering-port children)).
SubsystemCluster( // @004c8140
GaugeRate, ModeMask, L4GaugeRenderer *, int,
int x, int y, Subsystem *subsystem, GaugeRenderer *eng_renderer,
const char *port_name, const char *tile_image,
const char *background_image, int damage_zone_table,
ModeMask mfd_mode, L4GaugeRenderer *renderer, int owner_ID,
int mfd_port, int x, int y, Subsystem *subsystem, ModeMask eng_mode,
const char *eng_port_name, const char *tile_image,
const char *label, char **image_names,
const char *identification_string);
~SubsystemCluster(); // @004c87dc
Logical TestInstance() const;
void BecameActive(); // @004c88e4 (shared base Execute trampoline)
void Execute(); // @004c88e4
protected:
BackgroundBitmap
*background; // @0x90 this[0x24] BackgroundBitmap
GraphicGauge
*background, // @0x90 this[0x24] BackgroundBitmap
*generatorVoltageBar, // @0x94 this[0x25] ScalarBarGauge (evolt)
*temperatureBar, // @0x98 this[0x26] HorizTwoPartBar
*coolingLoopA, // @0x9C this[0x27] AnimatedSubsystemLamp
*coolingLoopB, // @0xA0 this[0x28]
@@ -347,12 +363,27 @@
*leakGauge; // @0xBC this[0x2F] LeakGauge
Subsystem *subsystem; // @0xC0 this[0x30]
Logical operating; // @0xC4 this[0x31]
int previousDrawState; // @0xC8 this[0x32] (Execute repaint key)
// internal helpers (non-virtual; @004c89c4 / @004c8820 / @004c8a28)
void DrawPanelFrame(int color); // @004c89c4
void ReleaseChildren(); // @004c8820
void SetChildrenEnable(int enable); // @004c8a28
public:
int GetDrawState(); // @004c8990 (operational-state virtual, vtbl+0x48)
protected:
};
class HeatSinkCluster : // @004c8a6c
public SubsystemCluster
{
public:
HeatSinkCluster( // @004c8a6c
ModeMask mfd_mode, L4GaugeRenderer *, int owner_ID, int mfd_port,
int x, int y, Subsystem *subsystem, Subsystem *hud, ModeMask eng_mode,
const char *eng_port_name, const char *tile_image, const char *label,
const char *fail_lamp_image, char **image_names,
const char *identification_string);
~HeatSinkCluster(); // @004c8d18
void Execute(); // @004c8db0
protected:
@@ -368,10 +399,39 @@
*heatNumeric; // @0xEC this[0x3B] NumericDisplayScalar
};
//
// MyomerCluster @004c8df4 (vtable 00519f88) : SubsystemCluster -- the myomer
// (muscle) panel. Adds a SeekVoltageGraph ("EngrGraph", edestryd.pcc) fed by
// an InputVoltage GeneratorVoltageConnection (writes seekValue@0x33) + a
// seek-step OneOfSeveralInt (bteseek.pcc, subsys+0x800). Execute = base.
//
class MyomerCluster : // @004c8df4
public SubsystemCluster
{
public:
MyomerCluster( // @004c8df4
ModeMask mfd_mode, L4GaugeRenderer *, int owner_ID, int mfd_port,
int x, int y, Subsystem *subsystem, ModeMask eng_mode,
const char *eng_port_name, const char *tile_image, const char *label,
char **image_names, const char *identification_string);
~MyomerCluster(); // @004c8f54
protected:
Scalar seekValue; // @0xCC this[0x33] (connection dst)
GraphicGauge
*seekGraph, // @0xD0 this[0x34] SeekVoltageGraph
*seekStepLamp; // @0xD4 this[0x35] OneOfSeveralInt
};
class WeaponCluster : // @004c8fc4
public SubsystemCluster
{
public:
WeaponCluster( // @004c8fc4
ModeMask mfd_mode, L4GaugeRenderer *, int owner_ID, int mfd_port,
int x, int y, Subsystem *subsystem, ModeMask eng_mode,
const char *eng_port_name, const char *tile_image, const char *label,
const char *cluster_image, char **image_names,
const char *identification_string);
~WeaponCluster(); // @004c91d4
void BecameActive(); // @004c9258
void Execute(); // @004c9290
@@ -390,6 +450,12 @@
public WeaponCluster
{
public:
EnergyWeaponCluster( // @004c93b0
ModeMask mfd_mode, L4GaugeRenderer *, int owner_ID, int mfd_port,
int x, int y, Subsystem *subsystem, ModeMask eng_mode,
const char *eng_port_name, const char *tile_image, const char *label,
const char *cluster_image, char **image_names,
const char *identification_string);
~EnergyWeaponCluster(); // @004c94dc
protected:
SeekVoltageGraph *seekGraph; // @0xE8 this[0x3A]
@@ -400,6 +466,13 @@
public WeaponCluster
{
public:
BallisticWeaponCluster( // @004c9558
ModeMask mfd_mode, L4GaugeRenderer *, int owner_ID, int mfd_port,
int x, int y, Subsystem *subsystem, ModeMask eng_mode,
const char *eng_port_name, const char *tile_image, const char *label,
const char *cluster_image, char **image_names,
const char *font_a, const char *font_b,
const char *identification_string);
~BallisticWeaponCluster(); // @004c9940
void BecameActive(); // @004c99cc
void Execute(); // @004c9a38
@@ -422,4 +495,24 @@
*ammoCountB; // @0x118 this[0x46] NumericDisplayInteger
};
//#######################################################################
// vehicleSubSystems -- the config primitive that builds the engineering-
// screen (MFD) subsystem cluster panels. Make @004cbaf0 (methodDescription
// @0x51c080, 8 typeString params = the 8 status strip bitmaps) is a per-
// subsystem factory: it walks the mech roster (skipping slot 0), and for each
// subsystem builds the right cluster (HeatSink/Myomer/Energy/Ballistic) onto
// one of 12 auxiliary MFD positions selected by subsystem[0x1dc] (the aux-
// screen position 1..12). This holder just carries the registered
// MethodDescription + the static Make dispatcher (there is no instance).
//#######################################################################
class VehicleSubSystems
{
public:
static MethodDescription methodDescription;
static Logical Make( // @004cbaf0
int display_port_index, Vector2DOf<int> position,
Entity *entity, GaugeRenderer *gauge_renderer);
};
#endif
+2
View File
@@ -66,6 +66,7 @@
#endif
#if !defined(BTL4GAUG_HPP)
# include <btl4gaug.hpp> // the BT gauge classes (Compass, etc.)
# include <btl4gau2.hpp> // the composite cluster gauges + VehicleSubSystems
# include <btl4rdr.hpp> // MapDisplay (the "map" radar gauge)
# include <btl4gau3.hpp> // PlayerStatus (the comm/score gauge)
#endif
@@ -141,6 +142,7 @@ MethodDescription
&OneOfSeveralPixInt::methodDescription, // "oneOfSeveralPixInt" -- button-state lamp (duck/light/mode)
&MapDisplay::methodDescription, // "map" -- the radar / tactical display
&PlayerStatus::methodDescription, // "PlayerStatus" -- comm/score name-tag gauge
&VehicleSubSystems::methodDescription, // "vehicleSubSystems" -- engineering-screen subsystem cluster panels
&BTL4ChainToPrevious
};