using System; using System.Linq; using AcDream.Core.Items; using Xunit; namespace AcDream.Core.Tests.Properties; /// /// Pins the three item-data enums the 2026-07-29 campaign added — all of them describe /// fields acdream already parses off the wire and stored as bare numbers. Tables are /// transcribed from docs/research/named-retail/acclient.h. /// public sealed class ItemWireEnumConformanceTests { /// acclient.h:4221, enum AMMO_TYPE. public static TheoryData RetailAmmoType => new() { { "None", 0x0 }, { "Arrow", 0x1 }, { "Bolt", 0x2 }, { "Atlatl", 0x4 }, { "ArrowCrystal", 0x8 }, { "BoltCrystal", 0x10 }, { "AtlatlCrystal", 0x20 }, { "ArrowChorizite", 0x40 }, { "BoltChorizite", 0x80 }, { "AtlatlChorizite", 0x100 }, }; [Theory] [MemberData(nameof(RetailAmmoType))] public void AmmoTypeMatchesRetail(string name, uint value) { Assert.True(Enum.IsDefined(typeof(AmmoType), name), $"AmmoType.{name} is missing"); Assert.Equal(value, (uint)Enum.Parse(name)); } [Fact] public void AmmoTypeDeclaresNothingRetailDoesNot() { var expected = RetailAmmoType.Select(r => (string)r[0]).OrderBy(n => n, StringComparer.Ordinal); Assert.Equal(expected, Enum.GetNames().OrderBy(n => n, StringComparer.Ordinal)); } /// acclient.h:6523, enum COMBAT_USE. [Theory] [InlineData("None", 0u)] [InlineData("Melee", 1u)] [InlineData("Missile", 2u)] [InlineData("Ammo", 3u)] [InlineData("Shield", 4u)] [InlineData("TwoHanded", 5u)] public void CombatUseMatchesRetail(string name, uint value) { Assert.True(Enum.IsDefined(typeof(CombatUse), name), $"CombatUse.{name} is missing"); Assert.Equal(value, (uint)Enum.Parse(name)); } /// acclient.h:6478, enum ITEM_USEABLE, including the composites. public static TheoryData RetailItemUseable => new() { { "Undef", 0x0 }, { "No", 0x1 }, { "Self", 0x2 }, { "Wielded", 0x4 }, { "Contained", 0x8 }, { "Viewed", 0x10 }, { "ContainedViewed", 0x18 }, { "Remote", 0x20 }, { "ViewedRemote", 0x30 }, { "ContainedViewedRemote", 0x38 }, { "NeverWalk", 0x40 }, { "RemoteNeverWalk", 0x60 }, { "ViewedRemoteNeverWalk", 0x70 }, { "ContainedViewedRemoteNeverWalk", 0x78 }, { "ObjSelf", 0x80 }, { "SourceMask", 0xFFFF }, { "SourceWieldedTargetWielded", 0x40004 }, { "SourceContainedTargetWielded", 0x40008 }, { "SourceViewedTargetWielded", 0x40010 }, { "SourceRemoteTargetWielded", 0x40020 }, { "SourceWieldedTargetContained", 0x80004 }, { "SourceContainedTargetContained", 0x80008 }, { "SourceViewedTargetContained", 0x80010 }, { "SourceRemoteTargetContained", 0x80020 }, { "SourceContainedTargetSelfOrContained", 0xA0008 }, { "SourceWieldedTargetViewed", 0x100004 }, { "SourceContainedTargetViewed", 0x100008 }, { "SourceViewedTargetViewed", 0x100010 }, { "SourceRemoteTargetViewed", 0x100020 }, { "SourceWieldedTargetRemote", 0x200004 }, { "SourceContainedTargetRemote", 0x200008 }, { "SourceViewedTargetRemote", 0x200010 }, { "SourceRemoteTargetRemote", 0x200020 }, { "SourceContainedTargetRemoteOrSelf", 0x220008 }, { "SourceWieldedTargetRemoteNeverWalk", 0x600004 }, { "SourceContainedTargetRemoteNeverWalk", 0x600008 }, { "SourceRemoteTargetRemoteNeverWalk", 0x600020 }, { "SourceContainedTargetObjSelfOrContained", 0x880008 }, { "TargetMask", 0xFFFF0000 }, }; [Theory] [MemberData(nameof(RetailItemUseable))] public void ItemUseableMatchesRetail(string name, uint value) { Assert.True(Enum.IsDefined(typeof(ItemUseable), name), $"ItemUseable.{name} is missing"); Assert.Equal(value, (uint)Enum.Parse(name)); } [Fact] public void ItemUseableDeclaresNothingRetailDoesNot() { var expected = RetailItemUseable.Select(r => (string)r[0]).OrderBy(n => n, StringComparer.Ordinal); Assert.Equal(expected, Enum.GetNames().OrderBy(n => n, StringComparer.Ordinal)); } /// /// The two halves partition the word, and at least one retail composite is /// deliberately not the obvious union — which is why they are transcribed rather /// than composed. /// [Fact] public void ItemUseableSourceAndTargetMasksPartitionTheWord() { Assert.Equal(0u, (uint)ItemUseable.SourceMask & (uint)ItemUseable.TargetMask); Assert.Equal(uint.MaxValue, (uint)ItemUseable.SourceMask | (uint)ItemUseable.TargetMask); uint naiveUnion = (uint)ItemUseable.ObjSelf | (uint)ItemUseable.Contained | ((uint)ItemUseable.Contained << 16); Assert.NotEqual(naiveUnion, (uint)ItemUseable.SourceContainedTargetObjSelfOrContained); } }