The gap found in 5.3.131 is closed. HeatWatcher has always streamed a
watchedSubsystem index and read it into a member; nothing ever turned it
into the link UpdateWatch resolves, so the entire watcher family --
PowerWatcher and the Gyroscope / Torso / HUD / AmmoBin leaves included --
resolved NULL and reported its target dead.
The Mech ctor now binds them in a post-walk pass, which is where it has
to be: a watcher may legally watch a subsystem with a higher roster id,
which does not exist yet while the segment walk is still building.
Out-of-range and self-referencing indices are skipped rather than
trusted.
THE BINDINGS PROVE THEMSELVES -- every index lands on a semantically
right target, which a wrong offset could not manage:
Gyroscope -> Avionics Torso -> Myomers
HUD -> Avionics Searchlight -> Avionics
AmmoBinAFC100 -> AFC100 AmmoBinLRM15_1 -> LRM15_1
AmmoBinLRM15_2 -> LRM15_2
The gyro and HUD watch the avionics bus, the torso watches the muscles
that move it, and every ammo bin watches its own gun.
With the link live the gyro's watchdog moved off the NULL fallback (0 ->
1) but has not reached Ready. UpdateWatch can produce 1 two ways --
NoVoltage, or a brownout on a target that IS ready -- and since Avionics
is a Sensor reporting voltState 4, the brownout branch is the suspect.
Recorded as the next question with the experiment that separates the two
causes, rather than quieting an alarm by moving a threshold.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
676 lines
22 KiB
C++
676 lines
22 KiB
C++
//===========================================================================//
|
|
// File: heat.hpp //
|
|
// Project: BattleTech //
|
|
// Contents: Implementation details for heatable subsystems //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#if !defined(HEAT_HPP)
|
|
# define HEAT_HPP
|
|
|
|
# if !defined(MECHSUB_HPP)
|
|
# include <mechsub.hpp>
|
|
# endif
|
|
|
|
# if !defined(AVERAGE_HPP)
|
|
# include <average.hpp>
|
|
# endif
|
|
|
|
//##################### Forward Class Declarations #######################
|
|
class Mech;
|
|
|
|
//###########################################################################
|
|
//################## HeatableSubsystem Model Resource ###################
|
|
//###########################################################################
|
|
|
|
struct HeatableSubsystem__SubsystemResource:
|
|
public MechSubsystem::SubsystemResource
|
|
{
|
|
Scalar startingTemperature;
|
|
Scalar degradationTemperature;
|
|
Scalar failureTemperature;
|
|
Scalar thermalConductance;
|
|
Scalar thermalMass;
|
|
};
|
|
|
|
//###########################################################################
|
|
//######################## HeatableSubsystem ############################
|
|
//###########################################################################
|
|
|
|
class HeatableSubsystem:
|
|
public MechSubsystem
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
public:
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Attribute Support. The cockpit gauges bind these by NAME through the
|
|
// interpreter (ParseAttribute -> GetAttributePointer): the 1995
|
|
// L4GAUGE.CFG spellings are the enum names. The whole heat/power chain
|
|
// publishes IDs 2..0x0E so PoweredSubsystem::NextAttributeID lands on the
|
|
// authentic 0x0F -- Sensor's table (surviving SENSOR.HPP) and
|
|
// MechWeapon's pinned 0x12 pads are both numbered off it. CONTIGUITY IS
|
|
// LOAD-BEARING: AttributeIndexSet::Build leaves uncovered gap slots
|
|
// uninitialized.
|
|
//
|
|
public:
|
|
enum {
|
|
CurrentTemperatureAttributeID = MechSubsystem::NextAttributeID, // 3
|
|
HeatLoadAttributeID, // 3
|
|
DegradationTemperatureAttributeID, // 4
|
|
FailureTemperatureAttributeID, // 5
|
|
NextAttributeID // 6
|
|
};
|
|
|
|
static const IndexEntry AttributePointers[];
|
|
static AttributeIndexSet AttributeIndex;
|
|
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Test Class Support
|
|
//
|
|
public:
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
void
|
|
ResetToInitialState();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction and Destruction
|
|
//
|
|
public:
|
|
typedef HeatableSubsystem__SubsystemResource SubsystemResource;
|
|
|
|
HeatableSubsystem(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
|
|
~HeatableSubsystem();
|
|
|
|
static int
|
|
CreateStreamedSubsystem(
|
|
NotationFile *model_file,
|
|
const char *model_name,
|
|
const char *subsystem_name,
|
|
SubsystemResource *subsystem_resource,
|
|
NotationFile *subsystem_file,
|
|
const ResourceDirectories *directories,
|
|
int passes = 1
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Local Data
|
|
//
|
|
public:
|
|
Scalar
|
|
CurrentTemperatureOf()
|
|
{ Check(this); return currentTemperature; }
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// The coolant-allocation trio (binary heatable +0x1d0/+0x15c/+0x1dc,
|
|
// ctor @004ae568). PUBLIC: the owning Mech's redistribute walks the
|
|
// heatable chain and writes all three (the duckCommand precedent).
|
|
//
|
|
// coolantPriority the draw-weight rung, born 1; the per-subsystem
|
|
// priority button (@004ae464, id TBD) steps it 0 -> 1 -> 5 ->
|
|
// 50 -> 0, and the mech's BalanceCoolant (0x16) resets every
|
|
// heatable to 1 (the equal split).
|
|
// coolantShare priority / total, written ONLY by the mech's
|
|
// RedistributeCoolantShares (@0049f788); the reservoir draw
|
|
// (@004aefa4) weights each heatable's coolant feed by it.
|
|
// balanceAlarm 3 levels (binary FUN_0041b9ec(+0x1dc, 3)); the
|
|
// redistribute blips it -- 2 = share shrank or held, 1 = grew,
|
|
// then back to 0 -- the cockpit gauge flash.
|
|
//
|
|
public:
|
|
int coolantPriority;
|
|
Scalar coolantShare;
|
|
AlarmIndicator balanceAlarm;
|
|
|
|
protected:
|
|
Scalar currentTemperature;
|
|
Scalar heatLoad;
|
|
Scalar degradationTemperature;
|
|
Scalar failureTemperature;
|
|
};
|
|
|
|
//###########################################################################
|
|
//########################## SubsystemConnection ########################
|
|
//###########################################################################
|
|
//
|
|
// A slot linking a heat sink to its master / linked heat sink.
|
|
//
|
|
class SubsystemConnection
|
|
{
|
|
public:
|
|
SubsystemConnection() { linked = NULL; }
|
|
void Add(Subsystem *s) { linked = s; }
|
|
Subsystem* Resolve() const { return linked; }
|
|
void Clear() { linked = NULL; }
|
|
protected:
|
|
Subsystem *linked;
|
|
int reserved[2];
|
|
};
|
|
|
|
//###########################################################################
|
|
//####################### HeatSink Model Resource #######################
|
|
//###########################################################################
|
|
|
|
struct HeatSink__SubsystemResource:
|
|
public HeatableSubsystem__SubsystemResource
|
|
{
|
|
//
|
|
// WIRE-VERIFIED (raw-stream dump): the roster index of the sink this
|
|
// one conducts its heat into -- the weapons/equipment link to the
|
|
// Condenser bank (slots 4-9), the Condensers to the central HeatSink.
|
|
// This was THE missing ancestry int that shifted every descendant
|
|
// resource block +1 (PoweredSubsystem voltageSourceIndex, the MechWeapon
|
|
// block, ...).
|
|
//
|
|
int linkedSinkIndex;
|
|
};
|
|
|
|
//###########################################################################
|
|
//############################## HeatSink ###############################
|
|
//###########################################################################
|
|
|
|
//###########################################################################
|
|
//################### HeatWatcher Model Resource #######################
|
|
//###########################################################################
|
|
|
|
struct HeatWatcher__SubsystemResource:
|
|
public MechSubsystem__SubsystemResource
|
|
{
|
|
int watchedSubsystem;
|
|
Scalar degradationTemperature;
|
|
Scalar failureTemperature;
|
|
};
|
|
|
|
//###########################################################################
|
|
//############################# HeatWatcher #############################
|
|
//###########################################################################
|
|
//
|
|
// Watches another subsystem's temperature and drives a 3-level alarm. A
|
|
// sibling branch to HeatableSubsystem (derives straight from MechSubsystem);
|
|
// PowerWatcher and the Torso/HUD/Gyroscope leaves descend from it.
|
|
//
|
|
class HeatWatcher:
|
|
public MechSubsystem
|
|
{
|
|
public:
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
void
|
|
ResetToInitialState(Logical powered);
|
|
|
|
//
|
|
// Respawn restore: base heal + the thermal state back to spawn
|
|
// (temperature/coolant via ResetToInitialState).
|
|
//
|
|
virtual void
|
|
DeathReset(Logical full_reset);
|
|
|
|
//
|
|
// The class-typed Performance shim, the same shape every sibling
|
|
// subsystem carries (the base takes the Subsystem-typed pointer).
|
|
//
|
|
typedef void
|
|
(HeatWatcher::*Performance)(Scalar time_slice);
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
void
|
|
WatchSimulation(Scalar time_slice);
|
|
|
|
public:
|
|
typedef HeatWatcher__SubsystemResource SubsystemResource;
|
|
|
|
HeatWatcher(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
~HeatWatcher();
|
|
|
|
protected:
|
|
SubsystemConnection watchedLink;
|
|
|
|
public:
|
|
//
|
|
// THE WATCH BIND (5.3.132). The streamed `watchedSubsystem` index
|
|
// has been read since this class landed, but nothing ever turned it
|
|
// into the link `UpdateWatch` resolves -- so every watcher in the
|
|
// mech resolved NULL and reported its target dead. The Mech ctor
|
|
// binds these in a post-walk pass: a watcher can legally watch a
|
|
// subsystem with a HIGHER roster id, which does not exist yet while
|
|
// the segment walk is still building, so the bind cannot live in
|
|
// this ctor.
|
|
//
|
|
int
|
|
WatchedSubsystemIndex() const
|
|
{ Check(this); return watchedSubsystem; }
|
|
void
|
|
BindWatchedSubsystem(Subsystem *watched)
|
|
{ Check(this); watchedLink.Add(watched); }
|
|
|
|
protected:
|
|
int watchedSubsystem;
|
|
Scalar degradationTemperature;
|
|
Scalar failureTemperature;
|
|
AlarmIndicator heatAlarm;
|
|
};
|
|
|
|
class HeatSink:
|
|
public HeatableSubsystem
|
|
{
|
|
friend class Condenser;
|
|
friend class Reservoir;
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
public:
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Attribute Support (the coolant family the cockpit bars read).
|
|
//
|
|
public:
|
|
enum {
|
|
CoolantMassAttributeID = HeatableSubsystem::NextAttributeID, // 6
|
|
CoolantCapacityAttributeID, // 7
|
|
CoolantMassLeakRateAttributeID, // 8
|
|
CoolantAvailableAttributeID, // 9
|
|
//
|
|
// Authored watcher, bound on Avionics / every Condenser /
|
|
// every Generator / Myomers / every weapon -- i.e. the whole
|
|
// heat-bearing family, which is why it belongs on HeatSink.
|
|
// Adding it here pushes PoweredSubsystem::NextAttributeID from
|
|
// 0x0F to 0x10, so MechWeapon drops one bridging pad to keep
|
|
// PercentDone on its binary-pinned 0x12 (see MECHWEAP.CPP).
|
|
//
|
|
ReportLeakAttributeID, // 0x0A
|
|
NextAttributeID // 0x0A
|
|
};
|
|
|
|
static const IndexEntry AttributePointers[];
|
|
static AttributeIndexSet AttributeIndex;
|
|
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Test Class Support
|
|
//
|
|
public:
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
void
|
|
ResetToInitialState(Logical powered);
|
|
|
|
//
|
|
// Respawn restore: base heal + the thermal state back to spawn.
|
|
//
|
|
virtual void
|
|
DeathReset(Logical full_reset);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Messaging Support. The cockpit cooling toggle rides the first
|
|
// subsystem-family message slot (id 3 = Receiver::NextMessageID); the
|
|
// per-class id-4 slot is claimed by each subclass (Condenser MoveValve,
|
|
// Reservoir InjectCoolant, ...).
|
|
//
|
|
public:
|
|
enum {
|
|
ToggleCoolingMessageID = Receiver::NextMessageID, // 3
|
|
NextMessageID // 4
|
|
};
|
|
|
|
static const HandlerEntry MessageHandlerEntries[];
|
|
static MessageHandlerSet MessageHandlers;
|
|
|
|
void
|
|
ToggleCoolingMessageHandler(ReceiverDataMessageOf<int> *message);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Heat state (carried in heatAlarm, 3 levels). The thresholds are the
|
|
// authored degradation/failure temperatures.
|
|
//
|
|
public:
|
|
enum {
|
|
NormalHeat = 0,
|
|
DegradationHeat,
|
|
FailureHeat,
|
|
HeatStateCount
|
|
};
|
|
|
|
unsigned
|
|
GetHeatState() { Check(this); return heatAlarm.GetLevel(); }
|
|
Scalar
|
|
CurrentTemperatureOf() { Check(this); return currentTemperature; }
|
|
Scalar
|
|
StartingTemperatureOf() { Check(this); return startingTemperature; }
|
|
void
|
|
AddPendingHeat(Scalar heat)
|
|
{ Check(this); pendingHeat += heat; }
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Simulation Support
|
|
//
|
|
public:
|
|
typedef void
|
|
(HeatSink::*Performance)(Scalar time_slice);
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
|
|
//
|
|
// The heat-model master switch (binary FUN_004ad7d4): the owning
|
|
// BTPlayer's heatModelOn experience flag, reached through the mech's
|
|
// playerLink. ON only for veteran / expert; a NULL player reads ON.
|
|
//
|
|
Logical
|
|
HeatModelActive();
|
|
|
|
void
|
|
HeatSinkSimulation(Scalar time_slice);
|
|
void
|
|
UpdateHeatLoad();
|
|
void
|
|
ConductHeat(Scalar time_slice);
|
|
Scalar
|
|
ComputeHeatFlow(HeatSink *other, Scalar time_slice);
|
|
void
|
|
UpdateCoolant(Scalar time_slice);
|
|
void
|
|
BalanceCoolant(Scalar time_slice);
|
|
virtual Scalar
|
|
DrawCoolant(Scalar requested);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction and Destruction
|
|
//
|
|
public:
|
|
typedef HeatSink__SubsystemResource SubsystemResource;
|
|
|
|
HeatSink(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
|
|
~HeatSink();
|
|
|
|
//
|
|
// The cockpit's cooling-loop lamp needs both of these from BT_L4:
|
|
// whether this sink has coolant, and which sink it is plumbed to
|
|
// (the loop master, whose Condenser number IS the lamp's frame).
|
|
//
|
|
int
|
|
GetCoolantAvailable() const { Check(this); return coolantAvailable; }
|
|
Scalar
|
|
GetCoolantLevel() const { Check(this); return coolantLevel; }
|
|
Scalar
|
|
GetThermalCapacity() const { Check(this); return thermalCapacity; }
|
|
Subsystem *
|
|
ResolveCoolingMaster() { Check(this); return linkedSinks.Resolve(); }
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Local Data
|
|
//
|
|
protected:
|
|
Scalar coolantEfficiency;
|
|
Scalar thermalCapacity;
|
|
Scalar coolantLevel;
|
|
Scalar coolantDraw;
|
|
int coolantAvailable;
|
|
int coolantActive;
|
|
Scalar startingTemperature;
|
|
Scalar thermalConductance;
|
|
Scalar filterDecay;
|
|
Scalar thermalMass;
|
|
Scalar heatEnergy;
|
|
Scalar coolantFlowScale;
|
|
Scalar massScale;
|
|
Scalar pendingHeat;
|
|
Scalar radiatedHeat;
|
|
SubsystemConnection linkedSinks;
|
|
AlarmIndicator heatAlarm;
|
|
AverageOf<Scalar> heatFilter;
|
|
//
|
|
// STAGED, appended last: no leak-reporting model yet. A Scalar
|
|
// because the audio watcher families instantiate Motion / Hinge /
|
|
// Scalar / StateIndicator, and this is not a *State name.
|
|
//
|
|
Scalar reportLeak;
|
|
};
|
|
|
|
//###########################################################################
|
|
//#################### Condenser Model Resource ########################
|
|
//###########################################################################
|
|
|
|
struct Condenser__SubsystemResource:
|
|
public HeatSink__SubsystemResource
|
|
{
|
|
Scalar refrigerationFactor;
|
|
};
|
|
|
|
//###########################################################################
|
|
//############################## Condenser #############################
|
|
//###########################################################################
|
|
//
|
|
// A HeatSink with active refrigeration (a coolant loop's condenser).
|
|
//
|
|
class Condenser:
|
|
public HeatSink
|
|
{
|
|
public:
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Attribute Support (the valve slider on the Eng page).
|
|
//
|
|
public:
|
|
enum {
|
|
ValveSettingAttributeID = HeatSink::NextAttributeID, // 0x0A
|
|
CondenserStateAttributeID, // authored watcher: CondenserN/CondenserState
|
|
NextAttributeID
|
|
};
|
|
|
|
static const IndexEntry AttributePointers[];
|
|
static AttributeIndexSet AttributeIndex;
|
|
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Messaging Support: the cockpit condenser-valve button (binary handler
|
|
// table @0x50E52C, exactly one entry -- id 4, "MoveValve"). Each press
|
|
// cycles this condenser's valve 1 -> 5 -> 50 -> 0 -> 1 and recomputes every
|
|
// condenser's coolant flow share (valve / sum-of-valves).
|
|
//
|
|
public:
|
|
enum {
|
|
MoveValveMessageID = HeatSink::NextMessageID, // 4
|
|
NextMessageID
|
|
};
|
|
|
|
static const HandlerEntry MessageHandlerEntries[];
|
|
static MessageHandlerSet MessageHandlers;
|
|
|
|
void
|
|
MoveValveMessageHandler(ReceiverDataMessageOf<int> *message);
|
|
|
|
//
|
|
// [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);
|
|
|
|
public:
|
|
typedef Condenser__SubsystemResource SubsystemResource;
|
|
|
|
Condenser(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
~Condenser();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Per-frame refrigeration (binary @4ae4d8): the condenser actively pumps
|
|
// heat toward the central bank -- massScale is recomputed each frame as
|
|
// (1 - own damage) * refrigerationFactor, clamped >= 1, so an undamaged
|
|
// condenser behaves refrigerationFactor-times "hotter" in the conduction
|
|
// exchange and chills itself below ambient (which is what cools the
|
|
// weapons equalizing against it). Damage degrades it toward a plain sink.
|
|
//
|
|
public:
|
|
typedef void
|
|
(Condenser::*Performance)(Scalar time_slice);
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
void
|
|
RefrigerationSimulation(Scalar time_slice);
|
|
|
|
//
|
|
// The loop number (1..6) -- the cockpit lamp's image-strip frame.
|
|
//
|
|
int
|
|
GetCondenserNumber() const { Check(this); return condenserNumber; }
|
|
|
|
protected:
|
|
int condenserNumber;
|
|
Scalar refrigerationFactor;
|
|
//
|
|
// APPENDED LAST ON PURPOSE. This class has offset-sensitive
|
|
// readers -- condenserNumber is reached as master+0x1d4 -- so a new
|
|
// member goes at the END of the CLASS (never into the resource
|
|
// struct above, which is a wire format).
|
|
//
|
|
//
|
|
// MUST BE A StateIndicator. The authored watcher for a *State
|
|
// name is an AudioStateWatcher, which is AudioWatcherOf<StateIndicator>
|
|
// and whose ctor immediately runs
|
|
// Cast_Object(StateIndicator*, attributePointer)->AddAudioWatcher(this)
|
|
// (AUDWTHR.CPP:891). Point it at a plain int and that call goes
|
|
// through garbage -- the pod dies on the extender.
|
|
//
|
|
StateIndicator condenserState; // authored watcher
|
|
};
|
|
|
|
//###########################################################################
|
|
//##################### AggregateHeatSink Resource ######################
|
|
//###########################################################################
|
|
|
|
struct AggregateHeatSink__SubsystemResource:
|
|
public HeatSink__SubsystemResource
|
|
{
|
|
int heatSinkCount;
|
|
};
|
|
|
|
//###########################################################################
|
|
//######################### AggregateHeatSink ###########################
|
|
//###########################################################################
|
|
//
|
|
// The mech's heat-sink BANK (binary classID 0x0BBE -- the value our VDATA
|
|
// enum names HeatSinkClassID; there is no streamed plain-HeatSink class).
|
|
// Holds the aggregate heat-sink count and the ambient-temperature setpoint,
|
|
// and runs the AMBIENT RADIATOR -- the only place heat ever LEAVES the mech.
|
|
//
|
|
class AggregateHeatSink:
|
|
public HeatSink
|
|
{
|
|
public:
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
public:
|
|
typedef AggregateHeatSink__SubsystemResource SubsystemResource;
|
|
|
|
AggregateHeatSink(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
~AggregateHeatSink();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// The radiator (binary @4ae73c) -- replaces the base HeatSinkSimulation on
|
|
// the bank: absorb, then relax toward the ambient setpoint (the heat EXIT),
|
|
// then top the bank's coolant up from the attached store.
|
|
//
|
|
public:
|
|
typedef void
|
|
(AggregateHeatSink::*Performance)(Scalar time_slice);
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
void
|
|
RadiatorSimulation(Scalar time_slice);
|
|
|
|
int
|
|
GetHeatSinkCount() const { Check(this); return heatSinkCount; }
|
|
|
|
protected:
|
|
int heatSinkCount;
|
|
Scalar ambientTemperature;
|
|
};
|
|
|
|
#endif
|