Files
TeslaRel410/restoration/source410/BT/MECH.HPP
T
CydandClaude Fable 5 d4f0aef6e1 BT410 Phase 5.3.17: the destruction cascade -- zone deaths DESTROY things
Mech::DamageZone::TakeDamage is the full binary cascade (@0049c690): LOD
artifact router with same-attacker clustering (@0049c40c, hysteresis 0.33),
artifact parent level = mean of children, Energy-hit generator shorts
through the crit plug binding (novice-exempt), weighted CriticalHit
(@0049ccc4), zone-death allotment push (SendSubsystemDamage @0049c9a8) and
the segment-table destruction descent (RecurseSegmentTable @0049cad4 --
SIBS + DESCEND via the engine EntitySegment iterators).

Supporting bricks: Mech's OWN handler table with the TakeDamage override
(latches lastInflictingID @0x43c; gyro feed staged; cylinder table
deferred); friend class Mech__DamageZone (authentic); subsystem private
zones ARMED (structureReference + armorByFacing[5] normalized -- crits are
measurable); ApplyDamageAndMeasure; ForceCriticalFailure sets
DestroyedState so the weapon FSMs' GetSimulationState()==1 hard gate went
live; Generator::ForceShort + PoweredSubsystem::ForceShortRecovery.

Fight-verified (mutual BT_SPAWN_ENEMY + BT_FORCE_ZONE=8 concentrated fire):
arm zone to 1.0 -> sibling searchlight zone dies (Searchlight2/ThermalSight
crits destroyed, HUD degrading) -> DESCEND kills the gun zone -> PPC_2 +
ERMLaser_2 + Condenser6 DESTROYED and FALL SILENT (0 shots after death;
undamaged PPC_1 keeps firing); vital-zone hit = MECH KILL; PPC hit shorted
GeneratorD. This art has zero artifact zones (redirect=0 across all 20 --
router verified dormant-correct). Smoke + novice regressions clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 11:13:28 -05:00

456 lines
14 KiB
C++

//===========================================================================//
// File: mech.hpp //
// Project: BattleTech Brick: Entity Manager //
// Contents: Implementation details for the Mech entity //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#if !defined(MECH_HPP)
# define MECH_HPP
# if !defined(JMOVER_HPP)
# include <jmover.hpp>
# endif
# if !defined(RETICLE_HPP)
# include <reticle.hpp>
# endif
# if !defined(ALARM_HPP)
# include <alarm.hpp>
# endif
# if !defined(STATE_HPP)
# include <state.hpp>
# endif
# if !defined(CHAIN_HPP)
# include <chain.hpp>
# endif
# if !defined(AVERAGE_HPP)
# include <average.hpp>
# endif
# if !defined(CSTR_HPP)
# include <cstr.hpp>
# endif
# if !defined(SEQCTL_HPP)
# include <seqctl.hpp>
# endif
# if !defined(NAMEFILT_HPP)
# include <namefilt.hpp>
# endif
# if !defined(ROTATION_HPP)
# include <rotation.hpp>
# endif
//##################### Forward Class Declarations #######################
class Mech;
class Subsystem;
class SubsystemMessageManager;
class ControlsMapping;
class PlatformTool;
class MechControlsMapper;
class Mech__DamageZone;
class Joint;
//###########################################################################
//######################### Mech Model Resource #########################
//###########################################################################
struct Mech__ModelResource:
public JointedMover::ModelResource
{
char animationPrefix[4];
Scalar maxAcceleration;
Scalar superStopAcceleration;
Scalar throttleAdjustment;
Scalar lookLeftAngle;
Scalar lookRightAngle;
Scalar lookFrontAngle;
Scalar lookBackAngle;
Scalar walkingTurnRate;
Scalar runningTurnRate;
Scalar reticleX;
Scalar reticleY;
Scalar relativeMechValue;
int deathEffectResourceID;
Scalar deathSplashDamage;
Scalar deathSplashRadius;
Scalar maxUnstableAcceleration;
Scalar unstableAccelerationEffect;
Scalar unstableGunTheEngineEffect;
Scalar unstableSuperStopEffect;
Scalar unstableHighVelocityEffect;
Scalar unstableStopedTurnEffect;
Scalar updatePositionDiffrence;
Scalar updateTurnVelocityDiffrence;
Scalar updateTurnDegreeDiffrence;
Scalar timeDelay;
Vector3D cameraOffset;
char shadowJointName[20];
};
//###########################################################################
//########################## Mech Make Message ##########################
//###########################################################################
class Mech__MakeMessage:
public JointedMover::MakeMessage
{
public:
char resourceNameA[20];
char resourceNameB[20];
char resourceNameC[20];
Mech__MakeMessage(
Receiver::MessageID message_ID,
size_t length,
const EntityID &entity_ID,
Entity::ClassID class_ID,
const EntityID &owner_ID,
ResourceDescription::ResourceID resource_ID,
LWord instance_flags,
const Origin &origin,
const Motion &velocity,
const Motion &acceleration,
const char *badge,
const char *color,
const char *patch
):
JointedMover::MakeMessage(
message_ID, length, entity_ID, class_ID, owner_ID,
resource_ID, instance_flags, origin, velocity, acceleration
)
{
Str_Copy(resourceNameA, badge, sizeof(resourceNameA));
Str_Copy(resourceNameB, color, sizeof(resourceNameB));
Str_Copy(resourceNameC, patch, sizeof(resourceNameC));
}
};
//###########################################################################
//############################## Mech ###############################
//###########################################################################
class Mech:
public JointedMover
{
//
// The per-zone damage code walks the roster / segment table / alarms
// directly (the 1995 arrangement, mirrored by the reconstruction).
//
friend class Mech__DamageZone;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
public:
static Derivation ClassDerivations;
static SharedData DefaultData;
static const HandlerEntry
MessageHandlerEntries[];
static MessageHandlerSet
MessageHandlers;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Class Support
//
public:
static Logical
TestClass(Mech &);
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
typedef Mech__ModelResource ModelResource;
typedef Mech__MakeMessage MakeMessage;
typedef Mech__DamageZone DamageZone;
static Mech*
Make(MakeMessage *creation_message);
Mech(
MakeMessage *creation_message,
SharedData &shared_data = DefaultData
);
~Mech();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// App interface
//
public:
void
SetMappingSubsystem(Subsystem *mapper);
//
// Resolve a skeleton joint by name (the shared resolver the subsystems
// use to bind their animated joints -- Torso twist, etc.):
// GetSegment(name) -> segment jointIndex -> JointSubsystem::GetJoint.
//
Joint*
ResolveJoint(const char *joint_name);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Per-frame simulation (the mech's body Performance; installed by the ctor
// and dispatched each frame from Simulation::PerformAndWatch).
//
public:
typedef void
(Mech::*Performance)(Scalar time_slice);
void
SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
void
Simulate(Scalar time_slice);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Resource creation
//
public:
static void
CreateMakeMessage(
MakeMessage *creation_message,
NotationFile *model_file,
const ResourceDirectories *directories
);
static ResourceDescription::ResourceID
CreateModelResource(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories,
ModelResource *model = 0
);
static ResourceDescription::ResourceID
CreateSubsystemStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
);
static ResourceDescription::ResourceID
CreateDamageZoneStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
);
static ResourceDescription::ResourceID
CreateSkeletonStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
);
static ResourceDescription::ResourceID
CreateExplosionTableStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
);
typedef Logical (*FindNameFunction)(
const char *control_name, ControlsMapping *mapping);
static ResourceDescription::ResourceID
CreateControlMappingStream(
const char *mapping_name,
NotationFile *mapping_file,
FindNameFunction find_name,
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories,
PlatformTool *current_tool
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Subsystem roster accessors (the roster itself -- subsystemArray /
// subsystemCount -- lives in the base Entity)
//
public:
Subsystem*
GetGyroSubsystem() { Check(this); return gyroSubsystem; }
Subsystem*
GetTorsoSubsystem() { Check(this); return sinkSourceSubsystem; }
Subsystem*
GetHudSubsystem() { Check(this); return hudSubsystem; }
Subsystem*
GetSensorSubsystem() { Check(this); return sensorSubsystem; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Locomotion parameters (read by MechControlsMapper::InterpretControls to
// shape the demands, and by the drive in Simulate). reverseStrideLength is
// the top/run cycle speed the throttle scales (the naming is the 1995
// field's; LoadLocomotionClips measures it from the run clips), walkStride
// Length the walk speed. Turn rates are radians/sec.
//
public:
Scalar GetReverseStrideLength() const { Check(this); return reverseStrideLength; }
Scalar GetWalkStrideLength() const { Check(this); return walkStrideLength; }
Scalar GetForwardThrottleScale() const { Check(this); return forwardThrottleScale; }
void SetForwardThrottleScale(Scalar s){ Check(this); forwardThrottleScale = s; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Eyepoint / aim-ray composition. The pilot's torso-elevation aim (stick
// pitch) does NOT tilt any skeleton joint on this mech family -- it pitches
// the COCKPIT EYE and the weapon boresight (pixel-calibrated in the BT411
// reverse-engineering: "pitch does not work" turned out to mean nothing
// consumed Torso's currentElevation, not that a joint was un-animated).
// Composed each frame in Simulate; DPLEyeRenderable / the aim ray read it.
//
public:
const EulerAngles&
GetEyepointRotation() const { Check(this); return eyepointRotation; }
//
// The current target (the binary's mech target slot @0x388): read by
// the weapons' HasActiveTarget / UpdateTargeting and the fire path.
// The authentic writer is the reticle targeting step (mech4, the
// render wave); the dev harness sets it directly.
//
Entity*
GetTargetEntity() const { Check(this); return targetEntity; }
void
SetTargetEntity(Entity *target) { Check(this); targetEntity = target; }
//
// Damage entry (overrides the Entity handler): latches the attacker
// (mech+0x43c, read by the zone LOD router) and feeds the gyro
// cockpit bounce before chaining to the base zone routing. The
// cylinder unaimed-hit resolver (type-0x1d table) is a later wave.
//
void
TakeDamageMessageHandler(TakeDamageMessage *message);
//
// Damage-side death flag: the body graphic alarm (statusAlarm,
// binary @0x714) at level >= 9 = the death/fall state.
//
Logical
IsMechDestroyed() { Check(this); return statusAlarm.GetLevel() >= 9; }
//
// Look-state commit (called by the controls mapper on a look-button
// state change): re-aim the eyepoint from the model's authored look
// angles. look_state = MechControlsMapper::LookState.
//
void
CommitLookState(int look_state);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Local Data
//
protected:
//
// Cached subsystem back-pointers (also held in the base roster).
//
Subsystem *sensorSubsystem;
Subsystem *gyroSubsystem;
Subsystem *sinkSourceSubsystem; // the real Torso
Subsystem *hudSubsystem;
SubsystemMessageManager *messageManager;
int weaponCount;
//
// Capability sub-rosters (Socket views onto the subsystem roster;
// populated per-frame -- phase 5).
//
ChainOf<Subsystem*> controllableSubsystems;
ChainOf<Subsystem*> watchedSubsystems;
ChainOf<Subsystem*> heatableSubsystems;
ChainOf<Subsystem*> weaponRoster;
ChainOf<Subsystem*> damageableSubsystems;
//
// Embedded status / animation / naming state.
//
NameFilter mechNameFilter;
AlarmIndicator masterAlarm;
AlarmIndicator heatAlarm;
AlarmIndicator stabilityAlarm;
AlarmIndicator statusAlarm;
Reticle targetReticle;
StateIndicator animationState;
StateIndicator replicantAnimationState;
StateIndicator collisionState;
SequenceController legAnimation;
SequenceController bodyAnimation;
AverageOf<Scalar> telemetryFilter[5];
CString resourceNameA;
CString resourceNameB;
CString resourceNameC;
//
// Locomotion state (Phase 5.3). Turn rates in rad/s, speeds/strides in
// world-units/s. reverseStrideLength = top (run) speed; walkStrideLength
// = walk speed; reverseSpeedMax = the low-speed turn-rate gate; forward
// ThrottleScale multiplies the forward demand; bodyTargetSpeed = the
// demanded speed; currentBodySpeed = the accel-tracked actual speed.
//
Scalar walkingTurnRate;
Scalar runningTurnRate;
Scalar reverseStrideLength;
Scalar walkStrideLength;
Scalar reverseSpeedMax;
Scalar forwardThrottleScale;
Scalar maxBodyAcceleration;
Scalar bodyTargetSpeed;
Scalar currentBodySpeed;
//
// Composed each frame in Simulate: the look-state eye component
// (lookPitch/lookYaw, set by CommitLookState from the authored look
// angles) plus the Torso elevation.
//
EulerAngles eyepointRotation;
Scalar lookPitch;
Scalar lookYaw;
Entity *targetEntity;
EntityID lastInflictingID; // binary mech+0x43c -- last
// attacker (zone LOD router)
//
// The model's authored look-view angles (rad; deg in the resource).
//
Scalar lookLeftAngle;
Scalar lookRightAngle;
Scalar lookFrontAngle;
Scalar lookBackAngle;
//
// Remaining per-frame targeting / animation state, advanced by the
// mech2/mech3/mech4 simulation. Reserved until that path is
// reconstructed with named fields.
//
int reservedState[199];
};
#endif