acdream/tests/AcDream.Core.Tests/Items/ItemInteractionPolicyTests.cs

289 lines
10 KiB
C#

using AcDream.Core.Items;
namespace AcDream.Core.Tests.Items;
public sealed class ItemInteractionPolicyTests
{
private const uint Player = 0x50000001u;
private const uint GroundContainer = 0x70000001u;
[Fact]
public void DetermineUseResult_looseItemAndComponentPack_matchRetailPickupBranch()
{
Assert.Equal(ItemPrimaryUseResult.PlaceInBackpack,
Determine(Obj(0x6001)));
var requiresSlot = Obj(0x6002) with
{
Flags = PublicWeenieFlags.RequiresPackSlot,
ItemsCapacity = 12,
};
Assert.Equal(ItemPrimaryUseResult.None, Determine(requiresSlot));
Assert.Equal(ItemPrimaryUseResult.PlaceInBackpack,
Determine(requiresSlot with { IsComponentPack = true }));
}
[Fact]
public void DetermineUseResult_onlyAllowsContainedPickupFromViewedGroundContainer()
{
var item = Obj(0x6001) with { ContainerId = GroundContainer };
Assert.Equal(ItemPrimaryUseResult.None,
ItemInteractionPolicy.DetermineUseResult(item, Player, 0));
Assert.Equal(ItemPrimaryUseResult.PlaceInBackpack,
ItemInteractionPolicy.DetermineUseResult(item, Player, GroundContainer));
}
[Fact]
public void DetermineUseResult_portsAllOwnedPrimaryClassifications()
{
var owned = Obj(0x6001) with
{
ContainerId = Player,
OwnedByPlayer = true,
Flags = PublicWeenieFlags.RequiresPackSlot,
};
Assert.Equal(ItemPrimaryUseResult.WieldRight,
Determine(owned with { CombatUse = 1 }));
Assert.Equal(ItemPrimaryUseResult.WieldLeft,
Determine(owned with { CombatUse = 1, Flags = owned.Flags | PublicWeenieFlags.WieldLeft }));
Assert.Equal(ItemPrimaryUseResult.AutoSort,
Determine(owned with { ValidLocations = EquipMask.HeadWear }));
Assert.Equal(ItemPrimaryUseResult.OpenSalvage,
Determine(owned with { Type = ItemType.TinkeringTool }));
Assert.Equal(ItemPrimaryUseResult.ItemUse,
Determine(owned with { Useability = ItemUseability.Contained }));
}
[Fact]
public void DetermineUseResult_nonOwnedGameAndPlayerPaths_areDistinct()
{
Assert.Equal(ItemPrimaryUseResult.BeginGame,
Determine(Obj(0x6001) with
{
Type = ItemType.Gameboard,
Flags = PublicWeenieFlags.RequiresPackSlot,
}));
Assert.Equal(ItemPrimaryUseResult.OpenSecureTrade,
Determine(Obj(0x6002) with
{
Flags = PublicWeenieFlags.Player | PublicWeenieFlags.RequiresPackSlot,
}));
}
[Fact]
public void UseObject_excludesResultEightFromEarlyClassifiedBound_thenStillWieldsLeft()
{
var source = Obj(0x6001) with
{
ContainerId = Player,
OwnedByPlayer = true,
CombatUse = 1,
Flags = PublicWeenieFlags.RequiresPackSlot | PublicWeenieFlags.WieldLeft,
};
var decision = ItemInteractionPolicy.DecideUse(Use(source));
Assert.Equal(new[] { ItemPolicyActionKind.WieldLeft },
decision.Actions.Select(a => a.Kind));
}
[Fact]
public void UseObject_readyVendorTradeAndWieldedSourceGates_areOrdered()
{
var direct = OwnedDirect();
Assert.Empty(ItemInteractionPolicy.DecideUse(
Use(direct) with { ReadyForInventoryRequest = false }).Actions);
Assert.Empty(ItemInteractionPolicy.DecideUse(
Use(direct) with { ActiveVendorId = 0x7001, Source = direct with { ContainerId = 0x7001 } }).Actions);
Assert.Equal(ItemPolicyActionKind.Reject,
Assert.Single(ItemInteractionPolicy.DecideUse(
Use(direct with { TradeState = 1 })).Actions).Kind);
Assert.Contains("wield", Assert.Single(ItemInteractionPolicy.DecideUse(
Use(direct with { Useability = ItemUseability.Wielded })).Actions).Message,
StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void UseObject_targetedUse_appliesKindAndLocationGate_thenSendsAndMarksBusy()
{
var source = OwnedDirect() with
{
Useability = 0x00080008u,
TargetType = (uint)ItemType.Misc,
};
var target = Obj(0x6002) with
{
ContainerId = Player,
OwnedByPlayer = true,
Type = ItemType.Misc,
};
var decision = ItemInteractionPolicy.DecideUse(Use(source) with
{
UseCurrentSelection = true,
SelectedTarget = target,
});
Assert.Equal(new[]
{
ItemPolicyActionKind.SendUseWithTarget,
ItemPolicyActionKind.IncrementBusy,
}, decision.Actions.Select(a => a.Kind));
}
[Theory]
[InlineData(PublicWeenieFlags.PlayerKillerSwitch, ItemPolicyActionKind.ConfirmPlayerKillerSwitch)]
[InlineData(PublicWeenieFlags.NonPlayerKillerSwitch, ItemPolicyActionKind.ConfirmNonPlayerKillerSwitch)]
[InlineData(PublicWeenieFlags.VolatileRare, ItemPolicyActionKind.ConfirmVolatileRare)]
public void UseObject_confirmationFlags_blockWireUse(
PublicWeenieFlags flag,
ItemPolicyActionKind expected)
{
var decision = ItemInteractionPolicy.DecideUse(
Use(OwnedDirect() with { Flags = flag | PublicWeenieFlags.RequiresPackSlot }));
Assert.Equal(expected, Assert.Single(decision.Actions).Kind);
}
[Fact]
public void Placement_vendorAndSecureTrade_actButPreserveRetailFalseReturn()
{
var item = OwnedDirect() with { StackSize = 10, MaxSplitSize = 10 };
var vendor = Obj(0x7001) with { Flags = PublicWeenieFlags.Vendor };
var sale = ItemInteractionPolicy.DecidePlacement(Place(item, vendor));
Assert.False(sale.ReturnValue);
Assert.Equal(ItemPolicyActionKind.SellToVendor, Assert.Single(sale.Actions).Kind);
var player = Obj(0x7002) with { Flags = PublicWeenieFlags.Player };
var trade = ItemInteractionPolicy.DecidePlacement(Place(item, player));
Assert.False(trade.ReturnValue);
Assert.Equal(ItemPolicyActionKind.StartSecureTrade, Assert.Single(trade.Actions).Kind);
}
[Fact]
public void Placement_groundStackAndAirborneMatrix_matchesRetail()
{
var item = OwnedDirect() with { StackSize = 10, MaxSplitSize = 10 };
var airborne = ItemInteractionPolicy.DecidePlacement(PlaceOnGround(item) with
{
PlayerOnGround = false,
});
Assert.False(airborne.ReturnValue);
Assert.Equal(ItemPolicyActionKind.Reject, Assert.Single(airborne.Actions).Kind);
var split = ItemInteractionPolicy.DecidePlacement(PlaceOnGround(item) with { SplitSize = 4 });
Assert.True(split.ReturnValue);
Assert.Equal(ItemPolicyActionKind.SplitToWorld, Assert.Single(split.Actions).Kind);
var full = ItemInteractionPolicy.DecidePlacement(PlaceOnGround(item));
Assert.True(full.ReturnValue);
Assert.Equal(ItemPolicyActionKind.DropToWorld, Assert.Single(full.Actions).Kind);
var alreadyWorld = ItemInteractionPolicy.DecidePlacement(
PlaceOnGround(item with { IsIn3DView = true }));
Assert.False(alreadyWorld.ReturnValue);
Assert.Contains("cancelled", Assert.Single(alreadyWorld.Actions).Message,
StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void Placement_containerRequiresOpenableAndCurrentGroundObject()
{
var item = OwnedDirect();
var container = Obj(GroundContainer) with { IsContainer = true };
var locked = ItemInteractionPolicy.DecidePlacement(Place(item, container) with
{
GroundObjectId = GroundContainer,
});
Assert.False(locked.ReturnValue);
var open = container with { Flags = PublicWeenieFlags.Openable };
var closedView = ItemInteractionPolicy.DecidePlacement(Place(item, open));
Assert.False(closedView.ReturnValue);
var placed = ItemInteractionPolicy.DecidePlacement(Place(item, open) with
{
GroundObjectId = GroundContainer,
});
Assert.True(placed.ReturnValue);
Assert.Equal(ItemPolicyActionKind.PlaceInContainer, Assert.Single(placed.Actions).Kind);
}
private static ItemPrimaryUseResult Determine(ItemPolicyObject item)
=> ItemInteractionPolicy.DetermineUseResult(item, Player, 0);
private static ItemPolicyObject OwnedDirect()
=> Obj(0x6001) with
{
ContainerId = Player,
OwnedByPlayer = true,
Flags = PublicWeenieFlags.RequiresPackSlot,
Useability = ItemUseability.Contained,
};
private static ItemPolicyObject Obj(uint id) => new(
id,
ItemType.Misc,
PublicWeenieFlags.None,
ContainerId: 0,
WielderId: 0,
ValidLocations: EquipMask.None,
CurrentLocation: EquipMask.None,
CombatUse: 0,
ItemsCapacity: 0,
ContainersCapacity: 0,
Useability: 0,
TargetType: 0,
OwnedByPlayer: false,
IsContainer: false,
IsComponentPack: false,
TradeState: 0,
StackSize: 1,
MaxSplitSize: 1,
IsIn3DView: false);
private static ItemUsePolicyInput Use(ItemPolicyObject source) => new(
source,
Player,
GroundObjectId: 0,
ReadyForInventoryRequest: true,
ActiveVendorId: 0,
BypassClassification: false,
UseCurrentSelection: false,
SelectedTarget: null,
ConfirmVolatileRareUses: true,
InNonCombatMode: false);
private static ItemPlacementPolicyInput Place(
ItemPolicyObject item,
ItemPolicyObject target) => new(
item,
Player,
GroundObjectId: 0,
ReadyForInventoryRequest: true,
TargetId: target.Id,
Target: target,
AllowGroundFallback: false,
MergeAccepted: false,
DragOnPlayerOpensSecureTrade: true,
PlayerOnGround: true,
SplitSize: item.StackSize);
private static ItemPlacementPolicyInput PlaceOnGround(ItemPolicyObject item) => new(
item,
Player,
GroundObjectId: 0,
ReadyForInventoryRequest: true,
TargetId: 0,
Target: null,
AllowGroundFallback: true,
MergeAccepted: false,
DragOnPlayerOpensSecureTrade: true,
PlayerOnGround: true,
SplitSize: item.StackSize);
}