fix(client): restore retail interaction parity
Harden keyboard and camera routing, inventory and vendor interactions, chat/emotes, relog portal flow, and paperdoll rendering. Add retail research, connected gate coverage, and release-gate validation.
This commit is contained in:
parent
0c699240e0
commit
f6fe0f2a4f
151 changed files with 10162 additions and 1211 deletions
|
|
@ -23,6 +23,7 @@ public sealed class ItemInteractionControllerTests
|
|||
public readonly List<(uint Item, uint Mask)> Wields = new();
|
||||
public readonly List<(uint Item, uint Container, int Placement)> Puts = new();
|
||||
public readonly List<(uint Item, uint Container, uint Placement, uint Amount)> SplitPuts = new();
|
||||
public readonly List<(uint Source, uint Target, uint Amount)> Merges = new();
|
||||
public readonly List<uint> ExternalRequests = new();
|
||||
public readonly List<(uint Item, uint Container, int Placement)> BackpackPlacements = new();
|
||||
public readonly List<uint> Drops = new();
|
||||
|
|
@ -130,7 +131,9 @@ public sealed class ItemInteractionControllerTests
|
|||
Sells.Add((vendorGuid, items));
|
||||
return true;
|
||||
},
|
||||
interfaceText: (text, type) => InterfaceTexts.Add((text, type)));
|
||||
interfaceText: (text, type) => InterfaceTexts.Add((text, type)),
|
||||
sendStackableMerge: (source, target, amount) =>
|
||||
Merges.Add((source, target, amount)));
|
||||
}
|
||||
|
||||
public ItemInteractionController Controller { get; }
|
||||
|
|
@ -589,7 +592,7 @@ public sealed class ItemInteractionControllerTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void EquippableItemWithFreeSlot_sendsGetAndWieldAndMovesOptimistically()
|
||||
public void EquippableItemWithFreeSlot_sendsGetAndWieldAndWaitsForServer()
|
||||
{
|
||||
var h = new Harness();
|
||||
h.AddContained(0x50000A05u, item =>
|
||||
|
|
@ -602,12 +605,12 @@ public sealed class ItemInteractionControllerTests
|
|||
|
||||
Assert.Equal(new[] { (0x50000A05u, (uint)EquipMask.HeadWear) }, h.Wields);
|
||||
var equipped = h.Objects.Get(0x50000A05u)!;
|
||||
Assert.Equal(Player, equipped.ContainerId);
|
||||
Assert.Equal(EquipMask.HeadWear, equipped.CurrentlyEquippedLocation);
|
||||
Assert.Equal(Pack, equipped.ContainerId);
|
||||
Assert.Equal(EquipMask.None, equipped.CurrentlyEquippedLocation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EquippableMultiSlotItemWithFreeSlots_sendsFullCoverageMaskAndMovesOptimistically()
|
||||
public void EquippableMultiSlotItemWithFreeSlots_sendsFullCoverageMaskAndWaitsForServer()
|
||||
{
|
||||
var h = new Harness();
|
||||
const EquipMask coatMask =
|
||||
|
|
@ -624,8 +627,8 @@ public sealed class ItemInteractionControllerTests
|
|||
|
||||
Assert.Equal(new[] { (0x50000A15u, (uint)coatMask) }, h.Wields);
|
||||
var equipped = h.Objects.Get(0x50000A15u)!;
|
||||
Assert.Equal(Player, equipped.ContainerId);
|
||||
Assert.Equal(coatMask, equipped.CurrentlyEquippedLocation);
|
||||
Assert.Equal(Pack, equipped.ContainerId);
|
||||
Assert.Equal(EquipMask.None, equipped.CurrentlyEquippedLocation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -654,7 +657,7 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.True(h.Controller.ActivateItem(0x50000A16u));
|
||||
|
||||
Assert.Equal(new[] { (0x50000A16u, (uint)coatMask) }, h.Wields);
|
||||
Assert.Equal(coatMask, h.Objects.Get(0x50000A16u)!.CurrentlyEquippedLocation);
|
||||
Assert.Equal(EquipMask.None, h.Objects.Get(0x50000A16u)!.CurrentlyEquippedLocation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -692,12 +695,13 @@ public sealed class ItemInteractionControllerTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void EquippableItemWithNoFreeSlot_sendsNothing()
|
||||
public void EquippableItemWithNoFreeSlot_movesBlockerThenWieldsAfterServerConfirm()
|
||||
{
|
||||
var h = new Harness();
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = 0x50000AF0u,
|
||||
Name = "Old Shield",
|
||||
Type = ItemType.Armor,
|
||||
CurrentlyEquippedLocation = EquipMask.Shield,
|
||||
});
|
||||
|
|
@ -712,9 +716,17 @@ public sealed class ItemInteractionControllerTests
|
|||
|
||||
bool activated = h.Controller.ActivateItem(0x50000A06u);
|
||||
|
||||
Assert.True(activated);
|
||||
Assert.Empty(h.Wields);
|
||||
Assert.False(activated);
|
||||
Assert.Equal(new[] { (0x50000AF0u, Player, 0) }, h.Puts);
|
||||
Assert.Equal(new[] { "Moving Old Shield to your backpack" }, h.SystemMessages);
|
||||
Assert.Equal(Pack, h.Objects.Get(0x50000A06u)!.ContainerId);
|
||||
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(0x50000AF0u, Player, 0u, 0));
|
||||
|
||||
Assert.Equal(
|
||||
new[] { (0x50000A06u, (uint)EquipMask.Shield) },
|
||||
h.Wields);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -752,14 +764,18 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.Equal(Pack, h.Objects.Get(bow)!.ContainerId);
|
||||
|
||||
// Authoritative 0x0022: only now does retail retry AutoWield.
|
||||
h.Objects.MoveItem(sword, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(sword, Player, 0u, 0));
|
||||
|
||||
Assert.Equal(new[] { (bow, (uint)EquipMask.MissileWeapon) }, h.Wields);
|
||||
Assert.Equal(EquipMask.None,
|
||||
h.Objects.Get(sword)!.CurrentlyEquippedLocation);
|
||||
Assert.Equal(EquipMask.None,
|
||||
h.Objects.Get(bow)!.CurrentlyEquippedLocation);
|
||||
Assert.Equal(Pack, h.Objects.Get(bow)!.ContainerId);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerWield(
|
||||
bow, Player, EquipMask.MissileWeapon));
|
||||
Assert.Equal(EquipMask.MissileWeapon,
|
||||
h.Objects.Get(bow)!.CurrentlyEquippedLocation);
|
||||
Assert.Equal(Player, h.Objects.Get(bow)!.ContainerId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -797,7 +813,7 @@ public sealed class ItemInteractionControllerTests
|
|||
// wand away. The transaction retains the initial active-combat intent
|
||||
// rather than consulting this intermediate state on its second pass.
|
||||
h.Combat.SetCombatMode(CombatMode.Melee);
|
||||
h.Objects.MoveItem(wand, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(wand, Player, 0u, 0));
|
||||
Assert.Equal(new[] { (bow, (uint)EquipMask.MissileWeapon) }, h.Wields);
|
||||
Assert.Empty(h.CombatModeRequests);
|
||||
|
||||
|
|
@ -860,7 +876,7 @@ public sealed class ItemInteractionControllerTests
|
|||
// replacement wield.
|
||||
h.Combat.SetCombatMode(CombatMode.Melee);
|
||||
h.Combat.SetCombatMode(CombatMode.NonCombat);
|
||||
h.Objects.MoveItem(bow, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(bow, Player, 0u, 0));
|
||||
Assert.Equal(new[] { (wand, (uint)EquipMask.Held) }, h.Wields);
|
||||
|
||||
Assert.True(h.Objects.ApplyConfirmedServerWield(
|
||||
|
|
@ -899,7 +915,7 @@ public sealed class ItemInteractionControllerTests
|
|||
|
||||
Assert.True(h.Controller.ActivateItem(wand));
|
||||
h.Combat.SetCombatMode(CombatMode.NonCombat);
|
||||
h.Objects.MoveItem(bow, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(bow, Player, 0u, 0));
|
||||
Assert.True(h.Objects.ApplyConfirmedServerWield(
|
||||
wand,
|
||||
Player,
|
||||
|
|
@ -935,7 +951,7 @@ public sealed class ItemInteractionControllerTests
|
|||
});
|
||||
|
||||
Assert.True(h.Controller.ActivateItem(bow));
|
||||
h.Objects.MoveItem(wand, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(wand, Player, 0u, 0));
|
||||
Assert.True(h.Objects.ApplyConfirmedServerWield(
|
||||
bow, Player, EquipMask.MissileWeapon));
|
||||
|
||||
|
|
@ -1027,7 +1043,7 @@ public sealed class ItemInteractionControllerTests
|
|||
});
|
||||
|
||||
Assert.True(h.Controller.ActivateItem(bow));
|
||||
h.Objects.MoveItem(sword, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(sword, Player, 0u, 0));
|
||||
Assert.Single(h.Wields);
|
||||
|
||||
// Bow is optimistic but ACE has not sent WieldObject yet. Retail's
|
||||
|
|
@ -1121,13 +1137,13 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.True(h.Controller.ActivateItem(bow));
|
||||
Assert.Equal(new[] { (sword, Player, 0) }, h.Puts);
|
||||
|
||||
h.Objects.MoveItem(sword, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(sword, Player, 0u, 0));
|
||||
Assert.Equal(
|
||||
new[] { (sword, Player, 0), (shield, Player, 0) },
|
||||
h.Puts);
|
||||
Assert.Empty(h.Wields);
|
||||
|
||||
h.Objects.MoveItem(shield, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(shield, Player, 0u, 0));
|
||||
Assert.Equal(new[] { (bow, (uint)EquipMask.MissileWeapon) }, h.Wields);
|
||||
}
|
||||
|
||||
|
|
@ -1164,12 +1180,12 @@ public sealed class ItemInteractionControllerTests
|
|||
});
|
||||
|
||||
Assert.True(h.Controller.ActivateItem(bow));
|
||||
h.Objects.MoveItem(sword, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(sword, Player, 0u, 0));
|
||||
Assert.Equal(
|
||||
new[] { (sword, Player, 0), (arrows, Player, 0) },
|
||||
h.Puts);
|
||||
|
||||
h.Objects.MoveItem(arrows, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(arrows, Player, 0u, 0));
|
||||
Assert.Equal(new[] { (bow, (uint)EquipMask.MissileWeapon) }, h.Wields);
|
||||
}
|
||||
|
||||
|
|
@ -1213,7 +1229,7 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.Empty(h.Wields);
|
||||
Assert.Equal(new[] { "Moving Shortbow to your backpack" }, h.SystemMessages);
|
||||
|
||||
h.Objects.MoveItem(bow, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(bow, Player, 0u, 0));
|
||||
|
||||
Assert.Equal(new[] { (sword, (uint)EquipMask.MeleeWeapon) }, h.Wields);
|
||||
Assert.Equal(EquipMask.MissileAmmo,
|
||||
|
|
@ -1247,7 +1263,7 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.Empty(h.Wields);
|
||||
Assert.Equal(new[] { "Moving Wand to your backpack" }, h.SystemMessages);
|
||||
|
||||
h.Objects.MoveItem(wand, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(wand, Player, 0u, 0));
|
||||
|
||||
Assert.Equal(new[] { (sword, (uint)EquipMask.MeleeWeapon) }, h.Wields);
|
||||
}
|
||||
|
|
@ -1292,14 +1308,14 @@ public sealed class ItemInteractionControllerTests
|
|||
crossbow, EquipMask.MissileWeapon));
|
||||
Assert.Equal(new[] { (bow, Player, 0) }, h.Puts);
|
||||
|
||||
h.Objects.MoveItem(bow, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(bow, Player, 0u, 0));
|
||||
|
||||
Assert.Equal(
|
||||
new[] { (bow, Player, 0), (arrows, Player, 0) },
|
||||
h.Puts);
|
||||
Assert.Empty(h.Wields);
|
||||
|
||||
h.Objects.MoveItem(arrows, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(arrows, Player, 0u, 0));
|
||||
|
||||
Assert.Equal(
|
||||
new[] { (crossbow, (uint)EquipMask.MissileWeapon) },
|
||||
|
|
@ -1333,7 +1349,11 @@ public sealed class ItemInteractionControllerTests
|
|||
new[] { (ring, (uint)EquipMask.FingerWearRight) },
|
||||
h.Wields);
|
||||
Assert.Equal(
|
||||
EquipMask.FingerWearRight,
|
||||
EquipMask.FingerWearLeft,
|
||||
h.Objects.Get(ring)!.CurrentlyEquippedLocation);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerWield(
|
||||
ring, Player, EquipMask.FingerWearRight));
|
||||
Assert.Equal(EquipMask.FingerWearRight,
|
||||
h.Objects.Get(ring)!.CurrentlyEquippedLocation);
|
||||
}
|
||||
|
||||
|
|
@ -1366,14 +1386,61 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.Empty(h.Wields);
|
||||
Assert.Equal(new[] { "Moving Right Ring to your backpack" }, h.SystemMessages);
|
||||
|
||||
h.Objects.MoveItem(rightRing, Player, 0, EquipMask.None);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(rightRing, Player, 0u, 0));
|
||||
|
||||
Assert.Equal(
|
||||
new[] { (leftRing, (uint)EquipMask.FingerWearRight) },
|
||||
h.Wields);
|
||||
Assert.Equal(
|
||||
EquipMask.FingerWearRight,
|
||||
EquipMask.FingerWearLeft,
|
||||
h.Objects.Get(leftRing)!.CurrentlyEquippedLocation);
|
||||
Assert.True(h.Objects.ApplyConfirmedServerWield(
|
||||
leftRing, Player, EquipMask.FingerWearRight));
|
||||
Assert.Equal(EquipMask.FingerWearRight,
|
||||
h.Objects.Get(leftRing)!.CurrentlyEquippedLocation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ActivateItem_whenEveryCompatibleSlotIsOccupied_movesRetailPreferredBlockerThenWields()
|
||||
{
|
||||
var h = new Harness();
|
||||
const uint leftRing = 0x50000B74u;
|
||||
const uint rightRing = 0x50000B75u;
|
||||
const uint requestedRing = 0x50000B76u;
|
||||
EquipMask valid = EquipMask.FingerWearLeft | EquipMask.FingerWearRight;
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = leftRing,
|
||||
Name = "Left Ring",
|
||||
Type = ItemType.Jewelry,
|
||||
ValidLocations = valid,
|
||||
});
|
||||
h.Objects.MoveItem(leftRing, Player, -1, EquipMask.FingerWearLeft);
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = rightRing,
|
||||
Name = "Right Ring",
|
||||
Type = ItemType.Jewelry,
|
||||
ValidLocations = valid,
|
||||
});
|
||||
h.Objects.MoveItem(rightRing, Player, -1, EquipMask.FingerWearRight);
|
||||
h.AddContained(requestedRing, item =>
|
||||
{
|
||||
item.Name = "New Ring";
|
||||
item.Type = ItemType.Jewelry;
|
||||
item.ValidLocations = valid;
|
||||
});
|
||||
|
||||
Assert.True(h.Controller.ActivateItem(requestedRing));
|
||||
Assert.Equal(new[] { (leftRing, Player, 0) }, h.Puts);
|
||||
Assert.Empty(h.Wields);
|
||||
Assert.Equal(new[] { "Moving Left Ring to your backpack" }, h.SystemMessages);
|
||||
|
||||
Assert.True(h.Objects.ApplyConfirmedServerMove(leftRing, Player, 0u, 0));
|
||||
|
||||
Assert.Equal(
|
||||
new[] { (requestedRing, (uint)EquipMask.FingerWearLeft) },
|
||||
h.Wields);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1400,7 +1467,7 @@ public sealed class ItemInteractionControllerTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void InventoryDragOutsideUi_sendsDropAndMovesToWorldOptimistically()
|
||||
public void InventoryDragOutsideUi_sendsDropAndWaitsForServerPlacement()
|
||||
{
|
||||
var h = new Harness();
|
||||
h.AddContained(0x50000A07u);
|
||||
|
|
@ -1413,7 +1480,7 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.True(h.Controller.DropToWorld(payload));
|
||||
|
||||
Assert.Equal(new[] { 0x50000A07u }, h.Drops);
|
||||
Assert.Equal(0u, h.Objects.Get(0x50000A07u)!.ContainerId);
|
||||
Assert.Equal(Pack, h.Objects.Get(0x50000A07u)!.ContainerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -1517,7 +1584,7 @@ public sealed class ItemInteractionControllerTests
|
|||
|
||||
Assert.Empty(h.Gives);
|
||||
Assert.Equal(new[] { item }, h.Drops);
|
||||
Assert.Equal(0u, h.Objects.Get(item)!.ContainerId);
|
||||
Assert.Equal(Pack, h.Objects.Get(item)!.ContainerId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -1898,6 +1965,126 @@ public sealed class ItemInteractionControllerTests
|
|||
Assert.False(h.Controller.TryGetPendingInventoryRequest(out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KeyboardPickup_AutoMergesWholeStackBeforeContainerPlacement()
|
||||
{
|
||||
var h = new Harness();
|
||||
const uint source = 0x70000B01u;
|
||||
const uint target = 0x50000B02u;
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = source,
|
||||
WeenieClassId = 77u,
|
||||
Name = "World stack",
|
||||
StackSize = 3,
|
||||
StackSizeMax = 10,
|
||||
});
|
||||
h.AddContained(target, item =>
|
||||
{
|
||||
item.WeenieClassId = 77u;
|
||||
item.StackSize = 5;
|
||||
item.StackSizeMax = 10;
|
||||
});
|
||||
var attempts = new List<(uint Source, uint Target)>();
|
||||
h.Controller.MergeAttempted += (from, into) => attempts.Add((from, into));
|
||||
|
||||
Assert.True(h.Controller.PlaceWorldItemInBackpack(source));
|
||||
|
||||
Assert.Equal(new[] { (source, target, 3u) }, h.Merges);
|
||||
Assert.Equal(new[] { (source, target) }, attempts);
|
||||
Assert.Empty(h.BackpackPlacements);
|
||||
Assert.True(h.Controller.TryGetPendingInventoryRequest(out var pending));
|
||||
Assert.Equal(InventoryRequestKind.Merge, pending.Kind);
|
||||
Assert.True(pending.Dispatched);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KeyboardPickup_UsesSelectedSplitQuantityAndSearchesNestedPacks()
|
||||
{
|
||||
var h = new Harness();
|
||||
const uint nestedPack = 0x50000B10u;
|
||||
const uint source = 0x70000B11u;
|
||||
const uint target = 0x50000B12u;
|
||||
h.AddContained(nestedPack, item => item.Type = ItemType.Container);
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = source,
|
||||
WeenieClassId = 88u,
|
||||
StackSize = 10,
|
||||
StackSizeMax = 10,
|
||||
});
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = target,
|
||||
WeenieClassId = 88u,
|
||||
StackSize = 8,
|
||||
StackSizeMax = 10,
|
||||
});
|
||||
h.Objects.MoveItem(target, nestedPack, 0);
|
||||
h.SelectedObject = source;
|
||||
h.SplitQuantity.Reset(10u, 2u);
|
||||
|
||||
Assert.True(h.Controller.PlaceWorldItemInBackpack(source));
|
||||
|
||||
Assert.Equal(new[] { (source, target, 2u) }, h.Merges);
|
||||
Assert.Empty(h.BackpackPlacements);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void KeyboardPickup_SkipsPartialMergeTargetAndFallsBackToPlacement()
|
||||
{
|
||||
var h = new Harness();
|
||||
const uint source = 0x70000B20u;
|
||||
const uint partialTarget = 0x50000B21u;
|
||||
h.Objects.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = source,
|
||||
WeenieClassId = 99u,
|
||||
StackSize = 3,
|
||||
StackSizeMax = 10,
|
||||
});
|
||||
h.AddContained(partialTarget, item =>
|
||||
{
|
||||
item.WeenieClassId = 99u;
|
||||
item.StackSize = 9;
|
||||
item.StackSizeMax = 10;
|
||||
});
|
||||
|
||||
Assert.True(h.Controller.PlaceWorldItemInBackpack(source));
|
||||
|
||||
Assert.Empty(h.Merges);
|
||||
Assert.Equal(new[] { (source, Player, 0) }, h.BackpackPlacements);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TrySplitToContainerDispatchesTheExactSelectedQuantity()
|
||||
{
|
||||
var h = new Harness();
|
||||
const uint source = 0x50000A30u;
|
||||
h.AddContained(source, item => item.StackSize = 10);
|
||||
|
||||
Assert.True(h.Controller.TrySplitToContainer(source, Pack, 3u, 2u));
|
||||
|
||||
Assert.Equal(new[] { (source, Pack, 3u, 2u) }, h.SplitPuts);
|
||||
Assert.True(h.Controller.TryGetPendingInventoryRequest(out var pending));
|
||||
Assert.Equal(InventoryRequestKind.SplitToContainer, pending.Kind);
|
||||
Assert.Equal(source, pending.ItemId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TrySplitToContainerRejectsZeroAndWholeStackAmounts()
|
||||
{
|
||||
var h = new Harness();
|
||||
const uint source = 0x50000A31u;
|
||||
h.AddContained(source, item => item.StackSize = 10);
|
||||
|
||||
Assert.False(h.Controller.TrySplitToContainer(source, Pack, 0u, 0u));
|
||||
Assert.False(h.Controller.TrySplitToContainer(source, Pack, 0u, 10u));
|
||||
|
||||
Assert.Empty(h.SplitPuts);
|
||||
Assert.False(h.Controller.TryGetPendingInventoryRequest(out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchingInventoryFailureReleasesGlobalRequest()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue