BT410 5.3.124: one ladder to rule the valves -- MoveValve unifies onto the coolant priorities, and valveState retires

The condenser valve button and the mech's BalanceCoolant now drive ONE
mechanism, as the binary does: MoveValve (@004ae464) steps the
heatable-base coolantPriority through the authentic 0 -> 1 -> 5 -> 50 -> 0
ladder and calls the mech's RedistributeCoolantShares (@0049f788);
valveState and the condenser-local renormalization are gone.
RecomputeValves survives only as the [T3] conduction-flow bridge: the
fight-verified pump (5.3.12-15 byte curves) consumes a CONDENSER-relative
fraction, refreshed from the redistribute tail -- numerically identical
to the old math, since non-condenser priorities cancel in the ratio.

Registration caveat recorded: the @0x50e534 name table sits in the HEAT
TU statics but its owning class is not proven, so the handler stays on
Condenser id 4 (the live-verified streamed binding).

Soak (pod_render_valve.conf, BT_PRESS_VALVE + BT_PRESS_BALANCE): spawn
equal split (total 20, flows 6 x 0.166667) -> valve press (Condenser1
priority 5, total 24, flows 0.5 / 5 x 0.1 -- the exact predicted ratios)
-> balance press restores the equal split, crash-sig 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-08-07 08:17:50 -05:00
co-authored by Claude Fable 5
parent 0b7c64202a
commit 5769208ec0
6 changed files with 149 additions and 45 deletions
@@ -0,0 +1,86 @@
# pod_render_norio.conf -- pod_render_rec with the RIO serial port OFF.
#
# The emulator log shows a steady stream of serial1 RX OVERRUN errors on
# the RIO pipe, and controls post their events at HighEventPriority
# UNCONDITIONALLY (CONTROLS.HPP:250) -- so a chattering RIO port would
# flood a priority the background pump always serves first, starving the
# priority-0 renderer events the load gate waits on. This conf tests that
# by removing the port entirely. Everything else is identical to the rec
# conf, so a launch here and a hang there isolates the RIO.
#
[sdl]
output=opengl
# higher,higher not highest: HIGH_PRIORITY_CLASS starved the host desktop;
# with the retry patches a rare dropout self-recovers (see gauge_rio.conf).
priority=higher,higher
[dosbox]
memsize=32
machine=svga_s3
[cpu]
core=dynamic
cputype=pentium
cycles=max
[sblaster]
sbtype=sb16
sbbase=220
irq=5
dma=1
hdma=5
[mixer]
# match the EMU8000s' native rate (no resample) and buffer ~60ms so brief
# emulation-thread stalls (RIO retry recovery) don't audibly chop
rate=44100
blocksize=1024
prebuffer=60
[serial]
# RIO on COM1 with the low-latency options (rxpollus/rxburst) so the board's
# few-ms ACK deadline is met; plasma display on COM2 (real pod has both).
# VWE fork namedpipe backend (com0com/realport retired -- COM1/COM2 gone):
# DOSBox = pipe client (retry), vRIO/vPLASMA apps = servers; an unconnected
# pipe behaves as an unplugged cable so the mission still runs. serialnamedpipe.h
serial1=disabled
serial2=namedpipe pipe:vplasma
# live UNBUFFERED game output: DOS char devices are not buffered, so
# redirecting stdout to COM3 lands every line immediately. A normal
# '> file' redirect stays 0 bytes until the process exits, which hides
# all progress on a run that does NOT crash.
serial3=file file:C:\VWE\TeslaRel410\emulator\render-bridge\podlog.txt
[autoexec]
mount c "C:\VWE\TeslaRel410\ALPHA_1"
c:
cd \REL410\BT
set VIDEOFORMAT=svga
rem production pod card init (PARAMETR.BAT:181-186): DIAGNOSE + AWEUTIL per
rem card -- AWEUTIL /S does the EMU8000 bring-up and DRAM detect the HMI SOS
rem driver relies on; skipping it left the cards uninitialized (silent).
rem aweutil /s SKIPPED for now: it verifies the AWE32 GM ROM, which the
rem emulated cards lack (hangs in a retry loop) -- restore once the ROM is
rem dumped from a real card. diagnose /s kept (passes, sets mixer config).
set BLASTER=A220 I5 D1 H5 P330 T6
c:\sb16\diagnose /s
set BLASTER=A240 I7 D3 H6 P300 T6
c:\sb16\diagnose /s
set BLASTER=A220 I5 D1 H5 P330 T6
set TEMP=c:\
rem arena1 city mission (TESTARN.EGG: map=arena1, time=day) with the RIO
rem attached; stdout redirected so mission-load progress survives kills.
set BT_JOINTS=1
set L4VIEWEXT=1
set BT_STACK_LOG=1
set BT_MECH_LOG=1
set BT_PRESS_BALANCE=1
set BT_PRESS_VALVE=1
set BT_GAUGE_LOG=1
set BT_FORCE_THROTTLE=0
set BT_FORCE_TURN=0
set HEAPSIZE=15000000
set L4GAUGE=640x480x16
call setenv.bat r s n p
32rtm.exe -x
BTL4REC.EXE -egg testarn.egg > COM3
echo GAME-RC=%errorlevel% >> RC.TXT
32rtm.exe -u
echo ALPHA1-RUN-DONE
pause
+24 -15
View File
@@ -1053,8 +1053,9 @@ Condenser::Condenser(
// (RecomputeValves: MoveValve presses, and once at mech spawn) assigns
// each condenser its share of the total valve opening.
//
valveState = 1;
coolantFlowScale = 0.0f;
coolantFlowScale = 0.0f; // the mech ctor's redistribute seeds the
// bank's flow shares (priority born 1 on
// the heatable base)
refrigerationFactor = subsystem_resource->refrigerationFactor;
massScale = refrigerationFactor;
@@ -1152,24 +1153,32 @@ void
return;
}
switch (valveState)
//
// Binary @004ae464: the ladder steps the HEATABLE-base coolant
// priority (+0x1d0 -- the same cell the mech's BalanceCoolant resets
// to 1 across the board) and the renormalization is the MECH's
// RedistributeCoolantShares (@0049f788), which also refreshes the
// conduction flow bridge.
//
switch (coolantPriority)
{
case 0: valveState = 1; break;
case 1: valveState = 5; break;
case 5: valveState = 50; break;
case 50: valveState = 0; break;
case 0: coolantPriority = 1; break;
case 1: coolantPriority = 5; break;
case 5: coolantPriority = 50; break;
case 50: coolantPriority = 0; break;
default: return; // unknown -> no change, no recompute
}
RecomputeValves((Entity *)owner);
owner->RedistributeCoolantShares();
}
//
//#############################################################################
// RecomputeValves -- assign every condenser its coolant flow share
// (valve / sum-of-valves) after a valve move (binary @0049f788). All valves
// at the spawn default (1) yield equal shares. (The condenser-alarm change
// pulse joins with the gauge wave.)
// RecomputeValves -- the [T3] conduction-flow bridge (see HEAT.HPP): every
// condenser's coolantFlowScale = its priority / the CONDENSER priority
// total, numerically identical to the retired valveState math for any
// priority pattern. Called from the tail of the mech's
// RedistributeCoolantShares.
//#############################################################################
//
void
@@ -1186,7 +1195,7 @@ void
Subsystem *s = owner_mech->GetSubsystem(i);
if (s != NULL && s->IsDerivedFrom(Condenser::ClassDerivations))
{
total += ((Condenser *)s)->valveState;
total += ((Condenser *)s)->coolantPriority;
}
}
@@ -1197,12 +1206,12 @@ void
{
Condenser *condenser = (Condenser *)s;
condenser->coolantFlowScale = (total > 0)
? ((Scalar)condenser->valveState / (Scalar)total)
? ((Scalar)condenser->coolantPriority / (Scalar)total)
: 0.0f;
if (getenv("BT_MECH_LOG"))
{
DEBUG_STREAM << "[valve] '" << condenser->GetName()
<< "' valve=" << condenser->valveState
<< "' priority=" << condenser->coolantPriority
<< " flow=" << condenser->coolantFlowScale << endl;
}
}
+9 -4
View File
@@ -511,9 +511,15 @@
MoveValveMessageHandler(ReceiverDataMessageOf<int> *message);
//
// Recompute every condenser's coolantFlowScale as its share of the
// total valve opening (called by MoveValve, and once at mech spawn so
// the initial all-1 valves yield equal shares).
// [T3 bridge] Recompute every condenser's coolantFlowScale as its
// CONDENSER-relative share of the coolant priorities -- the term the
// fight-verified conduction model (5.3.12-15 byte curves) consumes.
// Since 5.3.124 the ladder cell is the heatable-base coolantPriority
// (binary +0x1d0) and the caller is the tail of the mech's
// RedistributeCoolantShares, so valve presses, BalanceCoolant and
// spawn/Reset all refresh it through ONE path. Retire onto the
// real binary conduction cell once the @004ad6f8/pump reads are
// decoded.
//
static void
RecomputeValves(Entity *owner_mech);
@@ -556,7 +562,6 @@
GetCondenserNumber() const { Check(this); return condenserNumber; }
protected:
int valveState;
int condenserNumber;
Scalar refrigerationFactor;
//
+7 -7
View File
@@ -821,13 +821,6 @@ Mech::Mech(
}
}
//
// Seed the condenser flow shares: every valve spawns at 1, so the initial
// recompute yields equal shares across the bank (a MoveValve press
// re-shares them).
//
Condenser::RecomputeValves(this);
//
// Install the per-frame body Performance. Until now the mech ran the base
// DoNothingOnce; from here the engine dispatches Mech::Simulate every frame
@@ -1030,6 +1023,13 @@ void
<< " heatables, total priority " << total
<< ", first share " << first_share << endl << flush;
}
//
// The conduction-flow bridge (see HEAT.HPP RecomputeValves): the
// fight-verified condenser pump consumes a CONDENSER-relative
// fraction; refresh it whenever the shares move.
//
Condenser::RecomputeValves(this);
}
//
+10 -9
View File
@@ -694,6 +694,16 @@
Scalar
CurrentTorsoTwist();
//
// The coolant-share renormalizer (binary @0049f788): share =
// priority / total across the heatable chain, blipping each
// heatable's balance alarm with the change direction. PUBLIC:
// Condenser::MoveValve calls it (binary callers: the 0x16 handler,
// the ctor tail, Reset, and the valve stepper @004ae464).
//
void
RedistributeCoolantShares();
DamageLookupTable*
GetDamageLookupTable() const { Check(this); return damageLookupTable; }
@@ -983,15 +993,6 @@
void
BalanceCoolantMessageHandler(Receiver::Message *message);
//
// The coolant-share renormalizer (binary @0049f788): share =
// priority / total across the heatable chain, blipping each
// heatable's balance alarm with the change direction. Callers in
// the binary: the 0x16 handler, the ctor tail, Reset, and the
// per-subsystem priority stepper (@004ae464, not yet landed).
//
void
RedistributeCoolantShares();
void
SetStandingCollisionVolume(); // binary @004ac04c... see .CPP
void
+13 -10
View File
@@ -303,16 +303,19 @@ Still to land from the roster:
RedistributeCoolantShares @0049f788 + the heatable ctor sweep that
populates the heatableSubsystems chain + ctor/Reset redistribute calls;
soak: 20 heatables, first share 0.05, ctor + BT_PRESS_BALANCE both
renormalize, crash-sig 0). UNIFICATION OWED (5.3.124): the binary's
MoveValve handler is @004ae464 registered on the HEATABLE base (the
0x50e534 name table in the heatable statics region), novice-locked via
mapper+0x274 == 0 (FUN_004ac9c8 -- our NoviceLockout is correct),
stepping heatable+0x1d0 through 0 -> 1 -> 5 -> 50 -> 0 then calling the
MECH redistribute -- i.e. our Condenser::MoveValve / RecomputeValves /
valveState triple is the SAME mechanism scoped to condensers only;
retire it onto coolantPriority/RedistributeCoolantShares and re-home
the handler on HeatableSubsystem (ValveSetting attribute retargets to
the share/priority cells).
renormalize, crash-sig 0). UNIFIED 5.3.124: MoveValve
steps the heatable-base coolantPriority and calls the mech's
RedistributeCoolantShares; valveState and the condenser-local
renormalization are retired (RecomputeValves survives only as the [T3]
conduction-flow bridge -- the fight-verified pump consumes a
CONDENSER-relative fraction, refreshed from the redistribute tail; the
ratios are numerically identical to the old math since non-condenser
priorities cancel). REGISTRATION CAVEAT: the @0x50e534 name table sits
in the HEAT TU statics but its owning class (heatable base vs
Condenser) is NOT proven -- our registration stays Condenser id 4 (the
live-verified streamed binding); revisit if a non-condenser valve
binding ever surfaces. ValveSetting attribute still publishes
coolantFlowScale (the displayed fractions are unchanged).
* **EjectPilot @0049f854** (head read): gated on payload > 0 AND
**mech+0x414** -- THE EFFECTIVENESS-CENSUS CONSUMER FOUND: you can only
eject a CRIPPLED mech (@0049fa1c's weapons/coolant/generator/limp