Files
TeslaRel410/restoration/source410/BT/MECHWEAP.HPP
T
CydandClaude Fable 5 8c777e1e22 BT410 5.3.115: the damage hub consolidates -- MESSMGR's three runtime bodies, a dead 1995 feature recorded, and two more donor drifts caught
SubsystemMessageManager reconstructed from the raw decomp with the wire
format pinned by the engine's own parser (TakeDamageStreamMessageHandler:
count, then type/amount/subsystemID per record -- the chain KEY carries the
damage amount, which is why AddDamageMessage keys its plugs by it).
AddDamageMessage @0049b6d8: first hit of the frame wins the common record.
ConsolidateAndSendDamage @0049b784: one DynamicMessage(0x13, 0x34) at the
hit entity, the firing weapon's explosion resource bundled per record
(binary reads roster[id]+0x3e4 blind; [T1] guarded here), DeletePlugs
teardown, commons reset. CreateWeaponExplosions @0049baa0 under its
AUTHENTIC surviving-header signature (the donor's 'SendQueuedExplosions'
rename was drift): per queued resource an Explosion::MakeMessage --
MakeMessageID 3, ExplosionClassID 0x31 (our VDATA enum ordinal matches the
binary exactly), flags 0x100, identity-rotation Origin at the impact point
-- posted to the Registry at CreationEventPriority, staggered 0.1s apart.

The 1995 archaeology: the binary computes a terrain-hit flag from a
Derivation at 0x4e6f54 (unresolved BSS class) and passes it to a parameter
THE SHIPPED BODY NEVER READS; terrainHitExplosionID is resourced by the CSS
and consumed nowhere. A declared, streamed, abandoned feature -- shipped
anyway. We pass False [T3]; behavior is byte-identical.

Ctor corrections vs our stub: weaponExplosions is UNIQUE-keyed (binary
chain ctor flag 1), the Performance registers, resource fields copy from
the stream. MechWeapon grows a public ExplosionResourceIDOf() accessor.
The 0x160-byte engine helper at +0xE0 stays staged [T3]; the CSS stays in
the authoring-family batch. No feeders call AddDamageMessage yet -- the
consolidator idles empty per frame, soak-verified live (no faults, wheel
turning).

Stubs: 13 across 10 files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 08:30:06 -05:00

281 lines
9.4 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 const HandlerEntry MessageHandlerEntries[];
static MessageHandlerSet MessageHandlers;
//
// The weapon-group config buttons (binary ids 9/10, chained after
// the PoweredSubsystem generator panel 4-8).
//
enum {
ConfigureMappablesMessageID = PoweredSubsystem::NextMessageID, // 9
ChooseButtonMessageID, // 10
NextMessageID // 11
};
void
ConfigureMappablesMessageHandler(ReceiverDataMessageOf<int> *message);
void
ChooseButtonMessageHandler(ReceiverDataMessageOf<int> *message);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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 = PoweredSubsystem::NextAttributeID, // 0x0F
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;
//
// The projectile/explosion GameModel this weapon spawns (binary
// @0x3e4) -- read by SubsystemMessageManager's consolidator to
// bundle the firing weapon's explosion with the damage it caused.
//
ResourceDescription::ResourceID
ExplosionResourceIDOf()
{ Check(this); return explosionResourceID; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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();
virtual void
ComputeOutputVoltage(); // vtable slot 17; the Emitter overrides
// with its charge-voltage form
//
// Targeting: the owner mech's target slot gates the Loaded->Firing
// transition (no target = the denial blip, no shot); UpdateTargeting
// (binary @004b9bdc) refreshes rangeToTarget / targetWithinRange from
// the target's position each frame.
//
Logical
HasActiveTarget();
Logical
UpdateTargeting();
//
// Respawn restore: base heal + the fire machine back to a fresh
// Loading cycle (charge/recoil/trigger cleared; jams and the NoAmmo
// roach-motel release -- the bins restock in their own DeathReset).
//
virtual void
DeathReset(Logical full_reset);
//
// The muzzle world position (binary @004b9948): the MOUNT segment's
// world frame -- rounds and beams leave FROM THE GUN, following the
// torso twist. Falls back to the mech origin when the mount
// segment doesn't resolve.
//
void
GetMuzzlePoint(Point3D &point);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Local Data
//
protected:
Scalar rechargeRate;
Scalar weaponRange;
Scalar damageAmount;
int damageType;
Scalar heatCostToFire;
ResourceDescription::ResourceID
explosionResourceID; // binary @0x3e4 -- the projectile /
// explosion GameModel this weapon spawns
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