Under the documented rig (launch_pod.ps1 with the GL bridge up) the 'couldn't load object' count went to ZERO. .BGF loading was never a reconstruction problem, only a missing bridge. What blocks now is a series of authored AttributeWatchers: BTL4.RES binds them BY NAME and the engine Fails outright on any that does not resolve, so each is a name our subsystems must publish. Five rungs climbed, each run-verified: UnstablePercentage, SpeedEffect (Myomers table), AnimationState + CollisionState/CollisionNormal + ReduceButton (Mech), and the full Torso table (all six authentic names mapped onto existing members). The method that makes this cheap is banked: the shipped binary's string pool carries each class's attribute names CONTIGUOUSLY in ID ORDER after the class name, and in every case so far our member declarations sit in the same order -- which confirms the layout and lets ids be pinned rather than guessed. Intersecting those names with BTL4.RES gives the exact work list. A THIRD miswired SharedData found on the way: Myomers carried Subsystem's tables where it derives from PoweredSubsystem, the same defect as MissileLauncher (5.3.33). Worth a sweep across every subsystem. Staged member TYPES are provisional and documented as such: AttributeWatcherOf reads *(T*)attributePointer and the instantiation comes from the resource, which the string pool does not reveal. Nothing drives them yet, so settle the types with the models that write them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
221 lines
6.6 KiB
C++
221 lines
6.6 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)
|
|
};
|
|
|
|
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);
|
|
|
|
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");
|
|
}
|