fix(items): complete retail corpse looting feedback
Route corpse Use through the shared ItemHolder policy so Stuck corpses open instead of being sent as pickup requests. Restore the framed, horizontally resizable external-container strip and use a compact initial width. Port retail's target-list pending item projection so loot is marked in the chosen inventory slot without changing canonical ownership before the server confirms. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
20ce67b625
commit
d51a0fc825
13 changed files with 275 additions and 102 deletions
|
|
@ -627,6 +627,68 @@ public class InventoryControllerTests
|
|||
Assert.Equal(Player, objects.Get(0xFFFFu)!.ContainerId); // moved locally (instant)
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LootDrop_InsertsWaitingProjectionAtChosenSlotUntilServerConfirms()
|
||||
{
|
||||
const uint chest = 0x70000001u;
|
||||
const uint loot = 0x70000002u;
|
||||
var (layout, grid, _, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedContained(objects, 0xAu, Player, slot: 0);
|
||||
SeedContained(objects, 0xBu, Player, slot: 1);
|
||||
SeedContained(objects, loot, chest, slot: 0, type: ItemType.Misc);
|
||||
var selection = new SelectionState();
|
||||
selection.Select(loot, SelectionChangeSource.ExternalContainer);
|
||||
var puts = new List<(uint item, uint container, int placement)>();
|
||||
using var ctrl = Bind(layout, objects, puts: puts, selection: selection);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Ground };
|
||||
source.SetItem(loot, 0u);
|
||||
var payload = new ItemDragPayload(loot, ItemDragSource.Ground, 0, source);
|
||||
|
||||
ctrl.HandleDropRelease(grid, grid.GetItem(1)!, payload);
|
||||
|
||||
Assert.Equal(new[] { (loot, Player, 1) }, puts);
|
||||
Assert.Equal(chest, objects.Get(loot)!.ContainerId);
|
||||
Assert.Equal(loot, grid.GetItem(1)!.ItemId);
|
||||
Assert.True(grid.GetItem(1)!.WaitingVisual);
|
||||
Assert.True(grid.GetItem(1)!.Selected);
|
||||
Assert.Equal(0xBu, grid.GetItem(2)!.ItemId);
|
||||
|
||||
objects.ApplyConfirmedServerMove(loot, Player, 0u, newSlot: 1);
|
||||
|
||||
UiItemSlot confirmed = Enumerable.Range(0, grid.GetNumUIItems())
|
||||
.Select(i => grid.GetItem(i)!)
|
||||
.Single(cell => cell.ItemId == loot);
|
||||
Assert.False(confirmed.WaitingVisual);
|
||||
Assert.Equal(Player, objects.Get(loot)!.ContainerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LootDrop_ServerFailureRemovesOnlyThePendingProjection()
|
||||
{
|
||||
const uint chest = 0x70000001u;
|
||||
const uint loot = 0x70000002u;
|
||||
var (layout, grid, _, _, _, _, _, _) = BuildLayout();
|
||||
var objects = new ClientObjectTable();
|
||||
SeedContained(objects, 0xAu, Player, slot: 0);
|
||||
SeedContained(objects, loot, chest, slot: 0, type: ItemType.Misc);
|
||||
var puts = new List<(uint item, uint container, int placement)>();
|
||||
using var ctrl = Bind(layout, objects, puts: puts);
|
||||
var source = new UiItemSlot { SourceKind = ItemDragSource.Ground };
|
||||
source.SetItem(loot, 0u);
|
||||
var payload = new ItemDragPayload(loot, ItemDragSource.Ground, 0, source);
|
||||
|
||||
ctrl.HandleDropRelease(grid, grid.GetItem(1)!, payload);
|
||||
Assert.Equal(loot, grid.GetItem(1)!.ItemId);
|
||||
|
||||
objects.RejectMove(loot, weenieError: 0x29u);
|
||||
|
||||
Assert.DoesNotContain(
|
||||
Enumerable.Range(0, grid.GetNumUIItems()).Select(i => grid.GetItem(i)!.ItemId),
|
||||
id => id == loot);
|
||||
Assert.Equal(chest, objects.Get(loot)!.ContainerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Drop_onEmptyGridCell_appendsToFirstEmpty()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue