BTL4.RES stores each watcher as a (SUBSYSTEM, ATTRIBUTE) string pair, so the complete list can be extracted directly instead of discovering one name per 6-minute run. Banked the extraction method and the full normalised table. Sixth rung climbed: Torso/MotionState (staged member, appended at the end of Torso's own range so no downstream id moves). LocalVelocity and LocalAcceleration turn out to need nothing -- the engine's Mover already publishes them. Also banked, and deliberately NOT acted on: ReportLeak and ConfigureActivePress are base-class attributes inside the pinned range, and chasing them turned up what looks like the authentic attribute layout. The shipped pool gives MechSubsystem 1, HeatableSubsystem 3, HeatSink 6, PoweredSubsystem 5 -- which counted from Subsystem::NextAttributeID=2 lands MechWeapon's real ids on the binary-pinned 0x12 with EXACTLY ONE pad, where our tree needs three. That arithmetic is strong evidence for the original layout, and reconciling to it would replace three guessed pads with the real table. But it moves ids underneath a cockpit currently verified at 98.9% pixel-identical, so it wants a deliberate session with the A/B rig open rather than a bulk edit at the end of a long one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
223 lines
6.7 KiB
C++
223 lines
6.7 KiB
C++
//===========================================================================//
|
|
// File: torso.cpp //
|
|
// Project: BattleTech Brick: Mech subsystems //
|
|
// Contents: Torso -- torso twist / weapon elevation //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include <bt.hpp>
|
|
#pragma hdrstop
|
|
|
|
#if !defined(TORSO_HPP)
|
|
# include <torso.hpp>
|
|
#endif
|
|
|
|
#if !defined(MECH_HPP)
|
|
# include <mech.hpp>
|
|
#endif
|
|
|
|
#if !defined(JOINT_HPP)
|
|
# include <joint.hpp>
|
|
#endif
|
|
|
|
Derivation
|
|
Torso::ClassDerivations(
|
|
PowerWatcher::ClassDerivations,
|
|
"Torso"
|
|
);
|
|
|
|
const Torso::IndexEntry
|
|
Torso::AttributePointers[]=
|
|
{
|
|
ATTRIBUTE_ENTRY(Torso, RotationOfTorsoVertical, currentElevation),
|
|
ATTRIBUTE_ENTRY(Torso, RotationOfTorsoHorizontal, currentTwist),
|
|
ATTRIBUTE_ENTRY(Torso, HorizontalLimitRight, horizontalLimitRight),
|
|
ATTRIBUTE_ENTRY(Torso, HorizontalLimitLeft, horizontalLimitLeft),
|
|
ATTRIBUTE_ENTRY(Torso, SpeedOfTorsoVertical, baseElevationRate),
|
|
ATTRIBUTE_ENTRY(Torso, SpeedOfTorsoHorizontal, baseTwistRate),
|
|
ATTRIBUTE_ENTRY(Torso, MotionState, motionState)
|
|
};
|
|
|
|
Torso::AttributeIndexSet
|
|
Torso::AttributeIndex(
|
|
ELEMENTS(Torso::AttributePointers),
|
|
Torso::AttributePointers,
|
|
Subsystem::AttributeIndex
|
|
);
|
|
|
|
Torso::SharedData
|
|
Torso::DefaultData(
|
|
Torso::ClassDerivations,
|
|
Subsystem::MessageHandlers,
|
|
Torso::AttributeIndex,
|
|
Subsystem::StateCount
|
|
);
|
|
|
|
Torso::Torso(
|
|
Mech *owner,
|
|
int subsystem_ID,
|
|
SubsystemResource *r,
|
|
SharedData &shared_data
|
|
):
|
|
PowerWatcher(owner, subsystem_ID, r, shared_data)
|
|
{
|
|
Check(owner);
|
|
Check_Pointer(r);
|
|
|
|
motionState = 0; // staged: no gait state feed yet
|
|
isDamagedCopy = (owner->GetInstance() == Entity::ReplicantInstance);
|
|
|
|
statusFlags = 0;
|
|
buttonAccelerationPerSecond = r->buttonAccelerationPerSecond;
|
|
buttonAccelerationStart = r->buttonAccelerationStartValue;
|
|
|
|
baseTwistRate = r->horizontalRotationPerSecond * RAD_PER_DEG;
|
|
baseElevationRate = r->verticalRotationPerSecond * RAD_PER_DEG;
|
|
horizontalLimitRight= r->horizontalLimitRight * RAD_PER_DEG;
|
|
horizontalLimitLeft = r->horizontalLimitLeft * RAD_PER_DEG;
|
|
verticalLimitTop = r->verticalLimitTop * RAD_PER_DEG;
|
|
verticalLimitBottom = r->verticalLimitBottom * RAD_PER_DEG;
|
|
|
|
twistCenterHigh = verticalLimitTop;
|
|
twistCenterLow = verticalLimitBottom;
|
|
elevationCenter = verticalLimitTop;
|
|
elevationHalfBottom = verticalLimitBottom * 0.5f;
|
|
|
|
buttonRampActive = 0;
|
|
buttonRamp = 0.0f;
|
|
horizontalEnabled = r->torsoHorizontalEnabled;
|
|
|
|
//
|
|
// Resolve the named torso-twist skeleton joints (twist body + shadow) from
|
|
// the mech skeleton (now live). A mech with a fixed torso, or one whose
|
|
// joint name is absent from the skeleton, resolves NULL and simply never
|
|
// twists.
|
|
//
|
|
horizontalJointNode = owner->ResolveJoint(r->torsoHorizontalJoint);
|
|
horizontalShadowJointNode = owner->ResolveJoint(r->torsoHorizontalShadowJoint);
|
|
|
|
if (getenv("BT_MECH_LOG"))
|
|
{
|
|
DEBUG_STREAM << "[torso] horizJoint '" << r->torsoHorizontalJoint
|
|
<< "' -> " << (void *)horizontalJointNode;
|
|
if (horizontalJointNode != NULL)
|
|
{
|
|
DEBUG_STREAM << " type=" << (int)horizontalJointNode->GetJointType();
|
|
}
|
|
DEBUG_STREAM << " enabled=" << (int)horizontalEnabled << endl << flush;
|
|
}
|
|
|
|
currentTwist = 0.0f;
|
|
currentElevation = 0.0f;
|
|
analogElevationAxis = 0.0f;
|
|
analogTwistAxis = 0.0f;
|
|
for (int i = 0; i < 22; ++i)
|
|
{
|
|
dynamicsState[i] = 0.0f;
|
|
}
|
|
|
|
//
|
|
// Install the per-frame twist/elevation Performance (the replicant copy is
|
|
// driven by console updates via TorsoCopySimulation instead, still staged).
|
|
//
|
|
if (owner->GetInstance() != Entity::ReplicantInstance)
|
|
{
|
|
SetPerformance(&Torso::TorsoSimulation);
|
|
}
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
Torso::~Torso()
|
|
{
|
|
}
|
|
|
|
Logical
|
|
Torso::TestClass(Mech &)
|
|
{
|
|
return True;
|
|
}
|
|
|
|
Logical
|
|
Torso::TestInstance() const
|
|
{
|
|
return IsDerivedFrom(ClassDerivations);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// TorsoSimulation -- per-frame torso twist / weapon-elevation integration.
|
|
//
|
|
// Slews the current elevation/twist toward the analog aim axes (written by
|
|
// MechControlsMapper::InterpretControls) at the resource base rates, clamped to
|
|
// the resource limits. Authentic core (torso.cpp @004b6xxx): current += axis *
|
|
// baseRate * dt. APPLYING the resolved angles onto the skeleton torso/gun
|
|
// joints (horizontalJointNode / the elevation joint) is deferred with the
|
|
// skeleton-link + render wave; here we advance the scalar aim state (read by the
|
|
// HUD reticle / weapon aim and, once wired, the joints).
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Torso::TorsoSimulation(Scalar time_slice)
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
// Elevation (weapon pitch): slew toward the analog axis, clamp to limits.
|
|
//
|
|
currentElevation += analogElevationAxis * baseElevationRate * time_slice;
|
|
{
|
|
Scalar lo = (verticalLimitBottom < verticalLimitTop)
|
|
? verticalLimitBottom : verticalLimitTop;
|
|
Scalar hi = (verticalLimitBottom < verticalLimitTop)
|
|
? verticalLimitTop : verticalLimitBottom;
|
|
if (currentElevation < lo) currentElevation = lo;
|
|
if (currentElevation > hi) currentElevation = hi;
|
|
}
|
|
|
|
//
|
|
// Twist (horizontal torso rotation): only mechs with an enabled torso joint.
|
|
//
|
|
if (horizontalEnabled)
|
|
{
|
|
currentTwist += analogTwistAxis * baseTwistRate * time_slice;
|
|
Scalar lo = (horizontalLimitLeft < horizontalLimitRight)
|
|
? horizontalLimitLeft : horizontalLimitRight;
|
|
Scalar hi = (horizontalLimitLeft < horizontalLimitRight)
|
|
? horizontalLimitRight : horizontalLimitLeft;
|
|
if (currentTwist < lo) currentTwist = lo;
|
|
if (currentTwist > hi) currentTwist = hi;
|
|
|
|
//
|
|
// Push the twist onto the skeleton torso joint so the upper body rotates
|
|
// on the model. Hinge joints take the scalar angle about their axis;
|
|
// ball joints take it as the yaw component.
|
|
//
|
|
if (horizontalJointNode != NULL)
|
|
{
|
|
Joint::JointType jt = horizontalJointNode->GetJointType();
|
|
if (jt == Joint::HingeXJointType
|
|
|| jt == Joint::HingeYJointType
|
|
|| jt == Joint::HingeZJointType)
|
|
{
|
|
horizontalJointNode->SetRotation(Radian(currentTwist));
|
|
}
|
|
else if (jt == Joint::BallJointType)
|
|
{
|
|
horizontalJointNode->SetRotation(EulerAngles(0.0f, currentTwist, 0.0f));
|
|
}
|
|
}
|
|
}
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
Torso::TorsoCopySimulation(Scalar)
|
|
{
|
|
Fail("Torso::TorsoCopySimulation -- torso.cpp not yet reconstructed");
|
|
}
|