gauges: reconstruct + register vertBar (VertTwoPartBar) -- cockpit coolant bars
VertTwoPartBar was declared in btl4gaug.hpp (ctor/field offsets/decomp addrs) but never defined. Reconstruct Make (@004c462c) / ctor (@004c4724) / BecameActive (@004c48e0) / Execute (@004c48fc) / dtor + the "vertBar" methodDescription, and register it in BTL4MethodDescription[]. The Execute pixel math is x87 that Ghidra dropped (FUN_004dcd94 is just (int)ROUND(ST0); the operands are on the FPU stack) -- recovered by disassembling @004c4940/@004c4960: warnPix = clamp(round(height*low/high + 0.5), 0, height) valPix = clamp(round(height*value/high + 0.5), 0, height) value is first clamped to [0,high]; on a change it tile-blits the bitmap over [0,warnPix), fills [warnPix,valPix) with fillColor, clears [valPix,height) with extraColor (reusing the existing DrawTiledBitmap helper = FUN_004c2ff8; view methods SetPositionWithinPort/SetColor/MoveToAbsolute/DrawFilledRectangleTo Absolute = vtbl +0x08/+0x18/+0x24/+0x48). methodDescription param types (rate,modeMask,vector,string,color,color,color,attribute,attribute,attribute) match the config vertBar(rate,mode,(w,h),tile,bg,fill,extra,current,warn,max). For the coolant bars the config binds current=CoolantMass, warn=max=Coolant Capacity, so the warn line sits at full and the bar is a simple level gauge that empties as CoolantMass drops -- now driven by the HeatSink attribute table committed earlier. Verified live (BT_DEV_GAUGES): the Heat surface COOLANT/RES bars now render the btwarn.pcc hatch fill (was empty), reading the real coolant attributes (full hatch = coolantLevel~=capacity). No /FORCE unresolved externals on the new symbols. Combat un-regressed (TARGET DESTROYED after 8 hits), 0 crashes, and the gauge build + mission load are heap-clean under BT_HEAPCHECK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9e31408ba2
commit
18d58f38f6
@@ -1022,11 +1022,213 @@ static void
|
||||
// background fill for the remainder). Uses _DAT_004c452c (0.0) as the floor.
|
||||
//
|
||||
|
||||
//###########################################################################
|
||||
// VertTwoPartBar @004c462c Make / @004c4724 ctor / @004c48e0 BecameActive
|
||||
// @004c48fc Execute (vtable PTR_FUN_00518c78)
|
||||
//
|
||||
// @004c462c Make / @004c4724 ctor / @004c48e0 BecameActive / @004c48fc Execute
|
||||
// -- VertTwoPartBar: identical structure to HorizTwoPartBar but grows
|
||||
// bottom->top (vtable PTR_FUN_00518c78). Floor constant _DAT_004c4b00 (0.0).
|
||||
// A vertical two-part fill bar (config keyword "vertBar"). Three Scalar
|
||||
// connections drive it: value (current), low (warn threshold), high (max). The
|
||||
// bar grows bottom->top; pixels are value/high and low/high fractions of the bar
|
||||
// height. Used for the cockpit COOLANT bars (config binds current=CoolantMass,
|
||||
// warn=CoolantCapacity, max=CoolantCapacity -- so the warn line sits at full and
|
||||
// the bar simply empties as CoolantMass drops during firing).
|
||||
//###########################################################################
|
||||
|
||||
MethodDescription
|
||||
VertTwoPartBar::methodDescription =
|
||||
{
|
||||
"vertBar",
|
||||
VertTwoPartBar::Make,
|
||||
{
|
||||
//
|
||||
// CFG shape (L4GAUGE.CFG:4521):
|
||||
// vertBar( rate, mode, (w,h), tile.pcc, bg,fill,extra,
|
||||
// currentAttr, warnAttr, maxAttr )
|
||||
// e.g. vertBar(C,ModeAlwaysActive,(31,160),btwarn.pcc,255,255,0,
|
||||
// HeatSink/CoolantMass, HeatSink/CoolantCapacity,
|
||||
// HeatSink/CoolantCapacity);
|
||||
//
|
||||
{ ParameterDescription::typeRate, NULL }, // rate ID
|
||||
{ ParameterDescription::typeModeMask, NULL }, // mode mask
|
||||
{ ParameterDescription::typeVector, NULL }, // (width,height)
|
||||
{ ParameterDescription::typeString, NULL }, // tile bitmap name
|
||||
{ ParameterDescription::typeColor, NULL }, // background colour -> @0x94
|
||||
{ ParameterDescription::typeColor, NULL }, // fill colour -> @0x98
|
||||
{ ParameterDescription::typeColor, NULL }, // extra/empty colour-> @0x9C
|
||||
{ ParameterDescription::typeAttribute, NULL }, // current value -> @0xB0
|
||||
{ ParameterDescription::typeAttribute, NULL }, // warn threshold -> @0xB4
|
||||
{ ParameterDescription::typeAttribute, NULL }, // max -> @0xB8
|
||||
PARAMETER_DESCRIPTION_END
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// @004c462c -- Make. Allocate + construct, then verify the tile bitmap exists
|
||||
// (== the binary's "VertTwoPartBarNormalized: Missing image" warning path).
|
||||
//
|
||||
Logical
|
||||
VertTwoPartBar::Make(
|
||||
int display_port_index,
|
||||
Vector2DOf<int> position,
|
||||
Entity * /*entity -- unused*/,
|
||||
GaugeRenderer *gauge_renderer
|
||||
)
|
||||
{
|
||||
ParameterDescription *p = methodDescription.parameterList;
|
||||
|
||||
VertTwoPartBar *gauge = (VertTwoPartBar *)operator new(0xbc); // FUN_00402298(0xbc)
|
||||
if (gauge != NULL)
|
||||
{
|
||||
new (gauge) VertTwoPartBar( // FUN_004c4724
|
||||
p[0].data.rate, p[1].data.modeMask,
|
||||
(L4GaugeRenderer *)gauge_renderer,
|
||||
display_port_index, // graphics_port_number
|
||||
position.x, position.y, // left, bottom
|
||||
position.x + p[2].data.vector.x, // right = x + width
|
||||
position.y + p[2].data.vector.y, // top = y + height
|
||||
p[3].data.string, // tile bitmap
|
||||
p[4].data.color, // backgroundColor
|
||||
p[5].data.color, // fillColor
|
||||
p[6].data.color, // extraColor
|
||||
(Scalar *)p[7].data.attributePointer, // current value source
|
||||
(Scalar *)p[8].data.attributePointer, // warn threshold source
|
||||
(Scalar *)p[9].data.attributePointer, // max source
|
||||
"VertTwoPartBar");
|
||||
}
|
||||
|
||||
L4Warehouse *warehouse = (L4Warehouse *)gauge_renderer->warehousePointer;
|
||||
if (warehouse->bitMapBin.Get(p[3].data.string) == NULL) // FUN_00442aec
|
||||
{
|
||||
DebugStream << "VertTwoPartBarNormalized: Missing image '"
|
||||
<< p[3].data.string << "'\n";
|
||||
return False;
|
||||
}
|
||||
warehouse->bitMapBin.Release(p[3].data.string); // FUN_00442c12
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
// @004c4724 -- ctor. GraphicGauge base; intern + ref-count the tile bitmap; set
|
||||
// the graphics-port extent (bottom->top); store the three colours and the bar
|
||||
// size; wire three GaugeConnectionDirectOf<Scalar> feeds (value/low/high).
|
||||
//
|
||||
VertTwoPartBar::VertTwoPartBar(
|
||||
GaugeRate rate,
|
||||
ModeMask mode_mask,
|
||||
L4GaugeRenderer *renderer_in,
|
||||
int graphics_port_number,
|
||||
int left,
|
||||
int bottom,
|
||||
int right,
|
||||
int top,
|
||||
const char *tile_image,
|
||||
int background_color,
|
||||
int fill_color,
|
||||
int extra_color,
|
||||
Scalar *value_pointer,
|
||||
Scalar *low_pointer,
|
||||
Scalar *high_pointer,
|
||||
const char *identification_string
|
||||
):
|
||||
GraphicGauge(rate, mode_mask, renderer_in, 0, // FUN_00444818 (owner_ID 0)
|
||||
graphics_port_number, identification_string)
|
||||
{
|
||||
// Own a copy of the tile-bitmap name (Make passes the transient interpreter
|
||||
// scratch buffer) and hold a ref for the gauge's life.
|
||||
tileImage = new char[strlen(tile_image) + 1]; // @0x90 FUN_004700ac
|
||||
strcpy(tileImage, tile_image);
|
||||
L4Warehouse *warehouse = (L4Warehouse *)renderer_in->warehousePointer;
|
||||
warehouse->bitMapBin.Get(tileImage); // FUN_00442aec (held)
|
||||
|
||||
localView.SetPositionWithinPort(left, bottom, right, top); // this+0x48 vtbl+0x08
|
||||
|
||||
backgroundColor = background_color; // @0x94 this[0x25]
|
||||
fillColor = fill_color; // @0x98 this[0x26]
|
||||
extraColor = extra_color; // @0x9C this[0x27]
|
||||
width = (right - left) - 1; // @0xA0 this[0x28]
|
||||
height = top - bottom; // @0xA4 this[0x29]
|
||||
|
||||
AddConnection(new GaugeConnectionDirectOf<Scalar>(0, &value, value_pointer)); // @0xB0
|
||||
AddConnection(new GaugeConnectionDirectOf<Scalar>(0, &low, low_pointer)); // @0xB4
|
||||
AddConnection(new GaugeConnectionDirectOf<Scalar>(0, &high, high_pointer)); // @0xB8
|
||||
}
|
||||
|
||||
//
|
||||
// @004c486c -- dtor. Release the tile ref (keyed on tileImage, before the free),
|
||||
// free the interned name; the base chain runs implicitly.
|
||||
//
|
||||
VertTwoPartBar::~VertTwoPartBar()
|
||||
{
|
||||
L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer;
|
||||
warehouse->bitMapBin.Release(tileImage); // FUN_00442c12
|
||||
delete[] tileImage; // FUN_004022e8
|
||||
tileImage = NULL;
|
||||
}
|
||||
|
||||
Logical
|
||||
VertTwoPartBar::TestInstance() const
|
||||
{
|
||||
return GraphicGauge::TestInstance();
|
||||
}
|
||||
|
||||
//
|
||||
// @004c48e0 -- BecameActive: force a full redraw on the first Execute
|
||||
// (previousFull=0, previousFill=width -- neither can match a real pixel pair).
|
||||
//
|
||||
void
|
||||
VertTwoPartBar::BecameActive()
|
||||
{
|
||||
previousFull = 0; // @0xAC this[0x2B]
|
||||
previousFill = width; // @0xA8 this[0x2A]
|
||||
}
|
||||
|
||||
//
|
||||
// @004c48fc -- Execute. Clamp value to [0,high]; map value and warn to bar
|
||||
// pixels (half-up round of height*x/high, clamped to [0,height]); if either
|
||||
// changed, repaint: tile the bitmap over [0,warnPix), fill [warnPix,valPix) with
|
||||
// fillColor, and clear [valPix,height) with extraColor. (x87 pixel math recovered
|
||||
// by disassembly @004c4940/@004c4960 -- Ghidra dropped the FPU args.)
|
||||
//
|
||||
void
|
||||
VertTwoPartBar::Execute()
|
||||
{
|
||||
// clamp value to [0, high] (@004c4908 fcomp 0.0 ; @004c4929 fcomp high)
|
||||
if (value < 0.0f)
|
||||
value = 0.0f;
|
||||
else if (value > high)
|
||||
value = high;
|
||||
|
||||
int warnPix = (int)((Scalar)height * low / high + 0.5f); // warn threshold pixel
|
||||
int valPix = (int)((Scalar)height * value / high + 0.5f); // current value pixel
|
||||
if (warnPix < 0) warnPix = 0; else if (warnPix > height) warnPix = height;
|
||||
if (valPix < 0) valPix = 0; else if (valPix > height) valPix = height;
|
||||
|
||||
if (warnPix != previousFull || valPix != previousFill)
|
||||
{
|
||||
L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer;
|
||||
BitMap *tile = warehouse->bitMapBin.Get(tileImage); // FUN_00442aec
|
||||
|
||||
localView.SetColor(backgroundColor); // vtbl+0x18
|
||||
DrawTiledBitmap(&localView, 0, 0, width, warnPix - 1, extraColor, tile);
|
||||
warehouse->bitMapBin.Release(tileImage); // FUN_00442c12
|
||||
|
||||
if (warnPix < valPix) // normal fill above the warn line
|
||||
{
|
||||
localView.SetColor(fillColor);
|
||||
localView.MoveToAbsolute(0, warnPix); // vtbl+0x24
|
||||
localView.DrawFilledRectangleToAbsolute(width, valPix - 1); // vtbl+0x48
|
||||
}
|
||||
if (valPix < height) // empty region above the value
|
||||
{
|
||||
localView.SetColor(extraColor);
|
||||
localView.MoveToAbsolute(0, valPix);
|
||||
localView.DrawFilledRectangleToAbsolute(width, height);
|
||||
}
|
||||
|
||||
previousFull = warnPix;
|
||||
previousFill = valPix;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @004c4b84 ctor / @004c4cac BecameActive / @004c4cc0 Execute
|
||||
|
||||
@@ -264,12 +264,15 @@
|
||||
public GraphicGauge
|
||||
{
|
||||
public:
|
||||
// Registered in BTL4MethodDescription[] (btl4grnd.cpp) as "vertBar".
|
||||
static MethodDescription methodDescription;
|
||||
|
||||
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004c462c
|
||||
VertTwoPartBar( // @004c4724
|
||||
GaugeRate, ModeMask, L4GaugeRenderer *, int,
|
||||
VertTwoPartBar( // @004c4724 (ctor arg order = binary param_12..17)
|
||||
GaugeRate, ModeMask, L4GaugeRenderer *, int graphics_port_number,
|
||||
int left, int bottom, int right, int top,
|
||||
const char *tile_image, int fill_color, int background_color,
|
||||
int /*extra_color*/,
|
||||
const char *tile_image,
|
||||
int background_color, int fill_color, int extra_color,
|
||||
Scalar *value_pointer, Scalar *low_pointer, Scalar *high_pointer,
|
||||
const char *identification_string);
|
||||
~VertTwoPartBar();
|
||||
|
||||
@@ -134,6 +134,7 @@ MethodDescription
|
||||
&ColorMapperArmor::methodDescription, // "cmArmor" -- per-zone armor-damage tint
|
||||
&ColorMapperMultiArmor::methodDescription, // "colorMapperMultiArmor" -- worst-of-8-zones tint
|
||||
&ColorMapperCritical::methodDescription, // "cmCrit" -- subsystem-critical-state tint
|
||||
&VertTwoPartBar::methodDescription, // "vertBar" -- vertical fill bar (coolant/heat)
|
||||
&BTL4ChainToPrevious
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user