Gitea #55: respawn now restores COOLANT / heat / generator state (+ a Generator reset re-transcribed from the binary)
THE GAP: Mech::Reset sweeps every subsystem with the virtual DeathReset (mech4.cpp:1789), but only 7 weapon/ammo classes overrode it -- the entire heat/coolant/power family fell through to the empty Subsystem::DeathReset base (SUBSYSTM.h:161), so the respawn reset was a SILENT NO-OP for them. All the ResetToInitialState bodies already existed; nothing ever called them. Hence the field report: 'respawned with drained coolant'. Added DeathReset forwarders (ResetToInitialState is not virtual, so each class with its own body needs one): HeatableSubsystem, HeatSink, Condenser, PoweredSubsystem, Generator. HeatSink's also serves Reservoir -- the coolant tank -- which has no body of its own; that is the one that refills coolant. TWO MIS-TRANSCRIPTIONS FIXED, both verified against the binary with capstone: 1. HeatSink::ResetToInitialState chained HeatableSubsystem::ResetToInitialState with the comment 'FUN_004ac22c'. But @004ac22c is Subsystem's terminus -- disassembled: it reads the damage zone at this+0xe0, clears zone+0x158, and Set_Alarm_Levels zone+0x10 and this+0x2c to 0. And the binary's HeatSink @004ad760 calls only @004ad884 (ClearHeatFilter), @004ad7f0 (UpdateHeatLoad) and @004ac22c -- never HeatableSubsystem. Worse, HeatableSubsystem's body sets currentTemperature = 300.0f, CLOBBERING the startingTemperature that HeatSink assigned four lines earlier. Dropped the call; the terminus work is already done for every subsystem by MechSubsystem::RespawnRepair (mech4.cpp:1790). 2. Generator::ResetToInitialState chained HeatableSubsystem and set outputVoltage = 0 -- which matches GNRATOR.TCP, but BT's BINARY DIVERGES from the TCP source, and the binary is what shipped. Disassembled @004b215c instruction by instruction: it chains HeatSink (so the coolant refill DOES run for a generator), then generatorOn=1, startTimer=0, stateAlarm 0 then 2, **outputVoltage = ratedVoltage**, coolantAvailable=1, coolantFlowScale=1.0, startTimer=startTime. Every offset matches our declared members exactly. The old version brought generators back from a respawn at ZERO output voltage, so energy weapons could never charge -- no recharge ring, no ready dot, nothing damaged. That is a strong candidate for #54 (David's three dead lasers). LIVE VERIFICATION (sim3.py, 3 mechs + force damage): 4 death/respawn cycles, and every heat sink logged coolant == capacity on every respawn, with temp restored to startingTemperature (77) rather than the clobbered 300. Left as a silent regression guard that only speaks if a respawn leaves coolant short. KNOWN REMAINING [T3, noted in code]: Condenser's body chains HeatableSubsystem rather than HeatSink, so a coolant loop's VALVE DETENT may still persist across a respawn -- the binary's Condenser reset is not yet decompiled. Do not claim valves are fixed. 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
2518e43719
commit
08977ff128
@@ -426,6 +426,12 @@ Scalar
|
||||
// alarm goes idle; when restored it returns to "GeneratorOff" with the start
|
||||
// timer reset, but only while the source is actually Ready (state 2).
|
||||
//
|
||||
void
|
||||
PoweredSubsystem::DeathReset(int /*reset_command*/)
|
||||
{
|
||||
ResetToInitialState(True); // @004b0e6c
|
||||
}
|
||||
|
||||
void
|
||||
PoweredSubsystem::ResetToInitialState(Logical powered)
|
||||
{
|
||||
@@ -1086,10 +1092,56 @@ Logical Generator::TestInstance() const { return IsDerivedFrom(*GetClassDerivati
|
||||
// the generator output cold.
|
||||
//
|
||||
void
|
||||
Generator::ResetToInitialState(Logical /*powered*/)
|
||||
Generator::ResetToInitialState(Logical powered)
|
||||
{
|
||||
HeatableSubsystem::ResetToInitialState(True);
|
||||
outputVoltage = 0.0f;
|
||||
//
|
||||
// RE-TRANSCRIBED FROM THE BINARY (Gitea #55). The old body chained
|
||||
// `HeatableSubsystem::ResetToInitialState` and set `outputVoltage = 0` -- which
|
||||
// is what GNRATOR.TCP says (see gnrator.hpp), but **BT's binary diverges from
|
||||
// the TCP source here**, and the binary is what shipped in the pod.
|
||||
//
|
||||
// Disassembled @004b215c, instruction for instruction:
|
||||
// call 0x4ad760 (this, powered) -> HeatSink::ResetToInitialState (NOT
|
||||
// HeatableSubsystem -- so the coolant
|
||||
// refill DOES run for a generator)
|
||||
// [this+0x1d4] = 1 -> generatorOn = 1
|
||||
// [this+0x1f0] = 0 -> startTimer = 0
|
||||
// Set_Alarm_Level(this+0x1fc, 0) -> stateAlarm 0
|
||||
// Set_Alarm_Level(this+0x1fc, 2) -> stateAlarm 2 (on line)
|
||||
// eax = [this+0x1d8]; [this+0x1dc] = eax
|
||||
// -> outputVoltage = ratedVoltage
|
||||
// [this+0x134] = 1 -> coolantAvailable = 1
|
||||
// [this+0x15c] = 0x3f800000 -> coolantFlowScale = 1.0f
|
||||
// ecx = [this+0x1ec]; [this+0x1f0] = ecx
|
||||
// -> startTimer = startTime
|
||||
//
|
||||
// Why this matters: the old version brought a generator back from a respawn at
|
||||
// **ZERO output voltage** with its state alarm untouched. Energy weapons charge
|
||||
// from the generator's voltage, so a respawned pilot's lasers could never reach
|
||||
// ready -- no recharge ring, no fire-ready dot, nothing damaged (a strong
|
||||
// candidate for Gitea #54, David's three dead energy weapons).
|
||||
//
|
||||
HeatSink::ResetToInitialState(powered); // @004ad760 (was HeatableSubsystem)
|
||||
|
||||
generatorOn = 1; // @0x1D4
|
||||
startTimer = 0.0f; // @0x1F0 (cleared, then seeded below)
|
||||
stateAlarm.SetLevel(0); // @0x1FC
|
||||
stateAlarm.SetLevel(2); // ... to GeneratorOnLine
|
||||
outputVoltage = ratedVoltage; // @0x1DC = @0x1D8 -- back ON LINE
|
||||
coolantAvailable = 1; // @0x134
|
||||
coolantFlowScale = 1.0f; // @0x15C
|
||||
startTimer = startTime; // @0x1F0 = @0x1EC
|
||||
}
|
||||
|
||||
//
|
||||
// DeathReset (Gitea #55): the respawn sweep's entry for a Generator. Without it
|
||||
// the sweep hit the empty `Subsystem::DeathReset` base and a respawned mech kept
|
||||
// its previous life's generator state.
|
||||
//
|
||||
void
|
||||
Generator::DeathReset(int /*reset_command*/)
|
||||
{
|
||||
ResetToInitialState(True); // @004b215c
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user