feat(items): port retail external-container looting
Add the ClientUISystem ground-object lifecycle, authoritative root and nested ViewContents projections, replacement and close semantics, and the DAT-authored gmExternalContainerUI strip for chests and corpses. Route double-click loot and full or partial drag transfers through the shared retail item policy without optimistic external ownership. Remove the incorrect NoLongerViewingContents behavior from owned side packs and retire AP-106/#196. Release build succeeds and all 5,875 tests pass with five intentional skips. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
48a118db91
commit
20ce67b625
27 changed files with 1750 additions and 45 deletions
|
|
@ -140,6 +140,13 @@ public sealed class UiItemList : UiElement
|
|||
/// </summary>
|
||||
public bool SingleRow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The single row uses the shared pixel scroll model as a horizontal offset.
|
||||
/// Retail's external-container list (LayoutDesc 0x21000008) is the authored
|
||||
/// horizontal ItemList + Scrollbar consumer.
|
||||
/// </summary>
|
||||
public bool HorizontalScroll { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maintain a tail of empty UIItems that fills the visible horizontal extent.
|
||||
/// Port of UIElement_ItemList::UpdateEmptySlots @ 0x004E3700.
|
||||
|
|
@ -206,6 +213,28 @@ public sealed class UiItemList : UiElement
|
|||
: Columns < 1 ? 1 : Columns;
|
||||
int cellH = (int)MathF.Round(CellHeight);
|
||||
|
||||
if (SingleRow && HorizontalScroll)
|
||||
{
|
||||
int cellW = Math.Max(1, (int)MathF.Round(CellWidth));
|
||||
Scroll.LineHeight = cellW;
|
||||
Scroll.ContentHeight = _cells.Count * cellW;
|
||||
Scroll.ViewHeight = (int)MathF.Floor(Width);
|
||||
Scroll.SetScrollY(Scroll.ScrollY);
|
||||
float scrollX = Scroll.ScrollY;
|
||||
|
||||
for (int i = 0; i < _cells.Count; i++)
|
||||
{
|
||||
float left = i * CellWidth - scrollX;
|
||||
UiItemSlot cell = _cells[i];
|
||||
cell.Left = left;
|
||||
cell.Top = 0f;
|
||||
cell.Width = CellWidth;
|
||||
cell.Height = CellHeight;
|
||||
cell.Visible = left < Width && left + CellWidth > 0f;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Drive the shared scroll model from the current geometry, then re-clamp the offset to
|
||||
// the (possibly changed) max. ContentHeight/ViewHeight must be set BEFORE reading ScrollY
|
||||
// so the clamp uses the right max.
|
||||
|
|
@ -292,6 +321,16 @@ public sealed class UiItemList : UiElement
|
|||
public void ScrollItemIntoView(int index)
|
||||
{
|
||||
if (CellWidth <= 0f || index < 0 || index >= _cells.Count) return;
|
||||
if (SingleRow && HorizontalScroll)
|
||||
{
|
||||
float left = index * CellWidth;
|
||||
float right = left + CellWidth;
|
||||
if (left < Scroll.ScrollY)
|
||||
Scroll.SetScrollY((int)MathF.Floor(left));
|
||||
else if (right > Scroll.ScrollY + Width)
|
||||
Scroll.SetScrollY((int)MathF.Ceiling(right - Width));
|
||||
return;
|
||||
}
|
||||
int columns = Math.Max(1, Columns);
|
||||
int row = Flow == UiItemListFlow.ColumnMajor
|
||||
? index % Math.Max(1, RowCount(_cells.Count, columns))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue