Files
TeslaRel410/restoration/source410/BT/TORSO.CPP
T
CydandClaude Fable 5 3ecd88aaef BT410 5.3.44: read the whole watcher list out of the resource; Torso MotionState
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>
2026-07-28 01:25:40 -05:00

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");
}