gauges: reconstruct + register segmentArcRatio -- the cockpit SPEED arc
SegmentArcRatio (config keyword "segmentArcRatio") was declared but undefined. It is a thin subclass of the engine SegmentArc gauge: two Scalar connections (numerator=value, denominator=max) and an Execute override that computes the [0,1] fill fraction into the base's currentValue, then delegates drawing to SegmentArc::Execute (which lights numerator/denominator of the segments). Reconstruct Make (@004c62fc) / ctor (@004c6394) / Execute (@004c6488) / dtor + the methodDescription (rate,modeMask,scalar inner,scalar outer,scalar deg0, scalar deg1,integer segs,color bg,color fg,attribute numerator,attribute denominator -- matching the engine SegmentArcNormalized param types; the config gives inner/outer once and the Make duplicates them into inner0==inner1 / outer0==outer1). Execute recovered by disassembling the vtable override @004c6488 (Ghidra dropped the x87): if (denominator < 1) currentValue = 0; else currentValue = clamp(|numerator/denominator * segmentSpan|, 0, 1); SegmentArc::Execute(); where FUN_004dcd00 = fabs and the ctor precomputes segmentSpan = (Scalar)(|n|/(|n|-1)) * 0.75f // int division => 0.75 for n=36 (_DAT_004c6484 = 0.75f, read live from the binary). Fixed the header field type int segmentSpan -> Scalar (the ctor fstp's it and Execute fmul's it). The config binds numerator=LinearSpeed, denominator=MaxRunSpeed -- both now resolved by the Mech attribute table -- so the arc sweeps with speed. Verified live (BT_DEV_GAUGES + drive): the radar-surface SPEED dial now shows a green segmented arc filling with speed (was a plain ring). No /FORCE unresolved externals. Combat un-regressed (TARGET DESTROYED after 8 hits), 0 crashes. 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
18d58f38f6
commit
a2ee1181e6
@@ -1552,13 +1552,149 @@ void
|
||||
// segmentSpan = (int)( (float)(|n|/(|n|-1)) * 0.75f ) // _DAT_004c62d4
|
||||
// Deleting-dtor thunk @004c66b3 -> FUN_00474094 (arc base dtor).
|
||||
//
|
||||
// @004c62fc Make / @004c6394 ctor (vtable PTR_FUN_0051898c) -- SegmentArcRatio:
|
||||
// derives from the second MUNGA L4 arc primitive (FUN_00473f44) and adds TWO
|
||||
// GaugeConnectionDirectOf<Scalar> feeds (numerator @0x30, denominator @0x31,
|
||||
// FUN_00474855 x2); precomputes segmentSpan with _DAT_004c6484 (0.75f).
|
||||
// Make @004c62fc allocates 0xcc and supplies the arc geometry resources
|
||||
// (DAT_00517eb0..00518158) and the name "SegmentArcRatio".
|
||||
// Deleting-dtor thunk @004c668d -> FUN_00474094.
|
||||
//###########################################################################
|
||||
// SegmentArcRatio @004c62fc Make / @004c6394 ctor / @004c6488 Execute
|
||||
// (vtable PTR_FUN_0051898c; base = engine SegmentArc)
|
||||
//
|
||||
// A segmented arc dial (config keyword "segmentArcRatio"). Two Scalar
|
||||
// connections drive it -- numerator (value) and denominator (max) -- and Execute
|
||||
// lights numerator/denominator of the arc. Used for the cockpit SPEED arc
|
||||
// (config binds numerator=LinearSpeed, denominator=MaxRunSpeed), so the arc
|
||||
// sweeps as the mech accelerates. Unlike VertTwoPartBar, the drawing is
|
||||
// inherited from the engine SegmentArc base -- this class only computes the
|
||||
// [0,1] fill fraction into the base's currentValue, then delegates the render.
|
||||
//###########################################################################
|
||||
|
||||
MethodDescription
|
||||
SegmentArcRatio::methodDescription =
|
||||
{
|
||||
"segmentArcRatio",
|
||||
SegmentArcRatio::Make,
|
||||
{
|
||||
//
|
||||
// CFG shape (L4GAUGE.CFG:4964):
|
||||
// segmentArcRatio( rate, mode, inner,outer, deg0,deg1, segs,
|
||||
// bg,fg, valueAttr, maxAttr )
|
||||
// e.g. segmentArcRatio(C,ModeAlwaysActive,32,39,0,360,36,0,2,
|
||||
// LinearSpeed, MaxRunSpeed);
|
||||
//
|
||||
{ ParameterDescription::typeRate, NULL }, // rate ID
|
||||
{ ParameterDescription::typeModeMask, NULL }, // mode mask
|
||||
{ ParameterDescription::typeScalar, NULL }, // inner radius
|
||||
{ ParameterDescription::typeScalar, NULL }, // outer radius
|
||||
{ ParameterDescription::typeScalar, NULL }, // start angle (deg)
|
||||
{ ParameterDescription::typeScalar, NULL }, // end angle (deg)
|
||||
{ ParameterDescription::typeInteger, NULL }, // segment count (+dir)
|
||||
{ ParameterDescription::typeColor, NULL }, // background colour
|
||||
{ ParameterDescription::typeColor, NULL }, // foreground colour
|
||||
{ ParameterDescription::typeAttribute, NULL }, // numerator (value)
|
||||
{ ParameterDescription::typeAttribute, NULL }, // denominator (max)
|
||||
PARAMETER_DESCRIPTION_END
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// @004c62fc -- Make. Allocate + construct; no resource to verify (returns True).
|
||||
//
|
||||
Logical
|
||||
SegmentArcRatio::Make(
|
||||
int display_port_index,
|
||||
Vector2DOf<int> position,
|
||||
Entity * /*entity -- unused*/,
|
||||
GaugeRenderer *gauge_renderer
|
||||
)
|
||||
{
|
||||
ParameterDescription *p = methodDescription.parameterList;
|
||||
|
||||
SegmentArcRatio *gauge = (SegmentArcRatio *)operator new(0xcc); // FUN_00402298(0xcc)
|
||||
if (gauge != NULL)
|
||||
{
|
||||
new (gauge) SegmentArcRatio( // FUN_004c6394
|
||||
p[0].data.rate, p[1].data.modeMask,
|
||||
(L4GaugeRenderer *)gauge_renderer,
|
||||
display_port_index, // graphics_port_number
|
||||
position.x, position.y, // centre
|
||||
p[2].data.scalar, p[3].data.scalar, // inner, outer radius
|
||||
p[4].data.scalar, p[5].data.scalar, // start, end angle
|
||||
p[6].data.integer, // segment count (+dir)
|
||||
p[7].data.color, p[8].data.color, // bg, fg
|
||||
(Scalar *)p[9].data.attributePointer, // numerator source
|
||||
(Scalar *)p[10].data.attributePointer, // denominator source
|
||||
"SegmentArcRatio");
|
||||
}
|
||||
return True; // binary returns 1 unconditionally
|
||||
}
|
||||
|
||||
//
|
||||
// @004c6394 -- ctor. Engine SegmentArc base (inner0==inner1, outer0==outer1 --
|
||||
// the Make duplicates them, so the arc has a constant radius); precompute the
|
||||
// span factor and wire the two Scalar connections.
|
||||
//
|
||||
SegmentArcRatio::SegmentArcRatio(
|
||||
GaugeRate rate,
|
||||
ModeMask mode_mask,
|
||||
L4GaugeRenderer *renderer_in,
|
||||
int graphics_port_number,
|
||||
int center_x,
|
||||
int center_y,
|
||||
Scalar inner,
|
||||
Scalar outer,
|
||||
Scalar deg0,
|
||||
Scalar deg1,
|
||||
int number_of_segs,
|
||||
int background_color,
|
||||
int foreground_color,
|
||||
Scalar *numerator_pointer,
|
||||
Scalar *denominator_pointer,
|
||||
const char *identification_string
|
||||
):
|
||||
SegmentArc(rate, mode_mask, renderer_in, 0, // FUN_00473f44 (owner_ID 0)
|
||||
graphics_port_number, center_x, center_y,
|
||||
inner, outer, inner, outer, // inner0/outer0 == inner1/outer1
|
||||
deg0, deg1, number_of_segs,
|
||||
background_color, foreground_color,
|
||||
True, // use_thick_lines (binary param_20 = 1)
|
||||
identification_string)
|
||||
{
|
||||
// segmentSpan = (Scalar)(|n| / (|n|-1)) * 0.75f -- |n|/(|n|-1) is INTEGER
|
||||
// division (== 1 for n>=2), so this is 0.75 for the 36-segment speed arc.
|
||||
int n = (number_of_segs < 0) ? -number_of_segs : number_of_segs; // @0xC8
|
||||
segmentSpan = (Scalar)(n / (n - 1)) * 0.75f; // _DAT_004c6484 = 0.75f
|
||||
|
||||
AddConnection(new GaugeConnectionDirectOf<Scalar>(0, &numerator, numerator_pointer)); // @0xC0
|
||||
AddConnection(new GaugeConnectionDirectOf<Scalar>(0, &denominator, denominator_pointer)); // @0xC4
|
||||
}
|
||||
|
||||
//
|
||||
// @004c668d -- deleting-dtor thunk. Connections + arc base are released by the
|
||||
// implicit base-dtor chain (FUN_00474094); no own teardown.
|
||||
//
|
||||
SegmentArcRatio::~SegmentArcRatio()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// @004c6488 -- Execute. currentValue = clamp(|numerator/denominator * span|,0,1);
|
||||
// then delegate to the engine SegmentArc::Execute (0x474300) which lights that
|
||||
// fraction of the segments. (x87 recovered by disassembly: FUN_004dcd00 = fabs.)
|
||||
//
|
||||
void
|
||||
SegmentArcRatio::Execute()
|
||||
{
|
||||
if (denominator < 1.0f) // guard div-by-tiny / unpowered
|
||||
{
|
||||
currentValue = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentValue = numerator / denominator * segmentSpan;
|
||||
if (currentValue < 0.0f) currentValue = -currentValue; // FUN_004dcd00 = fabs
|
||||
if (currentValue < 0.0f)
|
||||
currentValue = 0.0f;
|
||||
else if (currentValue > 1.0f)
|
||||
currentValue = 1.0f;
|
||||
}
|
||||
SegmentArc::Execute(); // 0x474300 -- the base draw
|
||||
}
|
||||
|
||||
// === btl4gau2.cpp begins at @004c6798 (SeekVoltage gauge) -- not part of this TU.
|
||||
|
||||
@@ -518,16 +518,28 @@
|
||||
};
|
||||
|
||||
class SegmentArcRatio :
|
||||
public SegmentArc // MUNGA L4 base (FUN_00473f44; engine class SegmentArc)
|
||||
public SegmentArc // MUNGA L4 base (engine SegmentArc, L4GAUGE.cpp:4827)
|
||||
{
|
||||
public:
|
||||
// Registered in BTL4MethodDescription[] (btl4grnd.cpp) as "segmentArcRatio".
|
||||
static MethodDescription methodDescription;
|
||||
|
||||
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004c62fc
|
||||
SegmentArcRatio(/* ...arc geometry... */); // @004c6394
|
||||
SegmentArcRatio( // @004c6394
|
||||
GaugeRate, ModeMask, L4GaugeRenderer *, int graphics_port_number,
|
||||
int center_x, int center_y,
|
||||
Scalar inner, Scalar outer, Scalar deg0, Scalar deg1,
|
||||
int number_of_segs, int background_color, int foreground_color,
|
||||
Scalar *numerator_pointer, Scalar *denominator_pointer,
|
||||
const char *identification_string);
|
||||
~SegmentArcRatio(); // dtor thunk @004c668d
|
||||
|
||||
void Execute(); // @004c6488 (ratio -> currentValue -> SegmentArc::Execute)
|
||||
|
||||
protected:
|
||||
Scalar numerator; // @0xC0 this[0x30] (connection)
|
||||
Scalar denominator; // @0xC4 this[0x31] (connection)
|
||||
int segmentSpan; // @0xC8 this[0x32]
|
||||
Scalar segmentSpan; // @0xC8 this[0x32] (float, read by Execute)
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -135,6 +135,7 @@ MethodDescription
|
||||
&ColorMapperMultiArmor::methodDescription, // "colorMapperMultiArmor" -- worst-of-8-zones tint
|
||||
&ColorMapperCritical::methodDescription, // "cmCrit" -- subsystem-critical-state tint
|
||||
&VertTwoPartBar::methodDescription, // "vertBar" -- vertical fill bar (coolant/heat)
|
||||
&SegmentArcRatio::methodDescription, // "segmentArcRatio" -- segmented arc dial (speed)
|
||||
&BTL4ChainToPrevious
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user