THE MODEL RESOURCE NAMED THESE BLOCKS. The ctor loads (part_012.c:15798) tie the master perf's anonymous offsets to field names our Mech__ModelResource already carried, and the names confirm the arithmetic as surely as the arithmetic confirms the names: rec+0x48 -> +0x5bc superStopAcceleration rec+0x80 -> +0x784 maxUnstableAcceleration rec+0x84 -> +0x788 unstableAccelerationEffect rec+0x88 -> +0x78c unstableGunTheEngineEffect rec+0x94 -> +0x798 unstableStopedTurnEffect THE SUPER STOP (@0x4aa353): hauling the throttle negative while the mech still rolls forward is a hard brake, not a reverse. The edge swaps the gait's acceleration rate to the authored superStopAcceleration, marks the update, and throws ONE random-signed lurch through both gyro channels; while it holds above a walk it repeats a pitch kick every 0.4s -- the shudder of a hundred tons standing on its heels. A chassis authoring -1.1 disables the system entirely (the sentinel must survive the model read unguarded). THE INSTABILITY MODEL (tail @0x4aab8e): three weighted terms -- filtered acceleration (squared), gunning the engine, and turning on the spot -- clamped to 1 into unstablePercentage, which was ALREADY a published cockpit attribute holding a staged zero, and republished to the gyro (whose tip/sway machinery @004b275c consumes it; that's the next gyro brick). THE TELEMETRY RINGS (@0x4aafba): the binary's five rings ARE the engine's AverageOf<Scalar>, and our telemetryFilter[5] has been sized 15 and unfed since the layout wave. FUN_0043ae47 is CalculateOlympicAverage -- a judge-style trimmed mean, min and max discarded. Two oddities kept verbatim and flagged: the vel.y ring is never reduced, and the derived acceleration's components come from a mongrel basis (only its length is consumed). CORRECTION to 5.3.122: 'realMaxSpeed' was a duplicate member for mech+0x7a0, which our tree already carried as runSpeedMax; merged. And the +0x7a4 'computed my own cap' flag is set by the ctor's MYOMERS sweep -- a mech with myomers broadcasts its cap, one without adopts the streamed value. Soaks (pod_render_superstop / pod_render_telem, BT_SUPERSTOP_SOAK cycling +0.8 for 6s then -0.5 for 4s): the super stop engages on the correct edge (speed 35.6, demand -28.0) and releases cleanly, repeatedly; the rings fill and the instability sweeps its whole range to the 1.0 clamp; zero faults. The new gauge immediately earned its keep as a diagnostic -- it pins high while walking because the mech demands 35.9 u/s and the reconstructed gait delivers 7.0, which is now a measurable open question rather than an invisible one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
213 lines
6.8 KiB
C++
213 lines
6.8 KiB
C++
//===========================================================================//
|
|
// File: gyro.hpp //
|
|
// Project: BattleTech Brick: Mech subsystems //
|
|
// Contents: Gyroscope -- the eye/body stabilisation subsystem //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#if !defined(GYRO_HPP)
|
|
# define GYRO_HPP
|
|
|
|
# if !defined(POWERSUB_HPP)
|
|
# include <powersub.hpp>
|
|
# endif
|
|
|
|
//##################### Forward Class Declarations #######################
|
|
class Mech;
|
|
|
|
//###########################################################################
|
|
//################### Gyroscope Model Resource #########################
|
|
//###########################################################################
|
|
|
|
//
|
|
// One per-damage-type response row: how hard a hit of that type kicks
|
|
// the four gyro channels.
|
|
//
|
|
struct Gyroscope__DamageResponse
|
|
{
|
|
Scalar trans;
|
|
Scalar pitchRoll;
|
|
Scalar yaw;
|
|
Scalar vibration;
|
|
};
|
|
|
|
struct Gyroscope__SubsystemResource:
|
|
public PowerWatcher::SubsystemResource
|
|
{
|
|
Scalar reservedF4;
|
|
Scalar exageration;
|
|
Scalar maxAnimationNoise;
|
|
Scalar minAnimationNoise;
|
|
Scalar rotationPerSecond;
|
|
Scalar percentageOnNormal;
|
|
Scalar percentageOnDestruction;
|
|
Scalar percentageOnDegradation;
|
|
Scalar percentageOnFailure;
|
|
Vector3D springConstant;
|
|
Vector3D dampingConstant;
|
|
Vector3D posSpring;
|
|
Vector3D negSpring;
|
|
Vector3D rotationSpringConstant;
|
|
Vector3D rotationDampingConstant;
|
|
Vector3D rotationPosSpring;
|
|
Vector3D rotationNegSpring;
|
|
char eyeJoint[32];
|
|
char mechJoint[32];
|
|
Scalar collisionDamageMultiplier;
|
|
Scalar ballisticDamageMultiplier;
|
|
Scalar explosiveDamageMultiplier;
|
|
Scalar laserDamageMultiplier;
|
|
Scalar energyDamageMultiplier;
|
|
|
|
//
|
|
// The five response quads follow the multipliers in the stream
|
|
// (record size 0x21C -- binary-verified layout).
|
|
//
|
|
Gyroscope__DamageResponse collisionDamageResponse;
|
|
Gyroscope__DamageResponse ballisticDamageResponse;
|
|
Gyroscope__DamageResponse explosiveDamageResponse;
|
|
Gyroscope__DamageResponse laserDamageResponse;
|
|
Gyroscope__DamageResponse energyDamageResponse;
|
|
};
|
|
|
|
//###########################################################################
|
|
//############################## Gyroscope #############################
|
|
//###########################################################################
|
|
//
|
|
// The gyro drives the cockpit eye joint (view stabilisation) and the body
|
|
// lean. The tuning constants are read from the resource; the eye/body
|
|
// dynamics state (springs, forces, velocities, work matrices) is advanced by
|
|
// the per-frame GyroscopeSimulation and held in dynamicsState until that
|
|
// (staged) method is reconstructed with the named fields.
|
|
//
|
|
class Gyroscope:
|
|
public PowerWatcher
|
|
{
|
|
public:
|
|
static Derivation ClassDerivations;
|
|
static SharedData DefaultData;
|
|
|
|
typedef void
|
|
(Gyroscope::*Performance)(Scalar time_slice);
|
|
void
|
|
SetPerformance(Performance performance)
|
|
{
|
|
Check(this);
|
|
activePerformance = (Simulation::Performance)performance;
|
|
}
|
|
|
|
static Logical
|
|
TestClass(Mech &);
|
|
Logical
|
|
TestInstance() const;
|
|
void
|
|
ResetToInitialState();
|
|
void
|
|
GyroscopeSimulation(Scalar time_slice);
|
|
|
|
//
|
|
// The two integrators (called by the sim) and the two joint writes
|
|
// (called by the MECH master performance tail, after the gait --
|
|
// NOT by the sim; binary @0x4aaf74/83).
|
|
//
|
|
void
|
|
IntegrateEyeJoint(Scalar time_slice);
|
|
void
|
|
IntegrateBody(Scalar time_slice);
|
|
void
|
|
WriteEyeJoint();
|
|
void
|
|
WriteMechJoint();
|
|
|
|
//
|
|
// The hit-bounce feeds. ApplyDamageResponse is the damage hub's
|
|
// fan-out (every non-collision hit shakes the cockpit); the three
|
|
// primitive kicks are also fed directly by the collision CRUNCH.
|
|
//
|
|
void
|
|
ApplyDamageResponse(const Damage &damage);
|
|
void
|
|
ApplyDamageImpulse(Scalar x, Scalar y, Scalar z, Scalar magnitude);
|
|
void
|
|
ApplyDamageTorque(Scalar x, Scalar y, Scalar z, Scalar magnitude);
|
|
void
|
|
ApplyVerticalImpulse(Scalar pitch, Scalar magnitude);
|
|
|
|
public:
|
|
typedef Gyroscope__SubsystemResource SubsystemResource;
|
|
|
|
Gyroscope(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *subsystem_resource,
|
|
SharedData &shared_data = DefaultData
|
|
);
|
|
~Gyroscope();
|
|
|
|
protected:
|
|
Scalar exageration;
|
|
Scalar maxAnimationNoise;
|
|
Scalar minAnimationNoise;
|
|
Scalar rotationPerSecond;
|
|
Scalar percentageOnNormal;
|
|
Scalar percentageOnDestruction;
|
|
Scalar percentageOnDegradation;
|
|
Scalar percentageOnFailure;
|
|
Vector3D springConstant;
|
|
Vector3D dampingConstant;
|
|
Vector3D posSpring;
|
|
Vector3D negSpring;
|
|
Vector3D rotationSpringConstant;
|
|
Vector3D rotationDampingConstant;
|
|
Vector3D rotationPosSpring;
|
|
Vector3D rotationNegSpring;
|
|
Scalar damageMultiplier[5];
|
|
Gyroscope__DamageResponse
|
|
damageResponse[5];
|
|
|
|
//
|
|
// The eye TRANSLATION spring state (the steady eye offset + hit
|
|
// bounce) and the body ROTATION spring state (the hull tip). The
|
|
// clamps are COPIES of the spring pairs, taken at ctor time (the
|
|
// body pair scaled by 2).
|
|
//
|
|
Vector3D eyePosition, eyeVelocity, eyeForce, eyeWork;
|
|
Vector3D eyeClampUpper, eyeClampLower;
|
|
Vector3D bodyOrientation, bodyVelocity, bodyForce, bodyWork;
|
|
Vector3D bodyClampUpper, bodyClampLower;
|
|
|
|
//
|
|
// Sway (the animation-noise wander the sim slews between the
|
|
// powered/impaired percentages) and the placement scratch the
|
|
// damage fan-out rotates hit directions through.
|
|
//
|
|
//
|
|
// The mech's instability, republished here every master frame
|
|
// (binary gyro+0x3a8, written by the master perf tail). The gyro's
|
|
// own tip/sway machinery (@004b275c) reads it summed with +0x3b0
|
|
// against the +0x3bc threshold -- that consumer is a later brick;
|
|
// the publish lands now so the value is where the binary puts it.
|
|
//
|
|
public:
|
|
Scalar mechInstability;
|
|
|
|
protected:
|
|
Scalar swayAngle, swayBias, swayVelocity;
|
|
int swayActive;
|
|
Vector3D placeRot, placePos;
|
|
Scalar placeQuat[4];
|
|
Scalar workMatrix[12];
|
|
Scalar spare0;
|
|
Scalar *externalPitchPtr; // -> the torso twist (yaw-only hit
|
|
// frame); self-points at spare0
|
|
// until a torso binds it
|
|
Vector3D vibrationDirection; // the fixed up axis
|
|
Joint *eyeJointNode;
|
|
Joint *mechJointNode;
|
|
};
|
|
|
|
#endif
|