feat(D.2b): per-container capacity bar on inventory cells
Faithful port of retail UIElement_UIItem::UpdateCapacityDisplay (0x004e16e0): each container cell (side bags + main pack) shows a vertical UIElement_Meter (element 0x10000347, back 0x06004D22 / fill 0x06004D23) filled to GetNumContainedItems / ItemsCapacity, clamped [0,1]; hidden for non-containers (CapacityFill=-1). Drawn procedurally on UiItemSlot like the triangle/square overlays (back full + front clipped bottom-up). Right-anchored flush to the cell edge (visual gate: the dat X=26 sat ~5px off the right edge). Visually confirmed 2026-06-22. Divergence AP-59; polish deferred to ISSUES #146 (exact rect/anchor, fill direction vs m_eDirection 0x6f, closed-bag lazy-load). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
077586a0f0
commit
a45c421bd1
6 changed files with 112 additions and 1 deletions
|
|
@ -55,6 +55,16 @@ public sealed class UiItemSlot : UiElement
|
|||
/// on the 36×36 container cell too (whose prototype lacks the square child).</summary>
|
||||
public uint SelectedSprite { get; set; } = 0x06004D21u;
|
||||
|
||||
/// <summary>Container fullness [0..1], or -1 = hidden (the cell is not a container, or its
|
||||
/// itemsCapacity is unknown/0). Port of UIElement_UIItem::UpdateCapacityDisplay (0x004e16e0): a
|
||||
/// per-cell vertical UIElement_Meter (element 0x10000347, 5×30 at x=26,y=1) shown only when
|
||||
/// isContainer && itemsCapacity > 0, fill = numContainedItems / itemsCapacity (meter attr 0x69).</summary>
|
||||
public float CapacityFill { get; set; } = -1f;
|
||||
/// <summary>Capacity-bar track sprite (meter 0x10000347 DirectState).</summary>
|
||||
public uint CapacityBackSprite { get; set; } = 0x06004D22u;
|
||||
/// <summary>Capacity-bar fill sprite (meter 0x10000347 front child 0x00000002 DirectState).</summary>
|
||||
public uint CapacityFrontSprite { get; set; } = 0x06004D23u;
|
||||
|
||||
/// <summary>Accept/reject overlay state while a drag hovers this cell.</summary>
|
||||
public enum DragAcceptState { None, Accept, Reject }
|
||||
private DragAcceptState _dragAccept = DragAcceptState.None;
|
||||
|
|
@ -237,6 +247,33 @@ public sealed class UiItemSlot : UiElement
|
|||
}
|
||||
}
|
||||
|
||||
// Container capacity bar — UIElement_UIItem::UpdateCapacityDisplay (0x004e16e0): a vertical
|
||||
// UIElement_Meter (element 0x10000347, 5×30 at x=26,y=1) shown only for container cells
|
||||
// (CapacityFill >= 0). Track drawn full; fill clipped to the fraction from the BOTTOM (the
|
||||
// "how full" direction). Procedural — UiItemSlot is a behavioral leaf. Guard id != 0 first.
|
||||
if (CapacityFill >= 0f && SpriteResolve is not null)
|
||||
{
|
||||
const float by = 1f, bw = 5f, bh = 30f; // element 0x10000347 size (dat 5×30 at y=1)
|
||||
float bx = Width - bw; // flush to the cell's right edge (visual gate: the dat X=26 sat ~5px off the edge)
|
||||
if (CapacityBackSprite != 0)
|
||||
{
|
||||
var (bt, _, _) = SpriteResolve(CapacityBackSprite);
|
||||
if (bt != 0) ctx.DrawSprite(bt, bx, by, bw, bh, 0f, 0f, 1f, 1f, Vector4.One);
|
||||
}
|
||||
float f = Math.Clamp(CapacityFill, 0f, 1f);
|
||||
if (f > 0f && CapacityFrontSprite != 0)
|
||||
{
|
||||
var (ft, _, _) = SpriteResolve(CapacityFrontSprite);
|
||||
if (ft != 0)
|
||||
{
|
||||
// Bottom-up fill: draw the bottom f-fraction of the bar, sampling the matching
|
||||
// bottom slice of the front sprite (UV v from 1-f to 1).
|
||||
float fh = bh * f;
|
||||
ctx.DrawSprite(ft, bx, by + (bh - fh), bw, fh, 0f, 1f - f, 1f, 1f, Vector4.One);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Open-container triangle (retail SetOpenContainerState 0x004e1200) + selected-item square
|
||||
// (retail SetSelectedState 0x004e1240). Drawn procedurally like the digit/drag overlays;
|
||||
// guard id != 0 BEFORE resolving (feedback_ui_resolve_zero_magenta). Triangle under the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue