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>
72 lines
2.4 KiB
C#
72 lines
2.4 KiB
C#
using System.Numerics;
|
|
using DatReaderWriter;
|
|
|
|
namespace AcDream.App.UI.Layout;
|
|
|
|
/// <summary>
|
|
/// Resolved presentation of retail's spell-shortcut row prototype. The spellbook
|
|
/// list points at this prototype through ItemList attribute <c>0x1000000E</c>;
|
|
/// retail clones it for every learned spell.
|
|
/// </summary>
|
|
public readonly record struct SpellbookRowStyle(
|
|
float Width,
|
|
float Height,
|
|
float IconLeft,
|
|
float IconTop,
|
|
float IconWidth,
|
|
float IconHeight,
|
|
float LabelLeft,
|
|
float LabelWidth,
|
|
uint FontDid,
|
|
Vector4 LabelColor,
|
|
uint BackgroundSprite,
|
|
uint SelectedSprite)
|
|
{
|
|
public const uint CatalogLayoutId = 0x21000037u;
|
|
public const uint PrototypeId = 0x10000343u;
|
|
public const uint SelectedOverlayId = 0x10000342u;
|
|
public const uint LabelId = 0x10000344u;
|
|
public const uint IconId = 0x1000033Bu;
|
|
|
|
/// <summary>
|
|
/// Resolve the complete row geometry and media from the installed retail DAT.
|
|
/// Returns null if the authored prototype is incomplete; callers then leave the
|
|
/// panel unbound rather than inventing replacement art.
|
|
/// </summary>
|
|
public static SpellbookRowStyle? TryLoad(DatCollection dats)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(dats);
|
|
ElementInfo? prototype = LayoutImporter.ImportInfos(dats, CatalogLayoutId, PrototypeId);
|
|
if (prototype is null
|
|
|| Find(prototype, SelectedOverlayId) is not { } selected
|
|
|| Find(prototype, LabelId) is not { } label
|
|
|| Find(prototype, IconId) is not { } icon
|
|
|| !prototype.StateMedia.TryGetValue("", out var background)
|
|
|| !selected.StateMedia.TryGetValue("", out var selection)
|
|
|| prototype.Width <= 0f
|
|
|| prototype.Height <= 0f)
|
|
return null;
|
|
|
|
return new SpellbookRowStyle(
|
|
prototype.Width,
|
|
prototype.Height,
|
|
icon.X,
|
|
icon.Y,
|
|
icon.Width,
|
|
icon.Height,
|
|
label.X,
|
|
label.Width,
|
|
label.FontDid,
|
|
label.FontColor ?? Vector4.One,
|
|
background.File,
|
|
selection.File);
|
|
}
|
|
|
|
private static ElementInfo? Find(ElementInfo root, uint id)
|
|
{
|
|
if (root.Id == id) return root;
|
|
foreach (ElementInfo child in root.Children)
|
|
if (Find(child, id) is { } found) return found;
|
|
return null;
|
|
}
|
|
}
|