Whirlwind respawn: authentic death->drop-zone->recreate cycle (task #52)

Death transition (mech4) now dispatches VehicleDead(-1) to the owning
player; BTPlayer::VehicleDeadMessageHandler restructured to the authentic
@004c05c4 three-way branch: -1 = death bookkeeping + sever playerVehicle
(wreck stays) + 5s re-post; >=0 = engine drop-zone hunt -> DropZoneReply
-> CreatePlayerVehicle (new mech); -2 = the acquire probe. Guarded on a
DropZones group so a zone-less mission stays dead instead of aborting.

Three latent bugs the respawn path exposed, all fixed:
- IsMechDestroyed latched on graphicAlarm>=9 alone; a later leg hit on the
  wreck rewrites the alarm to 4/3, un-latching -> the death transition
  re-ran (double kill/score, abort). Now latches on movementMode 2||9.
- Score handlers dereferenced the severed playerVehicle during the dead
  window; guarded.
- The console score flush routed a NetworkClient::Message through the
  player's Entity::Dispatch, which stamps entityID past the smaller struct
  -> /RTC1 stack overflow. Sent via application->SendMessage instead.
- Renderer LoadMission re-entry (per viewpoint-make) re-read the env INI;
  its light block Fail'd on stale sceneLightCount. Reset it in
  DPLReadEnvironment so the respawn's second read is clean.

Verified 2-node self-drive: B killed repeatedly by A respawns each time
(wreck stays), ticks + reloads + takes fresh damage on the new mech, no
abort/hang across multiple death->respawn cycles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-09 20:26:55 -05:00
co-authored by Claude Opus 4.8
parent e430e474cb
commit 83b3f31957
6 changed files with 283 additions and 54 deletions
+18
View File
@@ -4706,6 +4706,24 @@ void
mObjectPaths.clear();
mMaterialPaths.clear();
mTexmapPaths.clear();
// BT (task #52): LoadMission runs ONCE PER VIEWPOINT-MAKE, not once per
// mission -- MakeAndLinkViewpointEntity (APP.cpp:1265) re-links the renderer
// and re-reads the environment every time a new viewpoint mech is built,
// which the RESPAWN path does. The light block in DPLReadINIPage Fails ("All
// lights must be defined on a single INI file page") when sceneLightCount is
// already non-zero -- true on the second read, since neither the ctor-only
// init nor DPLReadINIPage ever clears it. That invariant is meant to catch
// lights SPLIT ACROSS pages WITHIN one read; across separate reads the state
// must reset. Tear the prior mission's lights down so the re-read is clean.
if (sceneLight != NULL)
{
if (mDevice != NULL)
for (int li = 0; li < sceneLightCount; ++li)
mDevice->LightEnable(li, FALSE);
delete [] sceneLight;
sceneLight = NULL;
}
sceneLightCount = 0;
if (renderer_environment->PageExists("main"))
{
if (!(renderer_environment->GetLogicalEntry("main", "debug", &debug_printing)))