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 AnimatedSubsystemLamp( // @004c70a4
GaugeRate, ModeMask, L4GaugeRenderer *, int, GaugeRate, ModeMask, L4GaugeRenderer *, int,
int x, int y, const char *image, int columns, int rows, 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 ~AnimatedSubsystemLamp(); // @004c7134
protected: protected:
int selected; // @0xAC this[0x2B] (connection dst) int selected; // @0xAC this[0x2B] (connection dst)
@@ -186,7 +186,7 @@
AnimatedSourceLamp( // @004c7160 AnimatedSourceLamp( // @004c7160
GaugeRate, ModeMask, L4GaugeRenderer *, int, GaugeRate, ModeMask, L4GaugeRenderer *, int,
int x, int y, const char *image, int columns, int rows, 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 ~AnimatedSourceLamp(); // @004c71f0
protected: protected:
int selected; // @0xAC this[0x2B] int selected; // @0xAC this[0x2B]
@@ -202,14 +202,25 @@
// Both share dtor FUN_004c733c (chains the bar dtor @00472fb4). Used with // Both share dtor FUN_004c733c (chains the bar dtor @00472fb4). Used with
// the strings "GeneratorVoltage(slotOf)" / "GeneratorVoltage(scalar)". // the strings "GeneratorVoltage(slotOf)" / "GeneratorVoltage(scalar)".
//####################################################################### //#######################################################################
class ScalarBarGauge : // (best-effort) // ScalarBarGauge chains the MUNGA L4 bar primitive @00472ef0 == the engine
public GraphicGauge // MUNGA L4 bar primitive (FUN_00472ef0); engine has no plain "BarGraph" class // 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: 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 ~ScalarBarGauge(); // @004c733c
protected:
Scalar value; // @0xB4 this[0x2D] (connection dst)
}; };
@@ -322,19 +333,24 @@
public GraphicGauge public GraphicGauge
{ {
public: 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 SubsystemCluster( // @004c8140
GaugeRate, ModeMask, L4GaugeRenderer *, int, ModeMask mfd_mode, L4GaugeRenderer *renderer, int owner_ID,
int x, int y, Subsystem *subsystem, GaugeRenderer *eng_renderer, int mfd_port, int x, int y, Subsystem *subsystem, ModeMask eng_mode,
const char *port_name, const char *tile_image, const char *eng_port_name, const char *tile_image,
const char *background_image, int damage_zone_table, const char *label, char **image_names,
const char *identification_string); const char *identification_string);
~SubsystemCluster(); // @004c87dc ~SubsystemCluster(); // @004c87dc
Logical TestInstance() const; Logical TestInstance() const;
void BecameActive(); // @004c88e4 (shared base Execute trampoline) void BecameActive(); // @004c88e4 (shared base Execute trampoline)
void Execute(); // @004c88e4 void Execute(); // @004c88e4
protected: protected:
BackgroundBitmap
*background; // @0x90 this[0x24] BackgroundBitmap
GraphicGauge GraphicGauge
*background, // @0x90 this[0x24] BackgroundBitmap *generatorVoltageBar, // @0x94 this[0x25] ScalarBarGauge (evolt)
*temperatureBar, // @0x98 this[0x26] HorizTwoPartBar *temperatureBar, // @0x98 this[0x26] HorizTwoPartBar
*coolingLoopA, // @0x9C this[0x27] AnimatedSubsystemLamp *coolingLoopA, // @0x9C this[0x27] AnimatedSubsystemLamp
*coolingLoopB, // @0xA0 this[0x28] *coolingLoopB, // @0xA0 this[0x28]
@@ -347,12 +363,27 @@
*leakGauge; // @0xBC this[0x2F] LeakGauge *leakGauge; // @0xBC this[0x2F] LeakGauge
Subsystem *subsystem; // @0xC0 this[0x30] Subsystem *subsystem; // @0xC0 this[0x30]
Logical operating; // @0xC4 this[0x31] 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 class HeatSinkCluster : // @004c8a6c
public SubsystemCluster public SubsystemCluster
{ {
public: 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 ~HeatSinkCluster(); // @004c8d18
void Execute(); // @004c8db0 void Execute(); // @004c8db0
protected: protected:
@@ -368,10 +399,39 @@
*heatNumeric; // @0xEC this[0x3B] NumericDisplayScalar *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 class WeaponCluster : // @004c8fc4
public SubsystemCluster public SubsystemCluster
{ {
public: 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 ~WeaponCluster(); // @004c91d4
void BecameActive(); // @004c9258 void BecameActive(); // @004c9258
void Execute(); // @004c9290 void Execute(); // @004c9290
@@ -390,6 +450,12 @@
public WeaponCluster public WeaponCluster
{ {
public: 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 ~EnergyWeaponCluster(); // @004c94dc
protected: protected:
SeekVoltageGraph *seekGraph; // @0xE8 this[0x3A] SeekVoltageGraph *seekGraph; // @0xE8 this[0x3A]
@@ -400,6 +466,13 @@
public WeaponCluster public WeaponCluster
{ {
public: 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 ~BallisticWeaponCluster(); // @004c9940
void BecameActive(); // @004c99cc void BecameActive(); // @004c99cc
void Execute(); // @004c9a38 void Execute(); // @004c9a38
@@ -422,4 +495,24 @@
*ammoCountB; // @0x118 this[0x46] NumericDisplayInteger *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 #endif
+2
View File
@@ -66,6 +66,7 @@
#endif #endif
#if !defined(BTL4GAUG_HPP) #if !defined(BTL4GAUG_HPP)
# include <btl4gaug.hpp> // the BT gauge classes (Compass, etc.) # 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 <btl4rdr.hpp> // MapDisplay (the "map" radar gauge)
# include <btl4gau3.hpp> // PlayerStatus (the comm/score gauge) # include <btl4gau3.hpp> // PlayerStatus (the comm/score gauge)
#endif #endif
@@ -141,6 +142,7 @@ MethodDescription
&OneOfSeveralPixInt::methodDescription, // "oneOfSeveralPixInt" -- button-state lamp (duck/light/mode) &OneOfSeveralPixInt::methodDescription, // "oneOfSeveralPixInt" -- button-state lamp (duck/light/mode)
&MapDisplay::methodDescription, // "map" -- the radar / tactical display &MapDisplay::methodDescription, // "map" -- the radar / tactical display
&PlayerStatus::methodDescription, // "PlayerStatus" -- comm/score name-tag gauge &PlayerStatus::methodDescription, // "PlayerStatus" -- comm/score name-tag gauge
&VehicleSubSystems::methodDescription, // "vehicleSubSystems" -- engineering-screen subsystem cluster panels
&BTL4ChainToPrevious &BTL4ChainToPrevious
}; };