The 0xBBE heat-sink BANK was built as a plain HeatSink, so the numeric-R cockpit gauge binding HeatSink/AmbientTemperature (L4GAUGE.CFG:4552) had no publisher -> the LAST unresolved config attribute. Reconstruct AggregateHeatSink : HeatSink (ctor @4ae8d0, own GUID 0x50e590), byte-exact + static_assert-locked (heatSinkCount@0x1D0, ambientTemperature @0x1D4=300, helper@0x1D8 0xC link node, sizeof 0x1E4 == factory alloc @9993). Publish HeatSinkCount + AmbientTemperature via a dense-prefix attribute table chained to HeatSink::NextAttributeID (shared HeatSink table unchanged, so CoolantMass/CoolantCapacity keep resolving). Move CreateHeatSinkBankSubsystem into heatfamily_reslice.cpp (needs the class def) and build the real class at factory case 0xBBE; mech.cpp unchanged. DELIBERATE DEVIATION (documented in the class): keep the base HeatSinkSimulation the HeatSink ctor installs; do NOT reimplement the authentic Performance @4ae73c -- it derefs a raw self+0xE0 -> [+0x158] that does not map in our compiled layout (AV/NaN, and runs for EVERY mech), and ambientTemperature is a frozen constant so the gauge reads 300 either way. Authentic relaxation model deferred. Verified: [attr] HeatSink/AmbientTemperature OK; all 50 config attribute bindings resolve (0 NULL); no every-mech crash; combat TARGET DESTROYED, FIRED #41+, un-regressed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
389 lines
18 KiB
C++
389 lines
18 KiB
C++
//===========================================================================//
|
|
// File: heatfamily_reslice.hpp //
|
|
// Project: BattleTech Brick: Entity Manager //
|
|
// Contents: Re-slice of the heat/power family class bodies that fell OUTSIDE //
|
|
// the first heat decomp window (gap 0x4ae4d8 - 0x4afbe0). //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
//
|
|
// RECONSTRUCTED from the shipped binary (heatfamily_gap.c). This header is a
|
|
// companion to heat.hpp: it COMPLETES the Condenser class that heat.hpp/.cpp
|
|
// left best-effort, and adds the three other heat/power-family classes whose
|
|
// bodies live in the same gap:
|
|
//
|
|
// class primary vtable ctor classID base
|
|
// --------------- -------------- -------- ------- -----------------
|
|
// Condenser 0050ed88 @4ae568 0x0BBD HeatSink
|
|
// <HeatSink agg> 0050ed4c/ed50 @4ae8d0 0x0BBE HeatSink (name unconfirmed)
|
|
// HeatWatcher 0050ed10 @4aeb40 0x0BBF HeatableSubsystem
|
|
// Reservoir 0050ecd4/ecd8 @4af408 0x0BC0 HeatSink
|
|
//
|
|
// classID order (resource record +0x20) dovetails with the powersub family:
|
|
// ...0x0BBD Condenser, 0x0BBE <agg>, 0x0BBF HeatWatcher, 0x0BC0 Reservoir,
|
|
// 0x0BC1 Generator, 0x0BC2 PoweredSubsystem, ... 0x0BD5 PowerWatcher.
|
|
//
|
|
// HeatWatcher is the missing intermediate base of powersub's PowerWatcher
|
|
// (ctor @4b18a4 chains to the HeatWatcher base ctor @4aeb40). CLASSMAP.md
|
|
// previously listed PowerWatcher directly under Subsystem; the real chain is
|
|
// PowerWatcher : HeatWatcher : HeatableSubsystem : Subsystem.
|
|
//
|
|
// Field offsets are byte offsets into the shipped object (word index * 4).
|
|
// Hex float constants resolved from the CODE-section literal pool:
|
|
// _DAT_004ae530 = 1.0f _DAT_004ae708 = -1.0f _DAT_004ae89c = 300.0f
|
|
// _DAT_004ae8a0 = 3.0f _DAT_004ae8a4 = 1.0f _DAT_004ae8a8 = 0.0f
|
|
// _DAT_004ae8ac = 1.0e-4f _DAT_004aee28 = -1.0f _DAT_004aeedc = 0.0f
|
|
// _DAT_004af3a0 = 1.0e-4f _DAT_004af3a4 = 0.0f _DAT_004af3a8 = 0.0f
|
|
// _DAT_004af404 = 0.0f _DAT_004af694 = -1.0f
|
|
// _DAT_004ae974 ~= 1.738 (double 0x3FFBCC.., thermalMass-per-heat-sink scale)
|
|
// _DAT_004af518 ~= 0.x (double, coolant-capacity-per-master scale; low word)
|
|
//
|
|
|
|
#if !defined(HEATFAMILY_RESLICE_HPP)
|
|
# define HEATFAMILY_RESLICE_HPP
|
|
|
|
#if !defined(HEAT_HPP)
|
|
# include <heat.hpp> // HeatableSubsystem, HeatSink, Condenser base decls
|
|
#endif
|
|
|
|
//###########################################################################
|
|
//############### Watcher-branch-LOCAL layout types #####################
|
|
//###########################################################################
|
|
//
|
|
// BASE-CHAIN RE-BASE: the binary's HeatWatcher/PowerWatcher use a 0xC-byte
|
|
// connection (watchedLink) and a 0x54-byte gauge alarm (heatAlarm/watchdogAlarm
|
|
// -- a full GaugeAlarm), NOT the 4-byte SubsystemConnection / 8-byte HeatAlarm
|
|
// used on the HeatSink/PoweredSubsystem heat-leaf branch. These Watcher-LOCAL
|
|
// types close the 156-byte base deficit so a Watcher-branch leaf's own fields
|
|
// begin at 0x1D8 (== Torso::currentTwist, the gyro cross-link target), WITHOUT
|
|
// resizing the shared heat.hpp types the working heat leaves depend on. All
|
|
// access is through the API (Resolve/GetLevel), never a raw internal offset, so
|
|
// the interior padding layout is immaterial -- only the total sizeof must match.
|
|
//
|
|
struct WatchedConnection // binary watchedLink: 0xC bytes
|
|
{
|
|
Subsystem *linked;
|
|
char _pad[0x0C - sizeof(Subsystem*)];
|
|
WatchedConnection(int = 0) { linked = 0; }
|
|
void Add(Subsystem *s) { linked = s; }
|
|
Subsystem* Resolve() const { return linked; }
|
|
void Clear() { linked = 0; }
|
|
};
|
|
static_assert(sizeof(WatchedConnection) == 0x0C, "Watcher connection must be 0xC to close the deficit");
|
|
|
|
// The Watcher-branch 0x54 alarm is now the SAME type the heat-leaf branch uses
|
|
// (heat.hpp GaugeAlarm54): identical layout (levelCount@0, level@4, pad to 0x54),
|
|
// so the already-locked Watcher LayoutChecks stay valid, and there is one shared
|
|
// 0x54 alarm across the whole subsystem hierarchy.
|
|
typedef GaugeAlarm54 WatcherGaugeAlarm; // binary watcher alarm: 0x54 bytes
|
|
static_assert(sizeof(WatcherGaugeAlarm) == 0x54, "Watcher alarm must be 0x54 to close the deficit");
|
|
|
|
//###########################################################################
|
|
//############################# Condenser ###############################
|
|
//###########################################################################
|
|
//
|
|
// COMPLETION of heat.hpp's Condenser. It is NOT a passive subsystem (as
|
|
// heat.hpp guessed) -- it derives from HeatSink, models a refrigeration
|
|
// output that fights the master heat-sink's stored heat, carries a 3-way
|
|
// valve, and reports a condenser number parsed from its instance name.
|
|
//
|
|
// vtable @0050ed88 ctor @4ae568 dtor @4ae5fc classID CondenserClassID
|
|
//
|
|
// NOTE: the Condenser class + its resource record (Condenser__SubsystemResource)
|
|
// are now declared in heat.hpp (the completed HeatSink-derived form); this file
|
|
// only supplies the recovered method bodies for it.
|
|
|
|
// --- Condenser instance layout (HeatSink + the following) ---
|
|
// Scalar refrigerationOutput; // @0x160 (word 0x58) recomputed each frame
|
|
// int valveState; // @0x1D0 (word 0x74) init 1 (MoveValve 0..2)
|
|
// int condenserNumber; // @0x1D4 (word 0x75) last digit of name
|
|
// Scalar refrigerationFactor; // @0x1D8 (word 0x76) from resource +0xFC
|
|
// Scalar (unused/flow @0x15C set 0)// @0x15C (word 0x57)
|
|
// AlarmIndicator condenserAlarm; // @0x1DC (word 0x77) 3 levels
|
|
//
|
|
// Methods recovered:
|
|
// @4ae4d8 RefrigerationSimulation(Scalar) -- vtable slot 9
|
|
// @4ae568 Condenser(owner,id,res,shared) -- ctor
|
|
// @4ae5fc ~Condenser(byte flags) -- vtable slot 0
|
|
// @4ae63c TestInstance() -- IsDerivedFrom 0x50e4fc
|
|
// @4ae658 CreateStreamedSubsystem(...) -- parses RefrigerationFactor
|
|
// @4afbe0 MoveValve(message) [best-effort] -- cycles valveState 0->1->2->0,
|
|
// drives owner HUD gauges
|
|
|
|
//###########################################################################
|
|
//########################### HeatWatcher ###############################
|
|
//###########################################################################
|
|
//
|
|
// Abstract monitor that watches ANOTHER subsystem's temperature and raises
|
|
// a 3-level degradation/failure alarm. Base class of powersub's
|
|
// PowerWatcher (the "PowerWatcher base ctor @4aeb40" called out in the task).
|
|
//
|
|
// vtable @0050ed10 ctor @4aeb40 dtor @4aebe8 classID 0x0BBF
|
|
//
|
|
// RESOURCE-LAYOUT FIX (RESOURCE_AUDIT.md root cause A): HeatWatcher is a light
|
|
// MechSubsystem, NOT a full HeatableSubsystem -- verified from the binary: ctor
|
|
// @4aeb40 -> FUN_004ac644 (MechSubsystem base ctor), parser @4aec54 -> FUN_004ac9ec
|
|
// (MechSubsystem parse) + only Degradation/Failure/Watched, record ENDS 0xF0. The
|
|
// resource MUST inherit MechSubsystem__SubsystemResource (ends 0xE4); inheriting
|
|
// HeatableSubsystem::SubsystemResource (0xFC) slid these 3 fields to 0xFC/0x100/0x104.
|
|
struct HeatWatcher__SubsystemResource:
|
|
public MechSubsystem__SubsystemResource
|
|
{
|
|
int watchedSubsystem; // +0xE4 "WatchedSubsystem" (index, +2 bias)
|
|
Scalar degradationTemperature; // +0xE8 "DegradationTemperature" (sentinel -1.0f)
|
|
Scalar failureTemperature; // +0xEC "FailureTemperature" (sentinel -1.0f)
|
|
}; // ends 0xF0
|
|
|
|
// Compile-time guard: the record is loaded verbatim at binary offsets, so these MUST hold.
|
|
static_assert(offsetof(HeatWatcher__SubsystemResource, watchedSubsystem) == 0xE4, "HeatWatcher watchedSubsystem must be at 0xE4");
|
|
static_assert(offsetof(HeatWatcher__SubsystemResource, degradationTemperature) == 0xE8, "HeatWatcher degradationTemperature must be at 0xE8");
|
|
static_assert(offsetof(HeatWatcher__SubsystemResource, failureTemperature) == 0xEC, "HeatWatcher failureTemperature must be at 0xEC");
|
|
static_assert(sizeof(HeatWatcher__SubsystemResource) == 0xF0, "HeatWatcher record must end at 0xF0");
|
|
|
|
class HeatWatcher:
|
|
public MechSubsystem // was HeatableSubsystem (approximation); real base is
|
|
// MechSubsystem (ctor @4aeb40 -> FUN_004ac644). Re-basing
|
|
// also un-shadows degradation/failureTemperature.
|
|
{
|
|
public:
|
|
static Derivation *GetClassDerivations(); // name "HeatWatcher"
|
|
static SharedData DefaultData;
|
|
|
|
typedef HeatWatcher__SubsystemResource SubsystemResource;
|
|
|
|
typedef void
|
|
(HeatWatcher::*Performance)(Scalar time_slice);
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
|
|
static Logical TestClass(Mech&);
|
|
Logical TestInstance() const; // @4aec38
|
|
void ResetToInitialState(Logical powered); // @4aea9c (slot 10)
|
|
|
|
HeatWatcher(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
); // @4aeb40
|
|
~HeatWatcher(); // @4aebe8
|
|
|
|
// @4aeac4 -- the registered Performance: resolve the watched subsystem,
|
|
// read its currentTemperature (+0x114) and drive the alarm.
|
|
void WatchSimulation(Scalar time_slice);
|
|
|
|
static int CreateStreamedSubsystem( // @4aec54 (468 bytes)
|
|
NotationFile *model_file,
|
|
const char *model_name,
|
|
const char *subsystem_name,
|
|
SubsystemResource *subsystem_resource,
|
|
NotationFile *subsystem_file,
|
|
const ResourceDirectories *directories,
|
|
int passes = 1
|
|
);
|
|
|
|
public:
|
|
WatchedConnection watchedLink; // @0x114 (0xC) resolved subsystem -> 0x120
|
|
Scalar degradationTemperature; // @0x120 (word 0x48) resource +0xE8
|
|
Scalar failureTemperature; // @0x124 (word 0x49) resource +0xEC
|
|
int watchedSubsystem; // @0x128 (word 0x4a) resource +0xE4
|
|
WatcherGaugeAlarm heatAlarm; // @0x12C (0x54) 3 levels -> ends 0x180
|
|
}; // HeatWatcher own region 0x114..0x180 (0x6C); PowerWatcher own follows at 0x180.
|
|
|
|
// BASE-CHAIN RE-BASE locks: prove the Watcher base ends where the binary needs.
|
|
// (engine Subsystem 0xE0 + MechSubsystem 0x34 = 0x114 == HeatWatcher start.)
|
|
static_assert(offsetof(HeatWatcher, watchedLink) == 0x114, "HeatWatcher watchedLink must be at 0x114");
|
|
static_assert(offsetof(HeatWatcher, heatAlarm) == 0x12C, "HeatWatcher heatAlarm must be at 0x12C (0x54-byte alarm)");
|
|
static_assert(sizeof(HeatWatcher) == 0x180, "HeatWatcher must end at 0x180 (PowerWatcher own follows)");
|
|
|
|
//###########################################################################
|
|
//############################ Reservoir ################################
|
|
//###########################################################################
|
|
//
|
|
// Coolant reservoir: a HeatSink that stores a coolant charge and "squirts"
|
|
// it into the linked sinks on demand (the slot-14 DrawCoolant SOURCE).
|
|
//
|
|
// vtable @0050ecd4/ecd8 ctor @4af408 classID 0x0BC0
|
|
//
|
|
struct Reservoir__SubsystemResource:
|
|
public HeatableSubsystem::SubsystemResource
|
|
{
|
|
Scalar coolantCapacity; // +0xFC "CoolantCapacity" (sentinel -1.0f)
|
|
Scalar coolantSquirtMass; // +0x100 "CoolantSquirtMass" (sentinel -1.0f)
|
|
};
|
|
|
|
class Reservoir:
|
|
public HeatSink
|
|
{
|
|
public:
|
|
static Derivation *GetClassDerivations(); // name "Reservoir"
|
|
static SharedData DefaultData;
|
|
|
|
typedef Reservoir__SubsystemResource SubsystemResource;
|
|
|
|
typedef void
|
|
(Reservoir::*Performance)(Scalar time_slice);
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
|
|
static Logical TestClass(Mech&);
|
|
Logical TestInstance() const; // @4af564 -> IsDerivedFrom 0x50e650
|
|
|
|
Reservoir(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
); // @4af408
|
|
|
|
// @4aef78 -- registered Performance (this[7..9] = &CoolantInjection via 0050e6b4)
|
|
void CoolantSimulation(Scalar time_slice);
|
|
// @4aefa4 (1019 bytes) -- distribute coolant ("squirt") across the
|
|
// linked heat-sink network, clamped per-sink and per-frame.
|
|
void InjectCoolant(Scalar time_slice);
|
|
|
|
// @4af3b0 -- slot-14 DrawCoolant override: hand out up to coolantLevel.
|
|
Scalar DrawCoolant(Scalar requested);
|
|
|
|
Logical HandleMessage(int message); // @4aee70 ("InjectCoolant" msg)
|
|
void PrintState(); // @4aeef8 (ReservoirState)
|
|
void GetState(/*...*/); // @4aef40 (slot 7 state query)
|
|
|
|
static int CreateStreamedSubsystem( // @4af580
|
|
NotationFile *model_file,
|
|
const char *model_name,
|
|
const char *subsystem_name,
|
|
SubsystemResource *subsystem_resource,
|
|
NotationFile *subsystem_file,
|
|
const ResourceDirectories *directories,
|
|
int passes = 1
|
|
);
|
|
|
|
public:
|
|
// HeatSink base (ends 0x1D0) ... then Reservoir adds (ctor @4aef.., dtor param_1[0x74..0x8b]):
|
|
// coolantCapacity is the inherited HeatSink thermalCapacity@0x128 (word 0x4a);
|
|
// "injectActive" is reservoirAlarm's level (@0x1e4 == alarm+0x14, raw @4aef78);
|
|
// both were redeclared members that over-sized the object past the 0x230 alloc.
|
|
GaugeAlarm54 reservoirAlarm; // @0x1D0 (word 0x74) 0x54 alarm -> ends 0x224; level@0x1e4 = inject flag
|
|
Scalar coolantSquirtMass; // @0x224 (word 0x89) resource +0x100
|
|
Scalar injectAccumulator; // @0x228 (word 0x8a) inject elapsed-time accumulator
|
|
Scalar squirtEfficiency; // @0x22C (word 0x8b) init 0.5f -> ends 0x230
|
|
// coolantLevel @0x12C (word 0x4b) init = capacity (inherited).
|
|
|
|
friend struct ReservoirLayoutCheck;
|
|
};
|
|
|
|
struct ReservoirLayoutCheck {
|
|
static_assert(offsetof(Reservoir, reservoirAlarm) == 0x1D0, "Reservoir::reservoirAlarm @0x1D0 (word 0x74)");
|
|
static_assert(offsetof(Reservoir, coolantSquirtMass) == 0x224, "Reservoir::coolantSquirtMass @0x224 (word 0x89)");
|
|
static_assert(offsetof(Reservoir, injectAccumulator) == 0x228, "Reservoir::injectAccumulator @0x228 (word 0x8a)");
|
|
static_assert(offsetof(Reservoir, squirtEfficiency) == 0x22C, "Reservoir::squirtEfficiency @0x22C (word 0x8b)");
|
|
static_assert(sizeof(Reservoir) == 0x230, "sizeof(Reservoir) 0x230 (factory alloc)");
|
|
};
|
|
|
|
//###########################################################################
|
|
//######################## AggregateHeatSink ############################
|
|
//###########################################################################
|
|
//
|
|
// The mech's aggregate / master heat-sink BANK (classID 0x0BBE). A HeatSink
|
|
// subclass that parses "HeatSinkCount" and holds a frozen "AmbientTemperature"
|
|
// setpoint (300 K); the numeric-R cockpit gauge binds HeatSink/AmbientTemperature
|
|
// to this class (L4GAUGE.CFG:4552, the last config-binding NULL).
|
|
//
|
|
// vtable @0050ed4c/ed50 ctor @4ae8d0 classID 0x0BBE own GUID 0x50e590
|
|
//
|
|
// DELIBERATE DEVIATION (databinding-safe, zero-regression): the shipped ctor
|
|
// installs Performance @4ae73c (relax toward the ambient setpoint), which reads
|
|
// a RAW inherited-base pointer self+0xE0 -> [+0x158] (the engine subsystem's
|
|
// status/damage model, FUN_0041de1c). That offset does NOT map in our compiled
|
|
// layout (garbage ptr -> AV/NaN, and this ctor runs for EVERY mech). Since
|
|
// ambientTemperature is a FROZEN constant (@4ae73c never writes it, so the gauge
|
|
// reads 300 either way), we keep the VERIFIED base HeatSinkSimulation the HeatSink
|
|
// base ctor already installs and do NOT reimplement @4ae73c / deref self+0xE0.
|
|
// The authentic relaxation model is DEFERRED (see the deferred item in §10 / P4).
|
|
//
|
|
struct AggregateHeatSink__SubsystemResource:
|
|
public HeatableSubsystem::SubsystemResource // ends 0xFC
|
|
{
|
|
int heatSinkCount; // +0xFC "HeatSinkCount" (parser @4ae9dc; ctor reads res+0xFC)
|
|
};
|
|
|
|
class AggregateHeatSink:
|
|
public HeatSink
|
|
{
|
|
public:
|
|
static Derivation *GetClassDerivations(); // own GUID 0x50e590, name "HeatSinkBank"
|
|
static SharedData DefaultData;
|
|
|
|
enum {
|
|
HeatSinkCountAttributeID = HeatSink::NextAttributeID, // @0x1D0
|
|
AmbientTemperatureAttributeID, // @0x1D4 FROZEN 300
|
|
NextAttributeID
|
|
};
|
|
private:
|
|
static const IndexEntry AttributePointers[];
|
|
public:
|
|
static AttributeIndexSet& GetAttributeIndex();
|
|
|
|
static Logical TestClass(Mech&);
|
|
Logical TestInstance() const; // @4ae9c0 -> IsDerivedFrom 0x50e590
|
|
|
|
typedef AggregateHeatSink__SubsystemResource SubsystemResource;
|
|
|
|
AggregateHeatSink(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
); // @4ae8d0
|
|
~AggregateHeatSink();
|
|
|
|
static int CreateStreamedSubsystem( // @4ae9dc (offline content-build only)
|
|
NotationFile *model_file,
|
|
const char *model_name,
|
|
const char *subsystem_name,
|
|
SubsystemResource *subsystem_resource,
|
|
NotationFile *subsystem_file,
|
|
const ResourceDirectories *directories,
|
|
int passes = 1
|
|
);
|
|
|
|
public:
|
|
// HeatSink base ends 0x1D0; the aggregate adds:
|
|
int heatSinkCount; // @0x1D0 (word 0x74) res +0xFC
|
|
Scalar ambientTemperature; // @0x1D4 (word 0x75) = 300.0f, FROZEN
|
|
SubsystemConnection helper; // @0x1D8 (word 0x76) 0xC link node (vestigial/inert)
|
|
// object ends @0x1E4
|
|
|
|
friend struct AggregateHeatSinkLayoutCheck;
|
|
};
|
|
|
|
struct AggregateHeatSinkLayoutCheck {
|
|
static_assert(offsetof(AggregateHeatSink__SubsystemResource, heatSinkCount) == 0xFC, "res heatSinkCount @0xFC");
|
|
static_assert(offsetof(AggregateHeatSink, heatSinkCount) == 0x1D0, "heatSinkCount @0x1D0 (word 0x74)");
|
|
static_assert(offsetof(AggregateHeatSink, ambientTemperature) == 0x1D4, "ambientTemperature @0x1D4 (word 0x75)");
|
|
static_assert(offsetof(AggregateHeatSink, helper) == 0x1D8, "helper @0x1D8 (word 0x76)");
|
|
static_assert(sizeof(AggregateHeatSink) == 0x1E4, "sizeof 0x1E4 == factory alloc @9993");
|
|
};
|
|
|
|
//###########################################################################
|
|
//############# Engine collection-iterator helpers (NOT heat) ###########
|
|
//###########################################################################
|
|
//
|
|
// The thunks @4af9cf..@4afb96 are tiny ctor/dtor wrappers for the engine's
|
|
// generic collection/iterator library (vtables 0050eccc, 0050ecc4, 0050ecbc,
|
|
// 0050ec6c, 0050ec1c), used as locals inside Reservoir::InjectCoolant
|
|
// (@4aefa4). They are out of scope for the heat family and are documented
|
|
// in heatfamily_reslice.cpp only for completeness.
|
|
|
|
#endif
|