feat(ui): D.2b inventory finish — side-bag column slots (36px pitch + empties)
The side-bag column (0x100001CA, 36x252 = 7 slots) pads empty slot frames up to the player's ContainersCapacity (clamped to 7), at the correct 36px pitch (split from the contents grid's 32px). Reads like retail's bag column. Two existing tests updated for the now-padded count (divergence AP-52: 7-slot fallback when capacity is absent — register row added in the wrap-up commit). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fad807587d
commit
4112a53683
2 changed files with 42 additions and 7 deletions
|
|
@ -33,7 +33,9 @@ public sealed class InventoryController
|
|||
|
||||
// 3D-items grid: 192x96 → 6 cols x 3 rows of the 32x32 UIItem cell (template 0x21000037).
|
||||
private const int ContentsColumns = 6;
|
||||
private const float CellPx = 32f;
|
||||
private const float ContentsCellPx = 32f; // gm3DItemsUI grid (192x96 = 6x3 of 32px)
|
||||
private const float BackpackCellPx = 36f; // gmBackpackUI column cells (0x100001C9/CA = 36px)
|
||||
private const int SideBagSlots = 7; // 0x100001CA is 36x252 = 7 slots
|
||||
|
||||
private readonly ClientObjectTable _objects;
|
||||
private readonly Func<uint> _playerGuid;
|
||||
|
|
@ -73,8 +75,8 @@ public sealed class InventoryController
|
|||
if (_contentsGrid is not null)
|
||||
{
|
||||
_contentsGrid.Columns = ContentsColumns;
|
||||
_contentsGrid.CellWidth = CellPx;
|
||||
_contentsGrid.CellHeight = CellPx;
|
||||
_contentsGrid.CellWidth = ContentsCellPx;
|
||||
_contentsGrid.CellHeight = ContentsCellPx;
|
||||
}
|
||||
|
||||
// Bind the gutter scrollbar to the contents grid's scroll model (the factory built
|
||||
|
|
@ -94,8 +96,8 @@ public sealed class InventoryController
|
|||
if (_containerList is not null)
|
||||
{
|
||||
_containerList.Columns = 1;
|
||||
_containerList.CellWidth = CellPx;
|
||||
_containerList.CellHeight = CellPx;
|
||||
_containerList.CellWidth = BackpackCellPx;
|
||||
_containerList.CellHeight = BackpackCellPx;
|
||||
}
|
||||
|
||||
// Burden meter: vertical 11×58 bar (gmBackpackUI m_burdenMeter, retail direction 4).
|
||||
|
|
@ -177,6 +179,21 @@ public sealed class InventoryController
|
|||
list.AddItem(cell);
|
||||
}
|
||||
|
||||
// Side-bag column: pad with empty slot frames up to the player's container capacity
|
||||
// (clamped to the 7-slot column) so it reads like retail (bags on top, empty frames
|
||||
// below) rather than one lone cell. Falls back to the full 7 slots when capacity is
|
||||
// unknown (divergence AP-52).
|
||||
if (_containerList is not null)
|
||||
{
|
||||
int capacity = _objects.Get(p)?.ContainersCapacity ?? 0;
|
||||
int bags = _containerList.GetNumUIItems();
|
||||
int slots = capacity > 0 ? capacity : SideBagSlots;
|
||||
slots = Math.Max(slots, bags);
|
||||
slots = Math.Min(slots, SideBagSlots);
|
||||
while (_containerList.GetNumUIItems() < slots)
|
||||
_containerList.AddItem(new UiItemSlot { SpriteResolve = _containerList.SpriteResolve });
|
||||
}
|
||||
|
||||
// Main-pack cell: the player's own container. Icon = placeholder until a backpack
|
||||
// RenderSurface DID is pinned (spec §3 / divergence row). Bind the guid so a future
|
||||
// click can select it.
|
||||
|
|
|
|||
|
|
@ -83,8 +83,9 @@ public class InventoryControllerTests
|
|||
Assert.Equal(2, grid.GetNumUIItems()); // 2 loose
|
||||
Assert.Equal(0xAu, grid.GetItem(0)!.ItemId);
|
||||
Assert.Equal(0xBu, grid.GetItem(1)!.ItemId);
|
||||
Assert.Equal(1, containers.GetNumUIItems()); // 1 side bag
|
||||
Assert.Equal(7, containers.GetNumUIItems()); // 1 side bag + 6 empty (no capacity → 7-slot column)
|
||||
Assert.Equal(0xCu, containers.GetItem(0)!.ItemId);
|
||||
Assert.Equal(0u, containers.GetItem(1)!.ItemId); // padded empty frame
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -102,7 +103,8 @@ public class InventoryControllerTests
|
|||
|
||||
Assert.Equal(1, grid.GetNumUIItems()); // only the loose item
|
||||
Assert.Equal(0xAu, grid.GetItem(0)!.ItemId);
|
||||
Assert.Equal(0, containers.GetNumUIItems()); // equipped item is not a side bag either
|
||||
Assert.Equal(7, containers.GetNumUIItems()); // 7 empty slots (no bags; the equipped item isn't here)
|
||||
Assert.Equal(0u, containers.GetItem(0)!.ItemId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -203,6 +205,22 @@ public class InventoryControllerTests
|
|||
Assert.Same(grid.Scroll, bar.Model); // the bar drives the grid's scroll
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Side_bag_column_pads_empty_slots_up_to_capacity()
|
||||
{
|
||||
var (layout, _, containers, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
objects.AddOrUpdate(new ClientObject { ObjectId = Player, ContainersCapacity = 3 });
|
||||
SeedContained(objects, 0xC, Player, slot: 0, type: ItemType.Container); // one side bag
|
||||
|
||||
Bind(layout, objects);
|
||||
|
||||
Assert.Equal(3, containers.GetNumUIItems()); // 1 bag + 2 empty = capacity 3
|
||||
Assert.Equal(0xCu, containers.GetItem(0)!.ItemId); // the bag
|
||||
Assert.Equal(0u, containers.GetItem(1)!.ItemId); // empty frame
|
||||
Assert.Equal(0u, containers.GetItem(2)!.ItemId); // empty frame
|
||||
}
|
||||
|
||||
// Reads the text of the UiText caption child attached by the controller.
|
||||
private static string CaptionText(UiElement host)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue