//===========================================================================// // 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 # 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 *message); void SelectGeneratorBMessageHandler(ReceiverDataMessageOf *message); void SelectGeneratorCMessageHandler(ReceiverDataMessageOf *message); void SelectGeneratorDMessageHandler(ReceiverDataMessageOf *message); void ToggleGeneratorModeMessageHandler(ReceiverDataMessageOf *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