fix(combat): track targets with retail camera

Port ClientCombatSystem's Keep in View consumer through CameraSet's pivot-to-target boom heading, including the transformed half-metre target offset and melee/missile validity gates. Preserve the existing stateful chase damping and collision architecture, with conformance coverage and named-retail pseudocode.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-11 20:36:58 +02:00
parent 927fa7881a
commit 33cc9aa16a
5 changed files with 159 additions and 14 deletions

View file

@ -0,0 +1,77 @@
# Retail combat target camera pseudocode
Source: Sept 2013 EoR named retail client.
- `ClientCombatSystem::UpdateTargetTracking` (`0x0056A950`)
- `ClientCombatSystem::TrackTarget` (`0x0056AED0`)
- `CameraSet::TrackTarget` (`0x00458280`)
- `CameraSet::SetTargetForOffset` (`0x004576E0`)
- `CameraManager::SetTargetObject` (`0x00456380`)
- `CameraManager::UpdateCamera` (`0x00456660`)
## Option consumer
```text
UpdateTargetTracking():
if ViewCombatTarget is enabled
and combat mode is Melee or Missile
and current attack target is valid:
camera.TrackTarget(attackTarget)
else:
camera.TrackTarget(0)
```
## Camera state
```text
CameraSet.TrackTarget(targetId):
if targetId != 0:
targeting = true
camera.SetTargetObject(targetId, wholeObject)
camera.targetOffset = (0, 0, 0.5 metres)
else:
targeting = false
SetTargetForOffset(camera.viewerOffset)
SetTargetForOffset(viewerOffset), while targeting:
camera.targetStatus = LOOK_AT_OBJECT | LOOK_AT_PIVOT
```
## Per-frame pose
```text
pivot = player part position + transformed pivotOffset
direction = zero
if targetStatus contains LOOK_AT_OBJECT and target object exists:
targetPoint = target.position localToGlobal targetOffset
direction += normalize(targetPoint - pivot)
headingFrame = frameWhoseForwardIs(direction)
desiredEye = pivot + headingFrame.transformVector(viewerOffset)
if targetStatus contains LOOK_AT_PIVOT:
desiredForward = normalize(pivot - desiredEye)
damp current viewer toward (desiredEye, desiredForward)
```
The target therefore changes the direction of the boom around the player; it
does not replace the player as the boom's pivot. `LOOK_AT_PIVOT` keeps the
player centered while the target-facing boom keeps the combat target in view.
## Port mapping
- `GameWindow.GetCombatCameraTargetPoint` applies the option/mode/valid-target
gates and transforms the target-local 0.5 metre Z offset.
- `RetailChaseCamera.ComputeTrackedHeading` ports the pivot-to-target direction.
- Existing `RetailChaseCamera` boom construction and damping consume that
heading unchanged.
- The diagnostic legacy `ChaseCamera` remains intentionally non-retail under
existing divergence row TS-19; the production retail camera owns this behavior.
The ACE and ACME reference trees are not present in this worktree (only the
in-tree WorldBuilder reference is available), so no interpretation-aid cross
check was possible. The named retail functions above are complete for this
behavior and remain the ground truth.