fix(ui): select and examine favorite spells like retail

This commit is contained in:
Erik 2026-07-24 06:47:54 +02:00
parent 043ab10b3c
commit 3e31b0ac70
23 changed files with 974 additions and 34 deletions

View file

@ -219,6 +219,85 @@ Outbound character events (`CM_Character`):
0x0224 SetDesiredComponentLevel(componentDid:u32, amount:i32)
```
### Favorite press selection and local spell examination
Retail:
- `gmSpellcastingUI::ListenToElementMessage @ 0x004C7AB0`
- `SpellCastSubMenu::SetSelected @ 0x004C5B00`
- `UIElement_ItemList::ListenToElementMessage @ 0x004E4D50`
- `ClientUISystem::ExamineSpell @ 0x00564A70`
- `gmExaminationUI::ExamineSpell @ 0x004B6900`
- `SpellExamineUI::ExamineSpell @ 0x004B6210`
- `SpellExamineUI::DetermineSpellRange @ 0x004AD450`
A favorite spell is selected on the UIItem's left-button-down message, not on
button release. Double-click remains a completed gesture and casts the spell
that the press already selected.
```text
favorite UIItem message:
if message parameter == 7: // left press
submenu.SetSelected(spellId)
if message parameter == 10: // completed double click
Cast()
UIElement_ItemList right click:
if itemId != 0:
select itemId as the global weenie selection
ExamineObject(itemId)
else if spellId != 0:
ClientUISystem.ExamineSpell(spellId)
```
The spell branch is deliberately local. It never stores the spell ID in
`ACCWeenieObject::selectedID`, never sends an Appraise request, and never takes
a new UI-busy reference. The toolbar magnifying glass therefore remains an
object-only command; selecting a favorite cannot make it assess that spell.
The examination floaty is shared between object and spell subviews. Switching
to a spell cancels only an in-flight/current object appraisal:
```text
gmExaminationUI::ExamineSpell(spellId):
if awaiting object appraisal:
clear pending object
decrement that appraisal's UI-busy reference
clear current object
send Appraise(0)
else if a current object appraisal exists:
clear current object
send Appraise(0)
SpellExamineUI.ExamineSpell(spellId)
activate SpellPanel
show examination window
```
The authored spell subview is part of LayoutDesc `0x2100006B`:
```text
SpellPanel 0x10000153
school text 0x1000015E
spell icon 0x1000015F
mana text 0x10000160
duration text 0x10000161
range text 0x10000162
description/components text 0x10000163
formula list 0x1000032D
formula-cell template 0x1000032E
missing-component overlay 0x10000330
```
Presentation uses the current appropriate formula, preserving its order and
duplicates. Each component icon keeps the authored missing-component overlay
until the player owns that component. Duration is shown as integer seconds
below one minute and integer minutes from one minute upward. Range is
`min(baseConstant + baseModifier * schoolSkill, 75) / 0.9144`, displayed with
one decimal place in yards. School skill IDs are Creature `0x1F`, Item `0x20`,
Life `0x21`, War `0x22`, and Void `0x2B`; an unclassified spell uses the
highest of those five skills.
## Spellbook and component book
Retail: `gmSpellbookUI::PostInit` `0x0048B2B0` and