ROOT CAUSE: target designation wrote a Mech* into deathPending, disabling respawn (#57/#48)
MEASURED our compiled BTPlayer layout (new one-shot [layout] ctor diagnostic): sizeof=652 (0x28c) killCount@0x270 pad_0x280@0x274 objectiveMech@0x278 deathPending@0x284 The three target-designation sites wrote RAW at pilotArray[0]+0x284 intending the BINARY's objectiveMech. On our object 0x284 is deathPending -- the death-cycle latch. So EVERY target designation (the Comm bank 0x30-0x37, or the typed t/y/u/i/o keys) stored a Mech pointer into deathPending, and a non-zero deathPending makes VehicleDeadMessageHandler take its dedup early-return, which skips the warp, ++deathCount, the PLAYER_DEAD record AND the drop-zone hunt. => designating a target silently disabled your respawn for the rest of the process. That is #57's missing first cause: it explains David's very first death being swallowed with no prior death, and the 3-of-3 swallowed deaths in the final round. It also explains the operator's persistent observation that the trouble began when the comms panel went live -- before the pilot list populated, there was nothing to designate. And the designation never worked either: the value never reached objectiveMech (input-audit finding #1). FIX: all three sites now use named-member bridges in the complete-BTPlayer TU -- BTPilotSetObjectiveMech / BTPilotObjectiveMech / BTPilotVehicle / BTPilotPosition / BTVehicleDestroyed. Also retires the raw +0x1fc (playerVehicle) reads and the raw +0x100 position reads in ChooseNearestPilot, and routes its destroyed-check through the real Mech predicate instead of the Is_Destroyed stub. LAYOUT LOCKS: static_asserts on objectiveMech@0x278, deathPending@0x284, killCount@0x270 and sizeof==0x28c, in the friend fn BTPlayerLayoutSelfCheck, so a member shift fails the BUILD instead of silently clobbering the latch again. Rigs: scratchpad/commstest.py (drives designation + captures panels), valvetest.py, lampgallery.py (428-bitmap gallery for #48 visual search). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0166KTsC7ADm7VXEi1HF1jNg
This commit is contained in:
co-authored by
Claude Opus 5
parent
cb50a1d491
commit
2dd4ee3910
@@ -81,6 +81,21 @@
|
||||
extern void ToggleVoiceAssist(int voice_assist_subsystem);
|
||||
extern Logical Is_Destroyed(int entity_handle);
|
||||
|
||||
//
|
||||
// TARGET-DESIGNATION bridges (btplayer.cpp, the complete-BTPlayer TU). The three
|
||||
// designation sites used to write RAW at `pilotArray[0] + 0x284` -- the BINARY's
|
||||
// `objectiveMech` offset. Measured on our compiled object, 0x284 is
|
||||
// **`deathPending`**, the death-cycle latch, so every designation silently
|
||||
// disabled the pilot's respawn (Gitea #57) while the target never reached
|
||||
// `objectiveMech` at all (Gitea #48 / input-audit finding #1). Named members
|
||||
// only, from here on -- see the static_asserts in btplayer.cpp.
|
||||
//
|
||||
extern void BTPilotSetObjectiveMech(void *pilot, void *target_vehicle);
|
||||
extern void *BTPilotObjectiveMech(void *pilot);
|
||||
extern void *BTPilotVehicle(void *pilot);
|
||||
extern int BTPilotPosition(void *pilot, float *out_xyz);
|
||||
extern int BTVehicleDestroyed(void *vehicle);
|
||||
|
||||
//
|
||||
// Mech::GetHorizontalFiringReach -- the reachable horizontal firing half-arc
|
||||
// (radians) the mech's torso can bring its guns to bear off dead-ahead. Weapons
|
||||
@@ -1337,11 +1352,9 @@ void
|
||||
}
|
||||
|
||||
Pilot *chosen = pilotArray[index];
|
||||
if (chosen != 0)
|
||||
{
|
||||
target = *(int *)((int)chosen + 0x1fc);
|
||||
}
|
||||
*(int *)((int)pilotArray[0] + 0x284) = target;
|
||||
void *target_vehicle = (chosen != 0) ? BTPilotVehicle(chosen) : 0;
|
||||
BTPilotSetObjectiveMech(pilotArray[0], target_vehicle);
|
||||
(void)target;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1355,13 +1368,9 @@ void
|
||||
{
|
||||
if (pilotArrayBuilt && pilotArray[0] != 0)
|
||||
{
|
||||
int target = 0;
|
||||
Pilot *chosen = pilotArray[page];
|
||||
if (chosen != 0)
|
||||
{
|
||||
target = *(int *)((int)chosen + 0x1fc);
|
||||
}
|
||||
*(int *)((int)pilotArray[0] + 0x284) = target;
|
||||
void *target_vehicle = (chosen != 0) ? BTPilotVehicle(chosen) : 0;
|
||||
BTPilotSetObjectiveMech(pilotArray[0], target_vehicle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1383,28 +1392,40 @@ void
|
||||
int nearest_index = 0;
|
||||
Logical none_yet = True;
|
||||
|
||||
//
|
||||
// Positions come off each pilot's VEHICLE through the bridge (the binary's
|
||||
// raw `pilot + 0x100` is an Entity-layout offset that does not exist on our
|
||||
// Player). A pilot with no vehicle -- dead, or not yet acquired -- has no
|
||||
// position and cannot be the nearest target, so it is skipped.
|
||||
//
|
||||
float self_pos[3];
|
||||
if (!BTPilotPosition(pilotArray[0], self_pos))
|
||||
{
|
||||
Check_Fpu();
|
||||
return;
|
||||
}
|
||||
void *self_vehicle = BTPilotVehicle(pilotArray[0]);
|
||||
(void)self_id; // the binary compared raw handles
|
||||
|
||||
for (int i = 1; i < pilotCount; ++i)
|
||||
{
|
||||
int entity = *(int *)((int)pilotArray[i] + 0x1fc);
|
||||
Vector3D delta;
|
||||
delta.Subtract( // FUN_00408644
|
||||
*(Vector3D *)((int)pilotArray[i] + 0x100),
|
||||
*(Vector3D *)((int)pilotArray[0] + 0x100)
|
||||
);
|
||||
Scalar distance = delta.x * delta.x + delta.y * delta.y + delta.z * delta.z;
|
||||
void *entity = BTPilotVehicle(pilotArray[i]);
|
||||
float pos[3];
|
||||
if (entity == 0 || entity == self_vehicle)
|
||||
continue;
|
||||
if (BTVehicleDestroyed(entity)) // the binary's Is_Destroyed(+0x1fc)
|
||||
continue;
|
||||
if (!BTPilotPosition(pilotArray[i], pos))
|
||||
continue;
|
||||
|
||||
if (none_yet)
|
||||
{
|
||||
if (!Is_Destroyed(entity) && entity != self_id)
|
||||
{
|
||||
none_yet = False;
|
||||
nearest_distance = distance;
|
||||
nearest_index = i;
|
||||
}
|
||||
}
|
||||
else if (!Is_Destroyed(entity) && entity != self_id
|
||||
&& distance < nearest_distance)
|
||||
const float dx = pos[0] - self_pos[0];
|
||||
const float dy = pos[1] - self_pos[1];
|
||||
const float dz = pos[2] - self_pos[2];
|
||||
Scalar distance = dx * dx + dy * dy + dz * dz;
|
||||
|
||||
if (none_yet || distance < nearest_distance)
|
||||
{
|
||||
none_yet = False;
|
||||
nearest_distance = distance;
|
||||
nearest_index = i;
|
||||
}
|
||||
@@ -1413,12 +1434,10 @@ void
|
||||
if (!none_yet)
|
||||
{
|
||||
Pilot *chosen = pilotArray[nearest_index];
|
||||
if (chosen != 0)
|
||||
{
|
||||
target = *(int *)((int)chosen + 0x1fc);
|
||||
}
|
||||
*(int *)((int)pilotArray[0] + 0x284) = target;
|
||||
void *target_vehicle = (chosen != 0) ? BTPilotVehicle(chosen) : 0;
|
||||
BTPilotSetObjectiveMech(pilotArray[0], target_vehicle);
|
||||
}
|
||||
(void)target;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Reference in New Issue
Block a user