Six TUs born in one wave (4-agent re-hosting workflow from the BT411 donors + inline integration): BTL4GAUG (16 widget primitives + 5 connections, the TU anchor @004c3f6c), BTL4GAU2 (13 composite panel clusters), BTL4GAU3 (PilotList/PlayerStatus/SectorDisplay/MessageBoard/mapping group), BTL4RDR (the MapDisplay radar vs the authentic surviving header), BTL4GRND (the real renderer: L4LampManager + L4Warehouse + BuildConfigurationFile with the 19-entry BT registry chained onto the engine table). btl4.lib grows 7 -> 11 members; all 50 game TUs compile; link clean. VERIFIED LIVE: with L4GAUGE=640x480x16 the interpreter parses the full authentic L4GAUGE.CFG, Bhk1Init runs, ColorMapperArmor binds the live mech's damage zones by name (cross-chassis names take the authentic inert path), and the complete mutual missile fight runs with the cockpit stack updating from real combat -- 16/16 rounds, 138 zone hits, zero faults. Gauges-off regressions untouched. Engine bring-up deviation (documented): ParseAttribute normalizes unpublished attribute names to a shared writable zero cell -- the 1995 GaugeConnectionDirectOf ctor hard-derefs its source (first boot crashed there); widgets on unpublished names draw static zeros and light up automatically as the attribute waves publish the 1995 CFG spellings the bindings already carry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
440 lines
16 KiB
C++
440 lines
16 KiB
C++
//===========================================================================//
|
|
// File: btl4gau3.hpp //
|
|
// Project: BattleTech Brick: Gauge Renderer Manager //
|
|
// Contents: Cockpit instrument library, part 3 -- the MULTIPLAYER / TACTICAL //
|
|
// HUD displays: the scoreboard, pilot roster, per-player status //
|
|
// name-tags, the sector display and the message board. These read //
|
|
// the shared "Players" roster and the live mech roster rather than //
|
|
// a single subsystem. //
|
|
// * PlayerStatusMappingGroup -- 28-zone armour colour-tint group //
|
|
// * SectorDisplay -- grid-cell blit + dual numeric //
|
|
// * TeamStatusDisplay -- 8-row scoreboard (DEFERRED) //
|
|
// * PilotList -- 8-pilot KILLS/DEATHS roster //
|
|
// * PlayerStatus -- single-player status name-tag //
|
|
// * MessageBoard -- message / sender bitmap board //
|
|
//---------------------------------------------------------------------------//
|
|
// 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 BTL4GAU3.HPP survived; recovered from
|
|
// BTL4OPT.EXE and re-hosted onto the authentic 1995 engine headers
|
|
// (MUNGA/GAUGE.HPP + GAUGREND.HPP, MUNGA_L4/L4GAUGE.HPP). Class names from
|
|
// the per-instance identification strings near 0x51bb34:
|
|
// "SectorDisplay" 0x51bb34 "PilotList" 0x51bb4a "PlayerStatus" 0x51bb54
|
|
// "MessageBoard" 0x51bb61 "PlayerStatusMappingGroup" 0x51bdb4
|
|
// "Players" 0x51bcba/0x51bd97 (shared roster node)
|
|
//
|
|
// Translation-unit extent (BTL4.MAK: btl4gau2 -> btl4gau3 -> btl4grnd):
|
|
// first gau3 code @004c9bd0 (PlayerStatusMappingGroup builder)
|
|
// last gau3 code @004cbea0-1 (MessageBoard::Execute @004cb82c)
|
|
// btl4grnd begins @004cbea0 (BTL4GaugeRenderer ctor -- not this TU)
|
|
//
|
|
// Vtables (recovered from the ctors): SectorDisplay 0051beec,
|
|
// TeamStatusDisplay 0051bea8, PilotList 0051be64, PlayerStatus 0051be20,
|
|
// MessageBoard 0051bddc. All derive from GraphicGauge.
|
|
//
|
|
// The @0xNN member annotations are the BINARY object offsets (provenance
|
|
// only): the reconstructed engine bases are not byte-identical to the
|
|
// shipped objects, and every read in this TU is through named members.
|
|
//
|
|
|
|
#if !defined(BTL4GAU3_HPP)
|
|
# define BTL4GAU3_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
|
|
|
|
//##################### Forward Class Declarations #######################
|
|
class Player;
|
|
|
|
//
|
|
// Reconstruction alias: the binary's per-player recoloured "Pixmap" is the
|
|
// engine's 8-bit pixel map. (Only Pixmap* appears in this header / TU.)
|
|
//
|
|
typedef PixelMap8 Pixmap;
|
|
|
|
|
|
//#######################################################################
|
|
// PlayerStatusMappingGroup -- a colour-tint group of 28 ColorMapperArmor
|
|
// gauges, one per named damage zone ("dz_door"... PTR_s_dz_door_0051a240,
|
|
// 0x1C=28 entries). Built by PlayerStatus to tint a player's mech outline
|
|
// bitmap by per-zone armour damage. @004c9bd0 build / @004c9ca8 destroy /
|
|
// @004c9cf4 Execute-all / @004c9d18 SetColor-all. Each element is a
|
|
// ColorMapperArmor (btl4gaug) wired to a resolved damage-zone index.
|
|
// (palette files adpal.pcc / adpal2.pcc; name "PlayerStatusMappingGroup".)
|
|
//#######################################################################
|
|
enum { playerStatusZoneCount = 28 };
|
|
|
|
class PlayerStatusMappingGroup
|
|
{
|
|
public:
|
|
PlayerStatusMappingGroup( // @004c9bd0
|
|
GaugeRate rate,
|
|
ModeMask mode_mask,
|
|
L4GaugeRenderer *renderer,
|
|
int graphics_port_number,
|
|
Entity *mech,
|
|
int base_color_index,
|
|
const char *palette_a,
|
|
const char *palette_b,
|
|
const char *identification_string
|
|
);
|
|
~PlayerStatusMappingGroup(); // @004c9ca8
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
void
|
|
Execute(); // @004c9cf4 (run all 28)
|
|
void
|
|
SetColor(int color); // @004c9d18 (recolour all 28)
|
|
|
|
protected:
|
|
ColorMapperArmor
|
|
*zone[playerStatusZoneCount]; // this[0..0x1B]
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// SectorDisplay (config keyword "sectorDisplay") -- the radar SECTOR X/Z
|
|
// read-out on the Secondary overlay: a one-shot grid-cell background blit +
|
|
// two 3-digit NumericDisplays showing the linked mech's world sector coords
|
|
// (Round(-Z*0.01)+500, Round(X*0.01)+500 -> 100-unit sectors).
|
|
// @004c9d44 Make / @004c9e10 ctor / @004c9f94 dtor / @004ca038 BecameActive /
|
|
// @004ca068 LinkToEntity (slot 9) / @004ca07c Execute. vtable 0051beec.
|
|
// Was PROSE-ONLY (parse-skipped "sectorDisplay" line); reconstructed
|
|
// byte-verified from the disassembly + methodDescription PE-parse.
|
|
//#######################################################################
|
|
class SectorDisplay :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
static MethodDescription
|
|
methodDescription; // "sectorDisplay"
|
|
|
|
static Logical
|
|
Make( // @004c9d44
|
|
int display_port_index,
|
|
Vector2DOf<int> position,
|
|
Entity *entity,
|
|
GaugeRenderer *gauge_renderer
|
|
);
|
|
|
|
SectorDisplay( // @004c9e10 (owner folded to 0, like the siblings)
|
|
GaugeRate rate,
|
|
ModeMask mode_mask,
|
|
L4GaugeRenderer *renderer,
|
|
int graphics_port_number,
|
|
int x, int y,
|
|
const char *image,
|
|
int color,
|
|
int ok_color,
|
|
const char *identification_string
|
|
);
|
|
~SectorDisplay(); // @004c9f94
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
void
|
|
LinkToEntity(Entity *entity); // @004ca068 slot 9 -- caches the subject mech
|
|
void
|
|
BecameActive(); // @004ca038 slot 3 (non-inactivating)
|
|
void
|
|
Execute(); // @004ca07c
|
|
|
|
protected:
|
|
Entity *subject; // @0x90 LinkToEntity target (ctor=0)
|
|
char *gridImage; // @0x94 interned image name (nameCopy; blit source)
|
|
int cellWidth; // @0x98 imageWidth / 14
|
|
int gridLeft; // @0x9C cellWidth*12
|
|
int gridRight; // @0xA0 cellWidth*13 - 1
|
|
int gridHeight; // @0xA4 imageHeight
|
|
int numericColor; // @0xA8 param color (both numerics' color)
|
|
int gridColor; // @0xAC param okColor (blit color + numeric okColor)
|
|
int sectorBaseA; // @0xB0 = 500 (added to the -Z numeric)
|
|
int sectorBaseB; // @0xB4 = 500 (added to the +X numeric)
|
|
int dirty; // @0xB8 redraw flag (BecameActive=1, Execute clears)
|
|
NumericDisplay
|
|
*numericA, // @0xBC -Z sector readout
|
|
*numericB; // @0xC0 X sector readout
|
|
// Binary sizeof == 0xC4 (the Make alloc). Provenance only: the
|
|
// reconstructed GraphicGauge base is not byte-identical to 1995 and
|
|
// every read here is via named members.
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// TeamStatusDisplay -- the 8-slot multiplayer scoreboard. @004ca208 ctor /
|
|
// @004ca39c dtor / @004ca424 SetEnable / @004ca438 BecameActive /
|
|
// @004ca478 Execute. vtable 0051bea8. Each of the 8 rows owns a
|
|
// NumericDisplay pair (player number + kill count). Execute reads the
|
|
// shared "Players" node (FindByName @00403ad0, "Players" 0x51bcba), slots
|
|
// players by their player index (entity+0x1cc), draws each player's name
|
|
// bitmap / kill numeric and a selection highlight on the local player.
|
|
//
|
|
// DEFERRED: the donor reconstruction is PROSE-ONLY (no recovered bodies,
|
|
// no methodDescription, no config keyword registered) -- declaration kept
|
|
// so the binary class inventory stays visible; NO bodies exist in
|
|
// BTL4GAU3.CPP and nothing constructs it. See the deferred note there.
|
|
//#######################################################################
|
|
class TeamStatusDisplay :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
TeamStatusDisplay( // @004ca208
|
|
GaugeRate rate,
|
|
ModeMask mode_mask,
|
|
L4GaugeRenderer *renderer,
|
|
int graphics_port_number,
|
|
int x, int y,
|
|
const char *font_image,
|
|
int row_spacing,
|
|
int flags,
|
|
const char *identification_string
|
|
);
|
|
~TeamStatusDisplay(); // @004ca39c
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
void
|
|
SetEnable(Logical enable); // @004ca424 this[0x24]
|
|
void
|
|
BecameActive(); // @004ca438
|
|
void
|
|
Execute(); // @004ca478
|
|
|
|
protected:
|
|
Logical enabled; // @0x90 this[0x24]
|
|
int selectedRow; // @0x94 this[0x25] (=999)
|
|
int originX; // @0x98 this[0x26]
|
|
int originY; // @0x9C this[0x27] (param y - 0x20)
|
|
int flags; // @0xA0 this[0x28]
|
|
int rowSpacing; // @0xA4 this[0x29]
|
|
int highlightWidth; // @0xA8 this[0x2A]
|
|
struct Row { // 8 rows starting at this[0x3B]
|
|
NumericDisplay *numberDisplay; // player-number numeric
|
|
NumericDisplay *killDisplay; // kill-count numeric (flags&4)
|
|
} row[8];
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// PilotList (config keyword "pilotList") -- the Comm KILLS/DEATHS roster.
|
|
// @004ca90c Make / @004ca958 ctor / @004cab10 dtor / @004caba4 BecameActive /
|
|
// @004cabd0 Execute / @004cad70 DrawMechIcon. vtable 0051be64, binary
|
|
// sizeof 0x178. Each entry has three NumericDisplays laid out by a
|
|
// per-entry layout mode (0/1/2 -> the PE-parsed DAT_0051af88 table).
|
|
// Execute walks the pilot roster ONE slot per frame (round-robin over 8).
|
|
// Was PROSE-ONLY -> the "pilotList" line was parse-skipped and the Comm
|
|
// surface showed only the baked btcomm.pcx labels.
|
|
//#######################################################################
|
|
class PilotList :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
static MethodDescription
|
|
methodDescription; // "pilotList"
|
|
|
|
static Logical
|
|
Make( // @004ca90c
|
|
int display_port_index,
|
|
Vector2DOf<int> position,
|
|
Entity *entity,
|
|
GaugeRenderer *gauge_renderer
|
|
);
|
|
|
|
PilotList( // @004ca958 (NO x,y: positions come from DAT_0051af88)
|
|
GaugeRate rate,
|
|
ModeMask mode_mask,
|
|
L4GaugeRenderer *renderer,
|
|
int graphics_port_number,
|
|
const char *font_image,
|
|
const char *identification_string
|
|
);
|
|
~PilotList(); // @004cab10
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
void
|
|
BecameActive(); // @004caba4
|
|
void
|
|
Execute(); // @004cabd0
|
|
|
|
protected:
|
|
void
|
|
DrawMechIcon(Player *pilot, int selected); // @004cad70
|
|
// (DrawAmmoCount @004cae20 -- documented, no recovered caller.)
|
|
|
|
int currentSlot; // @0x90 this[0x24] (round-robin, =9 init)
|
|
Logical built; // @0x94 this[0x25]
|
|
struct Entry { // 8 entries (stride 0x1C) from this[0x26]
|
|
int x; // +0x00
|
|
int y; // +0x04
|
|
int resolvedMech; // +0x08 (=-1 after BecameActive)
|
|
int selected; // +0x0C
|
|
NumericDisplay *nameDisplay; // +0x10 KILLS numeric
|
|
NumericDisplay *mechDisplay; // +0x14 DEATHS numeric
|
|
NumericDisplay *scoreDisplay; // +0x18 erase-only
|
|
} entry[8];
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// PlayerStatus (config keyword "PlayerStatus") -- a single-player status
|
|
// name-tag. @004cae90 Make / @004cb1a8 ctor / @004cb28c dtor / @004cb310
|
|
// BecameActive / @004cb358 Execute. vtable 0051be20, 200-byte alloc.
|
|
// Make validates the player number (must be 1..8; warns "PlayerStatus:
|
|
// Make player number <n>"). Execute resolves player N from the shared
|
|
// "Players" roster ("Players" 0x51bd97), recolours its mech-outline bitmap
|
|
// per player palette via CreateMutantPixelmap8 (@004cafac, file-private) +
|
|
// PlayerStatusMappingGroup (adpal.pcc/adpal2.pcc), and shows the player
|
|
// score + an alive/dead colour state.
|
|
//#######################################################################
|
|
class PlayerStatus :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
static MethodDescription
|
|
methodDescription; // "PlayerStatus"
|
|
|
|
static Logical
|
|
Make( // @004cae90
|
|
int display_port_index,
|
|
Vector2DOf<int> position,
|
|
Entity *entity,
|
|
GaugeRenderer *gauge_renderer
|
|
);
|
|
|
|
PlayerStatus( // @004cb1a8 (13 args; owner folded to 0 in base call)
|
|
GaugeRate rate,
|
|
ModeMask mode_mask,
|
|
L4GaugeRenderer *renderer,
|
|
int graphics_port_number,
|
|
int x, int y,
|
|
int player_number,
|
|
const char *font_image,
|
|
int color,
|
|
int okColor,
|
|
int aliveColor,
|
|
int deadColor,
|
|
const char *identification_string
|
|
);
|
|
~PlayerStatus(); // @004cb28c
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
void
|
|
BecameActive(); // @004cb310
|
|
void
|
|
Execute(); // @004cb358
|
|
|
|
protected:
|
|
int port; // @0x90 this[0x24] graphics_port_number
|
|
int playerIndex; // @0x94 this[0x25] (player_number-1)
|
|
Player *player; // @0x98 this[0x26] cached roster player (non-owned)
|
|
BitMap *nameImage; // @0x9C this[0x27] name-cache BitMap (cache-owned)
|
|
Pixmap *recoloredMech; // @0xA0 this[0x28] CreateMutantPixelmap8 result (owned)
|
|
int color; // @0xA4 this[0x29]
|
|
int okColor; // @0xA8 this[0x2A]
|
|
int aliveColor; // @0xAC this[0x2B]
|
|
int deadColor; // @0xB0 this[0x2C]
|
|
PlayerStatusMappingGroup
|
|
*mappingGroup; // @0xB4 this[0x2D] (owned; the binary LEAKED it)
|
|
NumericDisplay
|
|
*scoreDisplay; // @0xB8 this[0x2E]
|
|
int dirty; // @0xBC this[0x2F] redraw flag
|
|
int previousStatus; // @0xC0 this[0x30] last alive/dead state
|
|
int previousMappingState; // @0xC4 this[0x31]
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// MessageBoard (config keyword "messageBoard") -- the secondary-MFD comm/
|
|
// status message ticker. @004cb678 Make / @004cb704 ctor / @004cb788 dtor /
|
|
// @004cb7fc BecameActive / @004cb818 SetSource / @004cb82c Execute.
|
|
// vtable 0051bddc, binary sizeof 0xA4 (the Make alloc). Blits one cell of
|
|
// the strip bitmap btsmsgs.pcx (message id -> cell (id&3)<<7, (id>>2)<<5)
|
|
// plus the sender's name bitmap. Was PROSE-ONLY -> "messageBoard" was
|
|
// parse-skipped.
|
|
//
|
|
// DEFERRED / EMPTY (authentic for bring-up): the source mech is never
|
|
// bound (SetSource @004cb818 has no recovered caller) AND the per-player
|
|
// status-message feed (Player::statusMessagePointer's producer pool) is
|
|
// not reconstructed, so there are no messages -> Execute early-returns on
|
|
// the NULL source (a safe no-op == the empty board).
|
|
//
|
|
// Field-order FIXes on record: trackedMech@0x90 (was decoded "int
|
|
// enabled"); previousNameId@0x9C=-1 / previousMessageId@0xA0=-2 (were
|
|
// swapped in the first decode).
|
|
//#######################################################################
|
|
class MessageBoard :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
static MethodDescription
|
|
methodDescription; // "messageBoard"
|
|
|
|
static Logical
|
|
Make( // @004cb678
|
|
int display_port_index,
|
|
Vector2DOf<int> position,
|
|
Entity *entity,
|
|
GaugeRenderer *gauge_renderer
|
|
);
|
|
|
|
MessageBoard( // @004cb704
|
|
GaugeRate rate,
|
|
ModeMask mode_mask,
|
|
L4GaugeRenderer *renderer,
|
|
int graphics_port_number,
|
|
int x, int y,
|
|
const char *strip_image,
|
|
int color,
|
|
const char *identification_string
|
|
);
|
|
~MessageBoard(); // @004cb788
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
void
|
|
BecameActive(); // @004cb7fc
|
|
void
|
|
SetSource(Entity *mech); // @004cb818 (binds trackedMech; no caller -> deferred)
|
|
void
|
|
Execute(); // @004cb82c
|
|
|
|
protected:
|
|
Entity *trackedMech; // @0x90 this[0x24] source mech (SetSource; ctor=0)
|
|
char *stripImage; // @0x94 this[0x25] interned btsmsgs.pcx (held ref)
|
|
int color; // @0x98 this[0x26] param (CFG 4th arg = 0)
|
|
int previousNameId; // @0x9C this[0x27] BecameActive=-1
|
|
int previousMessageId; // @0xA0 this[0x28] BecameActive=-2
|
|
};
|
|
|
|
|
|
// NOTE: CreateMutantPixelmap8 (@004cafac) + ReadStreamString (@004caf50)
|
|
// are file-PRIVATE in the binary -- declared static at the top of
|
|
// BTL4GAU3.CPP, not here.
|
|
|
|
#endif
|