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
|
|
@ -0,0 +1,74 @@
|
|||
# Combat live-gate corrections pseudocode
|
||||
|
||||
Sources: Sept 2013 EoR named retail client and ACE server source.
|
||||
|
||||
- `ClientCombatSystem::HandleAttackDoneEvent` (`0x0056C500`)
|
||||
- `gmCombatUI::RecvNotice_SetPowerbarLevel` (`0x004CC0E0`)
|
||||
- `CPhysicsObj::MoveOrTeleport` (`0x00516330`)
|
||||
- `CameraSet::Rotate` (`0x00458310`)
|
||||
- ACE `Player.OnAttackDone`, `Player_Melee.cs`
|
||||
- ACE `WeenieError.YouChargedTooFar`, `Player_Move.cs`
|
||||
|
||||
## Attack completion versus visible errors
|
||||
|
||||
```text
|
||||
HandleAttackDoneEvent(sequence, error):
|
||||
consume error as combat-controller state
|
||||
decide whether repeat may continue or the attack aborts
|
||||
do not write an error line to chat
|
||||
|
||||
ACE OnAttackDone(final sequence):
|
||||
send AttackDone(ActionCancelled) to reset the client power meter
|
||||
if the player must see a failure:
|
||||
send a separate WeenieError event
|
||||
```
|
||||
|
||||
Therefore `AttackDone(ActionCancelled)` is silent. A separate
|
||||
`YouChargedTooFar` (`0x003D`) remains visible and is formatted by the ordinary
|
||||
WeenieError path. ACE emits it when the charge exceeds 15 metres; target
|
||||
selection itself is not range-limited by retail.
|
||||
|
||||
## Power meter direction
|
||||
|
||||
```text
|
||||
RecvNotice_SetPowerbarLevel(level):
|
||||
find nested meter 0x10000050
|
||||
set meter scalar attribute 0x69 to level
|
||||
|
||||
authored meter direction = 1
|
||||
visible fill = rightmost (width * clamp(level)) pixels
|
||||
```
|
||||
|
||||
The red meter grows from the Power label at the right toward Speed at the
|
||||
left. The green desired-power thumb remains an independent scrollbar child.
|
||||
Clipping the rightmost portion must retain the full tiled image's UV offset.
|
||||
|
||||
## Persistent death motion
|
||||
|
||||
```text
|
||||
on UpdatePosition(position, velocity):
|
||||
update physics pose and velocity
|
||||
do not derive an interpreted motion command from velocity
|
||||
|
||||
on UpdateMotion(Dead):
|
||||
apply the persistent Dead motion cycle through the motion interpreter
|
||||
```
|
||||
|
||||
A corpse legitimately sends zero velocity. Turning that velocity into Ready
|
||||
overrides the server-authored Dead cycle and makes the creature stand again.
|
||||
Retail keeps position/velocity transport separate from interpreted motion.
|
||||
|
||||
## Keep in View orbit
|
||||
|
||||
See `2026-07-11-combat-target-camera-pseudocode.md`. The corrective detail is:
|
||||
|
||||
```text
|
||||
targetHeadingFrame = frame looking from player pivot toward target point
|
||||
viewerOffset.xy = the independently rotatable camera boom offset
|
||||
eye = pivot + targetHeadingFrame.transform(viewerOffset)
|
||||
forward = normalize(pivot - eye) // LOOK_AT_PIVOT
|
||||
```
|
||||
|
||||
Tracking changes the frame that transforms `viewerOffset`; it does not reset
|
||||
or discard the offset. Manual camera orbit therefore remains usable while
|
||||
Keep in View is active.
|
||||
|
|
@ -36,6 +36,10 @@ CameraSet.TrackTarget(targetId):
|
|||
|
||||
SetTargetForOffset(viewerOffset), while targeting:
|
||||
camera.targetStatus = LOOK_AT_OBJECT | LOOK_AT_PIVOT
|
||||
|
||||
CameraSet.Rotate(angle), including while targeting:
|
||||
viewerOffset.xy = rotate(viewerOffset.xy, angle)
|
||||
SetTargetForOffset(viewerOffset)
|
||||
```
|
||||
|
||||
## Per-frame pose
|
||||
|
|
@ -60,14 +64,17 @@ 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.
|
||||
The viewer offset remains independently rotatable: manual camera orbit rotates
|
||||
that offset inside the target-facing frame rather than being discarded or
|
||||
snapped back to zero.
|
||||
|
||||
## 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.
|
||||
- `RetailChaseCamera.ComputeDesiredPose` ports the heading-frame transform and
|
||||
preserves the viewer-offset yaw while tracking.
|
||||
- The diagnostic legacy `ChaseCamera` remains intentionally non-retail under
|
||||
existing divergence row TS-19; the production retail camera owns this behavior.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue