From 3a0920acc0258a9f5968917951684e8279f361f4 Mon Sep 17 00:00:00 2001 From: Cyd Date: Tue, 21 Jul 2026 16:02:54 -0500 Subject: [PATCH] BT410 Phase 5.3.3: torso weapon-elevation aim -- completes the control surface Reconstructs Torso::TorsoSimulation (installed as the Torso's per-frame Performance) and wires the torso aim into MechControlsMapper::InterpretControls, so the control surface now covers aiming as well as locomotion. - TORSO: analogElevationAxis/analogTwistAxis + SetAnalog* setters, CurrentElevation()/GetHorizontalEnabled() accessors. TorsoSimulation slews currentElevation += analogElevationAxis*baseElevationRate*dt clamped to the vertical limits, and (if horizontalEnabled) currentTwist by the twist axis clamped to the horizontal limits (authentic torso.cpp core; the skeleton-joint application is deferred with the render wave). - InterpretControls: routes stick pitch (stick_y, squared) into the torso elevation every mode; Std/Vet route stick yaw into the twist. BT_FORCE_ELEV dev hook. Verified: BT_FORCE_ELEV=0.8 -> the elevation slews up and clamps at the authentic verticalLimitTop = 0.349 rad = 20deg; neutral -> 0; zero Fail. Deferred: skeleton-joint application (render wave), HUD free-aim slew, look/eyepoint commit. Co-Authored-By: Claude Fable 5 --- restoration/source410/BT/MECHMPPR.CPP | 35 +++++++++++++ restoration/source410/BT/MECHMPPR.NOTES.md | 23 ++++++--- restoration/source410/BT/TORSO.CPP | 58 ++++++++++++++++++++-- restoration/source410/BT/TORSO.HPP | 20 +++++++- restoration/source410/BT/TORSO.NOTES.md | 34 +++++++++++++ 5 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 restoration/source410/BT/TORSO.NOTES.md diff --git a/restoration/source410/BT/MECHMPPR.CPP b/restoration/source410/BT/MECHMPPR.CPP index 4adb12da..3c98a406 100644 --- a/restoration/source410/BT/MECHMPPR.CPP +++ b/restoration/source410/BT/MECHMPPR.CPP @@ -19,6 +19,10 @@ # include #endif +#if !defined(TORSO_HPP) +# include +#endif + Derivation MechControlsMapper::ClassDerivations( Subsystem::ClassDerivations, @@ -184,8 +188,15 @@ void { stickPosition.x = (Scalar)atof(force_turn); } + const char *force_elev = getenv("BT_FORCE_ELEV"); + if (force_elev != NULL) + { + stickPosition.y = (Scalar)atof(force_elev); + } } + Torso *torso = (Torso *)mech->GetTorsoSubsystem(); + Scalar topSpeed = mech->GetReverseStrideLength(); Scalar walkSpeed = mech->GetWalkStrideLength(); @@ -209,17 +220,39 @@ void { stick_x = -stick_x; } + Scalar stick_y = stickPosition.y * stickPosition.y; + if (stickPosition.y < 0.0f) + { + stick_y = -stick_y; + } Scalar pedal_3 = pedalsPosition * pedalsPosition * pedalsPosition; turnDemand = 0.0f; + // + // Torso aim. Every control mode routes the stick pitch (stick_y) into the + // torso weapon-elevation axis. In Basic the stick yaw is the turn (legs); + // in Standard/Veteran the stick yaw is the torso twist (free aim) and the + // pedals steer. (The HUD free-aim slew + look/eyepoint commit are the + // aiming/camera wave, deferred.) + // if (controlMode == BasicMode) { turnDemand = stick_x; + if (torso != NULL) + { + torso->SetAnalogElevationAxis(stick_y); + torso->SetAnalogTwistAxis(0.0f); + } } else { turnDemand = pedal_3; + if (torso != NULL) + { + torso->SetAnalogElevationAxis(stick_y); + torso->SetAnalogTwistAxis(stick_x); + } } // @@ -248,9 +281,11 @@ void DEBUG_STREAM << "[mppr] thr=" << throttlePosition << " rev=" << reverseThrust << " stickX=" << stickPosition.x + << " stickY=" << stickPosition.y << " mode=" << controlMode << " -> speedDemand=" << speedDemand << " turnDemand=" << turnDemand + << " torsoElev=" << (torso ? torso->CurrentElevation() : 0.0f) << endl << flush; } } diff --git a/restoration/source410/BT/MECHMPPR.NOTES.md b/restoration/source410/BT/MECHMPPR.NOTES.md index f8343151..5a5ef7fe 100644 --- a/restoration/source410/BT/MECHMPPR.NOTES.md +++ b/restoration/source410/BT/MECHMPPR.NOTES.md @@ -35,11 +35,20 @@ drive are exercisable without hardware. `BT_MECH_LOG` prints a 1 Hz `[mppr]` demand trace. Verified: `throttle=1.0` → speedDemand=30; `throttle=0.3,turn=1.0` → the mech walks a circle; neutral → 0. See MECH.NOTES.md (Phase 5.3 inc 2). -## Deferred (the aiming wave) +## Torso aim wired (2026-07-21) -The torso/free-look half of the authentic InterpretControls is not yet -reconstructed: the torso analog axes (`Torso::SetAnalogElevationAxis/ -SetAnalogTwistAxis`), HUD free-aim slew (`HUD::SetFreeAimSlew`), the recenter -command, and the look/eyepoint commit (`BTCommitLookState`). These are the -aiming/camera surface, separate from locomotion; they come with the -Torso/HUD/eyepoint wave. +InterpretControls now routes the stick PITCH (`stick_y`, squared soft response) +into the torso weapon-elevation axis every control mode +(`Torso::SetAnalogElevationAxis`), and in Standard/Veteran the stick YAW into the +torso twist (`SetAnalogTwistAxis`); Basic keeps the stick yaw as the leg turn. +`Torso::TorsoSimulation` slews + clamps the elevation/twist (see TORSO.NOTES.md). +Verified: `BT_FORCE_ELEV=0.8` → torsoElev clamps at the authentic 20° limit. + +## Deferred (the free-aim / camera wave) + +Still not reconstructed: the HUD free-aim slew (`HUD::SetFreeAimSlew`, the +Standard/Veteran torso-disabled path), the torso recenter command, and the +look/eyepoint commit (`BTCommitLookState` — re-aims the eyepoint + re-arms the +per-view weapon fire enables). These are the free-aim/camera surface; they come +with the HUD/eyepoint wave. The skeleton-joint application of the torso angles +is deferred with the render wave (TORSO.NOTES.md). diff --git a/restoration/source410/BT/TORSO.CPP b/restoration/source410/BT/TORSO.CPP index 811b3279..f28fe718 100644 --- a/restoration/source410/BT/TORSO.CPP +++ b/restoration/source410/BT/TORSO.CPP @@ -75,11 +75,22 @@ Torso::Torso( currentTwist = 0.0f; currentElevation = 0.0f; - for (int i = 0; i < 24; ++i) + 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(); } @@ -100,12 +111,51 @@ Logical } // -// Per-frame torso twist / elevation integration. Not yet reconstructed. +//############################################################################# +// 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) + Torso::TorsoSimulation(Scalar time_slice) { - Fail("Torso::TorsoSimulation -- torso.cpp not yet reconstructed"); + 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; + } + + Check_Fpu(); } void diff --git a/restoration/source410/BT/TORSO.HPP b/restoration/source410/BT/TORSO.HPP index 4b8ce4e0..6b373d73 100644 --- a/restoration/source410/BT/TORSO.HPP +++ b/restoration/source410/BT/TORSO.HPP @@ -68,7 +68,21 @@ Logical TestInstance() const; Scalar - CurrentTwist() const { return currentTwist; } + CurrentTwist() const { Check(this); return currentTwist; } + Scalar + CurrentElevation() const { Check(this); return currentElevation; } + Logical + GetHorizontalEnabled() const{ Check(this); return horizontalEnabled; } + + // + // Analog aim inputs (written by MechControlsMapper::InterpretControls; + // consumed by TorsoSimulation to slew the twist/elevation each frame). + // + void + SetAnalogElevationAxis(Scalar axis) { Check(this); analogElevationAxis = axis; } + void + SetAnalogTwistAxis(Scalar axis) { Check(this); analogTwistAxis = axis; } + void TorsoSimulation(Scalar time_slice); void @@ -107,11 +121,13 @@ void *horizontalShadowJointNode; Scalar currentTwist; Scalar currentElevation; + Scalar analogElevationAxis; + Scalar analogTwistAxis; // // Twist/elevation dynamics accumulators advanced by TorsoSimulation. // Reserved until the per-frame sim is reconstructed (phase 5). // - Scalar dynamicsState[24]; + Scalar dynamicsState[22]; }; #endif diff --git a/restoration/source410/BT/TORSO.NOTES.md b/restoration/source410/BT/TORSO.NOTES.md new file mode 100644 index 00000000..f86e2d9b --- /dev/null +++ b/restoration/source410/BT/TORSO.NOTES.md @@ -0,0 +1,34 @@ +# TORSO.CPP / .HPP — reconstruction notes + +`Torso` (: PowerWatcher) drives torso twist (horizontal) and weapon elevation +(vertical). Tuning rates/limits stream from the resource +(`horizontal/verticalRotationPerSecond`, `horizontal/verticalLimit*`, +`torsoHorizontalEnabled`). + +## Reconstructed + +- Ctor: streams the base rates (deg→rad) + limits + `horizontalEnabled`, primes + `currentTwist`/`currentElevation`/analog axes to 0, and installs + `TorsoSimulation` as the per-frame Performance (the replicant copy is + console-driven via `TorsoCopySimulation`, still staged). +- `analogElevationAxis` / `analogTwistAxis` members + `SetAnalogElevationAxis` / + `SetAnalogTwistAxis` setters (written by `MechControlsMapper::InterpretControls`). +- `CurrentTwist()` / `CurrentElevation()` / `GetHorizontalEnabled()` accessors. +- `TorsoSimulation(Scalar)` — per-frame aim integration (authentic core): + - `currentElevation += analogElevationAxis · baseElevationRate · dt`, clamped + to [verticalLimitBottom, verticalLimitTop]; + - if `horizontalEnabled`: `currentTwist += analogTwistAxis · baseTwistRate · + dt`, clamped to [horizontalLimitLeft, horizontalLimitRight]. + +**VERIFIED** (`BT_MECH_LOG` `[mppr] torsoElev=`, forced-input `BT_FORCE_ELEV`): +stick pitch 0.8 slews the elevation up and clamps at the authentic +`verticalLimitTop` = 0.349 rad = **20°**. Zero Fail. + +## Deferred (skeleton-link + render wave) + +`TorsoSimulation` advances the SCALAR aim state (elevation/twist), which the HUD +reticle / weapon-aim read. APPLYING those angles onto the skeleton — rotating +the `horizontalJointNode` (torso twist) and the elevation joint so the model's +torso/gun barrels visibly aim — is deferred with the skeleton-joint-link + +renderer wave (the joint handles are resolved null for now). `TorsoCopySimulation` +(replicant console-driven aim) also stays staged.