gauges: reconstruct + register oneOfSeveralPixInt -- cockpit button-state lamps

The OneOfSeveral family was declared but undefined.  Reconstruct the shared base
(OneOfSeveral: ctor @004c4d88, BecameActive @004c4f14, Execute @004c4f28, dtor
@004c4e7c) and the OneOfSeveralPixInt subclass (Make @004c5204, ctor @004c52d8,
dtor @004c5364) + its methodDescription, and register "oneOfSeveralPixInt".

OneOfSeveral is a multi-frame strip selector: the base holds a BitMap or PixMap8
strip of columns*rows frames + the per-frame size (source size / columns,rows);
Execute picks frame `selected` (col=selected%columns, row=selected/columns) and
blits that sub-rectangle -- DrawPixelMap8(opaque) for a pixmap strip (its own
palette, no SetColor), or SetColor(bg)+DrawBitMapOpaque(fg) for a bitmap strip.
Added the missing OneOfSeveral::foregroundColor field (@0x9C -- the DrawBitMap
Opaque background arg).  OneOfSeveralPixInt forces the PixMap path (fromImageStrip
=0, bg/fg=0) and wires one GaugeConnectionDirectOf<int> to the frame index.
methodDescription = (rate,modeMask,string strip,integer columns,integer rows,
attribute state) matching oneOfSeveralPixInt(rate,mode,strip.pcc,cols,rows,attr).
Strip resource via warehouse->pixelMap8Bin (WRHOUS.h) .Get/.Release.

The config binds the duck / searchlight / display-mode / piloting-mode buttons;
ControlsMapper/DisplayMode already resolves (MechControlsMapper table), and
DuckState/Searchlight/LightOn degrade to frame 0 (safe) until their tables land.

Verified live (BT_DEV_GAUGES): the cockpit button-lamp PixMap8 icons now render
(were absent).  No /FORCE unresolved externals.  Combat un-regressed (TARGET
DESTROYED after 8 hits), 0 crashes, no missing-image.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-06 19:33:16 -05:00
co-authored by Claude Opus 4.8
parent c2c4ab1f67
commit a538d6438e
3 changed files with 233 additions and 3 deletions
+224
View File
@@ -1276,6 +1276,230 @@ void
// before chaining to OneOfSeveral::Execute @004c4f28. dtor @004c5500.
//
//
// @004c4d88 -- OneOfSeveral base ctor (vtable PTR_FUN_00518bf0). Intern the
// image name, hold a ref, read the source strip size from the appropriate cache
// (PixMap8Cache if !fromImageStrip, else BitMapCache), divide by columns/rows to
// get the per-frame size, and set the graphics-port origin.
//
OneOfSeveral::OneOfSeveral(
GaugeRate rate,
ModeMask mode_mask,
L4GaugeRenderer *renderer_in,
int graphics_port_number,
int x,
int y,
Logical from_image_strip,
const char *image_name,
int background_color,
int foreground_color,
int columns_in,
int rows_in,
const char *identification_string
):
GraphicGauge(rate, mode_mask, renderer_in, 0, // FUN_00444818 (owner_ID 0)
graphics_port_number, identification_string)
{
backgroundColor = background_color; // @0x98
foregroundColor = foreground_color; // @0x9C
columns = columns_in; // @0xA0
fromImageStrip = from_image_strip; // @0x90
imageName = new char[strlen(image_name) + 1]; // @0x94 FUN_004700ac
strcpy(imageName, image_name);
L4Warehouse *warehouse = (L4Warehouse *)renderer_in->warehousePointer;
if (fromImageStrip == 0) // PixMap8 strip
{
PixelMap8 *pm = warehouse->pixelMap8Bin.Get(imageName); // FUN_00442d2b (held)
frameWidth = (pm != NULL ? pm->Data.Size.x : 0) / columns_in; // @0xA4
frameHeight = (pm != NULL ? pm->Data.Size.y : 0) / rows_in; // @0xA8
}
else // BitMap strip
{
BitMap *bm = warehouse->bitMapBin.Get(imageName); // FUN_00442aec (held)
frameWidth = (bm != NULL ? bm->Data.Size.x : 0) / columns_in;
frameHeight = (bm != NULL ? bm->Data.Size.y : 0) / rows_in;
}
localView.SetOrigin(x, y); // this+0x48 vtbl+0x10
}
//
// @004c4e7c -- dtor. Release the image from the matching cache (keyed on
// imageName, before the free); base chain implicit.
//
OneOfSeveral::~OneOfSeveral()
{
L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer;
if (fromImageStrip == 0)
warehouse->pixelMap8Bin.Release(imageName); // FUN_00442e51
else
warehouse->bitMapBin.Release(imageName); // FUN_00442c12
delete[] imageName; // FUN_004022e8
imageName = NULL;
}
Logical
OneOfSeveral::TestInstance() const
{
return GraphicGauge::TestInstance();
}
//
// @004c4f14 -- BecameActive: previousSelected = -1 (force the first redraw).
//
void
OneOfSeveral::BecameActive()
{
previousSelected = -1; // @0xB0
}
//
// @004c4f28 -- Execute. On a change of `selected`, compute the frame's (col,row)
// within the strip and blit that sub-rectangle: DrawPixelMap8 (opaque) for a
// pixmap strip, or SetColor(bg)+DrawBitMapOpaque(fg,..) for a bitmap strip.
//
void
OneOfSeveral::Execute()
{
if (selected == previousSelected)
return;
previousSelected = selected;
int col, row;
if (columns == 1)
{
col = 0;
row = selected;
}
else
{
col = selected % columns;
row = selected / columns;
}
int sx0 = col * frameWidth;
int sx1 = frameWidth + sx0 - 1;
int sy0 = row * frameHeight;
int sy1 = frameHeight + sy0 - 1;
L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer;
if (fromImageStrip == 0) // PixMap8: own palette, no SetColor
{
PixelMap8 *pm = warehouse->pixelMap8Bin.Get(imageName); // FUN_00442d2b
localView.DrawPixelMap8(True, 0, pm, sx0, sy0, sx1, sy1); // vtbl+0x5C (opaque)
warehouse->pixelMap8Bin.Release(imageName); // FUN_00442e51
}
else // BitMap strip
{
localView.SetColor(backgroundColor); // vtbl+0x18
BitMap *bm = warehouse->bitMapBin.Get(imageName); // FUN_00442aec
localView.DrawBitMapOpaque(foregroundColor, 0, bm, sx0, sy0, sx1, sy1); // vtbl+0x58
warehouse->bitMapBin.Release(imageName); // FUN_00442c12
}
}
//###########################################################################
// OneOfSeveralPixInt @004c5204 Make / @004c52d8 ctor (vtable PTR_FUN_00518b68)
//
// The cockpit button-state lamps (config "oneOfSeveralPixInt"): a PixMap8 strip
// of N frames selected by an integer game attribute (DuckState / Searchlight/
// LightOn / ControlsMapper/DisplayMode). Drawing is inherited from OneOfSeveral;
// this subclass just forces the PixMap path and wires the int connection.
//###########################################################################
MethodDescription
OneOfSeveralPixInt::methodDescription =
{
"oneOfSeveralPixInt",
OneOfSeveralPixInt::Make,
{
//
// CFG shape (L4GAUGE.CFG:5001):
// oneOfSeveralPixInt( rate, mode, strip.pcc, columns, rows, stateAttr )
// e.g. oneOfSeveralPixInt(E,ModeAlwaysActive,bduck.pcc,3,1,DuckState);
//
{ ParameterDescription::typeRate, NULL }, // rate ID
{ ParameterDescription::typeModeMask, NULL }, // mode mask
{ ParameterDescription::typeString, NULL }, // pixmap strip name
{ ParameterDescription::typeInteger, NULL }, // columns (frame count)
{ ParameterDescription::typeInteger, NULL }, // rows
{ ParameterDescription::typeAttribute, NULL }, // integer state selector
PARAMETER_DESCRIPTION_END
}
};
//
// @004c5204 -- Make. Allocate + construct, then verify the pixmap strip exists.
//
Logical
OneOfSeveralPixInt::Make(
int display_port_index,
Vector2DOf<int> position,
Entity * /*entity -- unused*/,
GaugeRenderer *gauge_renderer
)
{
ParameterDescription *p = methodDescription.parameterList;
OneOfSeveralPixInt *gauge = (OneOfSeveralPixInt *)operator new(0xb4); // FUN_00402298(0xb4)
if (gauge != NULL)
{
new (gauge) OneOfSeveralPixInt( // FUN_004c52d8
p[0].data.rate, p[1].data.modeMask,
(L4GaugeRenderer *)gauge_renderer,
display_port_index, // graphics_port_number
position.x, position.y,
p[2].data.string, // pixmap strip
p[3].data.integer, p[4].data.integer, // columns, rows
(int *)p[5].data.attributePointer, // integer state source
"OneOfSeveralPixInt");
}
L4Warehouse *warehouse = (L4Warehouse *)gauge_renderer->warehousePointer;
if (warehouse->pixelMap8Bin.Get(p[2].data.string) == NULL) // FUN_00442d2b
{
DebugStream << "OneOfSeveralPixInt: Missing image '" << p[2].data.string << "'\n";
return False;
}
warehouse->pixelMap8Bin.Release(p[2].data.string); // FUN_00442e51
return True;
}
//
// @004c52d8 -- ctor. OneOfSeveral base with fromImageStrip=0 (PixMap8) and
// bg/fg=0 (the pixmap carries its own palette); one int connection -> selected.
//
OneOfSeveralPixInt::OneOfSeveralPixInt(
GaugeRate rate,
ModeMask mode_mask,
L4GaugeRenderer *renderer_in,
int graphics_port_number,
int x,
int y,
const char *image,
int columns_in,
int rows_in,
int *value_pointer,
const char *identification_string
):
OneOfSeveral(rate, mode_mask, renderer_in, graphics_port_number, x, y,
False, // fromImageStrip = 0 (PixMap)
image, 0, 0, // bg, fg = 0
columns_in, rows_in, identification_string)
{
selected = 0; // @0xAC this[0x2B]
AddConnection(new GaugeConnectionDirectOf<int>(0, &selected, value_pointer)); // FUN_004749de
}
//
// @004c5364 -- deleting-dtor thunk. All teardown is ~OneOfSeveral; implicit.
//
OneOfSeveralPixInt::~OneOfSeveralPixInt()
{
}
//###########################################################################
//###########################################################################
+8 -3
View File
@@ -358,6 +358,7 @@
Logical fromImageStrip; // @0x90 this[0x24]
char *imageName; // @0x94 this[0x25]
int backgroundColor; // @0x98 this[0x26]
int foregroundColor; // @0x9C this[0x27] (DrawBitMapOpaque bg arg)
int columns; // @0xA0 this[0x28]
int selected; // @0xAC this[0x2B] (connection)
int previousSelected; // @0xB0 this[0x2C]
@@ -387,10 +388,14 @@
public OneOfSeveral
{
public:
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *);
OneOfSeveralPixInt(GaugeRate, ModeMask, L4GaugeRenderer *, int,
// Registered in BTL4MethodDescription[] (btl4grnd.cpp) as "oneOfSeveralPixInt".
static MethodDescription methodDescription;
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004c5204
OneOfSeveralPixInt( // @004c52d8
GaugeRate, ModeMask, L4GaugeRenderer *, int graphics_port_number,
int x, int y, const char *image, int columns, int rows,
int *value_pointer, const char *);
int *value_pointer, const char *identification_string);
~OneOfSeveralPixInt(); // @004c5364
};
+1
View File
@@ -136,6 +136,7 @@ MethodDescription
&ColorMapperCritical::methodDescription, // "cmCrit" -- subsystem-critical-state tint
&VertTwoPartBar::methodDescription, // "vertBar" -- vertical fill bar (coolant/heat)
&SegmentArcRatio::methodDescription, // "segmentArcRatio" -- segmented arc dial (speed)
&OneOfSeveralPixInt::methodDescription, // "oneOfSeveralPixInt" -- button-state lamp (duck/light/mode)
&BTL4ChainToPrevious
};