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:
co-authored by
Claude Opus 4.8
parent
e430e474cb
commit
83b3f31957
@@ -141,6 +141,9 @@
|
||||
#include <BOXSOLID.hpp> // BoxedSolid / BoxedSolidCollision / BoxedSolidCollisionList
|
||||
#include <cultural.hpp> // CulturalIcon::IsStoppingCollisionVolume / GetClassDerivations
|
||||
#include <hostmgr.hpp> // HostManager::GetEntityPointer (band-effect attacker resolve)
|
||||
#if !defined(PLAYER_HPP)
|
||||
# include <player.hpp> // Player::VehicleDeadMessage -- the death->respawn notification (task #52)
|
||||
#endif
|
||||
#if !defined(EMITTER_HPP)
|
||||
# include <emitter.hpp> // Emitter/PPC beam state (the per-weapon beam render walk)
|
||||
#endif
|
||||
@@ -976,7 +979,20 @@ void
|
||||
Logical
|
||||
Mech::IsMechDestroyed()
|
||||
{
|
||||
// graphicAlarm level 9 = a vital zone / leg gone -> going down (mechdmg.cpp).
|
||||
// AUTHENTIC LATCH first: IsDestroyed == (movementMode 2 || 9) -- the death
|
||||
// modes (FUN_004ab1c8 zeroes locomotion for exactly these) [T1]. The death
|
||||
// modes never revert, so a wreck STAYS destroyed.
|
||||
//
|
||||
// graphicAlarm >= 9 is only the vital-kill TRIGGER that enters the death
|
||||
// transition (mechdmg.cpp:407/426). It is a STATUS indicator, not a latch:
|
||||
// a later leg hit on the wreck legitimately rewrites it to 4/3
|
||||
// (mechdmg.cpp:417/419), which -- when this predicate was the alarm alone --
|
||||
// "resurrected" the wreck (movementMode reverted to 1) and let the next
|
||||
// vital hit run the WHOLE death transition again: double kill score, and a
|
||||
// Score dispatched into the respawn window's severed playerVehicle -> the
|
||||
// engine's Check(playerVehicle) abort (task #52 cdb catch).
|
||||
if (movementMode == 2 || movementMode == 9)
|
||||
return True;
|
||||
return graphicAlarm.GetLevel() >= 9 ? True : False;
|
||||
}
|
||||
|
||||
@@ -1132,6 +1148,36 @@ void
|
||||
<< " DESTROYED (death effects dispatched from the death transition) ***\n"
|
||||
<< std::flush;
|
||||
}
|
||||
|
||||
//
|
||||
// --- RESPAWN CYCLE (task #52): notify the owning player of the death. ---
|
||||
// The BTPlayer VehicleDead handler @004c05c4 receives this with
|
||||
// deathCount == -1 (the ctor default = "immediate death notification"),
|
||||
// does the death bookkeeping, severs playerVehicle (this wreck entity
|
||||
// STAYS in the world) and re-posts the message to itself at +5 seconds
|
||||
// (5.0f @004c0830) -> the engine drop-zone hunt -> DropZoneReply ->
|
||||
// CreatePlayerVehicle (a NEW mech). Only the owner pod's master has a
|
||||
// live playerLink, which is exactly where the cycle must run; replicant
|
||||
// wrecks just mirror the master's death. [T1 the handler @004c05c4;
|
||||
// T3 this dispatch site -- the binary's exact sender is undecoded, but
|
||||
// the once-per-death transition is the only death edge and the message
|
||||
// ctor's deathCount=-1 default exists for precisely this notification.]
|
||||
//
|
||||
{
|
||||
Player *owner = GetPlayerLink();
|
||||
if (owner != 0)
|
||||
{
|
||||
Player::VehicleDeadMessage
|
||||
vehicle_dead(
|
||||
Player::VehicleDeadMessageID,
|
||||
sizeof(Player::VehicleDeadMessage)
|
||||
);
|
||||
owner->Dispatch(&vehicle_dead);
|
||||
if (getenv("BT_DEATH_LOG"))
|
||||
DEBUG_STREAM << "[death] VehicleDead(-1) dispatched to the owning player\n"
|
||||
<< std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user