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:
parent
927fa7881a
commit
33cc9aa16a
5 changed files with 159 additions and 14 deletions
|
|
@ -497,7 +497,7 @@ behavior. Estimated 17–26 days focused work, 3–5 weeks calendar.
|
|||
- **Wave 4.4e implemented — exact missile ammo number (live gate pending).** Pure Core reproduces retail's thrown-weapon-vs-separate-ammo resolution over the ordered player equipment list and its zero-to-one count normalization. Relevant equipment/stack events update authored missile indicator `0x10000194` with the DAT font. Warning-free Release build and 4,754-pass / 5-skip suite are green; AP-101 is retired.
|
||||
- **M2 held-object parenting shipped and live-gated 2026-07-11.** The combat toggle now ports `GetDefaultCombatMode` over ordered equipped contents, so a bow requests Missile instead of the old hardcoded Melee. CreateObject preserves parent/placement/timestamp fields, `0xF749` ParentEvent is handled, and `EquippedChildRenderController` renders the weapon as a separate child composed from the animated hand part + holding frame + child placement frame. Live gate passed: bow selected missile stance, rendered in-hand, followed animation, unequipped cleanly, and melee remained correct. App Release builds with zero warnings; the full 4,765-pass / 5-skip suite is green. AP-111 is retired; research: `docs/research/2026-07-11-combat-default-and-parent-event-pseudocode.md`.
|
||||
- **M2 local attack receive funnel implemented 2026-07-11; live gate pending.** Retail `ExecuteAttack` only sends the request; ACE chooses the concrete melee/missile action and returns it in a non-autonomous mt-0 `UpdateMotion`. The local branch now runs that state through the same constructor-defaulted `MoveToInterpretedState` funnel and 15-bit action-stamp gate as remotes, then applies sticky/long-jump tails. The old local-only direct `Commands[]` replay is deleted. Shared conversion lives in `InboundInterpretedMotionFactory`; research: `docs/research/2026-07-11-local-combat-motion-pseudocode.md`.
|
||||
- **M2 basic retail combat bar implemented 2026-07-11; corrective live visual gate pending.** Production now mounts authored `gmCombatUI` LayoutDesc `0x21000073`, shows it only for Melee/Missile, binds authored high/medium/low buttons and desired-power slider, and routes mouse plus keyboard through one `CombatAttackController`. The corrective pass ports local.dat StringInfo labels, `gmCombatUI::PostInit` runtime option captions, interactive `UIOption_Checkbox` controls, and structural horizontal-scrollbar track/thumb roles. Matching retail x86 recovered exact 1.0-second normal and 0.8-second dual-wield power-up times; the same constants retire the guessed jump charge. Keybinding schema v3 migrates attack actions from one-shot Press to transition-emitting Hold. Research: `docs/research/2026-07-11-retail-combat-bar-pseudocode.md`; AP-24/AP-95 retired, AP-110 narrowed, AP-112 records the remaining advanced/Recklessness and command-interpreter seams.
|
||||
- **M2 basic retail combat bar implemented 2026-07-11; corrective live visual gate pending.** Production now mounts authored `gmCombatUI` LayoutDesc `0x21000073`, shows it only for Melee/Missile, binds authored high/medium/low buttons and desired-power slider, and routes mouse plus keyboard through one `CombatAttackController`. The corrective pass ports local.dat StringInfo labels, `gmCombatUI::PostInit` runtime option captions, interactive `UIOption_Checkbox` controls, structural horizontal-scrollbar track/thumb roles, and `ClientCombatSystem::UpdateTargetTracking` so Keep in View rotates the retail chase-camera boom around the player toward the selected attack target. Matching retail x86 recovered exact 1.0-second normal and 0.8-second dual-wield power-up times; the same constants retire the guessed jump charge. Keybinding schema v3 migrates attack actions from one-shot Press to transition-emitting Hold. Research: `docs/research/2026-07-11-retail-combat-bar-pseudocode.md`, `docs/research/2026-07-11-combat-target-camera-pseudocode.md`; AP-24/AP-95 retired, AP-110 narrowed, AP-112 records the remaining advanced/Recklessness and command-interpreter seams.
|
||||
- **✓ SHIPPED — Character window** (`LayoutDesc 0x2100002E`, `CharacterStatController`, 2026-06-26, same branch). **Visually user-confirmed 2026-06-26 — Attributes tab reads as retail.** Three tabs, header (name/heritage/PK), large-gold level number (dat font, `largeDatFont` 18px), "Total Experience (XP):" + "XP for next level:" captions, 9-row attribute list (icons + right-aligned values + Health/Stamina/Mana vitals), click-to-select (top/bottom selection bars + footer State-B "{Attr}: {value}" / "Experience To Raise: Infinity!" + affordability-gated raise triangles), centered footer. User noted "still needs some polish for later" — deferred to Issue #158.
|
||||
- **✓ SHIPPED — D.5.4 — Client object/item data model (foundation).** Shipped 2026-06-18 (`b506f53`..`a33e897`, 11 commits). Renamed `ItemRepository`→`ClientObjectTable` / `ItemInstance`→`ClientObject`; broadened the table to hold EVERY server object (retail `weenie_object_table` shape). `CreateObject` is now the canonical merge-upsert (`ClientObjectTable.Ingest`, retail `SetWeenieDesc` semantics) via a new Core.Net `ObjectTableWiring` (off GameWindow); `DeleteObject` evicts; `PlayerDescription` is a membership manifest (`RecordMembership`); live container-membership index (`GetContents`, retail `object_inventory_table`). `_liveEntityInfoByGuid` retired (selection/describe resolve from the one table). Root fix: the old enrich-existing-only `EnrichItem` dropped `CreateObject`s for items with no `PlayerDescription` stub — live-Coldeve 4/6 hotbar slots blank; items are now created, not dropped. **Crux resolved:** retail is TWO tables (`object_table` + `weenie_object_table`), NOT one — acdream's `WorldEntity` (3D system) + `ClientObjectTable` (data/UI) split was already architecturally faithful; the fix was the ingestion path, not a table unification. 2671 tests green.
|
||||
- **Roadmap correction (2026-07-10):** the completion order is now the architecture-first campaign in `docs/superpowers/plans/2026-07-10-retail-ui-fidelity-completion.md`. Retail `gmToolbarUI` is object-only: preserve `ShortCutData.index_`, `objectID_`, and `spellID_`, but do not invent spell glyphs on this bar. `PlayerModule::favorite_spells_[8]` feeds separate spell bars.
|
||||
|
|
|
|||
77
docs/research/2026-07-11-combat-target-camera-pseudocode.md
Normal file
77
docs/research/2026-07-11-combat-target-camera-pseudocode.md
Normal 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue