Gyro: damage fan-out FUN_004b2980 -- the cockpit hit-BOUNCE is live (task #56)

Re-disassembled the unexported gap 0x4b2980-0x4b2d8b byte-exact (capstone over
section_dump.txt) and reconstructed Gyroscope::ApplyDamageResponse:
- zero-damage + Collision(type 0) no-op; hit direction = Damage::damageForce
  or a RANDOM horizontal fallback when ~zero (per-component sign roll then
  value roll -- binary-legal until senders fill damageForce)
- direction rotated by the yaw-only torso-twist frame (placeRot=(0,twist,0)
  -> euler->matrix, the FUN_00408744 raw row-dot reproduced verbatim)
- per-type scaling amount / damageMultiplier[type] * damageResponse[type]
  .{trans,pitchRoll,yaw,vibration}; Explosive alone multiplies burstCount;
  each clamped at 1.3f
- four kicks: impulse(trans, dir), torque(pitchRoll, dir), impulse(vibration,
  vibrationDirection@0x390) and verticalImpulse(yaw, dir)

Layout corrections (byte-verified): gyro+0x390 is ONE Vector3D vibration axis
init (0,1,0) -- was mis-split as scalars animationOffset/Scale/Phase; mech
+0x5c4 is a FLOAT rumble-period countdown (gyroRumbleTimer) -- was mis-typed
int clipLoadGuard.

Call sites wired (binary-gated):
- take-damage hub: mech.cpp TakeDamageMessageHandler, FIRST action (@0x4a0264
  in hub FUN_004a0230) -- an invalid-zone hit still bounces
- crushable-icon crunch: mech4.cpp, torque 0.4 along the bounce delta-v + up
  impulse 0.2 (@4aa81e/@4aa86c)
- firing recoil: projweap.cpp FireWeapon, damage>3 -> impulse (0,0.6,-1.5)
  x damage/16 (@4bc136-4bc19c) via the new Mech::GetGyroSubsystem accessor

DEFERRED (recorded in KB with the byte recipe): the alternate-gait engage
jolt + 0.4s rumble (@4aa158-4aa365) -- its gates are [T3]-flagged and it
mutates the #49/#50-stabilized gait machine.

Verified live: [gyro-dmg] fires per hit with correct type scaling; eyePosition
shows the damped bounce (ramp to ~0.015u, oscillating Y, decay to zero); kill
chain un-regressed; no NaN.

Also recorded in KB: the OFFSET-COCKPIT verification -- Thor's authored
jointeye tranx=+1.13 matches its canopy X-center exactly AND our in-game eye
reproduces it to the hundredth (the placement model is correct per-mech); and
the playable roster is 8 models (strider/raptor/firstrtr/blkjack have assets
but no model resource -- BT_FORCE_MODEL with those names = NULL-resource AV,
cdb-verified, not a code bug).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-11 07:36:25 -05:00
co-authored by Claude Fable 5
parent cb85517ede
commit 946323b696
10 changed files with 283 additions and 25 deletions
+11
View File
@@ -216,6 +216,7 @@ extern Subsystem *CreateGaussRifleSubsystem(Mech *, int, void *); // 0xBCE (WAVE
extern Subsystem *CreateGyroSubsystem(Mech *, int, void *); // 0xBC4 (task #56 -- ctor/integrators byte-exact, ENABLED)
extern void GyroFrameJointWrite(Subsystem *, Scalar, int, int); // task #56 -- mech-performance joint-write dispatch (mech4.cpp)
extern void GyroBindExternalPitch(Subsystem *, Scalar *); // task #56 -- post-stream gyro+0x258 = &torso twist
extern void GyroApplyDamage(Subsystem *, const Damage &); // task #56 -- the @0x4a0264 hit-bounce fan-out
extern Scalar *BTGetTorsoTwistAddr(Subsystem *); // torso.cpp bridge (complete-type TU)
// Post-stream entity glue + cosmetic objects.
@@ -594,6 +595,16 @@ void
<< " table=" << (void*)damageLookupTable
<< " zones=" << damageZoneCount << "\n" << std::flush;
// Binary @0x4a0264-0x4a0300 (hub FUN_004a0230): the cockpit hit-BOUNCE.
// Feed the gyro the raw Damage record FIRST -- before inflictor
// bookkeeping, threat feed and zone resolution (an invalid-zone hit still
// bounces). Sole gate: non-null gyro (mech+0x528). The fan-out no-ops
// CollisionDamageType(0) and damageAmount==0 itself (@4b298c/@4b299e); on
// a replicant the binary only WARNS ("Replicant Mech recieving
// takedamagemessage!", MECH.CPP:986) and proceeds -- no replicant gate.
if (gyroSubsystem != 0)
GyroApplyDamage(gyroSubsystem, message->damageData);
// Maintain the last-attacker bookkeeping (mech[0x43c]): read by the
// DamageZone LOD router (same-attacker redirect reuse, mechdmg.cpp:374)
// and by the damage-band effect orientation. Was declared but never