MP combat step 1 (target any peer) DONE; step 2 (cross-pod damage) localised (task #46)
STEP 1 -- target any peer mech: DONE + verified. A live-mech registry (BTRegisterMech/BTDeregisterMech from the Mech ctor/dtor) collects every mech -- player, dummy, and peer replicants. The boresight world-pick walks BTGetTargetCandidates (all mechs != shooter, closest ray hit) and the whole fire/damage block retargets from the solo gEnemyMech to the picked hotTarget; missile/projectile validation generalised via BTIsRegisteredMech. Verified one-box: instance A enumerates B's mech as a live ReplicantInstance (20 zones, ownerID=3). Solo un-regressed (pick->damage->kill clean, 28 hits + DESTROYED). STEP 2 -- cross-pod damage: dispatch + engine reroute are CORRECT and invoked with a valid owner, but the dispatched message doesn't reach the master. Entity::Dispatch (ENTITY.cpp:244) reroutes a replicant's msg via application->SendMessage(ownerID,...); BT_MP_FORCE_DMG proves A dispatches at B's replicant with ownerID=3, yet B takes 0 STEP-6 damage. Corrects the KB's [T3] "Dispatch already reroutes": the reroute FIRES; the break is downstream in the transport/delivery of a dispatched entity-message (update records flow fine -- net-rx works). Next MP task = that wire delivery. Diagnostics BT_MP_LOG / BT_MP_FORCE_DMG retained. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
48191d6fdf
commit
a9c3e96f20
@@ -117,6 +117,63 @@
|
||||
// current target. NULL when no enemy was spawned (BT_SPAWN_ENEMY unset).
|
||||
Entity *gEnemyMech = 0;
|
||||
|
||||
//
|
||||
// LIVE-MECH REGISTRY (task #46): every Mech (player, dummy, peer replicants)
|
||||
// (de)registers here from its ctor/dtor. The boresight world-pick walks it to
|
||||
// find target candidates -- generalising the solo gEnemyMech to MP peers. A
|
||||
// plain fixed array (mech counts are tiny -- <= a few per arena) avoids any
|
||||
// allocator interaction in the hot ctor path.
|
||||
//
|
||||
static Entity *gBTMechRegistry[32];
|
||||
static int gBTMechCount = 0;
|
||||
|
||||
void BTRegisterMech(Entity *m)
|
||||
{
|
||||
if (m == 0) return;
|
||||
for (int i = 0; i < gBTMechCount; ++i) // idempotent
|
||||
if (gBTMechRegistry[i] == m) return;
|
||||
if (gBTMechCount < 32)
|
||||
gBTMechRegistry[gBTMechCount++] = m;
|
||||
}
|
||||
|
||||
void BTDeregisterMech(Entity *m)
|
||||
{
|
||||
for (int i = 0; i < gBTMechCount; ++i)
|
||||
{
|
||||
if (gBTMechRegistry[i] == m)
|
||||
{
|
||||
gBTMechRegistry[i] = gBTMechRegistry[--gBTMechCount];
|
||||
gBTMechRegistry[gBTMechCount] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The target-candidate list for a given shooter: every registered mech that is
|
||||
// NOT the shooter itself. (Alive/pick filtering is the caller's -- mech4's
|
||||
// world-pick already tests IsMechDestroyed + the collision-box ray.)
|
||||
int BTGetTargetCandidates(Entity *shooter, Entity **out, int maxOut)
|
||||
{
|
||||
int n = 0;
|
||||
for (int i = 0; i < gBTMechCount && n < maxOut; ++i)
|
||||
{
|
||||
Entity *m = gBTMechRegistry[i];
|
||||
if (m != 0 && m != shooter)
|
||||
out[n++] = m;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// Is this entity a live registered mech? (Projectile-impact target validation
|
||||
// -- replaces the solo `== gEnemyMech` guard.)
|
||||
int BTIsRegisteredMech(Entity *e)
|
||||
{
|
||||
for (int i = 0; i < gBTMechCount; ++i)
|
||||
if (gBTMechRegistry[i] == e)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Reconstruction helpers / data referenced by the decomp that have no direct
|
||||
// analog in the surviving WinTesla headers (CROSS-FAMILY / engine gap -- see
|
||||
|
||||
Reference in New Issue
Block a user