fix(combat): match retail live attack feedback
Keep AttackDone control statuses out of chat, preserve dead motion across zero-velocity position updates, render the authored power meter from right to left, and retain the rotatable viewer offset during target tracking. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
33cc9aa16a
commit
5276a83087
16 changed files with 231 additions and 67 deletions
|
|
@ -156,7 +156,8 @@ public sealed class RetailChaseCamera : ICamera
|
|||
// CameraSet::TrackTarget 0x00458280 and CameraManager::UpdateCamera
|
||||
// 0x00456826-0x00456915.
|
||||
Vector3 pivotWorld = playerPosition + new Vector3(0f, 0f, PivotHeight);
|
||||
Vector3 heading = ComputeTrackedHeading(pivotWorld, trackedTargetPoint)
|
||||
Vector3? trackedHeading = ComputeTrackedHeading(pivotWorld, trackedTargetPoint);
|
||||
Vector3 heading = trackedHeading
|
||||
?? ComputeHeading(
|
||||
avgVel,
|
||||
playerYaw + YawOffset,
|
||||
|
|
@ -164,15 +165,14 @@ public sealed class RetailChaseCamera : ICamera
|
|||
contactPlaneNormal,
|
||||
CameraDiagnostics.AlignToSlope);
|
||||
|
||||
// 3. Orthonormal heading-frame basis.
|
||||
var (forward, _, up) = BuildBasis(heading);
|
||||
|
||||
// 4. Target pose.
|
||||
float horizontal = Distance * MathF.Cos(Pitch);
|
||||
float vertical = Distance * MathF.Sin(Pitch);
|
||||
// viewer_offset = -horizontal along forward + vertical along up.
|
||||
Vector3 targetEye = pivotWorld + forward * (-horizontal) + up * vertical;
|
||||
Vector3 targetForward = Vector3.Normalize(pivotWorld - targetEye);
|
||||
// 3-4. Target pose. Retail TrackTarget changes the frame that
|
||||
// transforms viewer_offset; it does not replace that offset. CameraSet::Rotate
|
||||
// (0x00458310) therefore continues to orbit viewer_offset.x/y while the
|
||||
// target supplies the frame heading. Without this local rotation, enabling
|
||||
// Keep in View snaps the camera behind the target and disables RMB orbit.
|
||||
float viewerYawOffset = trackedHeading.HasValue ? YawOffset : 0f;
|
||||
(Vector3 targetEye, Vector3 targetForward) = ComputeDesiredPose(
|
||||
pivotWorld, heading, Distance, Pitch, viewerYawOffset);
|
||||
|
||||
// 5. Stateful sought position (#180). Retail CameraManager::UpdateCamera
|
||||
// (0x00456660) interpolates FROM THE CURRENT SWEPT VIEWER toward the
|
||||
|
|
@ -380,6 +380,35 @@ public sealed class RetailChaseCamera : ICamera
|
|||
: Vector3.Normalize(towardTarget);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ports retail's heading-frame transform of <c>viewer_offset</c> in
|
||||
/// CameraManager::UpdateCamera (0x00456660), including the X/Y rotation
|
||||
/// retained by CameraSet::Rotate (0x00458310) while target tracking is active.
|
||||
/// The returned forward always looks back at the player pivot, matching
|
||||
/// LOOK_AT_PIVOT.
|
||||
/// </summary>
|
||||
internal static (Vector3 eye, Vector3 forward) ComputeDesiredPose(
|
||||
Vector3 pivotWorld,
|
||||
Vector3 heading,
|
||||
float distance,
|
||||
float pitch,
|
||||
float viewerYawOffset)
|
||||
{
|
||||
var (frameForward, frameRight, frameUp) = BuildBasis(heading);
|
||||
|
||||
// AC's frame-local +Y points opposite our screen-right basis. Rotating
|
||||
// viewer_offset.x/y by +yaw therefore produces this boom direction.
|
||||
Vector3 boomForward = Vector3.Normalize(
|
||||
frameForward * MathF.Cos(viewerYawOffset)
|
||||
- frameRight * MathF.Sin(viewerYawOffset));
|
||||
|
||||
float horizontal = distance * MathF.Cos(pitch);
|
||||
float vertical = distance * MathF.Sin(pitch);
|
||||
Vector3 eye = pivotWorld - boomForward * horizontal + frameUp * vertical;
|
||||
Vector3 forward = Vector3.Normalize(pivotWorld - eye);
|
||||
return (eye, forward);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build an orthonormal basis with <c>forward = heading</c>. World
|
||||
/// up is <c>(0, 0, 1)</c>; if <c>heading</c> is near-parallel to it
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue