diff --git a/emulator/render-bridge/gauge-ab/grab.ps1 b/emulator/render-bridge/gauge-ab/grab.ps1 index bb743e4f..d542b54f 100644 --- a/emulator/render-bridge/gauge-ab/grab.ps1 +++ b/emulator/render-bridge/gauge-ab/grab.ps1 @@ -1,52 +1,54 @@ -param( - [Parameter(Mandatory=$true)][string]$Out, - [string]$Match = "DOSBox-X" -) - -Add-Type @" -using System; -using System.Runtime.InteropServices; -public class W { - [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); - [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r); - [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h); - [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h); - [DllImport("user32.dll", CharSet=CharSet.Auto)] public static extern int GetWindowText(IntPtr h, System.Text.StringBuilder s, int n); - [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr p); - public delegate bool EnumProc(IntPtr h, IntPtr p); - [StructLayout(LayoutKind.Sequential)] public struct RECT { public int L, T, R, B; } -} -"@ - -$found = @() -$cb = [W+EnumProc]{ - param($h, $p) - if ([W]::IsWindowVisible($h)) { - $sb = New-Object System.Text.StringBuilder 512 - [void][W]::GetWindowText($h, $sb, 512) - $t = $sb.ToString() - if ($t -like "*$Match*") { $script:found += ,@($h, $t) } - } - return $true -} -[void][W]::EnumWindows($cb, [IntPtr]::Zero) - -if ($found.Count -eq 0) { Write-Output "NO-WINDOW"; exit 1 } - -Add-Type -AssemblyName System.Drawing -$i = 0 -foreach ($f in $found) { - $h = $f[0]; $title = $f[1] - $r = New-Object W+RECT - [void][W]::GetWindowRect($h, [ref]$r) - $w = $r.R - $r.L; $ht = $r.B - $r.T - if ($w -le 0 -or $ht -le 0) { continue } - $bmp = New-Object System.Drawing.Bitmap $w, $ht - $g = [System.Drawing.Graphics]::FromImage($bmp) - $g.CopyFromScreen($r.L, $r.T, 0, 0, (New-Object System.Drawing.Size $w, $ht)) - $path = if ($found.Count -eq 1) { $Out } else { $Out -replace '\.png$', "_$i.png" } - $bmp.Save($path, [System.Drawing.Imaging.ImageFormat]::Png) - $g.Dispose(); $bmp.Dispose() - Write-Output "SAVED $path ${w}x${ht} [$title]" - $i++ -} +param( + [Parameter(Mandatory=$true)][string]$Out, + [string]$Match = "DOSBox-X" +) + +Add-Type @" +using System; +using System.Runtime.InteropServices; +public class W { + [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); + [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r); + [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h); + [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h); + [DllImport("user32.dll", CharSet=CharSet.Auto)] public static extern int GetWindowText(IntPtr h, System.Text.StringBuilder s, int n); + [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr p); + public delegate bool EnumProc(IntPtr h, IntPtr p); + [StructLayout(LayoutKind.Sequential)] public struct RECT { public int L, T, R, B; } +} +"@ + +$found = @() +$cb = [W+EnumProc]{ + param($h, $p) + if ([W]::IsWindowVisible($h)) { + $sb = New-Object System.Text.StringBuilder 512 + [void][W]::GetWindowText($h, $sb, 512) + $t = $sb.ToString() + if ($t -like "*$Match*") { $script:found += ,@($h, $t) } + } + return $true +} +[void][W]::EnumWindows($cb, [IntPtr]::Zero) + +if ($found.Count -eq 0) { Write-Output "NO-WINDOW"; exit 1 } + +Add-Type -AssemblyName System.Drawing +$i = 0 +foreach ($f in $found) { + $h = $f[0]; $title = $f[1] + [void][W]::SetForegroundWindow($h) + Start-Sleep -Milliseconds 1200 + $r = New-Object W+RECT + [void][W]::GetWindowRect($h, [ref]$r) + $w = $r.R - $r.L; $ht = $r.B - $r.T + if ($w -le 0 -or $ht -le 0) { continue } + $bmp = New-Object System.Drawing.Bitmap $w, $ht + $g = [System.Drawing.Graphics]::FromImage($bmp) + $g.CopyFromScreen($r.L, $r.T, 0, 0, (New-Object System.Drawing.Size $w, $ht)) + $path = if ($found.Count -eq 1) { $Out } else { $Out -replace '\.png$', "_$i.png" } + $bmp.Save($path, [System.Drawing.Imaging.ImageFormat]::Png) + $g.Dispose(); $bmp.Dispose() + Write-Output "SAVED $path ${w}x${ht} [$title]" + $i++ +} diff --git a/restoration/source410/BT_L4/BTL4GAU2.CPP b/restoration/source410/BT_L4/BTL4GAU2.CPP index 0b380084..887fa462 100644 --- a/restoration/source410/BT_L4/BTL4GAU2.CPP +++ b/restoration/source410/BT_L4/BTL4GAU2.CPP @@ -1927,6 +1927,34 @@ SubsystemCluster::SubsystemCluster( } } + // + // The PANEL TITLE BANNER (299x26): the authored auxScreenLabel .pcc -- + // "SENSOR CLUSTER" / "MYOMERS" / "ERMED LASER RANGE 500M" / the weapon + // names. Cached on PoweredSubsystem at ctor time (its resource dies + // with the Mech ctor's stream buffer). The banner sits at the TOP of + // the quadrant; BackgroundBitmap places by (left, BOTTOM), so the row + // is the panel origin plus the quadrant height less the banner. + // + titleBanner = NULL; + if (subsystem_in != NULL + && subsystem_in->IsDerivedFrom(PoweredSubsystem::ClassDerivations)) + { + const char *title = + ((PoweredSubsystem *)subsystem_in)->GetAuxScreenLabel(); + if (title != NULL && *title != '') + { + // Placement measured against the shipped framebuffer + // (the A/B rig): the banner's bottom row sits 0xb3 above the + // panel origin, inset 0x0e from its left edge. + titleBanner = new BackgroundBitmap( + mfd_mode, renderer_in, owner_ID, mfd_port, + x + 0x09, y + 0xb3, title, + 1, 0xff, 0 + ); + Register_Object(titleBanner); + } + } + //------------------------------------------------------------ // Paint the panel frame image into the MFD port. //------------------------------------------------------------ diff --git a/restoration/source410/BT_L4/BTL4GAU2.HPP b/restoration/source410/BT_L4/BTL4GAU2.HPP index 8bb1ab3e..99400c01 100644 --- a/restoration/source410/BT_L4/BTL4GAU2.HPP +++ b/restoration/source410/BT_L4/BTL4GAU2.HPP @@ -1,572 +1,573 @@ -//===========================================================================// -// 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 // -// +-> MyomerCluster // -// +-> 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 // -//===========================================================================// -// -// STAGED RECONSTRUCTION. No BTL4GAU2.HPP survived; recovered from the shipped -// binary (BTL4OPT.EXE) and re-hosted onto the authentic 1995 engine headers -// (MUNGA GAUGE/GAUGREND + MUNGA_L4 L4GAUGE) for the BC++4.52 build. -// -// 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) -// plus VehicleSubSystems::Make @004cbaf0 -// -// 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 the BINARY's byte offsets (e.g. "@0x90" == -// this[0x24]); the recompiled objects are NOT byte-locked to them. -// -// 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 -# endif -# if !defined(L4GREND_HPP) -# include -# endif -# if !defined(L4GAUGE_HPP) -# include -# endif -# if !defined(BTL4GAUG_HPP) -# include -# endif -# if !defined(HEAT_HPP) -# include -# endif - // (see btl4gaug.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 a Scalar*), 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 by NAME ("CurrentSeekVoltageIndex" / - // "MinSeekVoltageIndex" / "MaxSeekVoltageIndex" / "SeekVoltage") and plots - // the subsystem's voltage-response curve (binary 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 == 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 (or NULL) - int *minSeekIndexPtr; // @0x98 this[0x26] attr ptr (or NULL) - int *maxSeekIndexPtr; // @0x9C this[0x27] attr ptr (or NULL) - 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 - // (never NULL: ctor normalises a miss to - // the file-scope unbound cell) - 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 LinkToEntity / - // @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; - // @004c6ee0 -- the GaugeBase::LinkToEntity OVERRIDE (vtbl slot 9, +0x24), - // NOT a "SetColor": it stores the viewpoint entity into @0x94 and Execute - // gates on it. GaugeRenderer::LinkToEntity (GAUGREND.CPP:3011) broadcasts - // it to every gauge when the viewpoint binds -- THAT is what lights the - // trigger-config joystick in the shipped game. (The old "SetColor, no - // callers -> authentically dormant" claim was a mislabel.) - void LinkToEntity(Entity *entity); // @004c6ee0 writes this[0x25] - void BecameActive(); // @004c6ef4 - void Execute(); // @004c6f1c - protected: - Entity *subsystem; // @0x90 this[0x24] (a Subsystem, stored - // as the ctor's Entity* -- cast back - // through Subsystem* before use) - Entity *linkedEntity; // @0x94 this[0x25] (Execute gate) - 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. - // 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".) - // - // SHADOW-FIELD FIX (kept on re-host): 'selected' is INHERITED from - // OneOfSeveral (@0xAC). A redeclared 'int selected;' here shadowed the - // base at a higher offset -- the connection wrote the shadow while - // OneOfSeveral::Execute read the base (always 0), freezing the lamp at - // frame 0. Neither class declares its own copy. - //####################################################################### - 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 - }; - - 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 - }; - - - //####################################################################### - // ScalarBarGauge -- a generator-voltage bar (derives from the engine - // BarGraphBitMapScalar, L4GAUGE.HPP -- WipeGaugeScalar : GraphicGauge). - // Two ctors, one vtable (0051a0e4), shared dtor @004c733c: - // @004c721c "slotOf" variant -- AddConnection(GeneratorVoltageConnection - // @004c3288) feeding the inherited currentValue from the - // subsystem's resolved voltage source. - // @004c72ac plain-Scalar variant -- a GaugeConnectionDirectOf - // (engine template) from a DIRECT Scalar*. - // Used with "GeneratorVoltage(slotOf)" / "GeneratorVoltage(scalar)". - // - // 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). - // - // BC++4.52 NOTE: the void* / Scalar* 15th-argument overload pair is - // ambiguous for a literal 0/NULL argument -- every call site must pass a - // TYPED pointer. - //####################################################################### - class ScalarBarGauge : - public BarGraphBitMapScalar - { - public: - ScalarBarGauge( // @004c721c (slotOf variant) - 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( // @004c72ac (plain-Scalar variant) - 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 (config keyword - // "GeneratorCluster": engineering buttons 9-12, GeneratorA..D). - // @004c7368 Make / @004c746c ctor / @004c7778 dtor. vtable PTR_FUN_0051a0a0. - // A GraphicGauge that owns five child gauges, parented to its own 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] - // Make resolves the named generator via FindSubsystem; warns - // "Subsystem not found". - //####################################################################### - class GeneratorCluster : - public GraphicGauge - { - public: - // Registered config primitive "GeneratorCluster" (15 params; NO leading - // rate token -- the panel rate is hard-wired 0xFFFF). - static MethodDescription methodDescription; - static Logical Make(int, Vector2DOf, 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") (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. - void BecameActive(); - void Execute(); - protected: - char *backgroundImage; // @0x90 this[0x24] interned .pcc (AddRef'd) - int secondaryColor; // @0x94 this[0x25] = leak colorB (stored, unread) - 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 -> binary 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 aux screen == this screen, - // dispatched by the subsystem's ClassID. - // (FIX kept from the decode: mech/screenNumber were SWAPPED in the first - // reconstruction, and the missing methodDescription parse-skipped all 12 - // CFG lines.) - //####################################################################### - class PrepEngrScreen : - public GraphicGaugeBackground - { - public: - static MethodDescription methodDescription; // "prepEngr" - static Logical Make(int, Vector2DOf, 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] - Entity *mech; // @0x70 this[0x1C] - char *statusImage[7]; // @0x74 this[0x1D..0x23] (interned .pcc names) - // binary sizeof == 0x90 (Make alloc); no offset locks (every read is - // via named members). - }; - - - //####################################################################### - // 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 art. - // - // HeatSinkCluster @004c8a6c (vtable 00519fd4) : SubsystemCluster - // adds 4 failure-annunciator TwoStates (btehfail/btepfail/btesfail) - // and a NumericDisplayScalar. Execute @004c8db0 scales heatLoad by - // 100 (_DAT_004c8df0) into the numeric read-out. - // - // MyomerCluster @004c8df4 (vtable 00519f88) : SubsystemCluster - // adds a SeekVoltageGraph ("EngrGraph") + seek-step OneOfSeveralInt. - // - // WeaponCluster @004c8fc4 (vtable 00519f38) : SubsystemCluster - // adds a SegmentArc270 (recharge dial, 0..360) + a ConfigMapGauge. - // Reads "PercentDone". Execute @004c9290 toggles the warning lamp - // past _DAT_004c92e0 (0.99). - // - // EnergyWeaponCluster @004c93b0 (vtable 00519ee8) : WeaponCluster - // adds a SeekVoltageGraph ("EngrGraph", edestryd.pcc) and a - // seek-step OneOfSeveralInt (bteseek.pcc). - // BallisticWeaponCluster @004c9558 (vtable 00519e98) : WeaponCluster - // adds 2x NumericDisplayInteger (ammo), jam/fire TwoStates - // (btejam/btefire), NumericDisplayScalarTwoState, an eject - // BitMapInverseWipeScalar (bteejtm), plus a GraphicsViewRecord - // erase tracker (this[0x3F]). - //####################################################################### - class SubsystemCluster : - public GraphicGauge - { - public: - // @004c8140. Binary param order (rate/mode are hardcoded 0xFFFF / - // ModeAlwaysActive 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(); // (re-host addition: forces the first repaint) - 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] AnimatedSourceLamp - *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, kept on re-host): the binary's - // *(subsystem+0x40)==1 means the subsystem FAILED -- it lights the - // destroyed-X TwoStates (the 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) - void DrawPanelFrame(int color); // @004c89c4 - void ReleaseChildren(); // @004c8820 - void SetChildrenEnable(int enable); // @004c8a28 - public: - int GetDrawState(); // @004c8990 (operational-state virtual, vtbl+0x48) - }; - - 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] (connection dst) - 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 a GeneratorVoltageConnection (writes seekValue) + a seek-step - // OneOfSeveralInt (bteseek.pcc). 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 - virtual void DrawWarningLamp(int on); // @004c932c (virtual: BallisticWeaponCluster overrides) - protected: - char *clusterImage; // @0xCC this[0x33] (interned) - 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] - }; - - 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 - void DrawWarningLamp(int on); // @004c9b50 (override: dot + ammo colour swap) - 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] (bring-up NULL) - 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 (NULL) - *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 displayable subsystem builds the right cluster (HeatSink/Myomer/ - // Energy/Ballistic) onto one of 12 auxiliary MFD positions. 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 position, - Entity *entity, GaugeRenderer *gauge_renderer); - }; - -#endif +//===========================================================================// +// 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 // +// +-> MyomerCluster // +// +-> 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 // +//===========================================================================// +// +// STAGED RECONSTRUCTION. No BTL4GAU2.HPP survived; recovered from the shipped +// binary (BTL4OPT.EXE) and re-hosted onto the authentic 1995 engine headers +// (MUNGA GAUGE/GAUGREND + MUNGA_L4 L4GAUGE) for the BC++4.52 build. +// +// 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) +// plus VehicleSubSystems::Make @004cbaf0 +// +// 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 the BINARY's byte offsets (e.g. "@0x90" == +// this[0x24]); the recompiled objects are NOT byte-locked to them. +// +// 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 +# endif +# if !defined(L4GREND_HPP) +# include +# endif +# if !defined(L4GAUGE_HPP) +# include +# endif +# if !defined(BTL4GAUG_HPP) +# include +# endif +# if !defined(HEAT_HPP) +# include +# endif + // (see btl4gaug.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 a Scalar*), 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 by NAME ("CurrentSeekVoltageIndex" / + // "MinSeekVoltageIndex" / "MaxSeekVoltageIndex" / "SeekVoltage") and plots + // the subsystem's voltage-response curve (binary 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 == 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 (or NULL) + int *minSeekIndexPtr; // @0x98 this[0x26] attr ptr (or NULL) + int *maxSeekIndexPtr; // @0x9C this[0x27] attr ptr (or NULL) + 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 + // (never NULL: ctor normalises a miss to + // the file-scope unbound cell) + 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 LinkToEntity / + // @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; + // @004c6ee0 -- the GaugeBase::LinkToEntity OVERRIDE (vtbl slot 9, +0x24), + // NOT a "SetColor": it stores the viewpoint entity into @0x94 and Execute + // gates on it. GaugeRenderer::LinkToEntity (GAUGREND.CPP:3011) broadcasts + // it to every gauge when the viewpoint binds -- THAT is what lights the + // trigger-config joystick in the shipped game. (The old "SetColor, no + // callers -> authentically dormant" claim was a mislabel.) + void LinkToEntity(Entity *entity); // @004c6ee0 writes this[0x25] + void BecameActive(); // @004c6ef4 + void Execute(); // @004c6f1c + protected: + Entity *subsystem; // @0x90 this[0x24] (a Subsystem, stored + // as the ctor's Entity* -- cast back + // through Subsystem* before use) + Entity *linkedEntity; // @0x94 this[0x25] (Execute gate) + 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. + // 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".) + // + // SHADOW-FIELD FIX (kept on re-host): 'selected' is INHERITED from + // OneOfSeveral (@0xAC). A redeclared 'int selected;' here shadowed the + // base at a higher offset -- the connection wrote the shadow while + // OneOfSeveral::Execute read the base (always 0), freezing the lamp at + // frame 0. Neither class declares its own copy. + //####################################################################### + 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 + }; + + 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 + }; + + + //####################################################################### + // ScalarBarGauge -- a generator-voltage bar (derives from the engine + // BarGraphBitMapScalar, L4GAUGE.HPP -- WipeGaugeScalar : GraphicGauge). + // Two ctors, one vtable (0051a0e4), shared dtor @004c733c: + // @004c721c "slotOf" variant -- AddConnection(GeneratorVoltageConnection + // @004c3288) feeding the inherited currentValue from the + // subsystem's resolved voltage source. + // @004c72ac plain-Scalar variant -- a GaugeConnectionDirectOf + // (engine template) from a DIRECT Scalar*. + // Used with "GeneratorVoltage(slotOf)" / "GeneratorVoltage(scalar)". + // + // 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). + // + // BC++4.52 NOTE: the void* / Scalar* 15th-argument overload pair is + // ambiguous for a literal 0/NULL argument -- every call site must pass a + // TYPED pointer. + //####################################################################### + class ScalarBarGauge : + public BarGraphBitMapScalar + { + public: + ScalarBarGauge( // @004c721c (slotOf variant) + 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( // @004c72ac (plain-Scalar variant) + 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 (config keyword + // "GeneratorCluster": engineering buttons 9-12, GeneratorA..D). + // @004c7368 Make / @004c746c ctor / @004c7778 dtor. vtable PTR_FUN_0051a0a0. + // A GraphicGauge that owns five child gauges, parented to its own 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] + // Make resolves the named generator via FindSubsystem; warns + // "Subsystem not found". + //####################################################################### + class GeneratorCluster : + public GraphicGauge + { + public: + // Registered config primitive "GeneratorCluster" (15 params; NO leading + // rate token -- the panel rate is hard-wired 0xFFFF). + static MethodDescription methodDescription; + static Logical Make(int, Vector2DOf, 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") (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. + void BecameActive(); + void Execute(); + protected: + char *backgroundImage; // @0x90 this[0x24] interned .pcc (AddRef'd) + int secondaryColor; // @0x94 this[0x25] = leak colorB (stored, unread) + 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 -> binary 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 aux screen == this screen, + // dispatched by the subsystem's ClassID. + // (FIX kept from the decode: mech/screenNumber were SWAPPED in the first + // reconstruction, and the missing methodDescription parse-skipped all 12 + // CFG lines.) + //####################################################################### + class PrepEngrScreen : + public GraphicGaugeBackground + { + public: + static MethodDescription methodDescription; // "prepEngr" + static Logical Make(int, Vector2DOf, 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] + Entity *mech; // @0x70 this[0x1C] + char *statusImage[7]; // @0x74 this[0x1D..0x23] (interned .pcc names) + // binary sizeof == 0x90 (Make alloc); no offset locks (every read is + // via named members). + }; + + + //####################################################################### + // 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 art. + // + // HeatSinkCluster @004c8a6c (vtable 00519fd4) : SubsystemCluster + // adds 4 failure-annunciator TwoStates (btehfail/btepfail/btesfail) + // and a NumericDisplayScalar. Execute @004c8db0 scales heatLoad by + // 100 (_DAT_004c8df0) into the numeric read-out. + // + // MyomerCluster @004c8df4 (vtable 00519f88) : SubsystemCluster + // adds a SeekVoltageGraph ("EngrGraph") + seek-step OneOfSeveralInt. + // + // WeaponCluster @004c8fc4 (vtable 00519f38) : SubsystemCluster + // adds a SegmentArc270 (recharge dial, 0..360) + a ConfigMapGauge. + // Reads "PercentDone". Execute @004c9290 toggles the warning lamp + // past _DAT_004c92e0 (0.99). + // + // EnergyWeaponCluster @004c93b0 (vtable 00519ee8) : WeaponCluster + // adds a SeekVoltageGraph ("EngrGraph", edestryd.pcc) and a + // seek-step OneOfSeveralInt (bteseek.pcc). + // BallisticWeaponCluster @004c9558 (vtable 00519e98) : WeaponCluster + // adds 2x NumericDisplayInteger (ammo), jam/fire TwoStates + // (btejam/btefire), NumericDisplayScalarTwoState, an eject + // BitMapInverseWipeScalar (bteejtm), plus a GraphicsViewRecord + // erase tracker (this[0x3F]). + //####################################################################### + class SubsystemCluster : + public GraphicGauge + { + public: + // @004c8140. Binary param order (rate/mode are hardcoded 0xFFFF / + // ModeAlwaysActive 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(); // (re-host addition: forces the first repaint) + void Execute(); // @004c88e4 + protected: + BackgroundBitmap + *background; + BackgroundBitmap *titleBanner; // the authored 299x26 panel title // @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] AnimatedSourceLamp + *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, kept on re-host): the binary's + // *(subsystem+0x40)==1 means the subsystem FAILED -- it lights the + // destroyed-X TwoStates (the 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) + void DrawPanelFrame(int color); // @004c89c4 + void ReleaseChildren(); // @004c8820 + void SetChildrenEnable(int enable); // @004c8a28 + public: + int GetDrawState(); // @004c8990 (operational-state virtual, vtbl+0x48) + }; + + 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] (connection dst) + 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 a GeneratorVoltageConnection (writes seekValue) + a seek-step + // OneOfSeveralInt (bteseek.pcc). 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 + virtual void DrawWarningLamp(int on); // @004c932c (virtual: BallisticWeaponCluster overrides) + protected: + char *clusterImage; // @0xCC this[0x33] (interned) + 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] + }; + + 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 + void DrawWarningLamp(int on); // @004c9b50 (override: dot + ammo colour swap) + 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] (bring-up NULL) + 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 (NULL) + *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 displayable subsystem builds the right cluster (HeatSink/Myomer/ + // Energy/Ballistic) onto one of 12 auxiliary MFD positions. 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 position, + Entity *entity, GaugeRenderer *gauge_renderer); + }; + +#endif diff --git a/restoration/source410/BT_L4/GAUGE-BLOCK.NOTES.md b/restoration/source410/BT_L4/GAUGE-BLOCK.NOTES.md index e347bb21..b7d436fc 100644 --- a/restoration/source410/BT_L4/GAUGE-BLOCK.NOTES.md +++ b/restoration/source410/BT_L4/GAUGE-BLOCK.NOTES.md @@ -515,3 +515,41 @@ come from the q-strip statusImage path (the 8 qblh*.pcc typeStrings VehicleSubSystems passes to DrawStatusCells), NOT from auxScreenLabel. That is the next thread. Name bitmaps stay inert (CreateMutantPixelmap8 / LookupPlayerNameBitmap bring-up stubs). + +## 5.3.29 -- THE PANEL TITLES (94.8% identical / 91% coverage) + +The 5.3.28 pass proved the titles do NOT come from auxScreenLabel's ENG-page +blit. Reading the art settled it: `qsensors.pcc` / `qmyomers.pcc` / +`qermlas.pcc` / `qppc.pcc` / `qstrk6.pcc` are **299x26 TITLE BANNERS**, while +the `qblh0..7.pcc` strings the cfg hands vehicleSubSystems are **77x120 MECH +ICONS** (which the 5.3.28 placement fix already lit). So the label IS the +title -- it just belongs on the MFD panel, not only the ENG page. + +SubsystemCluster now builds a titleBanner child from the cached +GetAuxScreenLabel(). Placement was MEASURED against the shipped +framebuffer with the A/B rig (BackgroundBitmap places by left/BOTTOM): +x + 0x09, y + 0xb3 from the panel origin -- found by a bring-up +BT_TITLE_DY knob, then a green-pixel correlation over the title band, then +baked. The authored data behind it (dumped live): Avionics screen=5 +placement=2 label=qsensors.pcc; Myomers 6/0/qmyomers; PPC_1 1/4/qppc; +PPC_2 10/6/qppc; ERMLaser_1 4/1/qermlas; ERMLaser_2 8/6; ERMLaser_3 7/4; +SRM6_1 2/1/qstrk6; SRM6_2 9/3. + +SCORE PROGRESSION vs the shipped cockpit (same GAUGE content, same mount): + 5.3.26 birth 90.1% identical / 82% coverage + 5.3.28 authored screens 93.2% / 85% + 5.3.29 titles (rough) 92.6% / 88% + 5.3.29 titles (tuned) 94.8% / 91% <-- current +"SENSOR CLUSTER", "MYOMERS", "TYPE II 65 TONS" and both "ERMED LASER RANGE +500M" banners now render in their authored positions. + +CAPTURE GOTCHA (cost two wasted runs): the grab script copies SCREEN +pixels, so any window in front of DOSBox is what gets captured (one grab +returned a white frame, another returned an unrelated 3-D app). +grab.ps1 now SetForegroundWindow()s the target and waits 1.2 s first. + +STILL OPEN: the pilot name bitmap ("Aeolus" -- CreateMutantPixelmap8 / +LookupPlayerNameBitmap bring-up stubs), some lamp frames ("OFF x" vs the +shipped state digits -- the mode accessor stand-in), and a stray magenta +"MID/ADV" block that lands over the top-left title (a widget drawing at a +wrong port offset; next thread).