gauges: reconstruct cmCrit -- subsystem-critical tint; ColorMapper family complete [widget recon 5]
Reconstructs ColorMapperCritical -- tints a schematic colour by a subsystem's operational state (the "critical" secondary display mode): - CriticalConnection (@004c3598/@004c3610): src==0 -> 0; src->simulationState==1 (DestroyedState) -> 100; else the subsystem's own damage-zone damageLevel*100. - ColorMapperCritical::Make/ctor (@004c3ddc/@004c3e40): FindSubsystem by name + wire the CriticalConnection. Resolved the subsystem damageZone@0xE0 shadow: MechSubsystem::damageZone is declared ReconDamageZone*, but the assignment (mechsub.cpp: damageZone = (ReconDamageZone*)new DamageZone(...)) shows the pointer IS a real engine DamageZone -- so cast it back and read damageLevel. Added public accessors GetSimulationState()/GetDamageZoneProxy() to MechSubsystem (those fields are protected; mirrors how HeatConnection reads the public currentTemperature). Completes the ColorMapper family (cmHeat, cmArmor, colorMapperMultiArmor, cmCrit). Verified: parses, builds, all subsystems resolve (0 warnings), no /FORCE unresolved, combat un-regressed (TARGET DESTROYED, 0 crashes), stable. 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
fb8c1d6ace
commit
d006b40927
+13
-3
@@ -327,9 +327,19 @@ widget — the table is cumulative across all registered gauges. **LESSON (add t
|
||||
corruption that surfaces in an INNOCENT later alloc, right after registering a gauge, is the interpreterTable
|
||||
overflow — the Insert bounds-`Verify` is dead at DEBUG_LEVEL 0.**
|
||||
|
||||
**Next increments (priority order from the map):** `cmCrit` (ColorMapperCritical -- needs the subsystem
|
||||
`damageZone@0xE0` shadow resolved; CriticalConnection = state==1?100:Round(subsys->damageZone->damageLevel*100)),
|
||||
then the
|
||||
**✅ Increment 5 — `cmCrit` (ColorMapperCritical) DONE — the ColorMapper family is COMPLETE.** Tints a
|
||||
schematic colour by a subsystem's operational state (the "critical" secondary display mode). Reconstructed
|
||||
`CriticalConnection` (@004c3598/@004c3610: `src==0 → 0`; `src->simulationState==1` [DestroyedState] `→ 100`;
|
||||
else the subsystem's own damage-zone `damageLevel × 100`) + `ColorMapperCritical::Make`/ctor (@004c3ddc/
|
||||
@004c3e40 — `FindSubsystem` by name + wire the CriticalConnection). **Resolved the subsystem `damageZone@0xE0`
|
||||
shadow:** the recon declared `MechSubsystem::damageZone` as a `ReconDamageZone*`, but the assignment
|
||||
(`mechsub.cpp: damageZone = (ReconDamageZone*)new DamageZone(...)`) shows the pointer IS a real engine
|
||||
`DamageZone` — so cast it back and read `damageLevel`. Added two public accessors to `MechSubsystem`
|
||||
(`GetSimulationState()`, `GetDamageZoneProxy()`) since those fields are protected (mirrors how HeatConnection
|
||||
reads the public `currentTemperature`). Verified: parses, builds, all subsystems resolve (0 warnings), no
|
||||
`/FORCE` unresolved, combat un-regressed (TARGET DESTROYED, 0 crashes), stable.
|
||||
|
||||
**Next increments (priority order from the map):** the
|
||||
`ArmorZoneConnection`/`MultiArmorConnection` classes reconstructed); then the attribute-table wave (`vertBar`/
|
||||
`segmentArcRatio` speed/`GeneratorCluster` — need `AttributePointers[]` on Mech/HeatableSubsystem, a separate
|
||||
pass); the XL items (`map`/`vehicleSubSystems`/`PlayerStatus`) last. The POD path needs the FULL 23-entry
|
||||
|
||||
+131
-11
@@ -271,6 +271,51 @@ void
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CriticalConnection (@004c3598 ctor / @004c3610 Transfer) -- drives a
|
||||
// ColorMapper's colour index from ONE subsystem's operational state. Used by
|
||||
// ColorMapperCritical. Transfer: no subsystem -> 0 (blank); subsystem DESTROYED
|
||||
// (simulationState == 1) -> 100 (full critical tint); else the subsystem's own
|
||||
// damage-zone damageLevel (0..1) as a 0..100 percentage (@0xE0 -> @0x158 * 100).
|
||||
//
|
||||
class CriticalConnection : public GaugeConnection
|
||||
{
|
||||
public:
|
||||
CriticalConnection(int *destination, Subsystem *source)
|
||||
: GaugeConnection(0), // FUN_00444124(this,0)
|
||||
subsystem(source),
|
||||
currentColorIndex(destination)
|
||||
{}
|
||||
|
||||
protected:
|
||||
void Update(); // override
|
||||
|
||||
Subsystem *subsystem; // @0x10 source
|
||||
int *currentColorIndex; // @0x14 destination
|
||||
};
|
||||
|
||||
void
|
||||
CriticalConnection::Update()
|
||||
{
|
||||
if (subsystem == NULL)
|
||||
{
|
||||
*currentColorIndex = 0;
|
||||
return;
|
||||
}
|
||||
MechSubsystem *sub = (MechSubsystem *)subsystem;
|
||||
if (sub->GetSimulationState() == 1) // DestroyedState -> full critical tint
|
||||
{
|
||||
*currentColorIndex = 100;
|
||||
return;
|
||||
}
|
||||
// else: the subsystem's own damage zone (the proxy IS a real DamageZone). The
|
||||
// binary reads @0xe0 unconditionally; guard NULL (not every recon subsystem has
|
||||
// its zone wired) -> 0, matching an intact/undamaged reading.
|
||||
DamageZone *dz = (DamageZone *)sub->GetDamageZoneProxy();
|
||||
*currentColorIndex = (dz != NULL) ? HeatRound(dz->damageLevel * 100.0f) : 0;
|
||||
}
|
||||
|
||||
|
||||
//###########################################################################
|
||||
//###########################################################################
|
||||
// File-private GaugeConnection subclasses
|
||||
@@ -685,20 +730,95 @@ ColorMapperMultiArmor::~ColorMapperMultiArmor()
|
||||
// ColorMapperCritical @004c3ddc Make / @004c3e40 ctor
|
||||
//###########################################################################
|
||||
//
|
||||
// @004c3ddc -- Make: allocate (0x6c) and construct with the four resource
|
||||
// strings (DAT_00514b50..) and name "ColorMapperCritical".
|
||||
// Tints one schematic colour by a subsystem's operational state (the "critical"
|
||||
// secondary display mode). CFG shape (L4GAUGE.CFG:143):
|
||||
// cmCrit( rate, mode, colourSlot, paletteA, paletteB, subsystemName )
|
||||
// e.g. cmCrit(H, ModeSecondaryCritical, 32, adpal.pcc, adpal2.pcc, GeneratorA);
|
||||
//
|
||||
// @004c3e40 -- ctor: ColorMapper base (vtable PTR_FUN_00518d44). Resolves the
|
||||
// named subsystem via Entity::FindSubObject (FUN_0041f98c); warns
|
||||
// "ColorMapperCritical warning: subsystem ... does not exist" if absent.
|
||||
// AddConnection(new CriticalConnection(¤tColorIndex, subsystem))
|
||||
// (connection ctor FUN_004c3598, 0x18 bytes).
|
||||
|
||||
MethodDescription
|
||||
ColorMapperCritical::methodDescription =
|
||||
{
|
||||
"cmCrit",
|
||||
ColorMapperCritical::Make,
|
||||
{
|
||||
{ ParameterDescription::typeRate, NULL }, // rate ID
|
||||
{ ParameterDescription::typeModeMask, NULL }, // mode mask
|
||||
{ ParameterDescription::typeColor, NULL }, // hardware colour slot
|
||||
{ ParameterDescription::typeString, NULL }, // palette name A
|
||||
{ ParameterDescription::typeString, NULL }, // palette name B
|
||||
{ ParameterDescription::typeString, NULL }, // subsystem name
|
||||
PARAMETER_DESCRIPTION_END
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// CriticalConnection::Transfer @004c3610:
|
||||
// no subsystem -> *destination = 0;
|
||||
// subsystem +0x40 == 1 -> *destination = 100; (fully operational)
|
||||
// else -> *destination = Round(<value>);
|
||||
// @004c3ddc -- Make.
|
||||
//
|
||||
Logical
|
||||
ColorMapperCritical::Make(
|
||||
int display_port_index,
|
||||
Vector2DOf<int> /*position*/,
|
||||
Entity *entity,
|
||||
GaugeRenderer *gauge_renderer
|
||||
)
|
||||
{
|
||||
ParameterDescription *p = methodDescription.parameterList;
|
||||
|
||||
ColorMapperCritical *gauge = (ColorMapperCritical *)operator new(0x6c); // FUN_00402298(0x6c)
|
||||
if (gauge != NULL)
|
||||
{
|
||||
new (gauge) ColorMapperCritical( // FUN_004c3e40
|
||||
p[0].data.rate, p[1].data.modeMask,
|
||||
(L4GaugeRenderer *)gauge_renderer,
|
||||
display_port_index, // graphics port number
|
||||
p[2].data.color, // colour slot
|
||||
entity,
|
||||
p[3].data.string, // palette A
|
||||
p[4].data.string, // palette B
|
||||
p[5].data.string, // subsystem name
|
||||
"ColorMapperCritical");
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
// @004c3e40 -- ctor: ColorMapper base + a CriticalConnection on the named subsystem.
|
||||
//
|
||||
ColorMapperCritical::ColorMapperCritical(
|
||||
GaugeRate rate,
|
||||
ModeMask mode_mask,
|
||||
L4GaugeRenderer *renderer,
|
||||
int graphics_port_number,
|
||||
int color_index,
|
||||
Entity *entity,
|
||||
const char *palette_a,
|
||||
const char *palette_b,
|
||||
const char *subsystem_name,
|
||||
const char *identification_string
|
||||
):
|
||||
ColorMapper( // FUN_004c37dc
|
||||
rate, mode_mask, renderer, graphics_port_number,
|
||||
color_index, palette_a, palette_b, identification_string)
|
||||
{
|
||||
Subsystem *subsystem = entity->FindSubsystem(subsystem_name); // FUN_0041f98c
|
||||
if (subsystem == NULL)
|
||||
{
|
||||
DebugStream << "ColorMapperCritical warning: subsystem "
|
||||
<< subsystem_name << " does not exist\n";
|
||||
}
|
||||
|
||||
CriticalConnection *connection =
|
||||
(CriticalConnection *)operator new(0x18); // FUN_004c3598 (0x18 bytes)
|
||||
if (connection != NULL)
|
||||
new (connection) CriticalConnection(¤tColorIndex, subsystem);
|
||||
AddConnection(connection);
|
||||
}
|
||||
|
||||
ColorMapperCritical::~ColorMapperCritical()
|
||||
{
|
||||
// base-dtor chain (~ColorMapper -> ~Gauge) releases the connection + palettes.
|
||||
}
|
||||
|
||||
//###########################################################################
|
||||
// ColorMapperHeat @004c3f08 Make / @004c3f6c ctor *** ANCHOR ***
|
||||
|
||||
@@ -184,6 +184,9 @@
|
||||
public ColorMapper
|
||||
{
|
||||
public:
|
||||
// Registered in BTL4MethodDescription[] (btl4grnd.cpp) as "cmCrit".
|
||||
static MethodDescription methodDescription;
|
||||
|
||||
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @004c3ddc
|
||||
ColorMapperCritical( // @004c3e40
|
||||
GaugeRate, ModeMask, L4GaugeRenderer *, int, int,
|
||||
|
||||
@@ -133,6 +133,7 @@ MethodDescription
|
||||
&HeadingPointer::methodDescription, // "headingPointer" -- compass needle + heading
|
||||
&ColorMapperArmor::methodDescription, // "cmArmor" -- per-zone armor-damage tint
|
||||
&ColorMapperMultiArmor::methodDescription, // "colorMapperMultiArmor" -- worst-of-8-zones tint
|
||||
&ColorMapperCritical::methodDescription, // "cmCrit" -- subsystem-critical-state tint
|
||||
&BTL4ChainToPrevious
|
||||
};
|
||||
|
||||
|
||||
@@ -230,6 +230,15 @@ class Damage;
|
||||
Logical
|
||||
IsDamaged(); // @0x4ac9c8 (bus-state query)
|
||||
|
||||
// Critical-state readouts for ColorMapperCritical (CriticalConnection):
|
||||
// the raw simulation state (DefaultState=0 / Destroyed=1 / Exploding=2) and
|
||||
// the subsystem's own damage zone (a real DamageZone behind the proxy type;
|
||||
// set in the ctor via `new DamageZone(...)`, mechsub.cpp).
|
||||
int
|
||||
GetSimulationState() const { return simulationState; }
|
||||
ReconDamageZone *
|
||||
GetDamageZoneProxy() const { return damageZone; }
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Internal helpers
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user