Weapons dump firing heat into their own sinks, sinks conduct through the Condenser bank into the central HeatSink, temperatures drive the degradation/ failure alarms, and every powered subsystem tracks its generator through the electrical state machine. Verified: the authentic fire-discipline game -- a PPC spikes 77->709K per shot, relaxes to 441K across its 5s reload, and sustained fire climbs 441->674->838->960K, brushing the authored 1000K degradation threshold. All calibration values match the BT411 audit exactly (central bank 1.39e6, PPC sink 174000, thresholds 77/1000/2000). - HEAT: HeatSinkSimulation (@004ad924 absorb->T->load->conduct->alarm), ConductHeat/ComputeHeatFlow (@004ad8ac/@004ad9ec two-body equilibrium relaxation; flow==0 exactly at uniform T), UpdateHeatLoad (15-sample filter); heat-state enum + accessors; installed by the HeatSink ctor. - WIRE-VERIFIED: HeatSink resource gains linkedSinkIndex -- THE missing ancestry int that shifted every descendant block +1 (voltageSourceIndex had been reading the linked-sink index: "power sources" appeared to be Condensers). Conduction topology wired from it at construction: weapons->Condensers1-6->central; Generators->Condensers; Reservoir->central. - MECHWEAP resource: authentic pip tail (pipPosition int + pipColor 3 floats + pipExtendedRange int) per the BT411 verified overlay; with linkedSinkIndex this closes the whole +3 alignment mystery (ProjectileWeapon pad deleted). True bhk1 reads: PPC recharge 5.0s (not 1.0), discharge 0.99s, range 900. - POWERSUB: ctor resolves voltageSourceIndex -> GeneratorA-D (wire-verified), taps via Generator::TapVoltageSource (-1 when full); PoweredSubsystemSimulation (@004b0bd0) electrical FSM (Starting/NoVoltage/Shorted/GeneratorOff/Ready); GeneratorSimulation partial (start/short-recovery timers). - Weapons: power step at sim head; Loading recharge gated on electrical Ready (authentic @4bbdf5); FireWeapon dumps firing heat. HEAT UNITS: the chain is 1e7-native with TWO authoring conventions -- energy weapons store small (PPC=11, x1e7 from the energy algebra), ballistics store native (SRM6=5.06e7, dumped raw; double-scaling it was the bring-up runaway-temperature bug). - SENSOR: authentic gating (@004b1c4c) -- power step, electrical-Ready gate, heat-state switch (Degradation x0.5 / Failure 0). Verified Ready + 100%. Deferred: coolant depletion/venting, the novice HeatModelOff gate, the charge model (TrackSeekVoltage/voltage sag/I2R), weapon gate 1 + jam roll, the central sink's forward-linked drain. Zero Fail across fire + neutral runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
224 lines
7.2 KiB
C++
224 lines
7.2 KiB
C++
//===========================================================================//
|
|
// File: mechweap.hpp //
|
|
// Project: BattleTech //
|
|
// Contents: Implementation details for mech weapons //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#if !defined(MECHWEAP_HPP)
|
|
# define MECHWEAP_HPP
|
|
|
|
# if !defined(POWERSUB_HPP)
|
|
# include <powersub.hpp>
|
|
# endif
|
|
|
|
# if !defined(DAMAGE_HPP)
|
|
# include <damage.hpp>
|
|
# endif
|
|
|
|
# if !defined(ALARM_HPP)
|
|
# include <alarm.hpp>
|
|
# endif
|
|
|
|
//##################### Forward Class Declarations #######################
|
|
class Mech;
|
|
|
|
//###########################################################################
|
|
//###################### MechWeapon Model Resource ######################
|
|
//###########################################################################
|
|
|
|
//
|
|
// WIRE-VERIFIED layout (raw-stream dump vs the BT411 verified overlay):
|
|
// eleven fields; the pip tail is pipPosition(int) + pipColor(3 floats) +
|
|
// pipExtendedRange(int). bhk1 PPC reads: recharge 5.0s, range 900,
|
|
// damage 12, type 4, heatCost 11, pipColor (0,0,1).
|
|
//
|
|
struct MechWeapon__SubsystemResource:
|
|
public PoweredSubsystem::SubsystemResource
|
|
{
|
|
Scalar rechargeRate;
|
|
Scalar weaponRange;
|
|
ResourceDescription::ResourceID
|
|
explosionModelFile;
|
|
Scalar damageAmount;
|
|
int damageType;
|
|
Scalar heatCostToFire;
|
|
int pipPosition;
|
|
Scalar pipColor[3];
|
|
int pipExtendedRange;
|
|
};
|
|
|
|
//###########################################################################
|
|
//############################ MechWeapon ###############################
|
|
//###########################################################################
|
|
|
|
class MechWeapon:
|
|
public PoweredSubsystem
|
|
{
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Shared Data Support
|
|
//
|
|
public:
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
static MessageHandlerSet MessageHandlers;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Attribute Support. The real IDs are PINNED to the 1995 binary numbering
|
|
// (table @0x511890, ids 0x12..0x1C): the streamed per-mech control mappings
|
|
// reference them by NUMBER -- TriggerState (0x13) is the fire-button binding.
|
|
// Our parent chain publishes nothing past Subsystem::NextAttributeID (2)
|
|
// yet, so pads bridge the gap 2..0x11 (they shrink to the authentic
|
|
// 0x0F..0x11 once the mechsub/heat/powersub attribute waves publish --
|
|
// SENSOR.HPP pins PoweredSubsystem::NextAttributeID at 0x0F). The pads are
|
|
// LOAD-BEARING: AttributeIndexSet::Build leaves unlisted gap slots as
|
|
// uninitialized garbage, so every ID up to the max must be covered.
|
|
//
|
|
public:
|
|
enum {
|
|
MechWeaponPadFirstAttributeID = Subsystem::NextAttributeID, // 2
|
|
PercentDoneAttributeID = 0x12,
|
|
TriggerStateAttributeID, // 0x13 -- the streamed fire-button binding
|
|
DistanceToTargetAttributeID, // 0x14
|
|
TargetWithinRangeAttributeID, // 0x15
|
|
WeaponRangeAttributeID, // 0x16
|
|
PipPositionAttributeID, // 0x17
|
|
PipColorAttributeID, // 0x18
|
|
PipExtendedRangeAttributeID, // 0x19
|
|
EstimatedReadyTimeAttributeID, // 0x1A
|
|
RearFiringAttributeID, // 0x1B
|
|
WeaponStateAttributeID, // 0x1C (binary table end)
|
|
NextAttributeID // 0x1D (the Emitter family starts here)
|
|
};
|
|
|
|
static const IndexEntry AttributePointers[];
|
|
static AttributeIndexSet AttributeIndex;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Test Class Support
|
|
//
|
|
public:
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Construction and Destruction
|
|
//
|
|
public:
|
|
typedef MechWeapon__SubsystemResource SubsystemResource;
|
|
|
|
MechWeapon(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
|
|
~MechWeapon();
|
|
|
|
static int
|
|
CreateStreamedSubsystem(
|
|
ResourceFile *resource_file,
|
|
NotationFile *model_file,
|
|
const char *model_name,
|
|
const char *subsystem_name,
|
|
SubsystemResource *subsystem_resource,
|
|
NotationFile *subsystem_file,
|
|
const ResourceDirectories *directories,
|
|
int passes = 1
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Weapon interface
|
|
//
|
|
public:
|
|
virtual void
|
|
FireWeapon();
|
|
|
|
void
|
|
SendDamage(
|
|
Entity *target,
|
|
Damage &damage
|
|
);
|
|
|
|
//
|
|
// View-fire gating (the look-state commit re-arms these): a weapon
|
|
// mounted on a back gun port (rearFiring) fires only into the LOOK-BACK
|
|
// view; the rest fire only in the forward view.
|
|
//
|
|
Logical
|
|
IsRearFiring() const { Check(this); return rearFiring; }
|
|
Logical
|
|
GetViewFireEnable() const { Check(this); return viewFireEnable; }
|
|
void
|
|
SetViewFireEnable(Logical enable){ Check(this); viewFireEnable = enable; }
|
|
|
|
//
|
|
// Fire state machine. The weapon state is carried in the weapon alarm
|
|
// level: 0 = Firing, 2 = Loaded (ready), 3 = Loading, 4 = the
|
|
// trigger-during-load blip. CheckFireEdge is the rising-edge detector
|
|
// on fireImpulse (binary @004b9608): TriggerState carries the raw
|
|
// ControlsButton INT bit-copied by the streamed direct mapping, so the
|
|
// compare works on the BIT PATTERNS as signed ints (sign-correct for
|
|
// the button ints AND genuine floats), reproducing the binary's x87
|
|
// semantics. ComputeOutputVoltage (@004b9c9c) is the recharge-dial
|
|
// writer.
|
|
//
|
|
enum {
|
|
FiringState = 0,
|
|
DryTriggerState = 1,
|
|
LoadedState = 2,
|
|
LoadingState = 3,
|
|
TriggerDuringLoadState = 4,
|
|
JammedState = 5,
|
|
TriggerDuringJamState = 6,
|
|
NoAmmoState = 7,
|
|
WeaponStateCount = 8
|
|
};
|
|
|
|
unsigned
|
|
GetWeaponState() { Check(this); return weaponAlarm.GetLevel(); }
|
|
Logical
|
|
CheckFireEdge();
|
|
void
|
|
ComputeOutputVoltage();
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Local Data
|
|
//
|
|
protected:
|
|
Scalar rechargeRate;
|
|
Scalar weaponRange;
|
|
Scalar damageAmount;
|
|
int damageType;
|
|
Scalar heatCostToFire;
|
|
int targetWithinRange;
|
|
Damage damageData;
|
|
Logical rearFiring;
|
|
Logical viewFireEnable;
|
|
//
|
|
// Fire-machine state (binary @0x31C/0x320/0x324/0x328/0x330/0x350/
|
|
// 0x3A4/0x3E8): the trigger sample pair, the recharge dial, targeting
|
|
// ranges, and the weapon-state alarm.
|
|
//
|
|
Scalar fireImpulse;
|
|
Scalar previousFireImpulse;
|
|
Scalar rechargeLevel;
|
|
Scalar rangeToTarget;
|
|
Scalar effectiveRange;
|
|
int estimatedReadyTime;
|
|
Scalar recoil;
|
|
AlarmIndicator weaponAlarm;
|
|
};
|
|
|
|
#endif
|