feat(ui): complete retail creature appraisal details

Port the separate creature rating list, layer the animated preview between authored row chrome and text, and follow selection while the examination floaty is visible. Preserve the remaining item-preview and font-state gaps in AP-110.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-23 14:04:19 +02:00
parent 7eaa68a5f4
commit d96ea2de98
11 changed files with 578 additions and 61 deletions

View file

@ -76,7 +76,7 @@ Copy this block when adding a new issue:
## #234 — Monster assessment held busy and examination used the shared panel
**Status:** DONE — 2026-07-23; creature presentation visual gate pending
**Status:** DONE — 2026-07-23; corrected creature presentation visual gate pending
**Severity:** HIGH
**Filed:** 2026-07-23
**Component:** appraisal protocol / retained examination UI / item writing
@ -98,6 +98,10 @@ retail's CP-1252 `SetInscription (0x00BF)` under its ownership/authorship rules.
The follow-up creature page now uses the authored row template and exact retail
stat order/formatting, creature-type EnumMapper, level property, fixed-heading
animated clone, bounding-box camera, and private-viewport light.
Its correction ports the second authored damage/critical/resistance rating
list, composites row chrome behind the animated preview and row text in front,
adds balanced text inset, and automatically reassesses each new selection
while the floaty remains visible.
**Files:** `src/AcDream.Core.Net/Messages/AppraiseInfoParser.cs`;
`src/AcDream.App/UI/RetailUiRuntime.cs`;
@ -113,7 +117,9 @@ examination window coexists with the shared primary panel; an owned
inscribable weapon can be edited/cleared and reassessed; foreign/nonowned/
noninscribable cases show retail's exact permission messages. Monster pages
show the animated target, mapped creature type, level, and nine ordered
retail stat rows.
retail stat rows; rated creatures show retail's paired rating rows; the
animated target remains above row chrome but below text; changing selection
updates the open window without another magnifier click.
---

View file

@ -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, item/creature/character reports, inscription transaction, and retail creature stat/animated-preview presentation, but still lacks item-object preview, exhaustive specialized detail/extra-rating regions, exact appraisal FontInfo-list selection, and selection-follow preference. | `src/AcDream.App/UI/RetailUiRuntime.cs`; `src/AcDream.App/UI/Layout/AppraisalUiController.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 loop cover the active loops; the remaining examination mechanisms require additional retail field/font/object-preview projections rather than fabricated content | Specialized assessments omit some retail fields and item-object presentation; 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`; `AttributeInfoRegion::Update @ 0x004F1D90`; `gmExaminationUI::SetAppraiseInfo @ 0x004ADAE0`; `ItemExamineUI::SetAppraiseInfo @ 0x004B72B0`; `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, item/creature/character reports, inscription transaction, retail creature stat/rating/animated-preview presentation, and default selection-follow, but still lacks item-object preview, exhaustive specialized item/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/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 loop cover the active loops; the remaining examination mechanisms require additional retail field/font/object-preview projections rather than fabricated content | Specialized item/character assessments omit some retail fields and item-object presentation; 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::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` |

View file

@ -137,8 +137,12 @@ resolves its type through retail EnumMapper `0x2200000E`, preserves the
authored Character/Level header, creates the exact nine stat rows from
template `0x10000166`, and renders a fixed-heading animated clone through a
private viewport using retail's bounding-box camera and distant light.
Item-object preview, specialized detail regions, exact appraisal font-state
selection, and selection-follow remain the narrowed AP-110 residual. Research:
The visual-gate correction also ports the separate `0x10000335`
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:
[`../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
@ -151,6 +155,11 @@ updates, hydrated mesh bounds, and retail camera fitting. The warning-free App c
Release solution build, 3,506 App tests / 3 skips, and 7,923 complete-solution
tests / 5 skips pass. The connected visual result remains the closeout gate.
The rating/layering/selection-follow correction adds 18 focused green tests,
passes the Release solution build with the 17 warnings already tracked by
#228, 3,510 App tests / 3 skips, and 7,927 complete-solution tests / 5 skips.
Its corrected connected visual result remains the closeout gate.
## Slice 1 — spell-bar overflow arrows
### Retail oracle

View file

@ -191,16 +191,27 @@ on time pulse:
send another Event_Appraise(currentAppraisalId)
```
When the examination window's selection-follow option is active, a selection
change appraises the new selected GUID; clearing selection hides the window.
That optional retail preference remains outside this slice.
`gmExaminationUI::gmExaminationUI @ 0x004AB2B0` initializes
`m_examineNewlySelectedItem` to one. Selection-follow is therefore retail's
default examination behavior, not an optional preference:
```text
on SelectionChanged:
if examination window is not visible:
return
if selected object id != 0:
ClientUISystem.ExamineObject(selected id)
else:
hide examination window
```
## Creature presentation
`BasicCreatureExamineUI` binds viewport `0x10000148`, list box `0x10000149`,
level value `0x1000014C`, and creature display name `0x1000014E`. Its stat
rows are instances of LayoutDesc `0x2100006B` template `0x10000166`, whose
label and value fields are `0x1000012A` and `0x1000012B`.
`BasicCreatureExamineUI` binds viewport `0x10000148`, base-stat list box
`0x10000149`, miscellaneous-rating list box `0x10000335`, level value
`0x1000014C`, and creature display name `0x1000014E`. Its rows are instances
of LayoutDesc `0x2100006B` template `0x10000166`, whose label and value fields
are `0x1000012A` and `0x1000012B`.
```text
on creature appraisal:
@ -222,6 +233,27 @@ on creature appraisal:
Health current secondary 2 / maximum secondary 1, show percent
Stamina current secondary 4 / maximum secondary 3
Mana current secondary 6 / maximum secondary 5
clear miscellaneous list
damageRating = int property 0x133
damageResistRating = int property 0x134
critRating = int property 0x139
critDamageRating = int property 0x13A
critResistRating = int property 0x13B
critDamageResist = int property 0x13C
healingBoostRating = int property 0x143
dotResistRating = int property 0x15E
lifeResistRating = int property 0x15F
if any displayed rating group is nonzero:
append blank row
if damageRating or critRating or critDamageRating is positive:
append "Dmg/CritDmg" = "Rating: damageRating/critDamageRating"
if damageResistRating or critResistRating or critDamageResist is positive:
append "Dmg/CritDmg" = "Resist: damageResistRating/critDamageResist"
if dotResistRating or lifeResistRating is positive:
append "DoT/Life:" = "Resist: dotResistRating/lifeResistRating"
append blank row
```
Successful primary values are decimal integers. Successful Health is
@ -230,6 +262,18 @@ assessment, Health still shows the percentage when both values are known,
while every other row is `???`. The profile highlight/color bitfields select
one of retail's four authored FontInfo entries (normal, beneficial,
detrimental, or incomplete); exact FontInfo-list binding remains AP-110.
The 2013 client reads HealingBoost but does not append it to this creature
rating list. CritRating and CritResistRating determine whether their paired
row exists, while the displayed right-hand value is CritDamageRating or
CritDamageResistRating exactly as retail formats it.
The authored viewport and list overlap. Retail draws the creature between the
row chrome and the row text. The modern retained RTT seam reproduces that
ordering with two synchronized copies of the same DAT row template: media-only
chrome below the viewport and media-free label/value descendants above it.
Both copies share one pixel scroll model. The 292-pixel authored row is inset
four pixels within the 300-pixel list surface, giving the text a balanced
left/right margin without changing template geometry.
The animated preview is a private `CreatureMode`, not the live world object:
@ -412,9 +456,9 @@ implements the same behavior.
The request lifetime, exact packet flags, independent floaty window,
inscription permission/edit/write transaction, subview choice, authored outer
layout, ordered creature stats, animated creature preview, scrollbar
ownership, and combat refresh are in scope. Retail's item-object preview,
exhaustive specialized `ItemExamineUI` detail branches, creature
extra-rating regions, exact appraisal FontInfo-list selection,
selection-follow preference, and PSR-only scribe-account/override behavior
remain explicit AP-110 work.
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
selection, and PSR-only scribe-account/override behavior remain explicit
AP-110 work.