feat(D.2b): InventoryController container-switching + open/selected indicators
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
842462e375
commit
7407a71d68
2 changed files with 234 additions and 44 deletions
|
|
@ -51,10 +51,19 @@ public class InventoryControllerTests
|
|||
}
|
||||
|
||||
private static InventoryController Bind(ImportedLayout layout, ClientObjectTable objects,
|
||||
int? strength = 100)
|
||||
int? strength = 100, List<uint>? uses = null, List<uint>? closes = null)
|
||||
=> InventoryController.Bind(layout, objects, () => Player,
|
||||
iconIds: (_, _, _, _, _) => 0u, // no real GL upload in tests
|
||||
strength: () => strength, datFont: null);
|
||||
strength: () => strength, datFont: null,
|
||||
sendUse: uses is null ? null : g => uses.Add(g),
|
||||
sendNoLongerViewing: closes is null ? null : g => closes.Add(g));
|
||||
|
||||
// Seed a side bag (a container) in the player's pack, plus optionally its own contents.
|
||||
private static void SeedBag(ClientObjectTable t, uint bag, int slot, int itemsCapacity = 24)
|
||||
{
|
||||
t.AddOrUpdate(new ClientObject { ObjectId = bag, Type = ItemType.Container, ItemsCapacity = itemsCapacity });
|
||||
t.MoveItem(bag, Player, slot);
|
||||
}
|
||||
|
||||
// Place an object in a container at a slot via the faithful production path:
|
||||
// AddOrUpdate registers it, MoveItem sets ContainerId+ContainerSlot and calls Reindex
|
||||
|
|
@ -253,6 +262,105 @@ public class InventoryControllerTests
|
|||
Assert.Equal(0x06005D9Cu, top.GetItem(0)!.EmptySprite); // the main-pack cell
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClickSideBag_sendsUse_andSwapsGridToBagContents()
|
||||
{
|
||||
var (layout, grid, containers, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedContained(objects, 0xA, Player, slot: 0); // a loose main-pack item
|
||||
SeedBag(objects, 0xC, slot: 1); // side bag (player slot 1)
|
||||
SeedContained(objects, 0xB1, 0xC, slot: 0); // a thing already known to be in the bag
|
||||
var uses = new List<uint>();
|
||||
Bind(layout, objects, uses: uses);
|
||||
|
||||
// The side-bag column's first cell holds the bag guid; click it.
|
||||
containers.GetItem(0)!.Clicked!();
|
||||
|
||||
Assert.Contains(0xCu, uses); // Use(bag) sent
|
||||
Assert.Equal(0xB1u, grid.GetItem(0)!.ItemId); // grid swapped to the bag's contents
|
||||
Assert.Equal(24, grid.GetNumUIItems()); // padded to the bag's ItemsCapacity
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClickMainPackCell_afterBag_closesBag_returnsToMainPack()
|
||||
{
|
||||
var (layout, grid, containers, top, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedContained(objects, 0xA, Player, slot: 0); // loose main-pack item
|
||||
SeedBag(objects, 0xC, slot: 1);
|
||||
SeedContained(objects, 0xB1, 0xC, slot: 0);
|
||||
var uses = new List<uint>();
|
||||
var closes = new List<uint>();
|
||||
var ctrl = Bind(layout, objects, uses: uses, closes: closes);
|
||||
|
||||
containers.GetItem(0)!.Clicked!(); // open the bag
|
||||
top.GetItem(0)!.Clicked!(); // click the main-pack cell
|
||||
|
||||
Assert.Contains(0xCu, closes); // NoLongerViewingContents(bag) sent
|
||||
Assert.DoesNotContain(Player, uses); // no Use for the main pack
|
||||
Assert.Equal(0xAu, grid.GetItem(0)!.ItemId); // grid back to the main pack
|
||||
Assert.Equal(102, grid.GetNumUIItems());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SwitchBetweenTwoBags_closesPrevious_opensNext()
|
||||
{
|
||||
var (layout, _, containers, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedBag(objects, 0xC1, slot: 0);
|
||||
SeedBag(objects, 0xC2, slot: 1);
|
||||
var uses = new List<uint>();
|
||||
var closes = new List<uint>();
|
||||
Bind(layout, objects, uses: uses, closes: closes);
|
||||
|
||||
containers.GetItem(0)!.Clicked!(); // open bag A (column index 0 → 0xC1)
|
||||
containers.GetItem(1)!.Clicked!(); // open bag B (column index 1 → 0xC2)
|
||||
|
||||
Assert.Equal(new[] { 0xC1u, 0xC2u }, uses.ToArray()); // Use(A) then Use(B)
|
||||
Assert.Equal(new[] { 0xC1u }, closes.ToArray()); // close A when switching to B (not the main pack)
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenBag_marksTriangleAndSquare_onTheBagCell()
|
||||
{
|
||||
var (layout, _, containers, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedBag(objects, 0xC, slot: 0);
|
||||
Bind(layout, objects, uses: new List<uint>());
|
||||
|
||||
containers.GetItem(0)!.Clicked!();
|
||||
|
||||
Assert.True(containers.GetItem(0)!.IsOpenContainer); // triangle on the open bag
|
||||
Assert.True(containers.GetItem(0)!.Selected); // square — the bag is also the selected item
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClickGridItem_movesSquareOnly_noWire_keepsOpenContainer()
|
||||
{
|
||||
var (layout, grid, _, top, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedContained(objects, 0xA, Player, slot: 0);
|
||||
var uses = new List<uint>();
|
||||
var closes = new List<uint>();
|
||||
Bind(layout, objects, uses: uses, closes: closes);
|
||||
|
||||
grid.GetItem(0)!.Clicked!(); // select the loose item
|
||||
|
||||
Assert.True(grid.GetItem(0)!.Selected); // square on the selected grid item
|
||||
Assert.True(top.GetItem(0)!.IsOpenContainer); // main pack still the open container (unchanged)
|
||||
Assert.Empty(uses); // selection sends no wire
|
||||
Assert.Empty(closes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Default_mainPackCell_isOpenContainer()
|
||||
{
|
||||
var (layout, _, _, top, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
Bind(layout, objects);
|
||||
Assert.True(top.GetItem(0)!.IsOpenContainer); // default open container = main pack
|
||||
}
|
||||
|
||||
// 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