gauges: reconstruct cmArmor -- the per-zone ARMOR DAMAGE schematic [widget recon 3]
Each armor zone on the cockpit schematic is now tinted by that zone's live damage. Render-verified: the schematic shows an all-green Blackhawk (all zones damageLevel=0 at spawn), replacing the static green+red it showed before cmArmor was registered -- i.e. cmArmor now owns those zone colors and shows the real undamaged state; damaged zones shift toward red. Reuses the ColorMapper base (from cmHeat) + two pieces reconstructed from the binary (Ghidra dropped the x87, recovered by disassembly): - ArmorZoneConnection (@004c33a4/@004c3430): resolves one zone from the owner's inherited Entity::damageZones[zone_index]; per-frame feed = zone==NULL ? 100 : Round(zone->damageLevel * 100) (the 0..1 damage ratio -> 0..100 percentage -> the colour index ColorMapper::Execute pushes into the palette slot). - ColorMapperArmor::Make/ctor (@004c3aa4/@004c3b98): Make resolves the CFG zone name (dz_ltorso etc., the 6th param) to an index via Entity::GetDamageZoneIndex (== the binary's FUN_0042076c, scanning damageZones[] by name); the ctor wires the ArmorZoneConnection. Decomp fact (corrects the cmHeat note): the ColorMapper base ctor takes NINE args -- an owner_ID sits between renderer and graphics_port_number. Our 8-arg ColorMapper::ColorMapper folds owner_ID=0 in (gauges have owner 0), so it is equivalent; cmArmor's mapping matches cmHeat plus the zone name. Verified: parses, builds, all dz_* zones resolve (0 "not found"), no /FORCE unresolved, combat un-regressed (TARGET DESTROYED, 0 crashes). The dynamic red-on-damage needs the player to take damage (the passive spawn dummy never hits back). Details: docs/GAUGE_COMPOSITE.md. 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
e869b00181
commit
1d2ddd8399
+136
-10
@@ -178,6 +178,46 @@ void
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ArmorZoneConnection (@004c33a4 ctor / @004c3430 Transfer) -- drives a
|
||||
// ColorMapper's colour index from ONE damage zone's live damage ratio. The ctor
|
||||
// resolves the zone from the owner's inherited Entity::damageZones[zone_index]
|
||||
// (raw *(entity+0x120)[idx]); Transfer feeds it each frame. Used by ColorMapperArmor.
|
||||
//
|
||||
class ArmorZoneConnection : public GaugeConnection
|
||||
{
|
||||
public:
|
||||
ArmorZoneConnection(int *destination, Entity *entity, int zone_index)
|
||||
: GaugeConnection(0), // FUN_00444124(this,0)
|
||||
zone((zone_index < 0) ? NULL : entity->damageZones[zone_index]),
|
||||
currentColorIndex(destination)
|
||||
{}
|
||||
|
||||
protected:
|
||||
//
|
||||
// Per-frame feed (@004c3430): no zone -> 100 (fail-safe full tint); else the
|
||||
// zone's damage RATIO (damageLevel @0x158, 0..1) scaled to a 0..100 percentage
|
||||
// and rounded -- ColorMapper::Execute clamps it + pushes the palette slot,
|
||||
// recolouring that zone on the cockpit ARMOR DAMAGE schematic.
|
||||
//
|
||||
void Update(); // override
|
||||
|
||||
DamageZone *zone; // source@0x10
|
||||
int *currentColorIndex; // destination@0x14
|
||||
};
|
||||
|
||||
void
|
||||
ArmorZoneConnection::Update()
|
||||
{
|
||||
if (zone == NULL)
|
||||
{
|
||||
*currentColorIndex = 100;
|
||||
return;
|
||||
}
|
||||
*currentColorIndex = HeatRound(zone->damageLevel * 100.0f); // zone+0x158 * 100
|
||||
}
|
||||
|
||||
|
||||
//###########################################################################
|
||||
//###########################################################################
|
||||
// File-private GaugeConnection subclasses
|
||||
@@ -377,19 +417,105 @@ void
|
||||
// ColorMapperArmor @004c3aa4 Make / @004c3b98 ctor
|
||||
//###########################################################################
|
||||
//
|
||||
// @004c3aa4 -- Make: build the damage-zone descriptor (DAT_00514414), look up
|
||||
// the zone index on the host subsystem (FUN_0042076c; warns "damage zone ...
|
||||
// not found" on failure), allocate (0x70) and construct a ColorMapperArmor
|
||||
// wired with an ArmorZoneConnection.
|
||||
// Tints ONE damage zone's colour on the cockpit ARMOR DAMAGE schematic by that
|
||||
// zone's live damage. CFG shape (L4GAUGE.CFG:4789, inside the colorMapArmor
|
||||
// macro): cmArmor( rate, mode, colourSlot, paletteA, paletteB, zoneName )
|
||||
// e.g. cmArmor(H, ModeSecondaryDamage, 32, adpal.pcc, adpal2.pcc, dz_ltorso);
|
||||
//
|
||||
// @004c3b98 -- ctor: ColorMapper base (vtable PTR_FUN_00518dcc), this[0x1B]=0,
|
||||
// then AddConnection(new ArmorZoneConnection(¤tColorIndex, subsystem,
|
||||
// zone_index)) (connection ctor FUN_004c33a4, 0x18 bytes).
|
||||
|
||||
MethodDescription
|
||||
ColorMapperArmor::methodDescription =
|
||||
{
|
||||
"cmArmor",
|
||||
ColorMapperArmor::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 }, // damage-zone name (e.g. "dz_ltorso")
|
||||
PARAMETER_DESCRIPTION_END
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// ArmorZoneConnection::Transfer @004c3430:
|
||||
// if (source == 0) *destination = 100;
|
||||
// else *destination = Round(<zone damage %>);
|
||||
// @004c3aa4 -- Make. Resolve the named damage zone to an index on the entity,
|
||||
// then construct. (The binary built a transient zone-name descriptor and called
|
||||
// FUN_0042076c; Entity::GetDamageZoneIndex IS that lookup -- it scans
|
||||
// damageZones[] matching each zone's name.)
|
||||
//
|
||||
Logical
|
||||
ColorMapperArmor::Make(
|
||||
int display_port_index,
|
||||
Vector2DOf<int> /*position*/,
|
||||
Entity *entity,
|
||||
GaugeRenderer *gauge_renderer
|
||||
)
|
||||
{
|
||||
ParameterDescription *p = methodDescription.parameterList;
|
||||
|
||||
int zone_index = entity->GetDamageZoneIndex(CString(p[5].data.string)); // FUN_0042076c
|
||||
if (zone_index < 0)
|
||||
{
|
||||
DebugStream << "ColorMapperArmor warning: damage zone "
|
||||
<< p[5].data.string << " not found\n";
|
||||
}
|
||||
|
||||
ColorMapperArmor *gauge = (ColorMapperArmor *)operator new(0x70); // FUN_00402298(0x70)
|
||||
if (gauge != NULL)
|
||||
{
|
||||
new (gauge) ColorMapperArmor( // FUN_004c3b98
|
||||
p[0].data.rate, p[1].data.modeMask,
|
||||
(L4GaugeRenderer *)gauge_renderer,
|
||||
display_port_index, // graphics port number (the runtime port)
|
||||
p[2].data.color, // colour slot
|
||||
entity,
|
||||
p[3].data.string, // palette A
|
||||
p[4].data.string, // palette B
|
||||
zone_index,
|
||||
"ColorMapperArmor");
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
// @004c3b98 -- ctor: ColorMapper base + wire an ArmorZoneConnection feeding the
|
||||
// resolved damage zone's live damage to the colour index.
|
||||
//
|
||||
ColorMapperArmor::ColorMapperArmor(
|
||||
GaugeRate rate,
|
||||
ModeMask mode_mask,
|
||||
L4GaugeRenderer *renderer,
|
||||
int graphics_port_number,
|
||||
int color_index,
|
||||
Entity *entity,
|
||||
const char *palette_a,
|
||||
const char *palette_b,
|
||||
int damage_zone_index,
|
||||
const char *identification_string
|
||||
):
|
||||
ColorMapper( // FUN_004c37dc (owner_ID 0 folded in, as for cmHeat)
|
||||
rate, mode_mask, renderer, graphics_port_number,
|
||||
color_index, palette_a, palette_b, identification_string)
|
||||
{
|
||||
unused = 0; // this[0x1B] @0x6C
|
||||
|
||||
ArmorZoneConnection *connection =
|
||||
(ArmorZoneConnection *)operator new(0x18); // FUN_004c33a4 (0x18 bytes)
|
||||
if (connection != NULL)
|
||||
new (connection) ArmorZoneConnection(¤tColorIndex, entity, damage_zone_index);
|
||||
AddConnection(connection); // (*this+0x34)
|
||||
}
|
||||
|
||||
//
|
||||
// ColorMapperArmor destructor. No extra work: the ArmorZoneConnection is
|
||||
// released by the base Gauge teardown, the palettes by ~ColorMapper -- the
|
||||
// base-dtor chain runs implicitly at the closing brace.
|
||||
//
|
||||
ColorMapperArmor::~ColorMapperArmor()
|
||||
{
|
||||
}
|
||||
|
||||
//###########################################################################
|
||||
// ColorMapperMultiArmor @004c3c48 Make / @004c3d60 ctor
|
||||
|
||||
Reference in New Issue
Block a user