Ladder rungs, each run-verified on the pod rig: ReportLeak (HeatSink), GeneratorOn (Generator -- member existed, publication missing), ConfigureActivePress (MechSubsystem -- likewise), AmmoState + FireCountdownStarted + the rest of the AmmoBin table. THE PINNED RANGE IS NOW THE AUTHENTIC SHAPE. Publishing ReportLeak on HeatSink and ConfigureActivePress on MechSubsystem shifts the chain down two, and MechWeapon's bridge to its binary-pinned PercentDone (0x12) collapses from THREE guessed pads to ONE -- which is exactly the arithmetic the shipped string pool predicts (MechSubsystem 1, HeatableSubsystem 3, HeatSink 6, PoweredSubsystem 5). Three pads of guesswork replaced by a real attribute and a real base-class row. HeatableSubsystem and Torso rebase onto MechSubsystem::AttributeIndex; MechControlsMapper does not (it derives from Subsystem directly). Types were chosen deliberately this time, per the AudioWatcher families the engine instantiates (Motion / Hinge / Scalar / StateIndicator): every *State name resolves to a StateIndicator, ReportLeak is a Scalar. RESULT: the pod run now gets past every authored watcher and DRAWS THE FULL COCKPIT -- sensor cluster, myomers, cooling, the weapon panels, kills/deaths -- with the board booted and audio running. It then exits without flushing its redirected stdout, so the exit reason is not yet known; next step is a run with the redirect removed so the console is readable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
491 lines
15 KiB
C++
491 lines
15 KiB
C++
//===========================================================================//
|
|
// File: powersub.hpp //
|
|
// Project: BattleTech //
|
|
// Contents: Implementation details for powered subsystems //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#if !defined(POWERSUB_HPP)
|
|
# define POWERSUB_HPP
|
|
|
|
# if !defined(HEAT_HPP)
|
|
# include <heat.hpp>
|
|
# endif
|
|
|
|
//##################### Forward Class Declarations #######################
|
|
class Mech;
|
|
|
|
//###########################################################################
|
|
//################### PoweredSubsystem Model Resource ###################
|
|
//###########################################################################
|
|
|
|
struct PoweredSubsystem__SubsystemResource:
|
|
public HeatSink::SubsystemResource
|
|
{
|
|
int voltageSourceIndex;
|
|
Scalar thermalResistivityCoefficient;
|
|
int auxScreenNumber;
|
|
int auxScreenPlacement;
|
|
char auxScreenLabel[64];
|
|
char engScreenLabel[64];
|
|
Scalar startTime;
|
|
};
|
|
|
|
//###########################################################################
|
|
//######################### PoweredSubsystem ############################
|
|
//###########################################################################
|
|
|
|
class PoweredSubsystem:
|
|
public HeatSink
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
public:
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Attribute Support. The electrical family; NextAttributeID lands on
|
|
// the AUTHENTIC 0x0F -- the surviving SENSOR.HPP numbers RadarPercent
|
|
// off it and MechWeapon's pinned table starts its real IDs at 0x12
|
|
// (three pads bridge 0x0F..0x11). Do not renumber without re-pinning
|
|
// both.
|
|
//
|
|
public:
|
|
enum {
|
|
InputVoltageAttributeID = HeatSink::NextAttributeID, // 0x0A
|
|
OutputVoltageAttributeID, // 0x0B
|
|
RatedVoltageAttributeID, // 0x0C
|
|
VoltageStateAttributeID, // 0x0D
|
|
ConnectModeAttributeID, // 0x0E
|
|
NextAttributeID // 0x0F
|
|
};
|
|
|
|
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);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Electrical state machine (carried in electricalStateAlarm, 5 levels) and
|
|
// the connection-mode indicator (modeAlarm, 3 levels).
|
|
//
|
|
public:
|
|
enum ElectricalState {
|
|
Starting = 0, // powering up; startTimer counts toward startTime
|
|
NoVoltage = 1, // voltage source missing / unresolvable
|
|
Shorted = 2, // source generator shorted
|
|
GeneratorOff = 3, // source generator off / not ready
|
|
Ready = 4 // powered and operating
|
|
};
|
|
|
|
enum ConnectMode {
|
|
ManualConnect = 0,
|
|
Connected = 1,
|
|
AutoConnect = 2
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Power support
|
|
//
|
|
public:
|
|
//
|
|
// The cockpit generator-select buttons (binary handler table
|
|
// @0x50F4EC, ids 4-8, chained onto the HeatSink set so id 3
|
|
// ToggleCooling stays reachable through every powered subsystem).
|
|
//
|
|
enum {
|
|
SelectGeneratorAMessageID = HeatSink::NextMessageID, // 4
|
|
SelectGeneratorBMessageID, // 5
|
|
SelectGeneratorCMessageID, // 6
|
|
SelectGeneratorDMessageID, // 7
|
|
ToggleGeneratorModeMessageID, // 8
|
|
NextMessageID // 9
|
|
};
|
|
|
|
static const HandlerEntry MessageHandlerEntries[];
|
|
static MessageHandlerSet MessageHandlers;
|
|
|
|
void
|
|
SelectGeneratorAMessageHandler(ReceiverDataMessageOf<int> *message);
|
|
void
|
|
SelectGeneratorBMessageHandler(ReceiverDataMessageOf<int> *message);
|
|
void
|
|
SelectGeneratorCMessageHandler(ReceiverDataMessageOf<int> *message);
|
|
void
|
|
SelectGeneratorDMessageHandler(ReceiverDataMessageOf<int> *message);
|
|
void
|
|
ToggleGeneratorModeMessageHandler(ReceiverDataMessageOf<int> *message);
|
|
|
|
//
|
|
// The manual generator re-tap (binary @004b0b18/@004b0dd8 family):
|
|
// find generator N in the owner's roster, release the current tap,
|
|
// tap the new source, drop the connect mode to Connected.
|
|
//
|
|
void
|
|
SelectGenerator(int generator_number);
|
|
Subsystem*
|
|
FindGeneratorByNumber(int generator_number);
|
|
void
|
|
DetachFromVoltageSource();
|
|
|
|
//
|
|
// Respawn restore: thermal + electrical re-init (the FSM restarts
|
|
// from GeneratorOff/Starting exactly like spawn).
|
|
//
|
|
virtual void
|
|
DeathReset(Logical full_reset);
|
|
|
|
//
|
|
// The AUTHORED aux-screen assignment (streamed). CACHED at ctor
|
|
// time because MechSubsystem::resource points into the Mech ctor's
|
|
// padded stream copy, which is FREED before the ctor returns -- the
|
|
// 5.3.24 use-after-free landmine. The cockpit's engineering panels
|
|
// key their screen number, background placement and title label off
|
|
// these.
|
|
//
|
|
int
|
|
GetAuxScreenNumber() const { Check(this); return auxScreenNumber; }
|
|
int
|
|
GetAuxScreenPlacement() const { Check(this); return auxScreenPlacement; }
|
|
const char*
|
|
GetAuxScreenLabel() const { Check(this); return auxScreenLabel; }
|
|
const char*
|
|
GetEngScreenLabel() const { Check(this); return engScreenLabel; }
|
|
|
|
Subsystem*
|
|
ResolveVoltageSource() { return voltageSource.Resolve(); }
|
|
int
|
|
AttachToVoltageSource(Subsystem *source);
|
|
unsigned
|
|
GetVoltageState() { Check(this); return electricalStateAlarm.GetLevel(); }
|
|
|
|
//
|
|
// The charge time-scale (binary @004b0d50) -- the heat/firepower
|
|
// feedback: the base voltageScale (the ctor-calibrated exponential
|
|
// charge constant) stretched by the powering generator's temperature
|
|
// rise above its start point.
|
|
//
|
|
Scalar
|
|
ChargeTimeScale();
|
|
|
|
//
|
|
// Short event (binary @004b11bc): drive the powering generator into
|
|
// the Shorted state and zero its output -- the electrical FSM then
|
|
// runs its short-recovery cycle. Gated on the not-novice experience
|
|
// predicate (both hops share the mech's player). Called by the
|
|
// special-damage path (a type-4 Energy hit on a zone with attached
|
|
// generator criticals).
|
|
//
|
|
void
|
|
ForceShortRecovery();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Per-frame simulation (heat step + the electrical state machine).
|
|
//
|
|
public:
|
|
typedef void
|
|
(PoweredSubsystem::*Performance)(Scalar time_slice);
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
|
|
void
|
|
PoweredSubsystemSimulation(Scalar time_slice);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction and Destruction
|
|
//
|
|
public:
|
|
typedef PoweredSubsystem__SubsystemResource SubsystemResource;
|
|
|
|
PoweredSubsystem(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
|
|
~PoweredSubsystem();
|
|
|
|
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
|
|
//
|
|
protected:
|
|
Scalar inputVoltage;
|
|
Scalar outputVoltage;
|
|
Scalar ratedVoltage;
|
|
SubsystemConnection voltageSource;
|
|
AlarmIndicator electricalStateAlarm;
|
|
AlarmIndicator modeAlarm;
|
|
int auxScreenNumber;
|
|
int auxScreenPlacement;
|
|
char auxScreenLabel[64];
|
|
char engScreenLabel[64];
|
|
Scalar thermalResistivityCoefficient;
|
|
Scalar startTime;
|
|
Scalar startTimer;
|
|
Scalar voltageScale;
|
|
};
|
|
|
|
//###########################################################################
|
|
//################### PowerWatcher Model Resource ######################
|
|
//###########################################################################
|
|
|
|
struct PowerWatcher__SubsystemResource:
|
|
public HeatWatcher::SubsystemResource
|
|
{
|
|
Scalar minVoltagePercent;
|
|
};
|
|
|
|
//###########################################################################
|
|
//############################ PowerWatcher ############################
|
|
//###########################################################################
|
|
//
|
|
// A HeatWatcher that also watches its subject's supply voltage. Base of the
|
|
// Torso / HUD / Gyroscope cockpit subsystems.
|
|
//
|
|
class PowerWatcher:
|
|
public HeatWatcher
|
|
{
|
|
public:
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
void
|
|
ResetToInitialState(Logical powered);
|
|
//
|
|
// Respawn restore: base heal + the watchdog re-baseline (the
|
|
// HeatWatcher::DeathReset it would otherwise inherit binds the
|
|
// NON-virtual ResetToInitialState statically and skips this one).
|
|
//
|
|
virtual void
|
|
DeathReset(Logical full_reset);
|
|
void
|
|
Simulation(Scalar time_slice);
|
|
|
|
public:
|
|
typedef PowerWatcher__SubsystemResource SubsystemResource;
|
|
|
|
PowerWatcher(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
~PowerWatcher();
|
|
|
|
protected:
|
|
Scalar minVoltage;
|
|
AlarmIndicator watchdogAlarm;
|
|
};
|
|
|
|
//###########################################################################
|
|
//#################### Generator Model Resource ########################
|
|
//###########################################################################
|
|
|
|
struct Generator__SubsystemResource:
|
|
public HeatSink::SubsystemResource
|
|
{
|
|
Scalar ratedVoltage;
|
|
int maxTapCount;
|
|
Scalar startTime;
|
|
Scalar shortRecoveryTime;
|
|
};
|
|
|
|
//###########################################################################
|
|
//############################## Generator #############################
|
|
//###########################################################################
|
|
//
|
|
// The voltage SOURCE a PoweredSubsystem attaches to (currentTapCount tracks
|
|
// attached loads). A HeatSink that produces power.
|
|
//
|
|
class Generator:
|
|
public HeatSink
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
public:
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Attribute Support (the generator panel reads these by name). A
|
|
// SIBLING branch of PoweredSubsystem off HeatSink -- the shared 0x0A
|
|
// base is correct, each branch owns its own index set.
|
|
//
|
|
public:
|
|
enum {
|
|
OutputVoltageAttributeID = HeatSink::NextAttributeID, // 0x0A
|
|
RatedVoltageAttributeID, // 0x0B
|
|
GeneratorNumberAttributeID, // 0x0C
|
|
GeneratorStateAttributeID, // authored watcher: GeneratorX/GeneratorState
|
|
//
|
|
// Authored watcher too (GeneratorX/GeneratorOn, 36 bindings).
|
|
// The member has been here since the generator wave -- only the
|
|
// publication was missing, the same as EyepointRotation.
|
|
//
|
|
GeneratorOnAttributeID2,
|
|
NextAttributeID
|
|
};
|
|
|
|
static const IndexEntry AttributePointers[];
|
|
static AttributeIndexSet AttributeIndex;
|
|
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
|
|
enum {
|
|
GeneratorOff = 0,
|
|
GeneratorStarting,
|
|
GeneratorReady,
|
|
GeneratorShorted,
|
|
GeneratorFailed,
|
|
GeneratorStateCount
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Test / reset
|
|
//
|
|
public:
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
void
|
|
ResetToInitialState();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Power interface
|
|
//
|
|
public:
|
|
Scalar MeasuredVoltage() { Check(this); return outputVoltage; }
|
|
Scalar RatedVoltageOf() { Check(this); return ratedVoltage; }
|
|
int GetGeneratorNumber(){ Check(this); return generatorNumber; }
|
|
unsigned
|
|
GeneratorStateOf() { Check(this); return stateAlarm.GetLevel(); }
|
|
|
|
//
|
|
// The short event landing ON this generator (the tail of binary
|
|
// @004b11bc): Shorted state + output killed; GeneratorSimulation
|
|
// runs the short-recovery timer back to Ready. Callers gate on the
|
|
// novice experience predicate.
|
|
//
|
|
void
|
|
ForceShort()
|
|
{
|
|
Check(this);
|
|
stateAlarm.SetLevel(GeneratorShorted);
|
|
outputVoltage = 0.0f;
|
|
}
|
|
|
|
//
|
|
// Tap the generator for one load (a PoweredSubsystem attaching): -1 when
|
|
// every tap is taken, else 0.
|
|
//
|
|
int
|
|
TapVoltageSource()
|
|
{
|
|
Check(this);
|
|
if (currentTapCount >= maxTapCount)
|
|
{
|
|
return -1;
|
|
}
|
|
++currentTapCount;
|
|
return 0;
|
|
}
|
|
virtual void
|
|
DeathReset(Logical full_reset);
|
|
|
|
void
|
|
UntapVoltageSource()
|
|
{
|
|
Check(this);
|
|
if (currentTapCount > 0)
|
|
{
|
|
--currentTapCount;
|
|
}
|
|
}
|
|
|
|
typedef void
|
|
(Generator::*Performance)(Scalar time_slice);
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
|
|
void
|
|
GeneratorSimulation(Scalar time_slice);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction and Destruction
|
|
//
|
|
public:
|
|
typedef Generator__SubsystemResource SubsystemResource;
|
|
|
|
Generator(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
|
|
~Generator();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Local Data
|
|
//
|
|
public:
|
|
Scalar percentVoltageAvailable;
|
|
int generatorOn;
|
|
Scalar ratedVoltage;
|
|
Scalar outputVoltage;
|
|
int generatorNumber;
|
|
int maxTapCount;
|
|
int currentTapCount;
|
|
Scalar startTime;
|
|
Scalar startTimer;
|
|
Scalar shortRecoveryTime;
|
|
Scalar shortTimer;
|
|
AlarmIndicator stateAlarm;
|
|
};
|
|
|
|
#endif
|