feat(ui): port retail spellbook interactions

Resolve the authored spell shortcut row prototype so the spellbook presents the retail icon, name, separator, selected overlay, and scrollbar geometry. Port exact school and level filters, stable display ordering, selection exposure, and learned-spell drags into the open favorite bar.

Route deletion through the shared retail confirmation dialog and send CM_Magic::Event_RemoveSpell only after an affirmative answer, leaving the inbound server notice authoritative for list state.

Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-15 16:26:30 +02:00
parent ad30c37a48
commit ac2ca8f965
17 changed files with 727 additions and 47 deletions

View file

@ -62,6 +62,7 @@ public sealed record MagicRuntimeBindings(
Action<int, int, uint> AddFavorite,
Action<int, uint> RemoveFavorite,
Action<uint> SendSpellbookFilter,
Action<uint> RemoveSpell,
Action<uint, uint> SetDesiredComponent,
Func<double> ServerTime);
@ -707,6 +708,7 @@ public sealed class RetailUiRuntime : IDisposable
private void MountSpellbook()
{
ImportedLayout? layout;
SpellbookRowStyle? rowStyle;
lock (_bindings.Assets.DatLock)
{
layout = LayoutImporter.Import(
@ -716,13 +718,19 @@ public sealed class RetailUiRuntime : IDisposable
_bindings.Assets.ResolveSprite,
_bindings.Assets.DefaultFont,
_bindings.Assets.ResolveFont);
rowStyle = SpellbookRowStyle.TryLoad(_bindings.Assets.Dats);
}
if (layout is null)
if (layout is null || rowStyle is null)
{
Console.WriteLine("[M3] spellbook: LayoutDesc 0x21000034 not found.");
Console.WriteLine("[M3] spellbook: layout or authored UIItem row prototype not found.");
return;
}
UiDatFont? rowFont = rowStyle.Value.FontDid == 0u
? _bindings.Assets.DefaultFont
: _bindings.Assets.ResolveFont(rowStyle.Value.FontDid)
?? _bindings.Assets.DefaultFont;
SpellbookWindowController? controller = Layout.SpellbookWindowController.Bind(
layout,
_bindings.Magic.Spellbook,
@ -735,8 +743,12 @@ public sealed class RetailUiRuntime : IDisposable
_bindings.Magic.SelectObject,
spellId => SpellcastingUiController?.AddFavorite(spellId),
_bindings.Magic.SendSpellbookFilter,
_bindings.Magic.RemoveSpell,
(message, completed) => ShowConfirmation(message, completed),
_bindings.Magic.SetDesiredComponent,
() => CloseWindow(WindowNames.Spellbook));
() => CloseWindow(WindowNames.Spellbook),
rowStyle.Value,
rowFont);
if (controller is null)
{
Console.WriteLine("[M3] spellbook: required controls missing in LayoutDesc 0x21000034.");