diff --git a/game/reconstructed/heat.cpp b/game/reconstructed/heat.cpp index 4736764..b3a5195 100644 --- a/game/reconstructed/heat.cpp +++ b/game/reconstructed/heat.cpp @@ -242,6 +242,13 @@ Derivation* return &classDerivations; } +// ~~~ Condenser ctor/dtor: the REAL bodies live in heatfamily_reslice.cpp +// (@4ae568, which sets valveState=1 / refrigerationFactor / condenserNumber). +// These STUBs were ODR-duplicates that WON under /FORCE (heat.obj links before +// heatfamily_reslice.obj) -> valveState was left 0xCDCDCDCD (garbage valve gauge). +// #if 0'd so the real ctor is the sole definition. DefaultData / GetClassDerivations +// / ResetToInitialState below are NOT duplicated in the reslice TU -- kept here. +#if 0 Condenser::Condenser( Mech *owner, int subsystem_ID, @@ -260,6 +267,7 @@ Condenser::~Condenser() Check(this); Check_Fpu(); } +#endif //########################################################################### // ResetToInitialState -- Condenser (HEAT.TCP) @@ -271,8 +279,13 @@ void } //########################################################################### -// TestClass -- Condenser (HEAT.TCP) +// TestClass / TestInstance / CreateStreamedSubsystem -- Condenser // +// The REAL bodies live in heatfamily_reslice.cpp (@4ae63c / @4ae658, the latter +// parsing "RefrigerationFactor"). These STUBs were ODR-duplicates -- #if 0'd so +// the reslice definitions are the sole ones (see the ctor note above). +// +#if 0 Logical Condenser::TestClass(Mech &) { @@ -310,6 +323,7 @@ int Check_Fpu(); return True; } +#endif //########################################################################### diff --git a/game/reconstructed/heatfamily_reslice.cpp b/game/reconstructed/heatfamily_reslice.cpp index 6ad0020..df2516d 100644 --- a/game/reconstructed/heatfamily_reslice.cpp +++ b/game/reconstructed/heatfamily_reslice.cpp @@ -811,3 +811,53 @@ Subsystem *CreateHeatSinkBankSubsystem(Mech *owner, int id, void *seg) AggregateHeatSink(owner, id, (AggregateHeatSink::SubsystemResource *)seg, AggregateHeatSink::DefaultData); } + +//===========================================================================// +// @0049f788 -- RecomputeCondenserValves. Distribute coolant flow across the +// mech's condensers so each one's ValveSetting gauge (coolantFlowScale@0x15C) +// reads its share of the total valve opening: flow_i = valveState_i / sum(valveState). +// +// The binary iterates the condenser chain @mech+0x7cc (GUID 0x50e4fc == Condenser); +// we walk the populated subsystem roster and filter for Condensers via IsDerivedFrom +// -- behaviorally identical (the chain holds exactly the condensers) and independent +// of whether the @0x7cc chain is wired. Called at the end of the Mech ctor (binary +// @9457, the post-init pass) so the valve gauge shows the authentic 1/N per condenser +// instead of 0 (the ctor leaves coolantFlowScale=0 by design; this is its first writer). +// +// The per-condenser condenserAlarm@0x1DC toggle (2 if flow<=old else 1, then 0) is the +// binary's change-notification pulse; reproduced exactly (FUN_0041bbd8 == SetLevel). +//===========================================================================// +void BTRecomputeCondenserValves(Entity *owner) +{ + Check(owner); + Derivation &condClass = *Condenser::GetClassDerivations(); + int count = owner->GetSubsystemCount(); + + // pass 1: total valve opening across all condensers + int total = 0; + for (int i = 0; i < count; ++i) + { + Subsystem *s = owner->GetSubsystem(i); + if (s != 0 && s->IsDerivedFrom(condClass)) + total += ((Condenser *)s)->valveState; // iVar3 += *(int*)(iVar1+0x1d0) + } + + // pass 2: each condenser's flow = its share of the total + for (int i = 0; i < count; ++i) + { + Subsystem *s = owner->GetSubsystem(i); + if (s == 0 || !s->IsDerivedFrom(condClass)) + continue; + Condenser *c = (Condenser *)s; + Scalar flow = 0.0f; // _DAT_0049f850 (no-condenser fallback) + if (total > 0) + flow = (Scalar)c->valveState / (Scalar)total; + c->condenserAlarm.SetLevel(flow <= c->coolantFlowScale ? 2 : 1); // @0x1dc change pulse + c->coolantFlowScale = flow; // *(float*)(iVar1+0x15c) = local_8 + c->condenserAlarm.SetLevel(0); + if (getenv("BT_VALVE_LOG")) + DEBUG_STREAM << "[valve] condenser#" << c->condenserNumber + << " valveState=" << c->valveState << " flow=" << c->coolantFlowScale + << " (total=" << total << ")\n" << std::flush; + } +} diff --git a/game/reconstructed/mech.cpp b/game/reconstructed/mech.cpp index 493fda9..439e713 100644 --- a/game/reconstructed/mech.cpp +++ b/game/reconstructed/mech.cpp @@ -190,6 +190,7 @@ struct MechControlsMapper : ReconSubsystemStub { template MechContro extern Subsystem *CreateCondenserSubsystem(Mech *, int, void *); // 0xBBD extern Subsystem *CreateHeatSinkBankSubsystem(Mech *, int, void *); // 0xBBE extern Subsystem *CreateReservoirSubsystem(Mech *, int, void *); // 0xBC0 +extern void BTRecomputeCondenserValves(Entity *); // @0049f788 (post-init valve distribution) extern Subsystem *CreateHUDSubsystem(Mech *, int, void *); // 0xBD6 extern Subsystem *CreateMechTechSubsystem(Mech *, int, void *); // 0xBDC extern Subsystem *CreateGeneratorSubsystem(Mech *, int, void *); // 0xBC1 (WAVE 3a) @@ -1237,7 +1238,11 @@ Mech::Mech( } dir->Add(this); // (**(dir[4]+4))(dir+4,this) - FinishConstruction(); // FUN_0049f788 (post-init pass) + // @0049f788 -- distribute coolant flow across the condensers (post-init pass). + // The real RecomputeCondenserValves; sets each condenser's coolantFlowScale to + // valveState/sum(valveState) so the ValveSetting gauge reads the authentic 1/N + // (was a no-op stub -> the valve gauge showed 0). + BTRecomputeCondenserValves(this); Check_Fpu(); } diff --git a/scratchpad/rdva.py b/scratchpad/rdva.py new file mode 100644 index 0000000..6267c9d --- /dev/null +++ b/scratchpad/rdva.py @@ -0,0 +1,21 @@ +import struct,sys +va=int(sys.argv[1],16) +f=open('content/BTL4OPT.EXE','rb').read() +# PE header +pe=struct.unpack_from('