fix(ui): match retail item appraisal semantics
Preserve PublicWeenieDesc hook identity from CreateObject through the item model so hook appraisals suppress sentinel capacities exactly. Use appraisal-only Value and Burden presence, retain AddItemInfo paragraph and authored font-color selection, and port retail lock, page, enchantment, and spell-block formatting. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
bc47bc4917
commit
d3c5e06fdd
21 changed files with 982 additions and 145 deletions
|
|
@ -107,7 +107,21 @@ text out from the top, and replaces the sparse property dump with retail's
|
|||
ordered item-report branches for common weapons, armor, magic and DAT spell
|
||||
descriptions, requirements, capacities, cooldown/special properties, uses,
|
||||
crafting, ratings, rare state, and prose. AP-110 records the remaining
|
||||
specialized/player-dependent/DAT-name/font/object-preview branches explicitly.
|
||||
specialized/player-dependent/DAT-name/creature-font/object-preview branches
|
||||
explicitly.
|
||||
|
||||
The item-format conformance correction then fixed the live Black Phyntos Hive
|
||||
counterexample at its source. CreateObject had walked past
|
||||
`PublicWeenieDesc.HookItemTypes` and `HookType` without retaining them, so the
|
||||
item formatter could not execute retail `ACCWeenieObject::IsHook`. It also
|
||||
fell back from a deliberately incomplete appraisal to public Value/Burden and
|
||||
printed the hook's 255/255 sentinel capacities as ordinary storage. Hook
|
||||
identity now survives the wire/session/object-table path; Value/Burden use
|
||||
only the appraisal profile and display `???`/`Unknown` when absent;
|
||||
`HasHookedItem` suppresses the hook capacity; lock wording and page-count
|
||||
property order match retail; and each report fragment preserves
|
||||
`AddItemInfo`'s line/paragraph flag plus LayoutDesc `0x1B`'s white/green/red
|
||||
font-color indices.
|
||||
|
||||
**Files:** `src/AcDream.Core.Net/Messages/AppraiseInfoParser.cs`;
|
||||
`src/AcDream.App/UI/RetailUiRuntime.cs`;
|
||||
|
|
@ -129,6 +143,9 @@ animated target remains above row chrome but below text; changing selection
|
|||
updates the open window without another magnifier click. Item text begins at
|
||||
the top and assessed melee/missile/armor/magic items show their retail-ordered
|
||||
stats and full DAT spell descriptions.
|
||||
The Black Phyntos Hive specifically reads `Value: ???`, `Burden: Unknown`,
|
||||
then its description after one retail paragraph break, without the bogus
|
||||
255-item/255-container line.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ AP-94..AP-112 for the confirmed retail-UI completion gaps.
|
|||
| ~~AP-107~~ | **RETIRED 2026-07-11 (Wave 3.3 / #197)** — typed `OfferPrimaryClick` returns `NotActive`, `ConsumedSuccess`, or `ConsumedRejected`; every retained item surface plus radar/world offers active target mode before local selection/open/use fallback. Rejections are consumed and cannot drift selection. | `src/AcDream.App/UI/ItemInteractionController.cs`; inventory/paperdoll/toolbar/radar/world call sites | — | — | `UIElement_ItemList::HandleTargetedUseLeftClick @ 0x004E24D0` |
|
||||
| AP-108 | Paperdoll/AutoWield still omit the remaining missile/held restrictions and corrupt-mask branch of full `AutoWieldIsLegal`, dual-wield/off-hand rules, double-click examine/drag from the doll, body-part selection lighting, and retail's synchronous `" - cannot unwield the %s"` failure suffix (the current send seam reports rejection asynchronously). **AutoWear legality retired from this row 2026-07-23:** inventory activation and paperdoll drops now apply the retail clothing-priority/location blocker lookup and exact `"You must remove your %s to wear that"` system notice. **Primary replacement retired 2026-07-14; Aetheria retired 2026-07-13.** | `src/AcDream.App/UI/Layout/PaperdollController.cs`; `src/AcDream.App/UI/AutoWieldController.cs` | Basic equip slots, Aetheria, live doll, AutoWear conflict reporting, and primary weapon/incompatible shield/mismatched ammo blocker sequencing work in peace and war | Remaining illegal/off-hand cases, asynchronous dequip rejection wording, doll examine/drag, and selection lighting still differ functionally | `CPlayerSystem::AutoWieldIsLegal @ 0x0055ED60`; `CPlayerSystem::AutoWearIsLegal @ 0x0055EF40`; `CPlayerSystem::AutoWield @ 0x00560A60`; `gmPaperDollUI @ 0x004A3590..0x004A5F90` |
|
||||
| AP-109 | Character Titles page is inert and live displayed-title/luminance state is absent | `src/AcDream.App/UI/Layout/CharacterStatController.cs`; `CharacterSheetProvider.cs` | Attributes/skills core output is user-accepted | Titles cannot be selected/displayed and level-200 luminance fields are missing | `gmCharacterTitleUI @ 0x0049A610`; `gmStatManagementUI::UpdateExperience @ 0x004F0A70` |
|
||||
| AP-110 | Remaining retained gameplay panels and world HUD are absent: advanced-combat powerbar, residual social/floating chat, quests/map/options/smartbox, vendor/trade/salvage/tinkering, mini-game gameplay, Link Status NAK/retransmission packet-loss averaging, and D.6 nameplates/floaters. Examination has its independent authored floaty layout, inscription transaction, retail creature stat/rating/animated-preview presentation, default selection-follow, and retail-ordered item reports covering weapon/armor/caster modifiers, spell names plus DAT descriptions, requirements, capacities, cooldown/special properties, uses, crafting, rare, and description data. It still lacks item-object preview, player-dependent effective shield projection, DAT display-name resolution for equipment sets and slayer creature types, some expiry/material/portal/PK-specialized description branches, exhaustive character detail regions, and exact appraisal FontInfo-list selection. | `src/AcDream.App/UI/RetailUiRuntime.cs`; `src/AcDream.App/UI/Layout/AppraisalUiController.cs`; `src/AcDream.App/UI/Layout/ItemAppraisalTextFormatter.cs`; `src/AcDream.App/UI/Layout/CreatureAppraisalRows.cs`; `src/AcDream.App/Rendering/CreatureAppraisalPresentation.cs`; `src/AcDream.Core.Net/LinkStatusSnapshot.cs`; D.5/D.6 roadmap | Basic combat, M3 magic/Link/Vitae surfaces, and the core examination request/presentation/inscription/creature-preview/item-report loop cover the active loops; the remaining examination mechanisms require player-state or DAT display-name resolvers and object-preview ownership rather than fabricated content | Uncommon item/character assessments may omit the listed specialized branches and item-object presentation; unresolved equipment-set/slayer values use their numeric identity; enchanted/incomplete appraisal rows use the normal authored font until the exact FontInfo list is bound; other absent panels remain unavailable; real packet loss is displayed as 0.00% instead of retail's moving average | `BasicCreatureExamineUI::Init @ 0x004AB9C0`; `CreatureExamineUI::SetAppraiseInfo @ 0x004B3FF0`; `gmExaminationUI::RecvNotice_SelectionChanged @ 0x004AB3D0`; `AttributeInfoRegion::Update @ 0x004F1D90`; `gmExaminationUI::SetAppraiseInfo @ 0x004ADAE0`; `ItemExamineUI::SetAppraiseInfo @ 0x004B72B0`; `ItemExamineUI::Appraisal_ShowSpecialProperties @ 0x004B0140`; `ItemExamineUI::Appraisal_ShowWeaponAndArmorData @ 0x004B10E0`; `ItemExamineUI::Appraisal_ShowMagicInfo @ 0x004B2E10`; `ItemExamineUI::SetInscription @ 0x004AE2F0`; `CM_Writing::Event_SetInscription @ 0x006A98B0`; `CLinkStatusAverages::GetAveragePacketLoss @ 0x00546610`; LayoutDesc catalog |
|
||||
| AP-110 | Remaining retained gameplay panels and world HUD are absent: advanced-combat powerbar, residual social/floating chat, quests/map/options/smartbox, vendor/trade/salvage/tinkering, mini-game gameplay, Link Status NAK/retransmission packet-loss averaging, and D.6 nameplates/floaters. Examination has its independent authored floaty layout, inscription transaction, retail creature stat/rating/animated-preview presentation, default selection-follow, and retail-ordered item reports covering weapon/armor/caster modifiers, spell names plus DAT descriptions, requirements, capacities, cooldown/special properties, uses, crafting, rare, and description data. Item reports also preserve appraisal-only unknowns, hook/capacity/lock presence rules, paragraph boundaries, and the authored normal/beneficial/detrimental color list. It still lacks item-object preview, player-dependent effective shield projection, DAT display-name resolution for equipment sets and slayer creature types, some expiry/material/portal/PK-specialized description branches, exhaustive character detail regions, and exact creature appraisal FontInfo-list selection. | `src/AcDream.App/UI/RetailUiRuntime.cs`; `src/AcDream.App/UI/Layout/AppraisalUiController.cs`; `src/AcDream.App/UI/Layout/ItemAppraisalTextFormatter.cs`; `src/AcDream.App/UI/Layout/CreatureAppraisalRows.cs`; `src/AcDream.App/Rendering/CreatureAppraisalPresentation.cs`; `src/AcDream.Core.Net/LinkStatusSnapshot.cs`; D.5/D.6 roadmap | Basic combat, M3 magic/Link/Vitae surfaces, and the core examination request/presentation/inscription/creature-preview/item-report loop cover the active loops; the remaining examination mechanisms require player-state or DAT display-name resolvers and object-preview ownership rather than fabricated content | Uncommon item/character assessments may omit the listed specialized branches and item-object presentation; unresolved equipment-set/slayer values use their numeric identity; enchanted/incomplete creature appraisal rows use the normal authored font until the exact FontInfo list is bound; other absent panels remain unavailable; real packet loss is displayed as 0.00% instead of retail's moving average | `BasicCreatureExamineUI::Init @ 0x004AB9C0`; `CreatureExamineUI::SetAppraiseInfo @ 0x004B3FF0`; `gmExaminationUI::RecvNotice_SelectionChanged @ 0x004AB3D0`; `AttributeInfoRegion::Update @ 0x004F1D90`; `gmExaminationUI::SetAppraiseInfo @ 0x004ADAE0`; `ItemExamineUI::SetAppraiseInfo @ 0x004B72B0`; `ItemExamineUI::AddItemInfo @ 0x004AC050`; `ItemExamineUI::Appraisal_ShowCapacity @ 0x004B2680`; `ItemExamineUI::Appraisal_ShowSpecialProperties @ 0x004B0140`; `ItemExamineUI::Appraisal_ShowWeaponAndArmorData @ 0x004B10E0`; `ItemExamineUI::Appraisal_ShowMagicInfo @ 0x004B2E10`; `ItemExamineUI::SetInscription @ 0x004AE2F0`; `CM_Writing::Event_SetInscription @ 0x006A98B0`; `CLinkStatusAverages::GetAveragePacketLoss @ 0x00546610`; LayoutDesc catalog |
|
||||
| ~~AP-111~~ | **RETIRED 2026-07-11 (M2 held-object parenting)** — equipped hand items are no longer omitted from the render world. CreateObject now preserves Placement/Parent/position timestamp bootstrap; live `0xF749` ParentEvent is parsed with retail sequence freshness; a focused render controller resolves `Setup.HoldingLocations`, applies the child's placement frame, and recomposes the separate child entity after every parent animation tick. Pickup retains the weenie's visual metadata for a later wield. | `src/AcDream.Core.Net/Messages/{CreateObject,ParentEvent}.cs`; `src/AcDream.Core/Meshing/EquippedChildAttachment.cs`; `src/AcDream.App/Rendering/EquippedChildRenderController.cs` | — | — | `ClientCombatSystem::GetDefaultCombatMode @ 0x0056B310`; `SmartBox::HandleParentEvent @ 0x004535D0`; `CPhysicsObj::set_parent @ 0x00515A90`; `CPhysicsObj::UpdateChild @ 0x00512D50` |
|
||||
| AP-112 | The basic combat bar ports visibility, height selection, desired-power slider, exact 1.0/0.8-second charge, ready-stance gating, request/release, `MaybeStopCompletely`, server-response queueing, and auto-repeat, but still omits `StartAttackRequest`'s `FinishJump` call and exact trained-Recklessness visibility semantics (IA-20 keeps the dark range as the accepted baseline) | `src/AcDream.App/Combat/CombatAttackController.cs`; `src/AcDream.App/UI/Layout/CombatUiController.cs` | The shared player movement owner now performs retail's server-control-gated full stop and movement report before an attack build; the remaining seams require the jump owner and a distinct Recklessness treatment | Starting an attack while charging a jump may not finish that jump exactly when retail does; trained/untrained Recklessness presentation is identical | `ClientCombatSystem::StartAttackRequest @ 0x0056C040`; `CommandInterpreter::MaybeStopCompletely @ 0x006B3B90`; `gmCombatUI::ListenToElementMessage @ 0x004CC430` |
|
||||
| AP-113 | Invalid lifestone-command arguments display the local text `Usage: /lifestone`; retail definitely emits a local usage/error line but Binary Ninja misidentifies the referenced wide-string address, so its exact wording is not yet recovered | `src/AcDream.UI.Abstractions/Panels/Chat/ChatCommandRouter.cs`; `RetailClientCommandCatalog.cs` | The behavior boundary is exact (handled locally, no chat and no game action); only a low-impact diagnostic sentence differs | `/ls now` can show different wording/color from retail while still refusing the invalid request correctly | `ClientCommunicationSystem::DoLifestone @ 0x0056FC70` |
|
||||
|
|
|
|||
|
|
@ -144,7 +144,11 @@ damage/critical/resistance rating list, places authored row chrome behind the
|
|||
animated preview and text in front, adds the balanced row inset, and follows
|
||||
the current selection automatically while the examination window is visible.
|
||||
Item-object preview, specialized item/character detail regions, and exact
|
||||
appraisal font-state selection remain the narrowed AP-110 residual. Research:
|
||||
creature appraisal font-state selection remain the narrowed AP-110 residual.
|
||||
The item report now retains `PublicWeenieDesc` hook identity, applies
|
||||
appraisal-only Value/Burden unknowns, suppresses mounted-hook sentinel
|
||||
capacities, preserves retail line/paragraph boundaries, and selects the
|
||||
authored white/green/red item font-color entries. Research:
|
||||
[`../research/2026-07-23-retail-appraisal-ui-pseudocode.md`](../research/2026-07-23-retail-appraisal-ui-pseudocode.md).
|
||||
The focused parser/router/request/controller/fixture tests pass, as do the
|
||||
Release solution build with 17 pre-existing tracked test warnings, 3,496 App
|
||||
|
|
@ -172,14 +176,26 @@ ports common weapon damage ranges/speed/range/ammunition, armor protection
|
|||
bands, defense/caster modifiers, workmanship, ratings, wield/use/activation
|
||||
requirements, item XP/capacity/lock/mana/uses/creator/rare data, cooldown and
|
||||
imbued special properties, and both short spell lists and full DAT spell
|
||||
descriptions. AP-110 now names only the remaining specialized,
|
||||
player-dependent, DAT-display-name, font-state, and object-preview gaps.
|
||||
descriptions. The conformance follow-up replaces public-value fallbacks with
|
||||
retail's appraisal presence semantics, restores hook/capacity/lock behavior,
|
||||
and carries each `AddItemInfo` fragment's paragraph and font-color index into
|
||||
the retained text shaper. AP-110 now names only the remaining specialized,
|
||||
player-dependent, DAT-display-name, creature-font-state, and object-preview gaps.
|
||||
Focused conformance fixtures cover the geometry layering plus melee, launcher,
|
||||
armor, spell, and special-property reports. The Release solution build passes
|
||||
with the 17 warnings already tracked by #228, 3,514 App tests / 3 skips, and
|
||||
7,931 complete-solution tests / 5 skips. The connected visual result remains
|
||||
the closeout gate.
|
||||
|
||||
The item-format conformance correction adds literal hook-tail cursor fixtures,
|
||||
wire/session/object-table propagation tests, the exact Black Phyntos Hive
|
||||
report, capacity/page/lock presence cases, structured paragraph checks, and
|
||||
LayoutDesc color-palette/enchantment-style coverage. The isolated Release
|
||||
solution build passes with the same 17 tracked warnings; 3,522 App tests / 3
|
||||
skips and 7,942 complete-solution tests / 5 skips pass while the previously
|
||||
launched client retains the normal Release output lock. The corrected
|
||||
connected item visual remains the closeout gate.
|
||||
|
||||
## Slice 1 — spell-bar overflow arrows
|
||||
|
||||
### Retail oracle
|
||||
|
|
|
|||
|
|
@ -23,6 +23,16 @@ retained examination window.
|
|||
- `Attribute2ndInfoRegion::Update @ 0x004F1E80`
|
||||
- `AppraisalSystem::InqCreatureDisplayName @ 0x005B59E0`
|
||||
- `ItemExamineUI::SetAppraiseInfo @ 0x004B72B0`
|
||||
- `ItemExamineUI::AddItemInfo @ 0x004AC050/0x004ADCA0`
|
||||
- `ItemExamineUI::Appraisal_ShowValueInfo @ 0x004ADEA0`
|
||||
- `ItemExamineUI::Appraisal_ShowBurdenInfo @ 0x004AE180`
|
||||
- `ItemExamineUI::Appraisal_ShowCapacity @ 0x004B2680`
|
||||
- `ItemExamineUI::Appraisal_ShowLockAppraiseInfo @ 0x004B2790`
|
||||
- `AppraisalProfile::HasHookedItem @ 0x00525C70`
|
||||
- `AppraisalProfile::InqIntEnchantmentMod @ 0x005B2C10`
|
||||
- `AppraisalProfile::InqFloatEnchantmentMod @ 0x005B2C70`
|
||||
- `AppraisalSystem::LockpickSuccessPercentToString @ 0x005B4600`
|
||||
- `ACCWeenieObject::IsHook @ 0x0058C660`
|
||||
- `ItemExamineUI::HandleInscriptionGainingFocus @ 0x004AC0E0`
|
||||
- `ItemExamineUI::HandleInscriptionMousePresses @ 0x004AC230`
|
||||
- `ItemExamineUI::SetInscriptionEditableState @ 0x004AC720`
|
||||
|
|
@ -333,6 +343,57 @@ The individual branches are not a generic property dump. They project the
|
|||
wire profile into retail prose:
|
||||
|
||||
```text
|
||||
AddItemInfo(text, fontColorIndex, sameParagraph):
|
||||
if the report already contains text:
|
||||
append sameParagraph ? "\n" : "\n\n"
|
||||
append text with font-list index 0 and the requested color-list index
|
||||
|
||||
ShowValueAndBurden(profile):
|
||||
if profile contains int 19:
|
||||
append "Value: <grouped value>"
|
||||
else:
|
||||
append "Value: ???"
|
||||
|
||||
if profile contains int 5:
|
||||
append "Burden: <grouped burden>"
|
||||
else:
|
||||
append "Burden: Unknown"
|
||||
|
||||
IsHook(object):
|
||||
return PublicWeenieDesc.HookType != 0
|
||||
and PublicWeenieDesc.HookItemTypes != TYPE_UNDEF
|
||||
|
||||
ShowCapacity(object, profile):
|
||||
if object is not a hook or profile does not contain a HookProfile:
|
||||
append authored item/container capacity as a new paragraph
|
||||
if profile contains PageCount (175) and PageUsed (174):
|
||||
append "<used> of <count> pages full." as a new paragraph
|
||||
|
||||
# A hook with a HookProfile describes its mounted item. Its sentinel
|
||||
# 255/255 PublicWeenieDesc capacities are not player-facing capacity.
|
||||
|
||||
ShowLock(object, profile):
|
||||
if object is a hook:
|
||||
return
|
||||
if Locked bool is absent:
|
||||
append nonzero LockpickResistance as
|
||||
"Bonus to Lockpick Skill: <signed value>"
|
||||
return
|
||||
append "Unlocked" and return when Locked is false
|
||||
append "Locked"
|
||||
if LockpickResistance is absent:
|
||||
append "You can't tell how hard the lock is to pick."
|
||||
else if LockpickSuccessPercent is present:
|
||||
map it through LockpickSuccessPercentToString
|
||||
append "The lock looks <grade> to pick (Resistance <value>)."
|
||||
|
||||
FontColor(profileBitfield, lowBit):
|
||||
if lowBit is absent:
|
||||
return normal color index 0
|
||||
if the corresponding bit 16 positions higher is present:
|
||||
return beneficial color index 1
|
||||
return detrimental color index 2
|
||||
|
||||
ShowWeaponAndArmor(validLocations, profile):
|
||||
ammoType = live PublicWeenieDesc ammo type
|
||||
if object is a hook:
|
||||
|
|
@ -470,6 +531,10 @@ The main text and inscription areas use their authored scrollbars. A newly
|
|||
selected object resets those scroll positions to the top; a refresh of the
|
||||
same object preserves the user's position.
|
||||
|
||||
LayoutDesc `0x2100006B` element `0x1000013C` authors the item report's
|
||||
font-color list as white, green, and red. Those are the concrete colors selected
|
||||
by the `AddItemInfo` indices above; they are not hard-coded by appraisal logic.
|
||||
|
||||
## Window behavior
|
||||
|
||||
The LayoutDesc root already contains retail's complete floaty window chrome,
|
||||
|
|
@ -603,7 +668,10 @@ The request lifetime, exact packet flags, independent floaty window,
|
|||
inscription permission/edit/write transaction, subview choice, authored outer
|
||||
layout, ordered creature stats and ratings, animated creature preview,
|
||||
viewport/list/text compositing, selection-follow, scrollbar ownership, and
|
||||
combat refresh are in scope. Retail's item-object preview, exhaustive
|
||||
specialized `ItemExamineUI` detail branches, exact appraisal FontInfo-list
|
||||
combat refresh are in scope. Common item report rows now preserve retail's
|
||||
appraisal-only unknown values, hook/capacity/lock presence rules, exact
|
||||
paragraph boundaries, and authored normal/beneficial/detrimental font-color
|
||||
selection. Retail's item-object preview, exhaustive specialized
|
||||
`ItemExamineUI` detail branches, creature incomplete/high/low FontInfo
|
||||
selection, and PSR-only scribe-account/override behavior remain explicit
|
||||
AP-110 work.
|
||||
|
|
|
|||
|
|
@ -437,7 +437,7 @@ Per-flag (in exact order):
|
|||
0x00400000 SpellId : uint16
|
||||
0x02000000 OwnerId : uint32
|
||||
0x04000000 Restrictions : RestrictionDB (house perms)
|
||||
0x20000000 HookItemTypes : uint16 (HookType)
|
||||
0x20000000 HookItemTypes : uint32 (ITEM_TYPE mask)
|
||||
0x00000040 MonarchId : uint32
|
||||
0x10000000 HookType : uint16
|
||||
0x40000000 IconOverlay : packedDWORD (minus 0x06000000)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue