Per-pilot mech paint: wire the color/badge/patch substitution end-to-end

- Mech::resourceNameA/B/C -> real CString members (the binary's 16-byte
  CStringRepresentation; deep-copy bind from the MakeMessage = FUN_00402a98,
  implicit member dtors) + paint-name accessors
- SetupMaterialSubstitutionList reads the real egg names ([paint] log);
  TearDown clears the callback first (FUN_004d11e8)
- dpl_SetMaterialNameCallback is real now (L4VIDEO registry); bgfload
  MaterialResolver::resolve() applies it to every material name -- the
  port analogue of the dpl board rewriting names at load
- MP_BHMC.EGG: color=Red -> Crimson (vehicletable has no Red; binary Fail()ed)

Verified live 2-node MP: crimson MadCat with hip hazard stripes + yellow VGL
leg emblems; white Blackhawk + emblems; replicants painted on both nodes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-17 09:50:23 -05:00
co-authored by Claude Fable 5
parent dda517b65c
commit e0474ff92a
10 changed files with 382 additions and 53 deletions
+244
View File
@@ -0,0 +1,244 @@
[mission]
adventure=BattleTech
map=cavern
scenario=freeforall
time=night
weather=clear
temperature=27
length=600
[ordinals]
bitmap=Ordinal::BitMap::1
bitmap=Ordinal::BitMap::2
bitmap=Ordinal::BitMap::3
bitmap=Ordinal::BitMap::4
[Ordinal::BitMap::1]
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=000038000003C000001FF00000000F00
bitmap=0000F8000003C000003FF80000000F00
bitmap=0001F8000003C00000707C0000000F00
bitmap=0001F8000003C00000603C0000000F00
bitmap=00007801FC0FF00000003C3DF807FF00
bitmap=00007803FE0FF00000003C3FFC0FFF00
bitmap=00007803C703C00000003C3E3C1F0F00
bitmap=000078078303C0000000783C1E1E0F00
bitmap=000078078003C0000000783C1E1E0F00
bitmap=00007807C003C0000000F03C1E1E0F00
bitmap=00007807F003C0000001E03C1E1E0F00
bitmap=00007803FC03C0000003C03C1E1E0F00
bitmap=00007801FE03C0000007803C1E1E0F00
bitmap=000078007F03C000000F003C1E1E0F00
bitmap=000078001F03C000001E003C1E1E0F00
bitmap=000078000F03C000003C003C1E1E0F00
bitmap=000078060F03C0000078003C1E1E0F00
bitmap=000078071E03E0000078003C1E1F1F00
bitmap=00007803FE01F000007FFC3C1E0FFF00
bitmap=00007801FC00F000007FFC3C1E07EF00
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
x=128
y=32
width=8
[Ordinal::BitMap::2]
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=001FFF0000003C0000003C03C0780000
bitmap=001FFF0000003C0000007C03C0780000
bitmap=00000E0000003C000000FC03C0780000
bitmap=00003C0000003C000001BC03C0780000
bitmap=0000700F3E1FFC000003BC0FF07BF000
bitmap=0001E00F7E3FFC0000073C0FF07FF800
bitmap=0003800FFE7C3C0000063C03C07C7800
bitmap=0007F80FFE783C00000C3C03C0783C00
bitmap=0007FE0F80783C0000183C03C0783C00
bitmap=00001E0F00783C0000383C03C0783C00
bitmap=00000F0F00783C0000703C03C0783C00
bitmap=00000F0F00783C00007FFF03C0783C00
bitmap=00000F0F00783C00007FFF03C0783C00
bitmap=00000F0F00783C0000003C03C0783C00
bitmap=00000F0F00783C0000003C03C0783C00
bitmap=00000F0F00783C0000003C03C0783C00
bitmap=00180F0F00783C0000003C03C0783C00
bitmap=001C1F0F007C7C0000003C03E0783C00
bitmap=000FFE0F003FFC0000003C01F0783C00
bitmap=0007FC0F001FBC0000003C00F0783C00
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
x=128
y=32
width=8
[Ordinal::BitMap::3]
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=001FFF03C07800000000FC03C0780000
bitmap=001FFF03C07800000003FC03C0780000
bitmap=001E0003C07800000007C003C0780000
bitmap=001E0003C0780000000F0003C0780000
bitmap=001E000FF07BF000000F000FF07BF000
bitmap=001E000FF07FF800001E000FF07FF800
bitmap=001E0003C07C7800001E0003C07C7800
bitmap=001FFC03C0783C00001EFC03C0783C00
bitmap=001FFE03C0783C00001FFE03C0783C00
bitmap=00001F03C0783C00001F1F03C0783C00
bitmap=00000F03C0783C00001E0F03C0783C00
bitmap=00000F03C0783C00001E0F03C0783C00
bitmap=00000F03C0783C00001E0F03C0783C00
bitmap=00000F03C0783C00001E0F03C0783C00
bitmap=00000F03C0783C00001E0F03C0783C00
bitmap=00000F03C0783C00001E0F03C0783C00
bitmap=00180F03C0783C00001E0F03C0783C00
bitmap=001C1F03E0783C00001F1F03E0783C00
bitmap=000FFE01F0783C00000FFE01F0783C00
bitmap=0007FC00F0783C000007FC00F0783C00
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
x=128
y=32
width=8
[Ordinal::BitMap::4]
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=001FFF03C07800000007FC03C0780000
bitmap=001FFF03C0780000000FFE03C0780000
bitmap=00000F03C0780000001F1F03C0780000
bitmap=00000F03C0780000001E0F03C0780000
bitmap=00000F0FF07BF000001E0F0FF07BF000
bitmap=00001F0FF07FF800001E0F0FF07FF800
bitmap=00001E03C07C7800001E0F03C07C7800
bitmap=00003E03C0783C00001E0F03C0783C00
bitmap=00003C03C0783C00000F1E03C0783C00
bitmap=00003C03C0783C000007FC03C0783C00
bitmap=00007803C0783C000007FC03C0783C00
bitmap=00007803C0783C00000F1E03C0783C00
bitmap=00007803C0783C00001E0F03C0783C00
bitmap=0000F003C0783C00001E0F03C0783C00
bitmap=0000F003C0783C00001E0F03C0783C00
bitmap=0000F003C0783C00001E0F03C0783C00
bitmap=0000F003C0783C00001E0F03C0783C00
bitmap=0000F003E0783C00000F1E03E0783C00
bitmap=0000F001F0783C00000FFE01F0783C00
bitmap=0000F000F0783C000007FC00F0783C00
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
x=128
y=32
width=8
[pilots]
pilot=127.0.0.1:1502
pilot=127.0.0.1:1602
[127.0.0.1:1502]
hostType=0
advancedDamage=1
loadzones=1
name=Aeolus
bitmapindex=1
experience=expert
badge=VGL
patch=Yellow
role=Role::Default
dropzone=one
vehicle=bhk1
vehicleValue=1000
color=White
[127.0.0.1:1602]
hostType=0
advancedDamage=1
loadzones=1
name=Boreas
bitmapindex=2
experience=expert
badge=VGL
patch=Yellow
role=Role::Default
dropzone=one
vehicle=madcat
vehicleValue=1000
color=Crimson
[largebitmap]
bitmap=BitMap::Large::Aeolus
[BitMap::Large::Aeolus]
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=000003FE0000000001E0000000000000
bitmap=000007FF0000000001E0000000000000
bitmap=00000F8F8000000001E0000000000000
bitmap=00000F078000000001E0000000000000
bitmap=00000F0781FF00FF81E0F0781FC00000
bitmap=00000F0783FF81FFC1E0F0783FE00000
bitmap=00000F0787C7C3E3E1E0F0783C700000
bitmap=00000F078783C3C1E1E0F07878300000
bitmap=00000F078783C3C1E1E0F07878000000
bitmap=00000FFF8783C3C1E1E0F0787C000000
bitmap=00000FFF8783C3C1E1E0F0787F000000
bitmap=00000F0787FFC3C1E1E0F0783FC00000
bitmap=00000F0787FFC3C1E1E0F0781FE00000
bitmap=00000F07878003C1E1E0F07807F00000
bitmap=00000F07878003C1E1E0F07801F00000
bitmap=00000F07878003C1E1E0F07800F00000
bitmap=00000F078780C3C1E1E0F07860F00000
bitmap=00000F0787C1C3E3E1E078F871E00000
bitmap=00000F0783FF81FFC1E07FF83FE00000
bitmap=00000F0781FF00FF81E03F781FC00000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
bitmap=00000000000000000000000000000000
x=128
y=32
width=8
[smallbitmap]
bitmap=BitMap::Small::Aeolus
[BitMap::Small::Aeolus]
bitmap=00000000000000000000000000000000
bitmap=0000000000000000003E00000C000000
bitmap=006300000C00000000631F0F8CC63C00
bitmap=00633198CCC66200007F3198CCC66000
bitmap=00633F98CCC6780000633018CCC61E00
bitmap=00633018CCC6060000633098CCC64600
bitmap=00631F0F8C7E3C000000000000000000
bitmap=00000000000000000000000000000000
x=64
y=16
width=4
[Role::Default]
model=dfltrole
[Role::NoReturn]
model=noretun
+4 -4
View File
@@ -644,10 +644,10 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
LIVENESS audit (does a live call path reach each reconstructed fn?) would catch this class.
## Rendering follow-ups (non-blocking)
- **Per-pilot mech PAINT (color/badge/patch) — art ships, port never engages it** (2026-07-17 audit;
full mechanics + fix path in [[rendering]] §Per-pilot mech PAINT). Wire egg color/badge/patch into
`SetupMaterialSubstitutionList`, apply `substituteMaterial` in `bgfload resolve()`, per-variant
mesh cache. This is the "missing warning stripes / coloration" report.
- ~~Per-pilot mech PAINT (color/badge/patch)~~**DONE 2026-07-17, verified live** (crimson MadCat +
yellow VGL emblems + hip hazard stripes). Mechanics + the vehicletable color/badge/patch name
tables in [[rendering]] §Per-pilot mech PAINT. Residual nit: eggs saying `color=Red` mean
**Crimson** (table has no Red; the binary Fail()ed on it, the port warns + drops).
- **.PFX effect-layer polish (deferred 2026-07-08; the layer itself is LIVE + verified).** The
reconstructed BT particle layer (L4VIDEO.cpp, see its banner) renders the authentic .PFX content
(fire + smoke, premultiplied blend, impact-frame oriented — weapon hits AND damage bands via
+16 -7
View File
@@ -126,13 +126,22 @@ never engaged by the port. Mechanics (all [T1] from the BMF/BGF/vehicletable con
top-left), shown through the paintable-zone materials and tinted by the pilot color. `EMBLEM0.BMF`
carries `lgoN_<patchcolor>_dz_ld/rdleg` materials (8 patch tints incl. yellow .89,.73,0) over
`LGO.BSL` slices 0-5 (slice 5 = VGL winged logo).
- PORT GAP: `SetupMaterialSubstitutionList` (btl4vid.cpp:2094) feeds NULL egg names (Mech's
resourceNameA/B/C not yet safely readable), and `substituteMaterial` (L4VIDEO.cpp:2565) is consumed
only by the legacy .X loader (L4D3D.cpp:151) — NOT by `bgfload`'s `MaterialResolver::resolve`. So
every mech renders base untinted paint + the hardwired `lgo6` (VGL) emblem. Verified live 2026-07-17:
MP MadCat renders white/gray, no tint/emblem/stripes. FIX PATH: (a) wire real egg color/badge/patch
into the substitution list; (b) apply the substitution in `resolve()` (BGF path); (c) per-variant
mesh caching (BgfData is cached per filename — two pilots' colors must not share a baked mesh). [T2]
- **WIRED 2026-07-17 (same-day fix), verified live**: MP MadCat renders crimson with hip hazard
stripes + yellow VGL leg emblems; Blackhawk white + emblems; replicants painted on both nodes.
The reconstruction: (a) `Mech::resourceNameA/B/C` are real `CString` members (the binary's exact
16-byte `CStringRepresentation` {size,len,text@+8,refs@+0xc}; ctor = part_012.c:9841-71, deep-copy
bind from the MakeMessage = `CString::operator=(const char*)` == FUN_00402a98 @10427-41, implicit
member dtors = 11388-403) with paint-name accessors; (b) `SetupMaterialSubstitutionList` reads them
(real egg names; `[paint]` log line); (c) `dpl_SetMaterialNameCallback` is REAL now
(L4VIDEO.cpp registry, cleared first in TearDown as FUN_004d11e8 does) and
`bgfload MaterialResolver::resolve()` runs every name through `dpl_ApplyMaterialNameCallback`;
no mesh-cache issue (LoadObject/LoadBgfFile don't cache — every load resolves fresh). [T2]
- DEVIATION (documented, btl4vid.cpp): on a vehicletable miss the binary Fail()ed ("Exiting"
@BTL4VID.CPP:0xbeb); the port warns + drops that placeholder (RP analogue). Real case: dev eggs
ship `color=Red` but the `[color]` table only has **Crimson** — MP_BHMC.EGG fixed to Crimson;
LAST.EGG pilot-2 still says Red (unused slot). The 7 valid egg colors:
Black/Brown/Crimson/Green/Grey/Tan/White; badges Davion/Kurita/Liao/Marik/None/Steiner/VGL;
patches Black/Blue/Green/Grey/Red/Violet/White/Yellow. [T1]
## The OLD-STYLE SPECIALFX layer (the weapon-impact action) — RECONSTRUCTED 2026-07-12 (firmware-decoded)
The per-weapon impact visuals are fully AUTHORED in `content/BTDPL.INI` `[effects_to_load]`:
+33
View File
@@ -2631,6 +2631,39 @@ char*
return source;
}
//#############################################################################
// dpl material-name callback registry (FUN_0049664c / DAT_00527f24).
//-----------------------------------------------------------------------------
// The 1995 dpl board applied the installed callback to every material name as
// a model loaded (dpl_LoadObject). The port analogue: the BGF loader
// (bgfload.cpp MaterialResolver::resolve) runs every "lib:material" name
// through dpl_ApplyMaterialNameCallback before resolving it, so the per-pilot
// paint substitutions (skin: -> _<color><serno>:, skin:lgo -> emblem<serno>:)
// installed by SetupMaterialSubstitutionList take effect on the mech model
// loads that happen between the Setup/TearDown bracket.
//#############################################################################
static char *(*gMaterialNameCallback)(char *source) = NULL;
void dpl_SetMaterialNameCallback(char *(*callback)(char *source))
{
gMaterialNameCallback = callback;
}
// C++-friendly wrapper honouring the callback's legacy protocol (the callback
// may delete[] the input and return a new[] buffer). Returns the (possibly
// substituted) name.
std::string dpl_ApplyMaterialNameCallback(const std::string &name)
{
if (gMaterialNameCallback == NULL)
return name;
char *buf = new char[name.size() + 1];
strcpy(buf, name.c_str());
buf = gMaterialNameCallback(buf);
std::string result(buf);
delete [] buf;
return result;
}
vector<MONITORINFO> DPLRenderer::MonitorsCreateAll(int &monitorCount)
{
monitorCount = gD3D->GetAdapterCount();
+7
View File
@@ -40,6 +40,13 @@ class NotationFile;
char*
substituteMaterial(char *source);
// dpl material-name callback registry (FUN_0049664c): install/clear the
// per-load substitution hook; dpl_ApplyMaterialNameCallback runs the installed
// hook over a name (identity when none installed). Consumed by the BGF
// loader's material resolver.
void dpl_SetMaterialNameCallback(char *(*callback)(char *source));
std::string dpl_ApplyMaterialNameCallback(const std::string &name);
void loadTables();
const char* opMaterialName(const char *fileName, int opId);
+10 -1
View File
@@ -11,6 +11,11 @@
#include <set>
#include <array>
// L4VIDEO.cpp: the dpl material-name callback registry. While a mech loads
// (the SetupMaterialSubstitutionList / TearDown bracket) this rewrites
// "blhskin:..." -> "blh_wht0:..." / "emblem0:..." -- the per-pilot paint.
std::string dpl_ApplyMaterialNameCallback(const std::string &name);
namespace {
// ---- DIV-BIZ2 tag ids (PFBIZTAG.H), masked form (tagword & 0x2fff) ----
@@ -503,7 +508,11 @@ struct MaterialResolver {
return libs.emplace(lib, std::move(table)).first->second;
}
MatInfo resolve(const std::string& full) {
MatInfo resolve(const std::string& fullIn) {
// Per-pilot paint: run the name through the installed dpl material-name
// callback first (identity when none) -- the board rewrote names at
// load time, before any material lookup.
std::string full = dpl_ApplyMaterialNameCallback(fullIn);
auto cached = resolvedCache.find(full);
if (cached != resolvedCache.end()) return cached->second;
MatInfo info;
+26 -16
View File
@@ -2128,23 +2128,25 @@ void
//
// Look up this mech's colour / badge / patch codes from the table, using
// the egg-supplied names carried on the entity (badge=resourceNameA @0x844,
// color=resourceNameB @0x848, patch=resourceNameC @0x84c).
// color=resourceNameB @0x848, patch=resourceNameC @0x84c). The binary
// reads the backing text straight off the ref-counted name objects
// (*(char**)(*(int*)(mech+0x848)+8) etc.); the reconstructed Mech now
// carries them as real CString members deep-copied from the MakeMessage,
// exposed via the paint-name accessors.
//
// The recovered code read these directly off the BattleTech mech egg
// (Mech::vehicleColor / vehicleBadge / vehiclePatch) and Fail()ed on a miss.
// TODO(bring-up): the reconstructed Mech carries those names as ref-counted
// creation-name objects (resourceNameA/B/C) whose backing string is the
// transient MakeMessage buffer -- not safely readable here yet, and the
// attribute-index path ("VehicleColor"/...) is not wired, so it returns
// garbage that FindNote then deref-crashed on (btl4vid.cpp:808). Follow the
// RP analogue (RPL4VID.cpp:1562) which simply tolerates a missing colour/
// badge: a NULL egg name or a table miss leaves veh_* == NULL and the
// placeholder substitution below drops to default materials. Re-wire the
// real egg names (a named Mech accessor) once the Mech layout is mapped.
// DEVIATION (documented): on a table miss the binary Fail()ed hard
// ("Exiting" @BTL4VID.CPP:0xbeb/0xbf2/0xbf9). We follow the RP analogue
// (RPL4VID.cpp:1562) and tolerate it -- a NULL/missing name leaves veh_* ==
// NULL and that placeholder expands empty (base materials) -- so a sparse
// test egg degrades to the old gray-metal look instead of killing the pod.
//
const char *egg_color = NULL; // [0x848] resourceNameB (color)
const char *egg_badge = NULL; // [0x844] resourceNameA (badge)
const char *egg_patch = NULL; // [0x84c] resourceNameC (patch)
Mech *mech = (Mech *)entity; // caller dispatched on MechClassID
const char *egg_color = mech->GetVehicleColorName(); // [0x848] resourceNameB
const char *egg_badge = mech->GetVehicleBadgeName(); // [0x844] resourceNameA
const char *egg_patch = mech->GetVehiclePatchName(); // [0x84c] resourceNameC
if (egg_color && !*egg_color) egg_color = NULL;
if (egg_badge && !*egg_badge) egg_badge = NULL;
if (egg_patch && !*egg_patch) egg_patch = NULL;
const char *veh_color = NULL, *veh_badge = NULL, *veh_patch = NULL;
if (egg_color && !veh_tbl->GetEntry("color", egg_color, &veh_color)) // @0051d94e
@@ -2166,6 +2168,14 @@ void
veh_patch = NULL;
}
DEBUG_STREAM << "[paint] mech egg color='" << (egg_color ? egg_color : "<none>")
<< "' badge='" << (egg_badge ? egg_badge : "<none>")
<< "' patch='" << (egg_patch ? egg_patch : "<none>")
<< "' -> codes color=" << (veh_color ? veh_color : "-")
<< " badge=" << (veh_badge ? veh_badge : "-")
<< " patch=" << (veh_patch ? veh_patch : "-")
<< " serno=" << gSerno << "\n" << std::flush;
//
// Generic substitution list, then expand placeholders per entry.
//
@@ -2257,6 +2267,7 @@ void
void
BTL4VideoRenderer::TearDownMaterialSubstitutionList()
{
dpl_SetMaterialNameCallback(NULL); // FUN_0049664c(0) -- first, as the binary does
if (materialSubstitutionList != NULL)
{
for (NameList::Entry *entry = materialSubstitutionList->GetFirstEntry();
@@ -2269,7 +2280,6 @@ void
delete materialSubstitutionList;
materialSubstitutionList = NULL;
}
// dpl_SetMaterialNameCallback(NULL);
}
//===========================================================================//
+5 -11
View File
@@ -247,17 +247,11 @@ LWord BT_GetSegmentFlags(Mech *owner)
return owner ? owner->simulationFlags : 0;
}
//===========================================================================//
// Legacy libDPL material-name callback.
//---------------------------------------------------------------------------//
// The dpl2d_ 2D display-list API (NewDisplayList/Begin/SetColor/Circle/
// PushMatrix/PopMatrix/MoveTo/End/Compile) was MOVED OUT of this file and
// reimplemented over Direct3D 9 in decomp/reconstructed/dpl2d.cpp (the HUD/
// reticle 2D layer). Only the 3D material-name-substitution hook -- which is
// part of the world renderer, not the 2D HUD -- remains stubbed here.
// TODO(bring-up): wire the material substitution table (FUN_00459eb8).
//===========================================================================//
void dpl_SetMaterialNameCallback(char *(*)(char *)) {}
// dpl_SetMaterialNameCallback is now REAL (per-pilot mech paint): it lives in
// engine/MUNGA_L4/L4VIDEO.cpp next to substituteMaterial, and the BGF loader
// (bgfload.cpp MaterialResolver::resolve) applies the installed callback to
// every material name -- the port analogue of the dpl board rewriting names
// at dpl_LoadObject time (FUN_0049664c / FUN_00459eb8).
//===========================================================================//
// BTL4VideoRenderer helper methods whose bodies were not reconstructed.
+15 -10
View File
@@ -888,10 +888,11 @@ Mech::Mech(
//
// Three ref-counted creation-name holders (badge/color/insignia).
// CString members now: their default ctors run in the member-init phase and
// allocate the empty CStringRepresentation + addref -- exactly the binary's
// new(0x10)/FUN_004023f4/refs++ triple @part_012.c:9841-9871. Nothing to
// do here.
//
resourceNameA = NewRefCounted(); // Wword(0x211)
resourceNameB = NewRefCounted(); // Wword(0x212)
resourceNameC = NewRefCounted(); // Wword(0x213)
instanceFlags |= 0x10; // this[10] |= 0x10
// Zero the optional-subsystem back-pointers up front (binary @9873-9875).
@@ -1710,11 +1711,14 @@ Mech::Mech(
}
//
// Bind the three creation-name strings from the MakeMessage.
// Bind the three creation-name strings from the MakeMessage. CString::
// operator=(const char*) releases the empty ctor rep and allocates a fresh
// rep COPYING the message's inline char[20] -- byte-for-byte FUN_00402a98
// (part_012.c:10427-10441); the names survive the transient message.
//
resourceNameA = creation_message->resourceNameA; // param_2+0x7c -> Wword(0x211)
resourceNameB = creation_message->resourceNameB; // param_2+0x90 -> Wword(0x212)
resourceNameC = creation_message->resourceNameC; // param_2+0xa4 -> Wword(0x213)
resourceNameA = creation_message->resourceNameA; // badge param_2+0x7c -> Wword(0x211)
resourceNameB = creation_message->resourceNameB; // color param_2+0x90 -> Wword(0x212)
resourceNameC = creation_message->resourceNameC; // patch param_2+0xa4 -> Wword(0x213)
//
// Register this Mech in the global "Mechs" directory.
@@ -1810,9 +1814,10 @@ Mech::~Mech()
delete (MechDeathHandler *)deathHandler; // real class -> plain delete
}
ReleaseRefCounted(resourceNameC); // Wword(0x213)
ReleaseRefCounted(resourceNameB); // Wword(0x212)
ReleaseRefCounted(resourceNameA); // Wword(0x211)
// resourceNameC/B/A: the binary's inline refcount-decrement/delete triple
// (part_012.c:11388-11403) is the CString member dtors -- implicit at the
// closing brace now that the members are real CStrings (dtor-epilogue rule:
// do NOT also write them out here).
//
// ⚠ RECONSTRUCTION RULE (root cause of the P5 death-row crash AND the app-exit
+22 -4
View File
@@ -50,6 +50,7 @@
# include <alarm.hpp> // GaugeAlarm
#endif
#include <tool.hpp> // PlatformTool
#include <cstr.hpp> // CString (the vehicle badge/color/patch creation names)
#include <affnmtrx.hpp> // AffineMatrix
#include <average.hpp> // AverageOf<T>
#include <scalar.hpp> // Scalar
@@ -764,10 +765,27 @@ protected:
// eye-slew system (HUD freeAimSlew / gyro eye chain) writes it.
EulerAngles eyepointRotation;
// Three ref-counted creation-name objects (badge/color/insignia).
void *resourceNameA; // @0x844 this[0x211]
void *resourceNameB; // @0x848 this[0x212]
void *resourceNameC; // @0x84c this[0x213]
// Three ref-counted creation-name strings (badge/color/insignia).
// CString members: each slot is a CStringRepresentation* -- the exact
// 16-byte object {size,len,text@+8,refs@+0xc} the binary's Mech ctor
// allocates (part_012.c:9841-9871) and the make handler re-binds from
// the MakeMessage via CString::operator=(const char*) == FUN_00402a98
// (part_012.c:10427-10441). SetupMaterialSubstitutionList reads the
// backing text (*(char**)(this+0x844..84c)+8) for the vehicle-table
// color/badge/patch lookups.
CString resourceNameA; // @0x844 this[0x211] (vehicle badge)
CString resourceNameB; // @0x848 this[0x212] (vehicle color)
CString resourceNameC; // @0x84c this[0x213] (vehicle patch)
public:
// Paint-name accessors (SetupMaterialSubstitutionList). CString's
// operator char*() returns the rep's stringText -- NULL for a
// default-constructed (never-bound) name; callers must tolerate NULL.
const char *GetVehicleBadgeName() const { return (const char *)resourceNameA; }
const char *GetVehicleColorName() const { return (const char *)resourceNameB; }
const char *GetVehiclePatchName() const { return (const char *)resourceNameC; }
protected:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Reconstruction additions -- members & methods whose bodies live in the