Reset-based respawn: reuse+heal the mech, not create-a-new-one (task #52)

The respawn glitches (2 mechs, on-fire respawn, camera-inside, can't-control,
wreck-never-disappears) all traced to one architectural divergence: our respawn
SEVERED playerVehicle on death and CREATED a new mech, leaving the old as a
permanent wreck and building a duplicate viewpoint whose old render tree was
never torn down.

The authentic engine (FUN_0049fb74 + RPPlayer) REUSES the same mech entity: on
respawn Mech::Reset heals it and moves it in place. Implemented faithfully,
adapted to our layout (the 1995 raw offsets map to different 2007 engine fields,
so reset the equivalent named members, not the offsets):
- Mech::Reset (real, was a reposition-only stub): reposition + kill dead-reckon
  (projectedOrigin/projectedVelocity/updateVelocity + our relocated gait
  accumulators) so the replicant stops lerping to the death spot; clear the
  death latch (movementMode=1, graphicAlarm=0); Heal every damage zone
  (new Mech__DamageZone::Heal: full structure, intact skin); DeathReset
  (vtable+0x28) every subsystem; ForceUpdate to broadcast.
- btplayer.cpp: VehicleDead no longer severs playerVehicle; the respawn re-post
  gates on the mech still being dead; DropZoneReply resets the EXISTING mech in
  place (heal+move) instead of creating a new one, then fires the warp. Warp
  moved to the shared placement (initial drop-in + respawn).

Verified 2-node: mech entity ID stays 3:22 across 3 deaths (reused, not a new
3:32); each Reset logs alive=1, 20 zones healed, 33 subsystems reset; A sees ONE
mech (no wreck+new pair). Warp fires each respawn.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-09 23:13:44 -05:00
co-authored by Claude Opus 4.8
parent efa7aeb683
commit 247e51e1e1
5 changed files with 196 additions and 69 deletions
+4 -32
View File
@@ -161,38 +161,10 @@ void Mech::RaiseStatusAlarm(int /*alarm_id*/)
{
}
// Mech::Reset (@0049fb74) -- place the mech at a (re)spawn origin.
// The shipped Reset additionally zeroes ~50 heat/damage/motion state fields and
// resets every subsystem in the roster (slot vtable+0x28 with the reset mode);
// that full sweep is deferred (TODO(bring-up)). For first spawn a freshly
// constructed mech is already clean, so positioning it + refreshing the world
// transform + forcing an update is enough to get it placed and rendering.
void Mech::Reset(const Origin &origin, int /*mode*/)
{
Check(this);
localOrigin = origin; // this+0x100 (FUN_0040a938 copy)
localToWorld = localOrigin; // this+0xd0 (FUN_0040ab44 rebuild)
ForceUpdate(); // FUN_004a4c54 family -- push to renderer/replicants
// BRING-UP (Tier-2 locomotion): get the player mech onto the per-frame
// simulation path so it can walk. Two engine gates block a freshly spawned
// master entity from being executed:
// (1) Entity::Execute only calls PerformAndWatch when the app is in
// RunningMission/EndingMission OR the entity IsPreRunnable()
// (ENTITY.cpp:~549) -> set the pre-run flag.
// (2) UpdateManager::Execute skips a master unless IsInteresting()
// (interestCount!=0) && IsNonReplicantExecutable() (UPDATE.cpp:148)
// -> force it interesting so the update manager ticks it.
// Without these the mech renders but is never simulated (static
// localToWorld). See Mech::PerformAndWatch (mech4.cpp).
SetPreRunFlag();
if (interestCount == 0) interestCount = 1; // Entity::interestCount (public)
DEBUG_STREAM << "[drive] Mech::Reset spawn at ("
<< localOrigin.linearPosition.x << ", "
<< localOrigin.linearPosition.y << ", "
<< localOrigin.linearPosition.z << ") -- prerun+interest forced\n" << std::flush;
Check_Fpu();
}
// Mech::Reset (@0049fb74) is now the real faithful reconstruction in mech4.cpp
// (reposition + kill dead-reckon + clear death/damage + ResetToInitialState every
// subsystem + heal every damage zone + ForceUpdate) -- no longer the reposition-
// only stub that lived here.
// (Mech__DamageZone::LoadCriticalSubsystems was a no-op stub here; it is now the
// real type-0x1e damage-state descriptor-table loader in mechdmg.cpp.)