feat(D.5.1): faithful toolbar slot numbers 1-9 (SetShortcutNum digit sprites, peace/war)
Port of UIElement_UIItem::SetShortcutNum (acclient_2013_pseudo_c.txt:229465) and
gmToolbarUI::RecvNotice_SetCombatMode (196610-196621). The 9 top-row toolbar slots
show digit labels 1-9 at all times (even when empty — confirmed from the user''s
retail screenshot). The digit sprites are real 32x32 PFID_A8R8G8B8 RenderSurfaces
with glyphs baked into the top-left corner (rest alpha=0), drawn Alphablend over
the slot icon/empty sprite.
Digit DID arrays (peace: property 0x10000042, war: 0x10000043) are read at startup
from LayoutDesc 0x21000037 element 0x1000034A under composite 0x10000346 using the
same ArrayBaseProperty{DataIdBaseProperty} pattern as LayoutImporter.ReadState.
A cited-constant fallback (same confirmed dat ids) is used if the dat navigation
fails. The war glyph set (darker/golden glyphs) switches on any combat stance;
peace glyphs (lighter) restore on NonCombat — re-stamped by RestampShortcutNumbers()
called from both Populate() and SetCombatMode().
Changes:
- UiItemSlot: ShortcutNum/ShortcutPeace/PeaceDigits/WarDigits state; SetShortcutNum/
ClearShortcutNum; OnDraw restructured (no early return) so digit draws after icon.
- ToolbarController: _peaceDigits/_warDigits/_peace fields; Bind() gains peaceDigits/
warDigits optional params; RestampShortcutNumbers() helper; Populate() and
SetCombatMode() both call RestampShortcutNumbers().
- GameWindow: reads digit arrays under _datLock from LayoutDesc 0x21000037, passes to
Bind(); cited constants as fallback.
- Tests: 5 new UiItemSlotTests (SetShortcutNum/ClearShortcutNum state); 4 new
ToolbarControllerTests (top-row/bottom-row labels, peace/war switch, array injection).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f21dbfad80
commit
b2a812d1fa
5 changed files with 328 additions and 6 deletions
|
|
@ -37,6 +37,40 @@ public sealed class UiItemSlot : UiElement
|
|||
|
||||
public void Clear() { ItemId = 0; IconTexture = 0; }
|
||||
|
||||
// ── Shortcut number (slot label) ─────────────────────────────────────────
|
||||
// Port of UIElement_UIItem::SetShortcutNum (acclient_2013_pseudo_c.txt:229465).
|
||||
// Retail draws the digit on the cell's ShortcutNum sub-element, picking the
|
||||
// digit image from a DID-array property: 0x10000042 (peace) / 0x10000043 (war),
|
||||
// indexed by slot position. Each digit is a 32×32 PFID_A8R8G8B8 RenderSurface
|
||||
// with the digit baked into the top-left corner (rest alpha=0), drawn Alphablend.
|
||||
|
||||
/// <summary>Slot position in the shortcut bar (0-indexed). -1 = no number (retail
|
||||
/// SetVisible(0) when edi < 0). Top row: 0..8 → digits 1..9. Bottom row: -1.</summary>
|
||||
public int ShortcutNum { get; private set; } = -1;
|
||||
|
||||
/// <summary>True = draw peace digit set; false = war digit set.</summary>
|
||||
public bool ShortcutPeace { get; private set; } = true;
|
||||
|
||||
/// <summary>Peace digit DID array. Index i → digit (i+1) sprite RenderSurface id.
|
||||
/// Injected by the controller after reading LayoutDesc 0x21000037.</summary>
|
||||
public uint[]? PeaceDigits { get; set; }
|
||||
|
||||
/// <summary>War digit DID array. Same layout as PeaceDigits.</summary>
|
||||
public uint[]? WarDigits { get; set; }
|
||||
|
||||
/// <summary>Set the slot's shortcut position and combat stance so the correct digit
|
||||
/// is drawn. Call with index 0..8 for the top row; pass peace=true for NonCombat.</summary>
|
||||
public void SetShortcutNum(int index, bool peace)
|
||||
{
|
||||
ShortcutNum = index;
|
||||
ShortcutPeace = peace;
|
||||
}
|
||||
|
||||
/// <summary>Clear the shortcut number label (hides the digit).</summary>
|
||||
public void ClearShortcutNum() { ShortcutNum = -1; }
|
||||
|
||||
// ── Events / draw ─────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Invoked by <see cref="OnEvent"/> when a left-button-down lands on
|
||||
/// a bound slot. Wired by <c>ToolbarController</c> to the use-item callback.</summary>
|
||||
public Action? Clicked { get; set; }
|
||||
|
|
@ -50,16 +84,37 @@ public sealed class UiItemSlot : UiElement
|
|||
|
||||
protected override void OnDraw(UiRenderContext ctx)
|
||||
{
|
||||
// Draw the icon (filled slot) or the empty-slot border. Both paths fall
|
||||
// through to the digit draw below, so the slot label shows on all top-row
|
||||
// slots regardless of whether they hold an item (retail screenshot confirms
|
||||
// numbers on empty slots).
|
||||
if (ItemId != 0 && IconTexture != 0)
|
||||
{
|
||||
ctx.DrawSprite(IconTexture, 0f, 0f, Width, Height, 0f, 0f, 1f, 1f, Vector4.One);
|
||||
return;
|
||||
}
|
||||
if (SpriteResolve is not null && EmptySprite != 0)
|
||||
else if (SpriteResolve is not null && EmptySprite != 0)
|
||||
{
|
||||
var (tex, _, _) = SpriteResolve(EmptySprite);
|
||||
if (tex != 0)
|
||||
ctx.DrawSprite(tex, 0f, 0f, Width, Height, 0f, 0f, 1f, 1f, Vector4.One);
|
||||
}
|
||||
|
||||
// Digit overlay: UIElement_UIItem::SetShortcutNum (acclient_2013_pseudo_c.txt:229465).
|
||||
// Each digit image is corner-baked (glyph in top-left, rest alpha=0) so we
|
||||
// draw it full-cell size and the transparent region is invisible. DrawMode=Alphablend.
|
||||
if (ShortcutNum >= 0 && SpriteResolve is not null)
|
||||
{
|
||||
var arr = ShortcutPeace ? PeaceDigits : WarDigits;
|
||||
if (arr is not null && ShortcutNum < arr.Length)
|
||||
{
|
||||
uint did = arr[ShortcutNum];
|
||||
if (did != 0)
|
||||
{
|
||||
var (tex, _, _) = SpriteResolve(did);
|
||||
if (tex != 0)
|
||||
ctx.DrawSprite(tex, 0f, 0f, Width, Height, 0f, 0f, 1f, 1f, Vector4.One);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue