WAVE 7 Phase A: wire the projectile/missile weapon SUBSYSTEMS byte-exact (un-mislabeled)
An 8-agent decomp-mapping workflow mapped every weapon-family ctor + fire/spawn path
(scratchpad/wave7_maps.txt). KEY IDENTITY CORRECTION via VDATA.h enum (base 3000=0xBB8):
the factory ctor-address comments were right but the built CLASS names were stubs/base --
0xBCD == ProjectileWeapon (was building the base MechWeapon stub)
0xBCE == GaussRifle (NOT MissileLauncher -- was a MissileLauncher stub)
0xBD0 == MissileLauncher (NOT BallisticWeapon -- was a BallisticWeapon stub)
Un-mislabeled + wired via Create<Class>Subsystem bridges (mirroring CreateEmitterSubsystem),
each static_assert-locked byte-exact on the now-locked MechWeapon(0x3F0)/Emitter(0x478) bases:
* ProjectileWeapon (0xBCD, @4bc3fc : MechWeapon, sizeof 0x448)
FIX: AmmoBinConnection was an empty 1-byte struct -> retyped to the binary's 0xC
SharedData::Connection (was making the object 8 bytes short, sliding
MissileLauncher's missileCount off 0x448).
* MissileLauncher (0xBD0, @4bcff0 : ProjectileWeapon, sizeof 0x44C)
FIX: deleted muzzleVelocity (ALIAS of inherited ProjectileWeapon launchVelocity@0x410)
and salvoCount (SHADOW of inherited MechWeapon damageData.burstCount@0x3d4),
keeping the single own field missileCount@0x448.
* GaussRifle (0xBCE, @4bdcb4 : Emitter, sizeof 0x484 = Emitter + Vector3D muzzleVelocity)
DEDICATED bridge (not CreateEmitter): its FireWeapon is a no-op (mov [eax+0x414],0) --
a non-functional weapon in this 1995 build. Also fixed GAUSS.CPP's discharge write
rechargeLevel -> currentLevel@0x414 (the binary writes this+0x414).
Phase A safe-stubs FireWeapon (consume round + recoil, NO spawn): the reconstructed
Projectile (@4be1bc, 0x340) + Missile (@4bf5b4, 0x368) ENTITY classes are NOT spawn-ready
(Entity-base phantom members overflow their New() alloc -> heap corruption; New() takes
(int)this instead of the 0xD4 descriptor; Entity base size unconfirmed 2007-vs-1995, the
Mech 0x638-vs-0x854 problem). The workflow's adversarial verify flagged the live spawn as a
heap-overflow hazard and recommended exactly this phasing. Phase B = the entity byte-exactness
+ descriptor build + New(MakeMessage*) so a fired shot becomes a flying entity that damages.
Factory now 18 of 20 cases wired to real ticking classes (remaining: SubsystemMessageManager
0xBD3 [WAVE 8], Gyroscope 0xBC4 [deferred]). Verified: Mad Cat (LRM/ballistic) + BLH construct
the real weapon classes + tick authentic charge/ammo/heat/recoil, DESTROYED-in-8, 0 crashes,
heapcheck-clean through construction. Energy weapons already damage via the mech4 beam path,
so combat is unaffected.
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
9d82be46a1
commit
2bcca26cea
@@ -107,14 +107,19 @@ class NotationFile;
|
||||
static SharedData DefaultData;
|
||||
|
||||
// Embedded ref-counted connection to the AmmoBin subsystem (resource
|
||||
// AmmoBin index). The shipped layout is a SharedData::Connection; the
|
||||
// reconstruction models it with this thin proxy (Construct/Connect/
|
||||
// Resolve/Destruct) so the recovered call sites compile unchanged.
|
||||
// AmmoBin index). The shipped layout is a 0xC-byte SharedData::Connection
|
||||
// (ctor FUN_004bcbb0->FUN_004179d4; resolver FUN_00417ab4 two-level-derefs +8),
|
||||
// NOT an empty proxy -- modeling it as 1 byte made ProjectileWeapon 8 bytes
|
||||
// short (0x440 vs the binary 0x448) and slid MissileLauncher's missileCount off
|
||||
// 0x448. Named access (Construct/Connect/Resolve/Destruct) is unchanged + inert
|
||||
// in bring-up (no plug resolves). Same 0xC pattern as SubsystemConnection.
|
||||
struct AmmoBinConnection {
|
||||
void Construct() {}
|
||||
template<class T> void Connect(T) {}
|
||||
void Destruct() {}
|
||||
void *Resolve() { return 0; }
|
||||
void *linked; // +0x00 (SharedData::Connection; inert here)
|
||||
int _reserved[2]; // pad to the binary 0xC connection
|
||||
void Construct() { linked = 0; _reserved[0] = _reserved[1] = 0; }
|
||||
template<class T> void Connect(T s) { linked = (void *)s; }
|
||||
void Destruct() { linked = 0; }
|
||||
void *Resolve() { return linked; }
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -309,10 +314,21 @@ class NotationFile;
|
||||
// --- ammunition ---
|
||||
int tracerInterval; // @0x438 resource TracerInterval (+0x1BC)
|
||||
AmmoBinConnection
|
||||
ammoBinLink; // @0x43C embedded connection to the AmmoBin subsystem
|
||||
// (12 bytes; ctor @004bcbb0, dtor @004bcbcf,
|
||||
// link vtable @00512424; resolved via the
|
||||
// resource AmmoBin index at +0x1C0)
|
||||
ammoBinLink; // @0x43C embedded 0xC connection to the AmmoBin subsystem
|
||||
// (ctor @004bcbb0, dtor @004bcbcf, link vtable
|
||||
// @00512424; resolved via the resource AmmoBin
|
||||
// index at +0x1C0) -- LAST field, object ends 0x448
|
||||
|
||||
friend struct ProjectileWeaponLayoutCheck;
|
||||
}; // sizeof == 0x448
|
||||
|
||||
struct ProjectileWeaponLayoutCheck {
|
||||
static_assert(offsetof(ProjectileWeapon, totalTimeToEject) == 0x3F0, "ProjectileWeapon::totalTimeToEject @0x3F0 (MechWeapon must end 0x3F0)");
|
||||
static_assert(offsetof(ProjectileWeapon, launchVelocity) == 0x410, "ProjectileWeapon::launchVelocity @0x410");
|
||||
static_assert(offsetof(ProjectileWeapon, leadPosition) == 0x420, "ProjectileWeapon::leadPosition @0x420");
|
||||
static_assert(offsetof(ProjectileWeapon, tracerInterval) == 0x438, "ProjectileWeapon::tracerInterval @0x438");
|
||||
static_assert(offsetof(ProjectileWeapon, ammoBinLink) == 0x43C, "ProjectileWeapon::ammoBinLink @0x43C");
|
||||
static_assert(sizeof(ProjectileWeapon) == 0x448, "sizeof(ProjectileWeapon) 0x448 (== factory alloc)");
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user