feat(ui): port retail creature appraisal presentation

Render assessed creatures through the shared private viewport with retail heading, bounding-box camera, and light. Build the exact authored nine-row stat list and resolve creature names from the retail EnumMapper while keeping remaining font/sequencer adaptations explicit.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-23 12:55:24 +02:00
parent f1a7912160
commit 7eaa68a5f4
26 changed files with 2780 additions and 237 deletions

View file

@ -13,9 +13,15 @@ retained examination window.
- `gmExaminationUI::SetActiveExamineUI @ 0x004AB420`
- `gmExaminationUI::UseTime @ 0x004AB530`
- `gmExaminationUI::SetAppraiseInfo @ 0x004ADAE0`
- `BasicCreatureExamineUI::Init @ 0x004AB9C0`
- `BasicCreatureExamineUI::BasicCreatureExamineUI @ 0x004ACD30`
- `BasicCreatureExamineUI::SetLevelValueText @ 0x004B3E70`
- `BasicCreatureExamineUI::SetAppraiseInfo @ 0x004B3F70`
- `CreatureExamineUI::SetAppraiseInfo @ 0x004B3FF0`
- `CharExamineUI::SetAppraiseInfo @ 0x004B45F0`
- `AttributeInfoRegion::Update @ 0x004F1D90`
- `Attribute2ndInfoRegion::Update @ 0x004F1E80`
- `AppraisalSystem::InqCreatureDisplayName @ 0x005B59E0`
- `ItemExamineUI::SetAppraiseInfo @ 0x004B72B0`
- `ItemExamineUI::HandleInscriptionGainingFocus @ 0x004AC0E0`
- `ItemExamineUI::HandleInscriptionMousePresses @ 0x004AC230`
@ -189,6 +195,79 @@ 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.
## 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`.
```text
on creature appraisal:
level = int property 25
level text = decimal level when positive, otherwise "???"
creatureType = int property 2
display name = EnumMapper 0x2200000E[creatureType]
replace underscores in display name with spaces
clear stat list
append rows in this exact order:
Strength primary attribute 1
Endurance primary attribute 2
Coordination primary attribute 4
Quickness primary attribute 3
Focus primary attribute 5
Self primary attribute 6
Health current secondary 2 / maximum secondary 1, show percent
Stamina current secondary 4 / maximum secondary 3
Mana current secondary 6 / maximum secondary 5
```
Successful primary values are decimal integers. Successful Health is
`current/max (percent %)`; Stamina and Mana are `current/max`. On a failed
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 animated preview is a private `CreatureMode`, not the live world object:
```text
clear the previous private creature
clone selected CPhysicsObj with makeObject
set clone heading to 191.367905 degrees
query the clone bounding box
width = bbox.max.x - bbox.min.x
depth = bbox.max.y - bbox.min.y
height = bbox.max.z - bbox.min.z
viewportHeightOverWidth = viewport.height / viewport.width
fittedVerticalSpan = max(height, width * viewportHeightOverWidth)
center = (bbox.min + bbox.max) / 2
camera.position = (
center.x,
center.y - (fittedVerticalSpan * 1.20710683 + depth / 2),
center.z)
camera.direction = identity (+Y)
viewport light:
type = DISTANT_LIGHT
intensity = 2
direction = (0.3, 1.9, 0.65)
insert clone into the private CreatureMode
```
ACDream's modern rendering equivalent uses the same isolated render-to-texture
owner as the inventory paperdoll. The examination clone has its own stable
render identity, fixed heading and retail camera/light, while its mesh-part
transforms are refreshed from the live target each frame so its current
animation is visible without registering a second gameplay entity. Retail's
clone instead advances the motion state copied by
`CPhysicsObj::MorphToExistingObject`; that narrow sequencer-ownership
adaptation is recorded under AP-92.
## Item presentation order
`ItemExamineUI::SetAppraiseInfo` clears and rebuilds the authored item text in
@ -333,7 +412,9 @@ implements the same behavior.
The request lifetime, exact packet flags, independent floaty window,
inscription permission/edit/write transaction, subview choice, authored outer
layout, basic report content, scrollbar ownership, and combat refresh are in
scope. Retail's exact 3D object/creature preview, exhaustive specialized
`ItemExamineUI` detail branches, selection-follow preference, and PSR-only
scribe-account/override behavior remain explicit AP-110 work.
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.