Files
BT411/game/reconstructed/btl4gau2.hpp
T
arcattackandClaude Fable 5 63b168cb92 SeekVoltageGraph: full reconstruction -- the eng-page POWER graph + top-box eraser (Gitea #11)
The #10 audit's one WRONG: the port Execute was a bring-up no-op, so the
emitter/myomer engineering pages never erased their top data box -> stale
sibling-page ghosts on the shared Eng bit-plane (SYSTEM 10 PPC showing the
Streak ammo box, etc).  Full faithful widget landed:

- btl4gau2: ctor/BecameActive/Execute/clear/ticks/cursor recovered from the
  capstone disasm of @004c6798/@004c6920/@004c6934/@004c6be4/@004c6c30/
  @004c6c6c (Ghidra dropped every x87 arg).  Plot: v=0..12000 step 1200,
  x=Round(response(v)*230), y=Round(v*(1/12000)*187) (ld80 @004c6bd0/@004c6d74
  = exactly 1/12000); change-test samples the response at 12000V vs the 9999
  activation sentinel; XOR op for tick/cursor move-by-redraw; destroyed branch
  centres edestryd.pcc and revives via own vtbl+0xC (BecameActive, slot 3 of
  PTR_0051a1fc -- vtable-dump verified).
- The vtbl+0x3C sampler identified from the binary vtables: Emitter slot 15
  @004bb42c = sqrt(P(v)/2.0e8), P @004bb3f4 = damageFraction*v^2*0.5*
  energyCoefficient; Myomers slot 15 @004b8f94 = sqrt(AvailableOutput(v)*3.6/
  350).  FUN_004dd138 == sqrt (part_015.c:4026): myomers' fabs reading
  corrected, GetSpeedReading renamed SeekVoltageResponse.  Port dispatch via
  complete-type bridges BTSeekVoltageSample/BTMyomersSeekSample +
  BTSubsystemDestroyed (databinding rule).
- Emitter's AUTHENTIC attribute table recovered (binary @0x511dd4, ids
  0x1D-0x25) and published: Laser*/Seek*/OutputVoltage@0x414 (currentLevel,
  RAW volts -- the live-cursor feed).  Field renames per the table:
  0x3F8 minSeekVoltageIndex / 0x3FC maxSeekVoltageIndex (static_assert-locked).
  The MechWeapon 0x1D OutputVoltage PORT ALIAS retired (binary table ends
  0x1C; Find walks lowest-id-first, the alias shadowed the authentic row).
  PPC::DefaultData -> Emitter::GetAttributeIndex().
- mech4: BT_PRESET_HOLD=<n> (freeze the #9 preset cycler after n pulses) for
  steady-state pixel verification; BT_SEEK_LOG diag.

Verified live (BLH, autofire): both #10 repro pairs held ghost-free for
minutes (SYS09->SYS10 PPC, SYS02->SYS04 ERMed, SYS05->SYS06 Myomers); curves
draw with live cursors; one replot per activation; quad panels/J-K-L/sec
panel un-regressed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 20:27:39 -05:00

573 lines
28 KiB
C++

//===========================================================================//
// File: btl4gau2.hpp //
// Project: BattleTech Brick: Gauge Renderer Manager //
// Contents: Cockpit instrument library, part 2 -- the COMPOSITE "panel" //
// gauges that the BattleTech engineering / weapon-status HUD is //
// assembled from. Where btl4gaug.cpp holds the primitive widgets //
// (bars, dials, lamps, colour-mappers), btl4gau2.cpp holds the //
// higher-level gauges that AGGREGATE those primitives into a single //
// subsystem read-out: //
// * SeekVoltageGraph -- energy-weapon seek-voltage curve //
// * ConfigMapGauge -- joystick / config-manager state lamp //
// * GeneratorCluster -- generator voltage + coolant + leak panel //
// * PrepEngrScreen -- per-weapon engineering screen builder //
// * SubsystemCluster +-> HeatSinkCluster //
// +-> WeaponCluster +-> EnergyWeaponCluster //
// +-> BallisticWeaponClu.//
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 02/22/96 CPB Initial coding. //
//---------------------------------------------------------------------------//
// Copyright (C) 1996, Virtual World Entertainment, Inc. All rights reserved //
// PROPRIETARY AND CONFIDENTIAL //
//===========================================================================//
//
// RECONSTRUCTED. No BTL4GAU2.HPP survived; recovered from the shipped binary
// (BTL4OPT.EXE). Ghidra pseudo-C is in recovered/all/part_014.c.
//
// Translation-unit extent (BTL4.MAK link order:
// btl4mode -> btl4rdr -> btl4gaug -> btl4gau2 -> btl4gau3 -> btl4grnd -> ...):
// first gau2 code @004c6798 (SeekVoltageGraph::SeekVoltageGraph)
// last gau2 code @004c9b50 (BallisticWeaponCluster helpers)
// btl4gau3 begins @004c9bd0 (PlayerStatusMappingGroup -- not this TU)
//
// Class names recovered from the CODE name-string pool around 0x519760
// (the gauge name list) and the per-instance identification strings:
// "GeneratorCluster" 0x519a8c "PrepEngr" 0x519a9d
// "ConfigMap" 0x519a38 "CoolingLoop" 0x519a42 "PowerSource" 0x519a4e
// "GeneratorVoltage(scalar)" 0x519a73 "GeneratorVoltage(slotOf)" 0x519a5a
// "EngrGraph" 0x519a2e "WeaponCluster ... " 0x519dcb
// Field offsets in comments are byte offsets (e.g. "@0x90" == this[0x24]).
//
// Bases (MUNGA L4 gauge primitives, shared with btl4gaug.cpp):
// GraphicGauge ctor FUN_00444818 dtor FUN_00444870 (GraphicsView @+0x48)
// Gauge group ctor FUN_004440d4 dtor FUN_00443f7c (owns a ChainOf<Gauge*>
// at +0x24; used by PrepEngrScreen -- it draws into a port and
// hosts no GraphicsView of its own)
// ArcGauge/BarGraph primitives FUN_00472ef0 (bar), FUN_004c6244 (SegmentArc270,
// in btl4gaug), FUN_004739d8 (TwoState), FUN_00471d00
// (BackgroundBitmap), FUN_004700bc (NumericDisplay),
// FUN_00470888 (NumericDisplayScalar),
// FUN_00473c94 (NumericDisplayScalarTwoState).
//
// Names flagged "(best-effort)" exist in the binary but their identification
// string could not be tied to them unambiguously.
//
#if !defined(BTL4GAU2_HPP)
# define BTL4GAU2_HPP
# if !defined(SLOT_HPP)
# include <slot.hpp>
# endif
# if !defined(L4GREND_HPP)
# include <l4grend.hpp>
# endif
# if !defined(L4GAUGE_HPP)
# include <l4gauge.hpp>
# endif
# if !defined(BTL4GAUG_HPP)
# include <btl4gaug.hpp>
# endif
# if !defined(HEAT_HPP)
# include <heat.hpp>
# endif
// (see btl4gaug.hpp -- <powersub.hpp> intentionally not pulled in; the
// composite gauges reference subsystems by pointer/attribute, not by type.)
//
// Reconstruction type: the original referenced an "AttributeAccessor" handle
// (a small object that samples one named subsystem attribute). Only its
// address is used here (it is immediately reinterpreted as an Entity*), so an
// opaque forward declaration is sufficient for this translation unit.
//
class AttributeAccessor;
//#######################################################################
// SeekVoltageGraph -- the energy-weapon / myomer "seek voltage" response
// graph on the engineering detail pages (the "POWER" box).
// @004c6798 ctor / @004c68ac dtor / @004c6920 BecameActive / @004c6934 Execute.
// vtable PTR_FUN_0051a1fc. Resolves the four SeekVoltage attribute
// POINTERS off the weapon subsystem (FUN_0041bfc0 returns subsystem+offset:
// "CurrentSeekVoltageIndex" / "MinSeekVoltageIndex" / "MaxSeekVoltageIndex"
// / "SeekVoltage") and plots the subsystem's voltage-response curve
// (vtbl slot 15 sampler: Emitter @004bb42c / Myomers @004b8f94) over the
// top data box (0x97,0x80)-(0x17d,0x13b): x = response(v)*230 (0..1
// normalised sqrt response), y = v/12000*187 (voltage axis), with per-gear
// tick marks (the current gear drawn as a full L) and, when draw_cursor,
// a live 8x8 XOR cursor at the subsystem's live voltage. When the
// subsystem is destroyed (simulationState@0x40==1) it shows a centred
// "destroyed" bitmap instead. Its Execute's full-box CLEAR (@004c6be4)
// is what erases the sibling eng pages' stale pixels on the shared Eng
// bit-plane -- the widget IS the top-box eraser (Gitea #10 finding A).
//#######################################################################
class SeekVoltageGraph :
public GraphicGauge
{
public:
SeekVoltageGraph( // @004c6798
GaugeRate rate, ModeMask mode_mask, L4GaugeRenderer *renderer,
int graphics_port_number, Entity *subsystem,
AttributeAccessor *seek_voltage_pointer,
const char *destroyed_image, Logical draw_cursor,
const char *identification_string);
~SeekVoltageGraph(); // @004c68ac
Logical TestInstance() const;
void BecameActive(); // @004c6920
void Execute(); // @004c6934
protected:
void ClearGraph(); // @004c6be4 (full-box erase)
void DrawTicks(); // @004c6c6c (per-gear ticks, XOR)
void DrawCursorBox(); // @004c6c30 (8x8 cursor, XOR)
char *destroyedImage; // @0x90 this[0x24]
int *currentSeekIndexPtr; // @0x94 this[0x25] attr ptr (subsys+off)
int *minSeekIndexPtr; // @0x98 this[0x26] attr ptr
int *maxSeekIndexPtr; // @0x9C this[0x27] attr ptr
Scalar *seekVoltageTablePtr; // @0xA0 this[0x28] attr ptr (array base)
Scalar *liveVoltage; // @0xA4 this[0x29] the ctor's
// seek_voltage_pointer ("OutputVoltage"
// attr ptr / cluster seekValue cache) --
// Execute derefs it for the live cursor
Subsystem *subsystem; // @0xA8 this[0x2A]
Scalar previousVoltage; // @0xAC this[0x2B] cached response at
// 12000 V (9999 sentinel = force replot)
Scalar xScale; // @0xB0 this[0x2C] =230.0f
Scalar yScale; // @0xB4 this[0x2D] =187.0f
int destroyedShown; // @0xB8 this[0x2E]
Logical drawCursor; // @0xBC this[0x2F]
int cursorX; // @0xC0 this[0x30] (-1 = no cursor drawn)
int cursorY; // @0xC4 this[0x31]
int tickIndexShown; // @0xC8 this[0x32] gear index the tick
// highlight was last drawn at
};
//#######################################################################
// ConfigMapGauge -- the joystick / config-manager (control-mapper) state
// lamp. @004c6d80 ctor / @004c6e54 dtor / @004c6ee0 SetColor /
// @004c6ef4 BecameActive / @004c6f1c Execute. vtable PTR_FUN_0051a1b8.
// Owns a base joystick bitmap ("btjoy.pcc") plus four config-state pixmaps
// (cm_off/cm_other/cm_only/cm_both .pcc) selected from a 4-entry table
// (DAT_00518eb8) driven by the control-mapper state. Named "ConfigMap".
//#######################################################################
class ConfigMapGauge :
public GraphicGauge
{
public:
ConfigMapGauge( // @004c6d80
GaugeRate, ModeMask, L4GaugeRenderer *, int graphics_port_number,
int x, int y, Entity *subsystem, const char *identification_string);
~ConfigMapGauge(); // @004c6e54
Logical TestInstance() const;
void SetColor(int color); // @004c6ee0 this[0x25]
void BecameActive(); // @004c6ef4
void Execute(); // @004c6f1c
protected:
Entity *subsystem; // @0x90 this[0x24]
int color; // @0x94 this[0x25]
char *joystickImage; // @0x98 this[0x26] "btjoy.pcc"
char *stateImage[4]; // @0x9C this[0x27..0x2A]
int previousState[4]; // @0xAC this[0x2B..0x2E]
Logical dirty; // @0xBC this[0x2F]
};
//#######################################################################
// Two small OneOfSeveral subclasses that drive the selected frame from a
// subsystem value through a file-private GaugeConnection (the same
// connection classes declared in btl4gaug.cpp).
// AnimatedSubsystemLamp @004c70a4 (vtable 0051a174) -- connection @004c3134
// AnimatedSourceLamp @004c7160 (vtable 0051a130) -- connection @004c31ec
// Both chain OneOfSeveral::OneOfSeveral (@004c4d88, fromImageStrip=1) and
// share dtor FUN_004c4e7c. Used for the cooling-loop / power-source lamps.
// (Class names best-effort; the gauge is generic and reused with the
// instance strings "CoolingLoop" and "PowerSource".)
//#######################################################################
class AnimatedSubsystemLamp : // (best-effort)
public OneOfSeveral
{
public:
AnimatedSubsystemLamp( // @004c70a4
GaugeRate, ModeMask, L4GaugeRenderer *, int,
int x, int y, const char *image, int columns, int rows,
void *subsystem, const char *identification_string);
~AnimatedSubsystemLamp(); // @004c7134
protected:
int selected; // @0xAC this[0x2B] (connection dst)
};
class AnimatedSourceLamp : // (best-effort)
public OneOfSeveral
{
public:
AnimatedSourceLamp( // @004c7160
GaugeRate, ModeMask, L4GaugeRenderer *, int,
int x, int y, const char *image, int columns, int rows,
void *source, const char *identification_string);
~AnimatedSourceLamp(); // @004c71f0
protected:
int selected; // @0xAC this[0x2B]
};
//#######################################################################
// ScalarBarGauge -- a generator-voltage bar (derives from the MUNGA L4 bar
// primitive @00472ef0). Two ctors:
// @004c721c (vtable 0051a0e4) adds an "AltId" connection (@004c3288)
// @004c72ac (same vtable) adds a plain GaugeConnectionDirectOf<Scalar>
// (@00474855)
// Both share dtor FUN_004c733c (chains the bar dtor @00472fb4). Used with
// the strings "GeneratorVoltage(slotOf)" / "GeneratorVoltage(scalar)".
//#######################################################################
// 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:
// @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);
// @004c72ac -- the plain-Scalar variant (a DIRECT Scalar* value source, a
// GaugeConnectionDirectOf<Scalar> instead of the GeneratorVoltageConnection).
// GeneratorCluster is its caller. Disambiguated from the void* overload by
// the Scalar* first arg (exact match here, std-conversion to void*).
ScalarBarGauge( // @004c72ac
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,
Scalar *value_source, const char *identification_string);
~ScalarBarGauge(); // @004c733c
};
//#######################################################################
// GeneratorCluster -- the generator read-out panel. @004c7368 Make /
// @004c746c ctor / @004c7778 dtor. vtable PTR_FUN_0051a0a0. A GraphicGauge
// that owns five child gauges, parented to its own graphics port:
// VertTwoPartBar (temperature) this[0x26]
// ScalarBarGauge (voltage 0..12kV) this[0x27]
// BitMapInverseWipe/Leak (coolant leak) this[0x28]
// TwoState x2 (status lamps) this[0x29],this[0x2A]
// Reads CurrentTemperature/DegradationTemperature/FailureTemperature/
// CoolantMassLeakRate/OutputVoltage attribute indices off the subsystem.
// Make resolves the named subsystem ("GeneratorCluster") via FindSubObject;
// warns "Subsystem <name> not found".
//#######################################################################
class GeneratorCluster :
public GraphicGauge
{
public:
// gauge wave P2: registered "GeneratorCluster" (engineering buttons 9-12,
// GeneratorA..D). Corrected ctor param order == binary FUN_004c746c; only
// the dtor is overridden (Execute/BecameActive/TestInstance inherited).
static MethodDescription methodDescription;
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004c7368
GeneratorCluster( // @004c746c (BINARY param order)
ModeMask, L4GaugeRenderer *, int owner_ID, int graphics_port_number,
int x, int y, Subsystem *subsystem,
const char *background_image, int extra_color,
const char *temp_tile, int temp_bg_color, int temp_fill_color,
const char *voltage_tile, int voltage_fg_color,
const char *leak_image, int leak_color_b,
const char *lampA_image, const char *lampB_image,
int lamp_on_color, int lamp_off_color,
const char *identification_string);
~GeneratorCluster(); // @004c7778
// A container panel MUST override BecameActive + Execute: the engine base
// Gauge::Execute is Fail("not overridden")->abort (GAUGE.cpp:598), and the
// default BecameActive self-inactivates. The panel draws its static
// background pixmap; the 5 self-registered child gauges draw the dynamic
// content. (The decode's "only the dtor is overridden" was wrong: the
// 1995 base Gauge::Execute was a no-op, the 2007 engine's aborts.)
void BecameActive();
void Execute();
protected:
char *backgroundImage; // @0x90 this[0x24] interned .pcc (pixelMap8Bin AddRef'd)
int secondaryColor; // @0x94 this[0x25] = leak colorB (stored, unread here)
GraphicGauge
*temperatureBar, // @0x98 this[0x26] VertTwoPartBar
*voltageBar, // @0x9C this[0x27] ScalarBarGauge (@004c72ac variant)
*leakGauge, // @0xA0 this[0x28] BitMapInverseWipe
*lampA, // @0xA4 this[0x29] TwoState
*lampB; // @0xA8 this[0x2A] TwoState
Subsystem *subsystem; // @0xAC this[0x2B]
int _reserved0xB0; // @0xB0 this[0x2C] (trailing pad -> sizeof 0xB4)
};
//#######################################################################
// PrepEngrScreen (config keyword "prepEngr") -- the per-engineering-screen
// STATIC LABEL overlay. @004c7b30 Make / @004c7bf0 ctor / @004c7d14 dtor /
// @004c7e48 BecameActive. vtable PTR_FUN_0051a06c.
//
// A GraphicGaugeBackground (paint-on-activation, NOT an Execute gauge -- the
// same base/vtable shape as the engine's BackgroundBitmap: only the dtor +
// BecameActive slots are overridden). Interns 7 status .pcc's (font + 6
// labels) and, when its MFD-Eng screen (1..12) activates, paints the labels
// for the ONE subsystem whose auxScreenNumber == this screen, dispatched by
// the subsystem's ClassID. Was a MISLABELED stub (base Gauge, Execute, and
// mech/screenNumber SWAPPED) with no methodDescription -> "prepEngr" was
// parse-skipped (12 CFG calls never built).
//#######################################################################
class PrepEngrScreen :
public GraphicGaugeBackground
{
public:
static MethodDescription methodDescription; // "prepEngr"
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004c7b30
PrepEngrScreen( // @004c7bf0
ModeMask, L4GaugeRenderer *, unsigned int owner_ID,
int graphics_port_number, Entity *mech, int screen_number,
const char *img0/*font*/, const char *img1, const char *img2,
const char *img3, const char *img4, const char *img5,
const char *img6, const char *identification_string = "PrepEngr");
~PrepEngrScreen(); // @004c7d14
void BecameActive(); // @004c7e48 (the paint slot -- NOT Execute)
protected:
int screenNumber; // @0x6C this[0x1B] (FIX: was mech)
Entity *mech; // @0x70 this[0x1C] (FIX: was screenNumber)
char *statusImage[7]; // @0x74 this[0x1D..0x23] (interned .pcc names)
// sizeof == 0x90 (Make alloc); no offset locks (2007 GraphicGaugeBackground
// base not byte-identical; every read is via named members / safe accessors).
};
//#######################################################################
// SubsystemCluster family -- the big composite panels. Each is a
// GraphicGauge that builds a dozen child gauges into one cockpit instrument.
//
// SubsystemCluster @004c8140 (vtable 0051a020) -- base "engineering"
// panel: HorizTwoPartBar + cooling/power loops + generator voltage +
// OneOfSeveralInt + OneOfSeveralStates + 2x VertTwoPartBar + LeakGauge
// + BackgroundBitmap. Uses the btXXloop / btXbus / evolt / btecmode /
// eleak palette files. Reads InputVoltage/HeatSink/CurrentTemperature/
// DegradationTemperature/FailureTemperature attributes.
//
// HeatSinkCluster @004c8a6c (vtable 00519fd4) : SubsystemCluster
// adds 4 failure-annunciator TwoStates (btehfail/btepfail/btesfail)
// and a NumericDisplayScalar. Execute @004c8db0 scales this[0x35] by
// _DAT_004c8df0 into the numeric read-out.
//
// WeaponCluster @004c8fc4 (vtable 00519f38) : SubsystemCluster
// adds a SegmentArc270 (recharge dial, 0..360) + a ConfigMapGauge.
// Make-time warns "WeaponCluster missing <name>". Reads "PercentDone".
// Execute @004c9290 toggles a warning lamp when this[0x36] > _DAT_004c92e0.
//
// EnergyWeaponCluster @004c93b0 (vtable 00519ee8) : WeaponCluster
// adds a SeekVoltageGraph ("EngrGraph", edestryd.pcc) and a
// seek-step OneOfSeveralInt (bteseek.pcc, subsys+0x3F0).
// BallisticWeaponCluster @004c9558 (vtable 00519e98) : WeaponCluster
// adds 2x NumericDisplayInteger (ammo), jam/fire TwoStates
// (btejam/btefire), NumericDisplayScalarTwoState, an eject
// BitMapInverseWipeScalar (bteejtm) reading subsys+0x3F8, plus a
// GraphicsViewRecord erase tracker (this[0x3F]). Execute @004c9a38
// tracks weaponAlarm==5 (Jammed) and the ammo-bin link (+0x43C).
//#######################################################################
class SubsystemCluster :
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
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
*generatorVoltageBar, // @0x94 this[0x25] ScalarBarGauge (evolt)
*temperatureBar, // @0x98 this[0x26] HorizTwoPartBar
*coolingLoopA, // @0x9C this[0x27] AnimatedSubsystemLamp
*coolingLoopB, // @0xA0 this[0x28]
*powerSourceA, // @0xA4 this[0x29]
*powerSourceB, // @0xA8 this[0x2A]
*vertBarA, // @0xAC this[0x2B] VertTwoPartBar
*vertBarB, // @0xB0 this[0x2C]
*modeLamp, // @0xB4 this[0x2D] OneOfSeveralInt
*stateLamp, // @0xB8 this[0x2E] OneOfSeveralStates
*leakGauge; // @0xBC this[0x2F] LeakGauge
Subsystem *subsystem; // @0xC0 this[0x30]
// POLARITY CORRECTED (PPC-dial fix, 2026-07-12): the binary's
// *(subsystem+0x40)==1 means the subsystem FAILED -- it lights the
// destroyed-X TwoStates (engine TwoState draws bright on NONZERO) and
// selects the dead-panel look (GetDrawState 1 = black fill). The old
// name `operating` had it backwards, inverting every consumer.
Logical failedState; // @0xC4 this[0x31] 1 = subsystem destroyed
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:
Subsystem *failSubsystem; // @0xCC this[0x33]
Logical failFlag; // @0xD0 this[0x34]
Scalar heatLoad; // @0xD4 this[0x35]
Scalar heatLoadScaled; // @0xD8 this[0x36]
GraphicGauge
*heatFailLamp, // @0xDC this[0x37] TwoState
*hsFailLamp, // @0xE0 this[0x38] TwoState (btehfail)
*powerFailLamp, // @0xE4 this[0x39] TwoState (btepfail)
*structFailLamp, // @0xE8 this[0x3A] TwoState (btesfail)
*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
void DrawWarningLamp(int color); // @004c932c
protected:
char *clusterImage; // @0xCC this[0x33]
GraphicGauge *rechargeArc; // @0xD0 this[0x34] SegmentArc270
ConfigMapGauge *configMap; // @0xD4 this[0x35]
Scalar percentDone; // @0xD8 this[0x36] (connection dst)
int warningCenterX; // @0xDC this[0x37]
int warningCenterY; // @0xE0 this[0x38]
int warningState; // @0xE4 this[0x39]
const char *diagWeaponName; // PORT diagnostic (appended; clusters are plain-new)
};
class EnergyWeaponCluster : // @004c93b0
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]
GraphicGauge *seekStepLamp; // @0xEC this[0x3B] OneOfSeveralInt
};
class BallisticWeaponCluster : // @004c9558
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
Logical TestInstance() const; // @004c9adc
protected:
Logical jammed; // @0xE8 this[0x3A]
Logical firing; // @0xEC this[0x3B]
Logical reloading; // @0xF0 this[0x3C]
int reloadStartTime; // @0xF4 this[0x3D]
Scalar reloadSeconds; // @0xF8 this[0x3E]
GraphicsViewRecord
*ammoErase; // @0xFC this[0x3F]
GraphicGauge
*ammoNumeric, // @0x100 this[0x40] NumericDisplayScalarTwoState
*destroyedLamp, // @0x104 this[0x41] TwoState
*jamLamp, // @0x108 this[0x42] TwoState (btejam)
*fireLamp, // @0x10C this[0x43] TwoState (btefire)
*ejectWipe, // @0x110 this[0x44] BitMapInverseWipeScalar
*ammoCountA, // @0x114 this[0x45] 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