PlayerStatus (btl4gau3) had only a BUGGY Make defined (it read raw DAT_ pools, passed (int)entity/(int)gauge_renderer as x/y, and DROPPED the graphics_port_number param -- the header ctor was one int short); the ctor/Execute/dtor/BecameActive and the PlayerStatusMappingGroup + CreateMutantPixelmap8 helpers were comment-only stubs. Reconstructed the whole family (mapped by the playerstatus-decomp-map workflow, 6 agents): * methodDescription (8 params: rate,modeMask,integer player#,string font,4x color) + rewired Make reading parameterList[] with the port/x/y bug fixed. * ctor (@004cb1a8): GraphicGauge base (owner folded to 0), store colours+port, SetOrigin, playerIndex=player_number-1, build a score NumericDisplay (fmt 2 = signedBlankedZeros). Fixed the header layout: nameImage is a BitMap* (not a Pixmap), and two missing members (dirty@0x2F, previousStatus@0x30). * dtor / BecameActive / TestInstance. * PlayerStatusMappingGroup (@004c9bd0): 28 ColorMapperArmor zone tints over the mech-outline schematic, one per dz_* damage zone (mech->GetDamageZoneIndex), using the EXISTING 10-arg ColorMapperArmor ctor (per the workflow's correction -- changing it would break cmArmor); added ColorMapper/Armor::SetColor (FUN_004c3c38, stores @0x6C). * Execute (@004cb358): resolve the player (WinTesla-clean via GetMissionPlayer for the local player, instead of the binary's raw App+0x24 "Players"-node dictionary walk), then draw the score + name box + alive/dead status box; null-guarded. KEY FINDING: PlayerStatus lives in the config's `cameraInit` block (the MISSION- REVIEW / spectator camera cockpit), NOT `MechInit` -- so it is NOT part of the mech cockpit and does not build during normal mech play (which is why the mech test shows it un-regressed and its Execute never runs). It is the post-mission scoreboard (all 8 players' name/score/mech-status), rendered by the BTCameraDirector game model. Registered in BTL4MethodDescription[] so `cameraInit` builds it instead of parse-skipping. STATE: complete reconstruction; compiles, links (no new /FORCE unresolved), and the mech cockpit is un-regressed (TARGET DESTROYED, 0 crashes). NOT runtime-verified -- cameraInit is only built by the mission-review camera model, which a normal `vehicle=<mech>` egg does not trigger. BRING-UP STUB (marked): CreateMutantPixelmap8 returns NULL (the mech-outline recolor needs the DynamicMemoryStream read API + Pixmap pixel-copy mapped) -> the score/name-box/status-box render but not the recoloured mech schematic. BT_PS_LOG traces the resolve. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
284 lines
13 KiB
C++
284 lines
13 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 / armour-mosaic display and the message //
|
|
// board. These read the shared "Players" node and the live mech //
|
|
// roster rather than a single subsystem. //
|
|
// * SectorDisplay -- bitmap status grid + dual numeric //
|
|
// * PlayerStatusMappingGroup -- 28-zone armour colour-tint group //
|
|
// * TeamStatusDisplay -- 8-row scoreboard //
|
|
// * PilotList -- 8-pilot roster (3 numerics each) //
|
|
// * PlayerStatus -- single-player status name-tag //
|
|
// * MessageBoard -- rank / message bitmap board //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 02/22/96 CPB Initial coding. //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1996, Virtual World Entertainment, Inc. All rights reserved //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
//
|
|
// RECONSTRUCTED. No BTL4GAU3.HPP survived; recovered from BTL4OPT.EXE.
|
|
// Ghidra pseudo-C in recovered/all/part_014.c (@004c9bd0..@004cbea0). Class
|
|
// names recovered 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 (ctor FUN_00444818).
|
|
//
|
|
|
|
#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
|
|
|
|
//
|
|
// 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 (FUN_004c3b98) wired to a resolved damage-zone index.
|
|
// (palette files adpal.pcc / adpal2.pcc; name "PlayerStatusMappingGroup".)
|
|
//#######################################################################
|
|
enum { playerStatusZoneCount = 28 };
|
|
class PlayerStatusMappingGroup
|
|
{
|
|
public:
|
|
PlayerStatusMappingGroup( // @004c9bd0
|
|
GaugeRate, ModeMask, L4GaugeRenderer *, int graphics_port_number,
|
|
Entity *mech, int base_color_index,
|
|
const char *palette_a, const char *palette_b,
|
|
const char *identification_string);
|
|
~PlayerStatusMappingGroup(); // @004c9ca8
|
|
void Execute(); // @004c9cf4 (run all 28)
|
|
void SetColor(int color); // @004c9d18 (recolour all 28)
|
|
protected:
|
|
ColorMapperArmor *zone[playerStatusZoneCount]; // this[0..0x1B]
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// SectorDisplay -- a 14-column bitmap status grid with two NumericDisplays.
|
|
// @004c9d44 Make / @004c9e10 ctor / @004c9f94 dtor / @004ca038 BecameActive /
|
|
// @004ca068 SetEnable / @004ca07c Execute. vtable PTR_FUN_0051beec.
|
|
// Make warns "SectorDisplay: Missing image <name>". The numeric pair shows
|
|
// a row/column read-out aligned to the grid bitmap (image width / 14).
|
|
//#######################################################################
|
|
class SectorDisplay :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004c9d44
|
|
SectorDisplay( // @004c9e10
|
|
GaugeRate, ModeMask, L4GaugeRenderer *, int,
|
|
int x, int y, const char *grid_image,
|
|
const char *font_image, int color,
|
|
const char *identification_string);
|
|
~SectorDisplay(); // @004c9f94
|
|
Logical TestInstance() const;
|
|
void SetEnable(Logical); // @004ca068 this[0x24]
|
|
void BecameActive(); // @004ca038
|
|
void Execute(); // @004ca07c
|
|
protected:
|
|
Logical enabled; // @0x90 this[0x24]
|
|
char *gridImage; // @0x94 this[0x25]
|
|
int cellWidth; // @0x98 this[0x26] imageW/14
|
|
int gridLeft; // @0x9C this[0x27] cellWidth*12
|
|
int gridRight; // @0xA0 this[0x28]
|
|
int gridHeight; // @0xA4 this[0x29]
|
|
int color; // @0xAC this[0x2B]
|
|
int baseLine; // @0xB0 this[0x2C] =500
|
|
int dirty; // @0xB4 this[0x2D] =500
|
|
NumericDisplay
|
|
*numericA, // @0xBC this[0x2F]
|
|
*numericB; // @0xC0 this[0x30]
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// TeamStatusDisplay -- the 8-slot multiplayer scoreboard. @004ca208 ctor /
|
|
// @004ca39c dtor / @004ca424 SetEnable / @004ca438 BecameActive /
|
|
// @004ca478 Execute. vtable PTR_FUN_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.
|
|
//#######################################################################
|
|
class TeamStatusDisplay :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
TeamStatusDisplay( // @004ca208
|
|
GaugeRate, ModeMask, L4GaugeRenderer *, int,
|
|
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); // @004ca424 this[0x24]
|
|
void BecameActive(); // @004ca438
|
|
void Execute(); // @004ca478
|
|
protected:
|
|
Logical enabled; // @0x90 this[0x24]
|
|
int originX; // @0x98 this[0x26]
|
|
int originY; // @0x9C this[0x27] (param_8-0x20)
|
|
int rowSpacing; // @0xA4 this[0x29]
|
|
int flags; // @0xA0 this[0x28]
|
|
int highlightWidth; // @0xA8 this[0x2A]
|
|
int selectedRow; // @0x94 this[0x25] (=999)
|
|
struct Row { // 8 rows starting at this[0x3B]
|
|
NumericDisplay *numberDisplay; // +0x00 (slot0..7 @+0xEC each row)
|
|
NumericDisplay *killDisplay; // +0x44
|
|
} row[8];
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// PilotList -- the 8-pilot roster (lance display). @004ca90c Make /
|
|
// @004ca958 ctor / @004cab10 dtor / @004caba4 BecameActive / @004cabd0
|
|
// Execute. vtable PTR_FUN_0051be64. Each entry has three NumericDisplays
|
|
// laid out by a per-entry layout mode (0/1/2 -> DAT_0051af88 table) giving
|
|
// the pilot's name, mech and ammo/score positions. Execute walks the lance
|
|
// roster via FUN_004b0898 (per-slot mech lookup) one slot per frame; helpers
|
|
// DrawMechIcon @004cad70 and DrawAmmoCount @004cae20.
|
|
//#######################################################################
|
|
class PilotList :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004ca90c
|
|
PilotList( // @004ca958
|
|
GaugeRate, ModeMask, L4GaugeRenderer *, int,
|
|
int x, int y, const char *font_image,
|
|
const char *identification_string);
|
|
~PilotList(); // @004cab10
|
|
Logical TestInstance() const;
|
|
void BecameActive(); // @004caba4
|
|
void Execute(); // @004cabd0
|
|
protected:
|
|
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)
|
|
int selected; // +0x0C
|
|
NumericDisplay *nameDisplay; // +0x10
|
|
NumericDisplay *mechDisplay; // +0x14
|
|
NumericDisplay *scoreDisplay; // +0x18
|
|
} entry[8];
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// PlayerStatus -- a single-player status name-tag. @004cae90 Make /
|
|
// @004cb1a8 ctor / @004cb28c dtor / @004cb310 BecameActive / @004cb358
|
|
// Execute. vtable PTR_FUN_0051be20. Make validates the player number
|
|
// (DAT_0051b07c, must be 1..8; warns "PlayerStatus: Make player number <n>").
|
|
// Execute resolves player N from the "Players" node (@00403ad0,
|
|
// "Players" 0x51bd97), recolours its mech-outline bitmap per player palette
|
|
// via CreateMutantPixelmap8 (@004cafac) + PlayerStatusMappingGroup
|
|
// (@004c9bd0, adpal.pcc/adpal2.pcc), and shows the player name + a damaged/
|
|
// destroyed colour state (subsys+0x1c4).
|
|
//#######################################################################
|
|
class PlayerStatus :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
// Registered in BTL4MethodDescription[] (btl4grnd.cpp) as "PlayerStatus".
|
|
static MethodDescription methodDescription;
|
|
|
|
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004cae90
|
|
PlayerStatus( // @004cb1a8 (13 args; owner folded to 0 in base call)
|
|
GaugeRate, ModeMask, L4GaugeRenderer *, 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)
|
|
Entity *player; // @0x98 this[0x26] cached (non-owned)
|
|
BitMap *nameImage; // @0x9C this[0x27] App name-cache BitMap (was mislabeled Pixmap)
|
|
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]
|
|
NumericDisplay
|
|
*scoreDisplay; // @0xB8 this[0x2E]
|
|
int dirty; // @0xBC this[0x2F] redraw flag
|
|
int previousStatus; // @0xC0 this[0x30] last player+0x1C4 alive/dead
|
|
int previousMappingState; // @0xC4 this[0x31]
|
|
};
|
|
|
|
|
|
//#######################################################################
|
|
// MessageBoard -- the rank / message bitmap board. @004cb678 Make /
|
|
// @004cb704 ctor / @004cb788 dtor / @004cb7fc BecameActive / @004cb82c
|
|
// Execute. vtable PTR_FUN_0051bddc. Tracks the local player's mech
|
|
// (App+0x6c -> +0x190 controller +0xc/+0x10 message ids) and blits the
|
|
// message strip cell ((id&3)<<7, (id>>2)<<5) plus a player name bitmap.
|
|
//#######################################################################
|
|
class MessageBoard :
|
|
public GraphicGauge
|
|
{
|
|
public:
|
|
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004cb678
|
|
MessageBoard( // @004cb704
|
|
GaugeRate, ModeMask, L4GaugeRenderer *, int,
|
|
int x, int y, const char *strip_image, int color,
|
|
const char *identification_string);
|
|
~MessageBoard(); // @004cb788
|
|
Logical TestInstance() const;
|
|
void BecameActive(); // @004cb7fc
|
|
void Execute(); // @004cb82c
|
|
protected:
|
|
int enabled; // @0x90 this[0x24]
|
|
char *stripImage; // @0x94 this[0x25]
|
|
int color; // @0x98 this[0x26]
|
|
int previousMessageId; // @0x9C this[0x27]
|
|
int previousNameId; // @0xA0 this[0x28]
|
|
};
|
|
|
|
|
|
// NOTE: CreateMutantPixelmap8 (@004cafac) + ReadStreamString (@004caf50) are
|
|
// file-PRIVATE in the binary -- declared static at the top of btl4gau3.cpp,
|
|
// not here (the old free-function decl had the wrong signature).
|
|
|
|
#endif
|