Coolant Flush end-to-end (Gitea #7): InjectCoolant id-4 handler + drain + FLUSH.PFX cloud + 'H' key
The playtest report (sound plays, no gauge drop, no cloud) traced to the
Reservoir's InjectCoolant chain being dead in three places:
- The handler was never REGISTERED: the binary's Reservoir handler table
@0x50e680 has one entry {4, "InjectCoolant", @4aee70}; added
Reservoir::GetMessageHandlers + the press/release handler (press starts
the flush gated on coolantLevel@0x12C > 0 -- the old body misread +0x12C
as currentTemperature; release stops it; novice lockout via FUN_004ac9c8).
- Reservoir::InjectCoolant (@4aefa4, 1019 bytes) was an empty stub -- the
drain the coolant gauge reads. Reconstructed in full: work list =
condenser/weapon/heatable chains (+0x7cc/+0x7bc/+0x7ac, roster-walk
emulation with the binary's duplicate-visit weighting; HeatSink-filtered
[T2 guarded]) + the linked master sink; per sink with flowScale != 0 move
squirtMass x flowScale x dt (clamped to the tank / sink capacity) and
credit pendingHeat with the negative carried-heat delta capped at
sinkMass x reservoir startingTemperature -- the set%-biased flush of the
manual (p24), riding the existing heat model.
- Two latent ctor decode bugs surfaced and fixed: the master gate @4af408
(and @4aeb40 HeatWatcher, swept) reads the OWNER MECH's simulationFlags
(*(param_2+0x28)), not the resource's subsystemFlags (the misread left
the CoolantSimulation Performance unregistered); and the capacity scale
FILDs the bank's INTEGER HeatSinkCount ((float10)*(int*)(link+0x1d0)) --
the float reinterpret gave ~1e-44 -> a permanently empty tank.
Capacity = 0.05 x heatSinkCount x streamed CoolantCapacity (BLH: 6.0).
Visual: the binary's mode-1 coolant-effect renderable (FUN_00456a68, built
for classID 0xBC0 on "ReservoirState", part_014.c:5439; tick @part_007.c:
8780) starts psfx 19 = FLUSH.PFX ("Coolant flush", BTDPL.INI) when the
state changes to 1 -- BTSpawnFlushCloud (mech4.cpp) spawns it on the same
alarm edge as an attached emitter at torso height.
Input: new CONTROLS.MAP action "Flush" on 'H' (HELD; press+release both
dispatch, the held-button payload). Diags: BT_FLUSH_LOG, BT_FLUSH_TEST.
Verified live (FOGDAY): [flush] Reservoir level 6 -> 0.13 -> 0 over ~0.6 s
held (= the manual's 3-4 punches to empty), the coolant vertBar source
Reservoir/CoolantMass drains, and the bluish condensation cloud rises from
the mech (scratchpad/flush_cloud.png vs flush_before.png).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d9ceddb12a
commit
2ae9bd43ae
@@ -661,6 +661,7 @@ static int gBTConfigKey = 0; // task #6: HOLD 'G' = the weapon-con
|
||||
static int gBTGenSelKey = 0; // task #12: F5..F8 = SelectGeneratorA..D, F9 = mode toggle
|
||||
// (0 idle; else the message id 4..8)
|
||||
static int gBTValveKey = 0; // task #13: 'C' = MoveValve on the selected condenser
|
||||
static int gBTFlushKey = 0; // Gitea #7: 'H' HELD = InjectCoolant (the coolant flush)
|
||||
|
||||
// Damage: each shot dispatches a REAL Entity::TakeDamageMessage to the target. Now
|
||||
// that the damage zones are constructed (mech.cpp Pass-3 zone build), the engine base
|
||||
@@ -899,6 +900,40 @@ void
|
||||
<< " at(" << mx << "," << my << "," << mz << ")\n" << std::flush;
|
||||
}
|
||||
|
||||
//###########################################################################
|
||||
// COOLANT-FLUSH CONDENSATION CLOUD (Gitea #7) -- the flush visual.
|
||||
//
|
||||
// BTDPL.INI psfx 19 = FLUSH.PFX, commented "Coolant flush" (both day and
|
||||
// night tables): a bluish (0.7/0.9/1.6 tint) firesmoke burst, ~3.5 s window.
|
||||
// The binary drives it with the mode-1 "coolant/reservoir" effect renderable
|
||||
// (FUN_00456a68, alloc 0x138), built for every classID-0xBC0 subsystem on
|
||||
// its "ReservoirState" attribute (BTL4VID.CPP build loop, part_014.c:5439;
|
||||
// missing attr = Verify "Reservoir did not have a ReservoirState...") and
|
||||
// DCS-parented to the mech; its per-frame tick (part_007.c:8780) starts the
|
||||
// effect exactly when the watched state CHANGES to 1. Manual p24: "other
|
||||
// pilots will see steam rise from your 'Mech on the battlefield".
|
||||
//
|
||||
// The port consolidates the BT effect renderables in the psfx layer, so this
|
||||
// helper is called on the same 0->1 alarm edge (Reservoir::
|
||||
// InjectCoolantMessageHandler) and rides the mech via the attached-emitter
|
||||
// follower (seg -1 = the torso-height entity fallback in
|
||||
// BTResolveSegmentWorld -- the cloud rises FROM the mech and trails it).
|
||||
//###########################################################################
|
||||
void
|
||||
BTSpawnFlushCloud(void *ownerMech)
|
||||
{
|
||||
if (ownerMech == 0)
|
||||
return;
|
||||
float pos[3], rows[9];
|
||||
if (!BTResolveSegmentWorld(ownerMech, -1, pos, rows))
|
||||
return;
|
||||
extern void BTStartPfxAttached(int, void *, int, float, float, float, const float *);
|
||||
BTStartPfxAttached(19, ownerMech, -1, pos[0], pos[1], pos[2], rows);
|
||||
if (getenv("BT_FLUSH_LOG"))
|
||||
DEBUG_STREAM << "[flush] condensation cloud (psfx 19 FLUSH.PFX) at("
|
||||
<< pos[0] << "," << pos[1] << "," << pos[2] << ")\n" << std::flush;
|
||||
}
|
||||
|
||||
//###########################################################################
|
||||
// PER-ROUND DETONATION (the binary's Missile::MoveAndCollide @004bef78: every
|
||||
// round spawns ITS OWN ExplosionModelFile at its impact point, resource
|
||||
@@ -2621,6 +2656,10 @@ void
|
||||
gBTGenSelKey = gBTInput.genSel;
|
||||
// task #13: the Valve action cycles the coolant valve.
|
||||
gBTValveKey = gBTInput.valve;
|
||||
// Gitea #7: the Flush action HELD = the coolant MFD's
|
||||
// top-right button (manual p24) -- InjectCoolant while
|
||||
// down, stop on release.
|
||||
gBTFlushKey = gBTInput.flush;
|
||||
// TORSO CONTROLS (2026-07-13): 'M' cycles the control mode
|
||||
// (Basic -> Standard -> Veteran -- the pod console button,
|
||||
// CycleControlModeMessageHandler); Q/E deflect the torso
|
||||
@@ -5110,6 +5149,59 @@ void
|
||||
gBTValveKey = (s_vtFrame >= 600 && s_vtFrame < 610) ? 1 : 0;
|
||||
}
|
||||
|
||||
// Gitea #7 scripted verify (BT_FLUSH_TEST=<frame>): hold the coolant
|
||||
// flush for ~60 sim frames starting at the given frame -- the
|
||||
// reservoir drains ([flush] log), the coolant vertBar drops, and the
|
||||
// FLUSH.PFX condensation cloud spawns on the 0->1 edge.
|
||||
if ((Entity *)this == application->GetViewpointEntity()
|
||||
&& getenv("BT_FLUSH_TEST"))
|
||||
{
|
||||
static int s_ftFrame = 0;
|
||||
++s_ftFrame;
|
||||
int t0 = atoi(getenv("BT_FLUSH_TEST"));
|
||||
if (t0 < 1) t0 = 600;
|
||||
gBTFlushKey = (s_ftFrame >= t0 && s_ftFrame < t0 + 60) ? 1 : 0;
|
||||
}
|
||||
|
||||
// Gitea #7: the COOLANT FLUSH button (the coolant MFD's top-right
|
||||
// button, manual p24 -- "punch (or hold down) the coolant button to
|
||||
// flush fresh coolant through your 'Mech's loops"). Press AND
|
||||
// release edges both dispatch: InjectCoolant (id 4, the Reservoir
|
||||
// table @0x50e680) starts the flush on data>=1 and stops it on
|
||||
// data<1 -- the same held-button payload the pod's streamed MFD
|
||||
// EventMapping delivers.
|
||||
if ((Entity *)this == application->GetViewpointEntity())
|
||||
{
|
||||
static int s_prevFlush = 0;
|
||||
if (gBTFlushKey != s_prevFlush)
|
||||
{
|
||||
int pressed = (gBTFlushKey != 0);
|
||||
s_prevFlush = gBTFlushKey;
|
||||
Subsystem *reservoir = 0;
|
||||
for (int s = 1; s < GetSubsystemCount(); ++s)
|
||||
{
|
||||
Subsystem *sub = GetSubsystem(s);
|
||||
if (sub != 0 && (int)sub->GetClassID() == 0xBC0) // Reservoir
|
||||
{
|
||||
reservoir = sub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reservoir != 0)
|
||||
{
|
||||
if (getenv("BT_FLUSH_LOG"))
|
||||
DEBUG_STREAM << "[flush-tx] InjectCoolant "
|
||||
<< (pressed ? "PRESS" : "RELEASE") << " -> "
|
||||
<< reservoir->GetName() << std::endl;
|
||||
ReceiverDataMessageOf<ControlsButton> msg(
|
||||
4 /*Reservoir::InjectCoolantMessageID*/,
|
||||
sizeof(ReceiverDataMessageOf<ControlsButton>),
|
||||
(ControlsButton)(pressed ? 1 : 0));
|
||||
reservoir->Dispatch(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// task #13 dev harness: the COOLANT VALVE lever. 'C' edge -> dispatch
|
||||
// MoveValve (id 4, the Condenser table @0x50E52C) to the selected
|
||||
// condenser -- the same press payload the pod's engineering-screen aux
|
||||
|
||||
Reference in New Issue
Block a user