Files
TeslaRel410/restoration/source410/BT/TORSO.NOTES.md
T
CydandClaude Fable 5 ea99e8987f BT410 5.3.114: the replicant torso aims -- TorsoCopySimulation + ComputeTargetTwist, decomp-verified, two donor drifts corrected
The damaged-copy twist path (@004b65f8 + @004b6510), reconstructed from the
raw decomp rather than the BT411 donor -- which drifted twice: its ease aged
by lastUpdate (+0x14) where the binary reads lastPerformance (+0x10), and it
calls the joint-write helper from the copy sim where 1995 does not (port-era
addition, dropped). The extrapolator predicts targetTwist = twistAtUpdate +
twistRate * elapsed on two time bases (settled = this frame's window, slewing
= the command window), and the copy sim snaps when settled or eases by the
remaining-time form dt/((stamp - now) + dt) -- landing exactly when the clock
reaches the command stamp. The decomp's DAT_0052140c divide is just
Time::operator- inlined; no hand conversion existed.

Members carved from the dynamicsState reserve (16->12): targetTwist @0x218,
twistAtUpdate @0x21C, twistRate @0x238, lastUpdateTime @0x254. The ctor now
registers the copy Performance on replicants (PTR @00510c1c); [T2] the gate
mirrors the binary's simulationFlags 0xC/0x100 pair with the instance test,
same as the whole watcher family, until the stream builders that seed those
bits are reconstructed. Feeders (Read/WriteUpdateRecord) stay staged --
zero-init eases a copy to centre, correct-by-vacuity in single-pod.

Stubs: 16 across 10 files. Regression: clean mission soak on the rig
(no faults, wheel turning, pacing steady).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 07:55:14 -05:00

94 lines
5.1 KiB
Markdown

# 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.
## Skeleton-joint binding (2026-07-21)
The twist joints are now RESOLVED and BOUND: the ctor calls
`owner->ResolveJoint(torsoHorizontalJoint / torsoHorizontalShadowJoint)` (the
skeleton is live — see MECH.NOTES.md), stores them as `Joint*`, and
`TorsoSimulation` pushes `currentTwist` onto `horizontalJointNode` via
`Joint::SetRotation` (hinge → `Radian`; ball → `EulerAngles` yaw).
The bring-up TEST.EGG mech has a FIXED torso (`horizJoint=''`, `enabled=0`), so
its twist path is inert — correctly guarded (null joint → no apply, no crash). A
torso-twist mech drives the joint. Verified headlessly; the VISUAL rotation
needs the renderer.
## Elevation does NOT drive a gun joint (corrected 2026-07-21)
Checked BT411 before reconstructing a "gun-elevation joint": no such joint
binding exists anywhere in the authentic engine. `currentElevation` instead
composes into `Mech::eyepointRotation` (the cockpit-eye / weapon-boresight
pitch) — see MECH.NOTES.md "PHASE 5.3 INCREMENT 5". `TorsoSimulation` only
needed to keep advancing the scalar state, which it already did; the missing
piece was the CONSUMER (`Mech::Simulate`'s eyepoint composition), now
reconstructed and verified (`torsoElev` == `eyePitch` every frame).
## TorsoCopySimulation + ComputeTargetTwist (2026-08-04, 5.3.114)
The replicant (damaged-copy) twist path is real, verified line-by-line against
the raw decomp (part_013.c):
- `ComputeTargetTwist` @004b6510 (232B): two time bases — settled uses
`lastPerformance - lastUpdate` (the engine `Simulation` fields at +0x10/+0x14),
slewing (a copy whose command stamp `lastUpdateTime` @0x254 is ahead of the
clock) uses `lastUpdateTime - lastUpdate`. `targetTwist = twistAtUpdate +
twistRate * elapsed`, clamped (left = upper, right = lower). Returns the
slewing flag. The decomp's `DAT_0052140c` divide is `Time::operator-`
(ticks / SystemClock::ticksPerSecond) inlined — NOT a hand-written
MsPerSecond conversion.
- `TorsoCopySimulation` @004b65f8 (188B): settled → snap to target; slewing →
`Lerp(current, target, dt / ((lastUpdateTime - lastPerformance) + dt))` — the
remaining-time ease that lands exactly when the clock reaches the command
stamp. Then the same clamp pair applied to `targetTwist` again.
**Two BT411 donor drifts corrected against the decomp**: the donor's ease aged
by `lastUpdate` (+0x14) where the binary reads `lastPerformance` (+0x10); and
the donor calls the joint-write helper (@004b67ec) from the copy sim — the
binary does not (port-era addition; our copy sim leaves joints to the master
path exactly as 1995 shipped).
Members carved from `dynamicsState[16]` → `[12]`: `targetTwist` @0x218,
`twistAtUpdate` @0x21C, `twistRate` @0x238, `lastUpdateTime` @0x254 (`Time`,
init `0L` — plain `0` is ambiguous between the long/float assignment operators
under BC4.52). Ctor now registers the copy Performance on replicants
(binary PTR @00510c1c). [T2] The registration gate mirrors the binary's
`(owner->simulationFlags & 0xC) == 0 && (flags & 0x100) != 0` with the
instance test, consistent with the whole watcher family, until the mech
stream builders (which seed those flag bits) are reconstructed.
**Staged feeders**: `Read/WriteUpdateRecord` (the census remainder in this TU)
stamp `twistAtUpdate`/`twistRate`/`lastUpdateTime` from console updates.
Zero-init means a copy eases to centre — correct-by-vacuity in single-pod,
inert until MP replication lands.
## Deferred
- HUD free-aim slew, the look-button state machine (`BTCommitLookState` /
`gBTLookPitch`/`gBTLookYaw` — composes with elevation into the full
eyepoint) — still staged.
- `Torso::Read/WriteUpdateRecord` — the copy sim's update feeders (see above).