feat(ui): D.2b inventory finish — contents grid shows full main-pack capacity

The contents grid now pads empty slot frames up to the main-pack capacity
(player ItemsCapacity, default 102 per retail "up to 102 items"), so the pack
reads like retail's fixed 102-slot grid you scroll through — not just the loose
items. Mirrors the side-bag column padding. Three existing grid tests updated
for the now-padded count; new test covers the 102-pad.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-21 21:21:20 +02:00
parent a1e7041ba8
commit 1be7e65fad
2 changed files with 36 additions and 4 deletions

View file

@ -36,6 +36,7 @@ public sealed class InventoryController
private const float ContentsCellPx = 32f; // gm3DItemsUI grid (192x96 = 6x3 of 32px) private const float ContentsCellPx = 32f; // gm3DItemsUI grid (192x96 = 6x3 of 32px)
private const float BackpackCellPx = 36f; // gmBackpackUI column cells (0x100001C9/CA = 36px) private const float BackpackCellPx = 36f; // gmBackpackUI column cells (0x100001C9/CA = 36px)
private const int SideBagSlots = 7; // 0x100001CA is 36x252 = 7 slots private const int SideBagSlots = 7; // 0x100001CA is 36x252 = 7 slots
private const int MainPackSlots = 102; // retail main-pack capacity (Wiki: "up to 102 items")
private readonly ClientObjectTable _objects; private readonly ClientObjectTable _objects;
private readonly Func<uint> _playerGuid; private readonly Func<uint> _playerGuid;
@ -179,6 +180,18 @@ public sealed class InventoryController
list.AddItem(cell); list.AddItem(cell);
} }
// Contents grid: show the FULL main-pack capacity (default 102) — occupied slots + empty
// frames — so the pack reads like retail (a fixed 102-slot grid you scroll), not just the
// loose items. The grid shows the SELECTED pack (default = the main pack / player); side-pack
// contents are a container-switch (later). Capacity = the player's ItemsCapacity, else 102.
if (_contentsGrid is not null)
{
int cap = _objects.Get(p)?.ItemsCapacity ?? 0;
int slots = cap > 0 ? cap : MainPackSlots;
while (_contentsGrid.GetNumUIItems() < slots)
_contentsGrid.AddItem(new UiItemSlot { SpriteResolve = _contentsGrid.SpriteResolve });
}
// Side-bag column: pad with empty slot frames up to the player's container capacity // 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 // (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 // below) rather than one lone cell. Falls back to the full 7 slots when capacity is

View file

@ -80,9 +80,10 @@ public class InventoryControllerTests
Bind(layout, objects); Bind(layout, objects);
Assert.Equal(2, grid.GetNumUIItems()); // 2 loose Assert.Equal(102, grid.GetNumUIItems()); // 2 loose + 100 empty (main-pack capacity)
Assert.Equal(0xAu, grid.GetItem(0)!.ItemId); Assert.Equal(0xAu, grid.GetItem(0)!.ItemId);
Assert.Equal(0xBu, grid.GetItem(1)!.ItemId); Assert.Equal(0xBu, grid.GetItem(1)!.ItemId);
Assert.Equal(0u, grid.GetItem(2)!.ItemId); // padded empty
Assert.Equal(7, containers.GetNumUIItems()); // 1 side bag + 6 empty (no capacity → 7-slot column) Assert.Equal(7, containers.GetNumUIItems()); // 1 side bag + 6 empty (no capacity → 7-slot column)
Assert.Equal(0xCu, containers.GetItem(0)!.ItemId); Assert.Equal(0xCu, containers.GetItem(0)!.ItemId);
Assert.Equal(0u, containers.GetItem(1)!.ItemId); // padded empty frame Assert.Equal(0u, containers.GetItem(1)!.ItemId); // padded empty frame
@ -101,7 +102,7 @@ public class InventoryControllerTests
Bind(layout, objects); Bind(layout, objects);
Assert.Equal(1, grid.GetNumUIItems()); // only the loose item Assert.Equal(102, grid.GetNumUIItems()); // 1 loose + 101 empty (main-pack capacity)
Assert.Equal(0xAu, grid.GetItem(0)!.ItemId); Assert.Equal(0xAu, grid.GetItem(0)!.ItemId);
Assert.Equal(7, containers.GetNumUIItems()); // 7 empty slots (no bags; the equipped item isn't here) Assert.Equal(7, containers.GetNumUIItems()); // 7 empty slots (no bags; the equipped item isn't here)
Assert.Equal(0u, containers.GetItem(0)!.ItemId); Assert.Equal(0u, containers.GetItem(0)!.ItemId);
@ -123,12 +124,13 @@ public class InventoryControllerTests
var (layout, grid, _, _, _, _, _, _) = BuildLayout(); var (layout, grid, _, _, _, _, _, _) = BuildLayout();
var objects = new ClientObjectTable(); var objects = new ClientObjectTable();
Bind(layout, objects); Bind(layout, objects);
Assert.Equal(0, grid.GetNumUIItems()); Assert.Equal(102, grid.GetNumUIItems()); // empty grid still shows the full 102-slot pack
Assert.Equal(0u, grid.GetItem(0)!.ItemId); // slot 0 empty before the add
objects.Ingest(new WeenieData(0xA, "Sword", ItemType.MeleeWeapon, 1, 0, 0, 0, 0, objects.Ingest(new WeenieData(0xA, "Sword", ItemType.MeleeWeapon, 1, 0, 0, 0, 0,
null, null, null, 5, Player, null, null, null, null, null, null, null, null, null)); null, null, null, 5, Player, null, null, null, null, null, null, null, null, null));
Assert.Equal(1, grid.GetNumUIItems()); Assert.Equal(102, grid.GetNumUIItems()); // still 102; the item fills slot 0
Assert.Equal(0xAu, grid.GetItem(0)!.ItemId); Assert.Equal(0xAu, grid.GetItem(0)!.ItemId);
} }
@ -205,6 +207,23 @@ public class InventoryControllerTests
Assert.Same(grid.Scroll, bar.Model); // the bar drives the grid's scroll Assert.Same(grid.Scroll, bar.Model); // the bar drives the grid's scroll
} }
[Fact]
public void Contents_grid_pads_empty_slots_to_main_pack_capacity()
{
// The grid shows the full main-pack capacity (default 102) — occupied + empty — so the
// pack reads like retail's fixed 102-slot grid you scroll, not just the loose items.
var (layout, grid, _, _, _, _, _, _) = BuildLayout();
var objects = new ClientObjectTable();
objects.AddOrUpdate(new ClientObject { ObjectId = Player, ItemsCapacity = 102 });
SeedContained(objects, 0xA, Player, slot: 0, burden: 5); // one loose item
Bind(layout, objects);
Assert.Equal(102, grid.GetNumUIItems()); // 1 item + 101 empty frames = 102
Assert.Equal(0xAu, grid.GetItem(0)!.ItemId);
Assert.Equal(0u, grid.GetItem(50)!.ItemId); // a padded empty slot
}
[Fact] [Fact]
public void Side_bag_column_pads_empty_slots_up_to_capacity() public void Side_bag_column_pads_empty_slots_up_to_capacity()
{ {