#118: the eject slot graphic returns -- vtbl+0x58 is DrawBitMapOpaque [T0]

The proper RE the corruption arc demanded: counting GRAPH2D.h's declared
virtual order, GraphicsView vtbl+0x18 = SetColor and +0x24 = MoveToAbsolute
land exactly -- and +0x58 is NOT DrawBitMap (+0x54) but the NEXT virtual,
DrawBitMapOpaque(background, rotation, bmp, sx1, sy1, sx2, sy2).  The wipe
is a two-span OPAQUE draw with INVERTED fg/bg pairs -- the literal "inverse
wipe" -- and FUN_004c5fb8 transcribes byte-exactly with the real signature
(the ++level between spans is inclusive-bounds bookkeeping, no gap).  The
base ctor fields were already right (colors +0x94/+0x98, bitmap Size.x/y at
+0x9C/+0xA0, decomp @004c5e84).

BallisticWeaponCluster::ejectWipe re-wired (bteejtm.pcc <- PercentOfEject).
Stress-verified: 4 gens dead + autofire jams + leak warning, weapon pages
pristine end to end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-03 23:56:53 -05:00
co-authored by Claude Fable 5
parent 5cd1947b65
commit 5a4ee55e4e
2 changed files with 24 additions and 16 deletions
+17 -10
View File
@@ -2210,8 +2210,21 @@ void BitMapInverseWipeScalar::BecameActive() // @004c5fa4
//
// @004c5fb8 -- Execute. level = round(value x width) clamped to [0, width]
// (the x87 form Ghidra drops -- fild width / fmul value, gotcha #19), and on
// a change draw the two column spans with INVERTED colour pairs: [0..level]
// fg colorA over bg colorB, [level+1..width] fg colorB over bg colorA.
// a change draw the two source-column spans OPAQUE with INVERTED colour
// pairs -- the literal "inverse wipe".
//
// SETTLED 2026-08-03 (the MFD-corruption arc): the binary's draw call is
// vtbl+0x58 = GraphicsView::DrawBitMapOpaque(background, rotation, bitmap,
// sx1, sy1, sx2, sy2) [T0 GRAPH2D.h slot 22 -- the NEXT virtual after
// DrawBitMap at +0x54; verified by counting the declaration order:
// +0x18 SetColor, +0x24 MoveToAbsolute both land exactly]. The earlier
// reconstruction guessed DrawBitMap and fed it a colour as "rotation" --
// the striped-garbage smear the operator captured. Byte-exact spans:
// level != 0: MoveTo(0,0); SetColor(colorA);
// DrawBitMapOpaque(colorB, 0, bmp, 0, 0, level, height);
// ++level; // inclusive-bounds step
// level < w: MoveTo(level,0); SetColor(colorB);
// DrawBitMapOpaque(colorA, 0, bmp, level, 0, width, height);
//
void BitMapInverseWipeScalar::Execute()
{
@@ -2228,24 +2241,18 @@ void BitMapInverseWipeScalar::Execute()
if (bmp != NULL)
{
int split = level;
// DrawBitMap's first argument is ALWAYS 0 in the sibling wipe's
// Execute (btl4gaug LeakGauge) -- passing a colour there smeared
// the whole gauge surface (field-caught: striped garbage across
// the weapon MFD pages, git/capture.png 2026-08-03). Colour
// selection is SetColor only; the two spans carry the inverted
// pair via SetColor alone.
if (split != 0)
{
localView.MoveToAbsolute(0, 0);
localView.SetColor(colorA);
localView.DrawBitMap(0, bmp, 0, 0, split, height);
localView.DrawBitMapOpaque(colorB, 0, bmp, 0, 0, split, height);
++split; // the binary's iVar2++
}
if (split < width)
{
localView.MoveToAbsolute(split, 0);
localView.SetColor(colorB);
localView.DrawBitMap(0, bmp, split, 0, width, height);
localView.DrawBitMapOpaque(colorA, 0, bmp, split, 0, width, height);
}
warehouse->bitMapBin.Release(imageName);
}