fix #211: index login-equipped items under player

Project PlayerDescription equipment through the same contained-by-wielder ownership and ordered contents index as live WieldObject updates. Preserve equip masks and priorities so retail GetObjectAtLocation selects Missile for an already-equipped crossbow instead of sending a server-rejected Melee request.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-13 10:40:29 +02:00
parent e74efc5c06
commit ab98cda26b
6 changed files with 150 additions and 12 deletions

View file

@ -46,9 +46,41 @@ Copy this block when adding a new issue:
---
## #211 — Login-equipped missile weapon incorrectly requests melee combat
**Status:** IN-PROGRESS — implementation complete 2026-07-13, pending user gate
**Severity:** HIGH
**Component:** inventory projection / combat mode
**Description:** After relaunching with a bow or crossbow already equipped,
the combat button and grave key briefly selected Melee before ACE restored
NonCombat, so the character could not enter combat.
**Root cause:** PlayerDescription recorded equipped entries with their equip
mask but no player ownership/container index. Live WieldObject updates did
index the same item under the player. `ToggleLiveCombatMode` reads the player's
ordered contents for retail `GetObjectAtLocation`, so it missed login equipment,
defaulted to Melee, and sent a mode incompatible with ACE's equipped missile
weapon. ACE correctly returned authoritative NonCombat.
**Resolution:** PlayerDescription equipment now uses the same
contained-by-wielder projection as live WieldObject while preserving its wire
order, equip mask, and layering priority. The production combat planner now
selects Missile for the login-equipped crossbow. The connected gate completed
NonCombat → Missile → NonCombat → Missile, including a Jump press, without a
server rejection.
**Research:** `docs/research/2026-07-11-combat-default-and-parent-event-pseudocode.md`
**Acceptance:** Relaunch with the crossbow already equipped. The combat button
and grave key enter Missile mode, the combat bar appears, returning to peace
hides it, and Jump followed by combat still works without a crash.
---
## #210 — Mouse-up crashes when a UI callback changes pointer capture
**Status:** IN-PROGRESS — implementation complete 2026-07-13, pending live gate
**Status:** DONE — 2026-07-13, user confirmed the crash no longer occurs (`e74efc5c`)
**Severity:** HIGH
**Component:** retained UI / input lifecycle

View file

@ -60,6 +60,29 @@ GetDefaultCombatMode(showError):
returns the first entry whose location intersects the requested mask (and whose
priority intersects the requested priority when that priority is non-zero).
### Login projection invariant
PlayerDescription carries loose inventory and equipped objects as two ordered
lists. They must feed one player-owned location lookup after parsing:
```text
OnPlayerDescription(player, inventory, equipped):
replace player-owned loose contents with inventory, preserving wire order
for each equipped entry in wire order:
record item as owned by player
record equipped location and layering priority
append it to the same ordered player-owned lookup
```
This is the login equivalent of a live `WieldObject`, which also models the
item as contained by its wielder with a non-zero equipped location. Keeping
login equipment outside that lookup makes `GetDefaultCombatMode` miss an
already-equipped bow/crossbow and request Melee; ACE then correctly rejects the
mode because a missile weapon is equipped. ACE's
`Player.HandleActionChangeCombatMode_Inner` performs that rejection, while
holtburger independently retains PlayerDescription's `equipped_objects` list
for its suggested-combat-mode decision.
## ParentEvent wire and freshness
```text