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
|
|
@ -54,7 +54,7 @@ public class InventoryControllerTests
|
|||
}
|
||||
|
||||
private static InventoryController Bind(ImportedLayout layout, ClientObjectTable objects,
|
||||
int? strength = 100, List<uint>? uses = null, List<uint>? closes = null,
|
||||
int? strength = 100, List<uint>? uses = null,
|
||||
List<(uint item, uint container, int placement)>? puts = null,
|
||||
List<(uint item, uint container, uint placement, uint amount)>? splits = null,
|
||||
List<(uint source, uint target, uint amount)>? merges = null,
|
||||
|
|
@ -68,7 +68,6 @@ public class InventoryControllerTests
|
|||
strength: () => strength, datFont: null,
|
||||
ownerName: ownerName is null ? null : () => ownerName,
|
||||
sendUse: uses is null ? null : g => uses.Add(g),
|
||||
sendNoLongerViewing: closes is null ? null : g => closes.Add(g),
|
||||
sendPutItemInContainer: puts is null ? null : (i, c, p) => puts.Add((i, c, p)),
|
||||
sendStackableSplitToContainer: splits is null
|
||||
? null
|
||||
|
|
@ -410,7 +409,7 @@ public class InventoryControllerTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void ClickMainPackCell_afterBag_closesBag_returnsToMainPack()
|
||||
public void ClickMainPackCell_afterBag_returnsToMainPack_withoutExternalCloseWire()
|
||||
{
|
||||
var (layout, grid, containers, top, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
|
|
@ -418,34 +417,30 @@ public class InventoryControllerTests
|
|||
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);
|
||||
var ctrl = Bind(layout, objects, uses: uses);
|
||||
|
||||
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()
|
||||
public void SwitchBetweenTwoBags_opensEach_withoutExternalCloseWire()
|
||||
{
|
||||
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);
|
||||
Bind(layout, objects, uses: uses);
|
||||
|
||||
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]
|
||||
|
|
@ -469,15 +464,13 @@ public class InventoryControllerTests
|
|||
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);
|
||||
Bind(layout, objects, uses: uses);
|
||||
|
||||
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]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue