diff --git a/src/AcDream.Core/Properties/PropertyBool.cs b/src/AcDream.Core/Properties/PropertyBool.cs new file mode 100644 index 00000000..3989866d --- /dev/null +++ b/src/AcDream.Core/Properties/PropertyBool.cs @@ -0,0 +1,221 @@ +// +// Regenerate with the 2026-07-29 enum verification campaign tooling; see +// docs/research/2026-07-29-enum-verification-campaign.md for the oracle set, +// the extraction method, and the open-question ledger. +// Hand edits are pinned by PropertyEnumConformanceTests — change the oracle, +// not the enum. +// + +namespace AcDream.Core.Properties; + +/// +/// AC's PropertyBool property table — the numeric keys the server sends in +/// PrivateUpdatePropertyBool (0x02C9) / PublicUpdatePropertyBool (0x02CA) +/// and in the property bundles carried by CreateObject / PlayerDescription / +/// IdentifyResponse. The CLR payload for this table is bool. +/// +/// Verified 2026-07-29 against two independent oracles: the vendored +/// client-side enum catalog (references/acclientlib/UtilityBelt.Common/Enums/Enums.cs, +/// which names this table BoolId) and the 38,985-file ACE weenie export corpus +/// (references/weenies/), whose per-stat _comment carries the enum member +/// name beside the numeric key. 59 of these 131 members are attested by BOTH +/// oracles with zero value conflicts; the remainder are single-sourced from the +/// catalog because no weenie in the corpus sets them. +/// +/// This enum is a vocabulary, not a parser contract: the wire carries a raw +/// uint and unknown keys must still round-trip untouched, so never assume a +/// received key is a defined member. +/// +public enum PropertyBool : uint +{ + Undef = 0, + /// 21884 weenie attestations. + Stuck = 1, + /// 1077 weenie attestations. + Open = 2, + /// 646 weenie attestations. + Locked = 3, + RotProof = 4, + AllegianceUpdateRequest = 5, + /// 1282 weenie attestations. + AiUsesMana = 6, + /// 16 weenie attestations. + AiUseHumanMagicAnimations = 7, + /// 853 weenie attestations. + AllowGive = 8, + CurrentlyAttacking = 9, + AttackerAi = 10, + /// 6212 weenie attestations. + IgnoreCollisions = 11, + /// 9020 weenie attestations. + ReportCollisions = 12, + /// 15282 weenie attestations. + Ethereal = 13, + /// 7376 weenie attestations. + GravityStatus = 14, + /// 3382 weenie attestations. + LightsStatus = 15, + /// 139 weenie attestations. + ScriptedCollision = 16, + /// 475 weenie attestations. + Inelastic = 17, + /// 1677 weenie attestations. + Visibility = 18, + /// 3972 weenie attestations. + Attackable = 19, + SafeSpellComponents = 20, + AdvocateState = 21, + /// 15455 weenie attestations. + Inscribable = 22, + /// 7755 weenie attestations. + DestroyOnSell = 23, + /// 6728 weenie attestations. + UiHidden = 24, + IgnoreHouseBarriers = 25, + HiddenAdmin = 26, + PkWounder = 27, + PkKiller = 28, + /// 262 weenie attestations. + NoCorpse = 29, + UnderLifestoneProtection = 30, + ItemManaUpdatePending = 31, + GeneratorStatus = 32, + /// 831 weenie attestations. + ResetMessagePending = 33, + /// 831 weenie attestations. + DefaultOpen = 34, + /// 511 weenie attestations. + DefaultLocked = 35, + DefaultOn = 36, + OpenForBusiness = 37, + IsFrozen = 38, + /// 1049 weenie attestations. + DealMagicalItems = 39, + LogoffImDead = 40, + /// 2208 weenie attestations. + ReportCollisionsAsEnvironment = 41, + /// 1327 weenie attestations. + AllowEdgeSlide = 42, + AdvocateQuest = 43, + IsAdmin = 44, + IsArch = 45, + IsSentinel = 46, + IsAdvocate = 47, + CurrentlyPoweringUp = 48, + GeneratorEnteredWorld = 49, + /// 890 weenie attestations. + NeverFailCasting = 50, + /// 264 weenie attestations. + VendorService = 51, + /// 1421 weenie attestations. + AiImmobile = 52, + /// 1 weenie attestations. + DamagedByCollisions = 53, + /// 34 weenie attestations. + IsDynamic = 54, + /// 81 weenie attestations. + IsHot = 55, + IsAffecting = 56, + /// 49 weenie attestations. + AffectsAis = 57, + SpellQueueActive = 58, + GeneratorDisabled = 59, + IsAcceptingTells = 60, + /// 1 weenie attestations. + LoggingChannel = 61, + /// 5 weenie attestations. + OpensAnyLock = 62, + /// 20 weenie attestations. + UnlimitedUse = 63, + GeneratedTreasureItem = 64, + /// 97 weenie attestations. + IgnoreMagicResist = 65, + /// 87 weenie attestations. + IgnoreMagicArmor = 66, + AiAllowTrade = 67, + /// 2 weenie attestations. + SpellComponentsRequired = 68, + /// 4617 weenie attestations. + IsSellable = 69, + /// 4 weenie attestations. + IgnoreShieldsBySkill = 70, + /// 6275 weenie attestations. + NoDraw = 71, + ActivationUntargeted = 72, + HouseHasGottenPriorityBootPos = 73, + /// 12 weenie attestations. + GeneratorAutomaticDestruction = 74, + HouseHooksVisible = 75, + /// 8 weenie attestations. + HouseRequiresMonarch = 76, + HouseHooksEnabled = 77, + HouseNotifiedHudOfHookCount = 78, + /// 15 weenie attestations. + AiAcceptEverything = 79, + IgnorePortalRestrictions = 80, + /// 5 weenie attestations. + RequiresBackpackSlot = 81, + /// 444 weenie attestations. + DontTurnOrMoveWhenGiving = 82, + /// 442 weenie attestations. + NpcLooksLikeObject = 83, + /// 210 weenie attestations. + IgnoreCloIcons = 84, + /// 178 weenie attestations. + AppraisalHasAllowedWielder = 85, + ChestRegenOnClose = 86, + LogoffInMinigame = 87, + /// 17 weenie attestations. + PortalShowDestination = 88, + /// 30 weenie attestations. + PortalIgnoresPkAttackTimer = 89, + /// 43 weenie attestations. + NpcInteractsSilently = 90, + /// 230 weenie attestations. + Retained = 91, + /// 1 weenie attestations. + IgnoreAuthor = 92, + Limbo = 93, + AppraisalHasAllowedActivator = 94, + ExistedBeforeAllegianceXpChanges = 95, + IsDeaf = 96, + IsPsr = 97, + Invincible = 98, + /// 1068 weenie attestations. + Ivoryable = 99, + /// 687 weenie attestations. + Dyable = 100, + CanGenerateRare = 101, + CorpseGeneratedRare = 102, + /// 14 weenie attestations. + NonProjectileMagicImmune = 103, + ActdReceivedItems = 104, + Unknown105 = 105, + FirstEnterWorldDone = 106, + RecallsDisabled = 107, + /// 13 weenie attestations. + RareUsesTimer = 108, + ActdPreorderReceivedItems = 109, + Afk = 110, + IsGagged = 111, + ProcSpellSelfTargeted = 112, + IsAllegianceGagged = 113, + EquipmentSetTriggerPiece = 114, + Uninscribe = 115, + WieldOnUse = 116, + ChestClearedWhenClosed = 117, + NeverAttack = 118, + SuppressGenerateEffect = 119, + TreasureCorpse = 120, + EquipmentSetAddLevel = 121, + BarberActive = 122, + TopLayerPriority = 123, + NoHeldItemShown = 124, + LoginAtLifestone = 125, + OlthoiPk = 126, + Account15Days = 127, + HadNoVitae = 128, + NoOlthoiTalk = 129, + /// 14 weenie attestations. + AutowieldLeft = 130, +} diff --git a/src/AcDream.Core/Properties/PropertyDataId.cs b/src/AcDream.Core/Properties/PropertyDataId.cs new file mode 100644 index 00000000..2d22b902 --- /dev/null +++ b/src/AcDream.Core/Properties/PropertyDataId.cs @@ -0,0 +1,134 @@ +// +// Regenerate with the 2026-07-29 enum verification campaign tooling; see +// docs/research/2026-07-29-enum-verification-campaign.md for the oracle set, +// the extraction method, and the open-question ledger. +// Hand edits are pinned by PropertyEnumConformanceTests — change the oracle, +// not the enum. +// + +namespace AcDream.Core.Properties; + +/// +/// AC's PropertyDataId property table — the numeric keys the server sends in +/// PrivateUpdatePropertyDataId (0x02E1) / PublicUpdatePropertyDataId (0x02E2) +/// and in the property bundles carried by CreateObject / PlayerDescription / +/// IdentifyResponse. The CLR payload for this table is uint (DAT file id). +/// +/// Verified 2026-07-29 against two independent oracles: the vendored +/// client-side enum catalog (references/acclientlib/UtilityBelt.Common/Enums/Enums.cs, +/// which names this table DataId) and the 38,985-file ACE weenie export corpus +/// (references/weenies/), whose per-stat _comment carries the enum member +/// name beside the numeric key. 41 of these 62 members are attested by BOTH +/// oracles with zero value conflicts; the remainder are single-sourced from the +/// catalog because no weenie in the corpus sets them. +/// +/// This enum is a vocabulary, not a parser contract: the wire carries a raw +/// uint and unknown keys must still round-trip untouched, so never assume a +/// received key is a defined member. +/// +public enum PropertyDataId : uint +{ + Undef = 0, + /// 38985 weenie attestations. + Setup = 1, + /// 12219 weenie attestations. + MotionTable = 2, + /// 23696 weenie attestations. + SoundTable = 3, + /// 4319 weenie attestations. + CombatTable = 4, + /// 2 weenie attestations. + QualityFilter = 5, + /// 13875 weenie attestations. + PaletteBase = 6, + /// 9049 weenie attestations. + ClothingBase = 7, + /// 38985 weenie attestations. + Icon = 8, + /// 741 weenie attestations. + EyesTexture = 9, + /// 741 weenie attestations. + NoseTexture = 10, + /// 741 weenie attestations. + MouthTexture = 11, + DefaultEyesTexture = 12, + DefaultNoseTexture = 13, + DefaultMouthTexture = 14, + /// 741 weenie attestations. + HairPalette = 15, + /// 741 weenie attestations. + EyesPalette = 16, + /// 741 weenie attestations. + SkinPalette = 17, + HeadObject = 18, + /// 4 weenie attestations. + ActivationAnimation = 19, + /// 4 weenie attestations. + InitMotion = 20, + ActivationSound = 21, + /// 23266 weenie attestations. + PhysicsEffectTable = 22, + /// 138 weenie attestations. + UseSound = 23, + /// 48 weenie attestations. + UseTargetAnimation = 24, + /// 4 weenie attestations. + UseTargetSuccessAnimation = 25, + /// 2 weenie attestations. + UseTargetFailureAnimation = 26, + /// 232 weenie attestations. + UseUserAnimation = 27, + /// 3696 weenie attestations. + Spell = 28, + /// 156 weenie attestations. + SpellComponent = 29, + /// 794 weenie attestations. + PhysicsScript = 30, + /// 497 weenie attestations. + LinkedPortalOne = 31, + /// 861 weenie attestations. + WieldedTreasureType = 32, + /// 5 weenie attestations. + UnknownGuessedname = 33, + UnknownGuessedname2 = 34, + /// 2000 weenie attestations. + DeathTreasureType = 35, + /// 2276 weenie attestations. + MutateFilter = 36, + /// 1253 weenie attestations. + ItemSkillLimit = 37, + /// 1 weenie attestations. + UseCreateItem = 38, + DeathSpell = 39, + VendorsClassId = 40, + /// 13 weenie attestations. + ItemSpecializedOnly = 41, + /// 6274 weenie attestations. + HouseId = 42, + AccountHouseId = 43, + /// 6274 weenie attestations. + RestrictionEffect = 44, + CreationMutationFilter = 45, + /// 584 weenie attestations. + TsysMutationFilter = 46, + LastPortal = 47, + /// 1 weenie attestations. + LinkedPortalTwo = 48, + OriginalPortal = 49, + /// 1000 weenie attestations. + IconOverlay = 50, + /// 16 weenie attestations. + IconOverlaySecondary = 51, + /// 554 weenie attestations. + IconUnderlay = 52, + AugmentationMutationFilter = 53, + AugmentationEffect = 54, + /// 84 weenie attestations. + ProcSpell = 55, + AugmentationCreateItem = 56, + AlternateCurrency = 57, + BlueSurgeSpell = 58, + YellowSurgeSpell = 59, + RedSurgeSpell = 60, + OlthoiDeathTreasureType = 61, +} diff --git a/src/AcDream.Core/Properties/PropertyFloat.cs b/src/AcDream.Core/Properties/PropertyFloat.cs new file mode 100644 index 00000000..e58caebb --- /dev/null +++ b/src/AcDream.Core/Properties/PropertyFloat.cs @@ -0,0 +1,289 @@ +// +// Regenerate with the 2026-07-29 enum verification campaign tooling; see +// docs/research/2026-07-29-enum-verification-campaign.md for the oracle set, +// the extraction method, and the open-question ledger. +// Hand edits are pinned by PropertyEnumConformanceTests — change the oracle, +// not the enum. +// + +namespace AcDream.Core.Properties; + +/// +/// AC's PropertyFloat property table — the numeric keys the server sends in +/// PrivateUpdatePropertyFloat (0x02D5) / PublicUpdatePropertyFloat (0x02D6) +/// and in the property bundles carried by CreateObject / PlayerDescription / +/// IdentifyResponse. The CLR payload for this table is double. +/// +/// Verified 2026-07-29 against two independent oracles: the vendored +/// client-side enum catalog (references/acclientlib/UtilityBelt.Common/Enums/Enums.cs, +/// which names this table FloatId) and the 38,985-file ACE weenie export corpus +/// (references/weenies/), whose per-stat _comment carries the enum member +/// name beside the numeric key. 86 of these 172 members are attested by BOTH +/// oracles with zero value conflicts; the remainder are single-sourced from the +/// catalog because no weenie in the corpus sets them. +/// +/// This enum is a vocabulary, not a parser contract: the wire carries a raw +/// uint and unknown keys must still round-trip untouched, so never assume a +/// received key is a defined member. +/// +public enum PropertyFloat : uint +{ + Undef = 0, + /// 4243 weenie attestations. + HeartbeatInterval = 1, + /// 4243 weenie attestations. + HeartbeatTimestamp = 2, + /// 4361 weenie attestations. + HealthRate = 3, + /// 4361 weenie attestations. + StaminaRate = 4, + /// 7706 weenie attestations. + ManaRate = 5, + /// 79 weenie attestations. + HealthUponResurrection = 6, + /// 79 weenie attestations. + StaminaUponResurrection = 7, + /// 79 weenie attestations. + ManaUponResurrection = 8, + StartTime = 9, + StopTime = 10, + /// 1749 weenie attestations. + ResetInterval = 11, + /// 3290 weenie attestations. + Shade = 12, + /// 6001 weenie attestations. + ArmorModVsSlash = 13, + /// 6005 weenie attestations. + ArmorModVsPierce = 14, + /// 6005 weenie attestations. + ArmorModVsBludgeon = 15, + /// 6005 weenie attestations. + ArmorModVsCold = 16, + /// 6005 weenie attestations. + ArmorModVsFire = 17, + /// 6005 weenie attestations. + ArmorModVsAcid = 18, + /// 6005 weenie attestations. + ArmorModVsElectric = 19, + CombatSpeed = 20, + /// 2733 weenie attestations. + WeaponLength = 21, + /// 3174 weenie attestations. + DamageVariance = 22, + CurrentPowerMod = 23, + AccuracyMod = 24, + StrengthMod = 25, + /// 1386 weenie attestations. + MaximumVelocity = 26, + /// 233 weenie attestations. + RotationSpeed = 27, + MotionTimestamp = 28, + /// 3892 weenie attestations. + WeaponDefense = 29, + WimpyLevel = 30, + /// 2169 weenie attestations. + VisualAwarenessRange = 31, + AuralAwarenessRange = 32, + PerceptionLevel = 33, + /// 1987 weenie attestations. + PowerupTime = 34, + MaxChargeDistance = 35, + /// 1892 weenie attestations. + ChargeSpeed = 36, + /// 1049 weenie attestations. + BuyPrice = 37, + /// 1049 weenie attestations. + SellPrice = 38, + /// 18233 weenie attestations. + DefaultScale = 39, + /// 10 weenie attestations. + LockpickMod = 40, + /// 2195 weenie attestations. + RegenerationInterval = 41, + RegenerationTimestamp = 42, + /// 2135 weenie attestations. + GeneratorRadius = 43, + /// 66 weenie attestations. + TimeToRot = 44, + DeathTimestamp = 45, + PkTimestamp = 46, + VictimTimestamp = 47, + LoginTimestamp = 48, + CreationTimestamp = 49, + /// 4 weenie attestations. + MinimumTimeSincePk = 50, + DeprecatedHousekeepingPriority = 51, + AbuseLoggingTimestamp = 52, + LastPortalTeleportTimestamp = 53, + /// 9152 weenie attestations. + UseRadius = 54, + /// 46 weenie attestations. + HomeRadius = 55, + ReleasedTimestamp = 56, + MinHomeRadius = 57, + Facing = 58, + ResetTimestamp = 59, + LogoffTimestamp = 60, + EconRecoveryInterval = 61, + /// 3523 weenie attestations. + WeaponOffense = 62, + /// 1223 weenie attestations. + DamageMod = 63, + /// 4361 weenie attestations. + ResistSlash = 64, + /// 4361 weenie attestations. + ResistPierce = 65, + /// 4361 weenie attestations. + ResistBludgeon = 66, + /// 4361 weenie attestations. + ResistFire = 67, + /// 4361 weenie attestations. + ResistCold = 68, + /// 4361 weenie attestations. + ResistAcid = 69, + /// 4361 weenie attestations. + ResistElectric = 70, + /// 4361 weenie attestations. + ResistHealthBoost = 71, + /// 4361 weenie attestations. + ResistStaminaDrain = 72, + /// 4361 weenie attestations. + ResistStaminaBoost = 73, + /// 4361 weenie attestations. + ResistManaDrain = 74, + /// 4361 weenie attestations. + ResistManaBoost = 75, + /// 794 weenie attestations. + Translucency = 76, + /// 269 weenie attestations. + PhysicsScriptIntensity = 77, + /// 761 weenie attestations. + Friction = 78, + /// 761 weenie attestations. + Elasticity = 79, + /// 1076 weenie attestations. + AiUseMagicDelay = 80, + ItemMinSpellcraftMod = 81, + ItemMaxSpellcraftMod = 82, + ItemRankProbability = 83, + Shade2 = 84, + Shade3 = 85, + Shade4 = 86, + /// 15 weenie attestations. + ItemEfficiency = 87, + ItemManaUpdateTimestamp = 88, + SpellGestureSpeedMod = 89, + SpellStanceSpeedMod = 90, + AllegianceAppraisalTimestamp = 91, + PowerLevel = 92, + AccuracyLevel = 93, + AttackAngle = 94, + AttackTimestamp = 95, + CheckpointTimestamp = 96, + SoldTimestamp = 97, + UseTimestamp = 98, + UseLockTimestamp = 99, + /// 22 weenie attestations. + HealkitMod = 100, + FrozenTimestamp = 101, + HealthRateMod = 102, + AllegianceSwearTimestamp = 103, + /// 4361 weenie attestations. + ObviousRadarRange = 104, + /// 81 weenie attestations. + HotspotCycleTime = 105, + /// 74 weenie attestations. + HotspotCycleTimeVariance = 106, + SpamTimestamp = 107, + SpamRate = 108, + /// 26 weenie attestations. + BondWieldedTreasure = 109, + /// 1039 weenie attestations. + BulkMod = 110, + /// 1039 weenie attestations. + SizeMod = 111, + GagTimestamp = 112, + GeneratorUpdateTimestamp = 113, + DeathSpamTimestamp = 114, + DeathSpamRate = 115, + WildAttackProbability = 116, + /// 312 weenie attestations. + FocusedProbability = 117, + CrashAndTurnProbability = 118, + CrashAndTurnRadius = 119, + CrashAndTurnBias = 120, + /// 186 weenie attestations. + GeneratorInitialDelay = 121, + /// 575 weenie attestations. + AiAcquireHealth = 122, + /// 6 weenie attestations. + AiAcquireStamina = 123, + /// 6 weenie attestations. + AiAcquireMana = 124, + /// 4361 weenie attestations. + ResistHealthDrain = 125, + LifestoneProtectionTimestamp = 126, + /// 72 weenie attestations. + AiCounteractEnchantment = 127, + /// 10 weenie attestations. + AiDispelEnchantment = 128, + TradeTimestamp = 129, + AiTargetedDetectionRadius = 130, + /// 29 weenie attestations. + EmotePriority = 131, + LastTeleportStartTimestamp = 132, + EventSpamTimestamp = 133, + EventSpamRate = 134, + /// 5 weenie attestations. + InventoryOffset = 135, + /// 396 weenie attestations. + CriticalMultiplier = 136, + /// 15 weenie attestations. + ManaStoneDestroyChance = 137, + /// 351 weenie attestations. + SlayerDamageBonus = 138, + AllegianceInfoSpamTimestamp = 139, + AllegianceInfoSpamRate = 140, + NextSpellcastTimestamp = 141, + AppraisalRequestedTimestamp = 142, + AppraisalHeartbeatDueTimestamp = 143, + /// 209 weenie attestations. + ManaConversionMod = 144, + LastPkAttackTimestamp = 145, + FellowshipUpdateTimestamp = 146, + /// 395 weenie attestations. + CriticalFrequency = 147, + LimboStartTimestamp = 148, + /// 356 weenie attestations. + WeaponMissileDefense = 149, + /// 368 weenie attestations. + WeaponMagicDefense = 150, + /// 87 weenie attestations. + IgnoreShield = 151, + /// 135 weenie attestations. + ElementalDamageMod = 152, + StartMissileAttackTimestamp = 153, + LastRareUsedTimestamp = 154, + /// 69 weenie attestations. + IgnoreArmor = 155, + ProcSpellRate = 156, + /// 93 weenie attestations. + ResistanceModifier = 157, + AllegianceGagTimestamp = 158, + /// 18 weenie attestations. + AbsorbMagicDamage = 159, + CachedMaxAbsorbMagicDamage = 160, + GagDuration = 161, + AllegianceGagDuration = 162, + GlobalXpMod = 163, + HealingModifier = 164, + /// 391 weenie attestations. + ArmorModVsNether = 165, + ResistNether = 166, + /// 369 weenie attestations. + CooldownDuration = 167, + WeaponAuraOffense = 168, + WeaponAuraDefense = 169, + WeaponAuraElemental = 170, + WeaponAuraManaConv = 171, +} diff --git a/src/AcDream.Core/Properties/PropertyInstanceId.cs b/src/AcDream.Core/Properties/PropertyInstanceId.cs new file mode 100644 index 00000000..c386c1ed --- /dev/null +++ b/src/AcDream.Core/Properties/PropertyInstanceId.cs @@ -0,0 +1,79 @@ +// +// Regenerate with the 2026-07-29 enum verification campaign tooling; see +// docs/research/2026-07-29-enum-verification-campaign.md for the oracle set, +// the extraction method, and the open-question ledger. +// Hand edits are pinned by PropertyEnumConformanceTests — change the oracle, +// not the enum. +// + +namespace AcDream.Core.Properties; + +/// +/// AC's PropertyInstanceId property table — the numeric keys the server sends in +/// PrivateUpdatePropertyInstanceId (0x02E5) / PublicUpdatePropertyInstanceId (0x02E6) +/// and in the property bundles carried by CreateObject / PlayerDescription / +/// IdentifyResponse. The CLR payload for this table is uint (object guid). +/// +/// Verified 2026-07-29 against two independent oracles: the vendored +/// client-side enum catalog (references/acclientlib/UtilityBelt.Common/Enums/Enums.cs, +/// which names this table InstanceId) and the 38,985-file ACE weenie export corpus +/// (references/weenies/), whose per-stat _comment carries the enum member +/// name beside the numeric key. 2 of these 46 members are attested by BOTH +/// oracles with zero value conflicts; the remainder are single-sourced from the +/// catalog because no weenie in the corpus sets them. +/// +/// This enum is a vocabulary, not a parser contract: the wire carries a raw +/// uint and unknown keys must still round-trip untouched, so never assume a +/// received key is a defined member. +/// +public enum PropertyInstanceId : uint +{ + Undef = 0, + Owner = 1, + Container = 2, + Wielder = 3, + Freezer = 4, + Viewer = 5, + Generator = 6, + Scribe = 7, + CurrentCombatTarget = 8, + CurrentEnemy = 9, + ProjectileLauncher = 10, + CurrentAttacker = 11, + CurrentDamager = 12, + CurrentFollowTarget = 13, + CurrentAppraisalTarget = 14, + CurrentFellowshipAppraisalTarget = 15, + /// 130 weenie attestations. + ActivationTarget = 16, + Creator = 17, + Victim = 18, + Killer = 19, + Vendor = 20, + Customer = 21, + Bonded = 22, + Wounder = 23, + Allegiance = 24, + Patron = 25, + Monarch = 26, + CombatTarget = 27, + HealthQueryTarget = 28, + LastUnlocker = 29, + CrashAndTurnTarget = 30, + AllowedActivator = 31, + HouseOwner = 32, + House = 33, + Slumlord = 34, + ManaQueryTarget = 35, + CurrentGame = 36, + RequestedAppraisalTarget = 37, + /// 2 weenie attestations. + AllowedWielder = 38, + AssignedTarget = 39, + LimboSource = 40, + Snooper = 41, + TeleportedCharacter = 42, + Pet = 43, + PetOwner = 44, + PetDevice = 45, +} diff --git a/src/AcDream.Core/Properties/PropertyInt.cs b/src/AcDream.Core/Properties/PropertyInt.cs new file mode 100644 index 00000000..b288dda3 --- /dev/null +++ b/src/AcDream.Core/Properties/PropertyInt.cs @@ -0,0 +1,611 @@ +// +// Regenerate with the 2026-07-29 enum verification campaign tooling; see +// docs/research/2026-07-29-enum-verification-campaign.md for the oracle set, +// the extraction method, and the open-question ledger. +// Hand edits are pinned by PropertyEnumConformanceTests — change the oracle, +// not the enum. +// + +namespace AcDream.Core.Properties; + +/// +/// AC's PropertyInt property table — the numeric keys the server sends in +/// PrivateUpdatePropertyInt (0x02CD) / PublicUpdatePropertyInt (0x02CE) +/// and in the property bundles carried by CreateObject / PlayerDescription / +/// IdentifyResponse. The CLR payload for this table is int. +/// +/// Verified 2026-07-29 against two independent oracles: the vendored +/// client-side enum catalog (references/acclientlib/UtilityBelt.Common/Enums/Enums.cs, +/// which names this table IntId) and the 38,985-file ACE weenie export corpus +/// (references/weenies/), whose per-stat _comment carries the enum member +/// name beside the numeric key. 189 of these 391 members are attested by BOTH +/// oracles with zero value conflicts; the remainder are single-sourced from the +/// catalog because no weenie in the corpus sets them. +/// +/// This enum is a vocabulary, not a parser contract: the wire carries a raw +/// uint and unknown keys must still round-trip untouched, so never assume a +/// received key is a defined member. +/// +public enum PropertyInt : uint +{ + Undef = 0, + /// UtilityBelt catalog calls this ObjectType; 37329 weenie attestations. + ItemType = 1, + /// 6140 weenie attestations. + CreatureType = 2, + /// 8344 weenie attestations. + PaletteTemplate = 3, + /// 1597 weenie attestations. + ClothingPriority = 4, + /// 25793 weenie attestations. + EncumbranceVal = 5, + /// 8633 weenie attestations. + ItemsCapacity = 6, + /// 8618 weenie attestations. + ContainersCapacity = 7, + /// 23605 weenie attestations. + Mass = 8, + /// 20797 weenie attestations. + ValidLocations = 9, + CurrentWieldedLocation = 10, + /// 4373 weenie attestations. + MaxStackSize = 11, + /// 4373 weenie attestations. + StackSize = 12, + /// 3181 weenie attestations. + StackUnitEncumbrance = 13, + /// 3181 weenie attestations. + StackUnitMass = 14, + /// 3181 weenie attestations. + StackUnitValue = 15, + /// 37280 weenie attestations. + ItemUseable = 16, + /// 21 weenie attestations. + RareId = 17, + /// 5705 weenie attestations. + UiEffects = 18, + /// 25852 weenie attestations. + Value = 19, + /// 1 weenie attestations. + CoinValue = 20, + TotalExperience = 21, + AvailableCharacter = 22, + TotalSkillCredits = 23, + AvailableSkillCredits = 24, + /// 6140 weenie attestations. + Level = 25, + /// 28 weenie attestations. + AccountRequirements = 26, + /// 5476 weenie attestations. + ArmorType = 27, + /// 1657 weenie attestations. + ArmorLevel = 28, + AllegianceCpPool = 29, + /// 1 weenie attestations. + AllegianceRank = 30, + ChannelsAllowed = 31, + ChannelsActive = 32, + /// 6252 weenie attestations. + Bonded = 33, + MonarchsRank = 34, + AllegianceFollowers = 35, + /// 997 weenie attestations. + ResistMagic = 36, + /// 575 weenie attestations. + ResistItemAppraisal = 37, + /// 677 weenie attestations. + ResistLockpick = 38, + DeprecatedResistRepair = 39, + /// 1634 weenie attestations. + CombatMode = 40, + CurrentAttackHeight = 41, + CombatCollisions = 42, + /// 1 weenie attestations. + NumDeaths = 43, + /// 3717 weenie attestations. + Damage = 44, + /// 3357 weenie attestations. + DamageType = 45, + /// 2973 weenie attestations. + DefaultCombatStyle = 46, + /// 2364 weenie attestations. + AttackType = 47, + /// 3393 weenie attestations. + WeaponSkill = 48, + /// 3394 weenie attestations. + WeaponTime = 49, + /// 972 weenie attestations. + AmmoType = 50, + /// 4499 weenie attestations. + CombatUse = 51, + /// 440 weenie attestations. + ParentLocation = 52, + /// 440 weenie attestations. + PlacementPosition = 53, + WeaponEncumbrance = 54, + WeaponMass = 55, + ShieldValue = 56, + ShieldEncumbrance = 57, + MissileInventoryLocation = 58, + FullDamageType = 59, + /// 545 weenie attestations. + WeaponRange = 60, + AttackersSkill = 61, + DefendersSkill = 62, + AttackersSkillValue = 63, + AttackersClass = 64, + Placement = 65, + /// 179 weenie attestations. + CheckpointStatus = 66, + /// 219 weenie attestations. + Tolerance = 67, + /// 2151 weenie attestations. + TargetingTactic = 68, + /// 48 weenie attestations. + CombatTactic = 69, + HomesickTargetingTactic = 70, + NumFollowFailures = 71, + /// 494 weenie attestations. + FriendType = 72, + FoeType = 73, + /// UtilityBelt catalog calls this MerchandiseObjectTypes; 1049 weenie attestations. + MerchandiseItemTypes = 74, + /// 1049 weenie attestations. + MerchandiseMinValue = 75, + /// 1049 weenie attestations. + MerchandiseMaxValue = 76, + NumItemsSold = 77, + NumItemsBought = 78, + MoneyIncome = 79, + MoneyOutflow = 80, + /// 2195 weenie attestations. + MaxGeneratedObjects = 81, + /// 2195 weenie attestations. + InitGeneratedObjects = 82, + /// 787 weenie attestations. + ActivationResponse = 83, + OriginalValue = 84, + NumMoveFailures = 85, + /// 815 weenie attestations. + MinLevel = 86, + /// 115 weenie attestations. + MaxLevel = 87, + /// 10 weenie attestations. + LockpickMod = 88, + /// 525 weenie attestations. + BoosterEnum = 89, + /// 532 weenie attestations. + BoostValue = 90, + /// 800 weenie attestations. + MaxStructure = 91, + /// 713 weenie attestations. + Structure = 92, + /// 38985 weenie attestations. + PhysicsState = 93, + /// 3570 weenie attestations. + TargetType = 94, + /// 2668 weenie attestations. + RadarBlipColor = 95, + /// 472 weenie attestations. + EncumbranceCapacity = 96, + LoginTimestamp = 97, + /// 119 weenie attestations. + CreationTimestamp = 98, + /// 4 weenie attestations. + PkLevelModifier = 99, + /// 575 weenie attestations. + GeneratorType = 100, + /// 1265 weenie attestations. + AiAllowedCombatStyle = 101, + LogoffTimestamp = 102, + /// 158 weenie attestations. + GeneratorDestructionType = 103, + ActivationCreateClass = 104, + /// 693 weenie attestations. + ItemWorkmanship = 105, + /// 4213 weenie attestations. + ItemSpellcraft = 106, + /// 4173 weenie attestations. + ItemCurMana = 107, + /// 4211 weenie attestations. + ItemMaxMana = 108, + /// 3091 weenie attestations. + ItemDifficulty = 109, + /// 1043 weenie attestations. + ItemAllegianceRankLimit = 110, + /// 2940 weenie attestations. + PortalBitmask = 111, + AdvocateLevel = 112, + /// 749 weenie attestations. + Gender = 113, + /// 4502 weenie attestations. + Attuned = 114, + /// 1640 weenie attestations. + ItemSkillLevelLimit = 115, + GateLogic = 116, + /// 66 weenie attestations. + ItemManaCost = 117, + Logoff = 118, + /// 365 weenie attestations. + Active = 119, + AttackHeight = 120, + NumAttackFailures = 121, + AiCpThreshold = 122, + AiAdvancementStrategy = 123, + Version = 124, + /// 1 weenie attestations. + Age = 125, + /// 1048 weenie attestations. + VendorHappyMean = 126, + /// 1048 weenie attestations. + VendorHappyVariance = 127, + CloakStatus = 128, + VitaeCpPool = 129, + NumServicesSold = 130, + /// 586 weenie attestations. + MaterialType = 131, + NumAllegianceBreaks = 132, + /// 10541 weenie attestations. + ShowableOnRadar = 133, + /// 3138 weenie attestations. + PlayerKillerStatus = 134, + VendorHappyMaxItems = 135, + /// 5 weenie attestations. + ScorePageNum = 136, + /// 5 weenie attestations. + ScoreConfigNum = 137, + /// 5 weenie attestations. + ScoreNumScores = 138, + DeathLevel = 139, + /// 1411 weenie attestations. + AiOptions = 140, + OpenToEveryone = 141, + /// 297 weenie attestations. + GeneratorTimeType = 142, + /// 51 weenie attestations. + GeneratorStartTime = 143, + /// 50 weenie attestations. + GeneratorEndTime = 144, + /// 257 weenie attestations. + GeneratorEndDestructionType = 145, + /// 4361 weenie attestations. + XpOverride = 146, + NumCrashAndTurns = 147, + ComponentWarningThreshold = 148, + /// 7 weenie attestations. + HouseStatus = 149, + /// 4715 weenie attestations. + HookPlacement = 150, + /// 6799 weenie attestations. + HookType = 151, + /// UtilityBelt catalog calls this HookObjectType; 5 weenie attestations. + HookItemType = 152, + AiPpThreshold = 153, + GeneratorVersion = 154, + /// 6274 weenie attestations. + HouseType = 155, + /// 10 weenie attestations. + PickupEmoteOffset = 156, + /// 1 weenie attestations. + WeenieIteration = 157, + /// 2557 weenie attestations. + WieldRequirements = 158, + /// 2557 weenie attestations. + WieldSkilltype = 159, + /// 2557 weenie attestations. + WieldDifficulty = 160, + /// 654 weenie attestations. + HouseMaxHooksUsable = 161, + HouseCurrentHooksUsable = 162, + /// 8 weenie attestations. + AllegianceMinLevel = 163, + AllegianceMaxLevel = 164, + HouseRelinkHookCount = 165, + /// 537 weenie attestations. + SlayerCreatureType = 166, + ConfirmationInProgress = 167, + ConfirmationTypeInProgress = 168, + /// 728 weenie attestations. + TsysMutationData = 169, + /// 36 weenie attestations. + NumItemsInMaterial = 170, + /// 228 weenie attestations. + NumTimesTinkered = 171, + /// 358 weenie attestations. + AppraisalLongDescDecoration = 172, + /// 133 weenie attestations. + AppraisalLockpickSuccessPercent = 173, + /// 103 weenie attestations. + AppraisalPages = 174, + /// 103 weenie attestations. + AppraisalMaxPages = 175, + /// 355 weenie attestations. + AppraisalItemSkill = 176, + /// 281 weenie attestations. + GemCount = 177, + /// 281 weenie attestations. + GemType = 178, + /// 495 weenie attestations. + ImbuedEffect = 179, + AttackersRawSkillValue = 180, + ChessRank = 181, + ChessTotalGames = 182, + ChessGamesWon = 183, + ChessGamesLost = 184, + /// 71 weenie attestations. + TypeOfAlteration = 185, + /// 71 weenie attestations. + SkillToBeAltered = 186, + SkillAlterationCount = 187, + /// 807 weenie attestations. + HeritageGroup = 188, + /// 30 weenie attestations. + TransferFromAttribute = 189, + /// 30 weenie attestations. + TransferToAttribute = 190, + AttributeTransferCount = 191, + FakeFishingSkill = 192, + /// 3 weenie attestations. + NumKeys = 193, + DeathTimestamp = 194, + PkTimestamp = 195, + VictimTimestamp = 196, + /// 22 weenie attestations. + HookGroup = 197, + AllegianceSwearTimestamp = 198, + HousePurchaseTimestamp = 199, + RedirectableEquippedArmorCount = 200, + MeleedefenseImbuedEffectTypeCache = 201, + MissileDefenseImbuedEffectTypeCache = 202, + MagicDefenseImbuedEffectTypeCache = 203, + /// 121 weenie attestations. + ElementalDamageBonus = 204, + ImbueAttempts = 205, + ImbueSuccesses = 206, + CreatureKills = 207, + PlayerKillsPk = 208, + PlayerKillsPkl = 209, + RaresTierOne = 210, + RaresTierTwo = 211, + RaresTierThree = 212, + RaresTierFour = 213, + RaresTierFive = 214, + AugmentationStat = 215, + AugmentationFamilyStat = 216, + AugmentationInnateFamily = 217, + AugmentationInnateStrength = 218, + AugmentationInnateEndurance = 219, + AugmentationInnateCoordination = 220, + AugmentationInnateQuickness = 221, + AugmentationInnateFocus = 222, + AugmentationInnateSelf = 223, + AugmentationSpecializeSalvaging = 224, + AugmentationSpecializeItemTinkering = 225, + AugmentationSpecializeArmorTinkering = 226, + AugmentationSpecializeMagicItemTinkering = 227, + AugmentationSpecializeWeaponTinkering = 228, + AugmentationExtraPackSlot = 229, + AugmentationIncreasedCarryingCapacity = 230, + AugmentationLessDeathItemLoss = 231, + AugmentationSpellsRemainPastDeath = 232, + AugmentationCriticalDefense = 233, + AugmentationBonusXp = 234, + AugmentationBonusSalvage = 235, + AugmentationBonusImbueChance = 236, + AugmentationFasterRegen = 237, + AugmentationIncreasedSpellDuration = 238, + AugmentationResistanceFamily = 239, + AugmentationResistanceSlash = 240, + AugmentationResistancePierce = 241, + AugmentationResistanceBlunt = 242, + AugmentationResistanceAcid = 243, + AugmentationResistanceFire = 244, + AugmentationResistanceFrost = 245, + AugmentationResistanceLightning = 246, + RaresTierOneLogin = 247, + RaresTierTwoLogin = 248, + RaresTierThreeLogin = 249, + RaresTierFourLogin = 250, + RaresTierFiveLogin = 251, + RaresLoginTimestamp = 252, + RaresTierSix = 253, + RaresTierSeven = 254, + RaresTierSixLogin = 255, + RaresTierSevenLogin = 256, + /// 1 weenie attestations. + ItemAttributeLimit = 257, + /// 1 weenie attestations. + ItemAttributeLevelLimit = 258, + ItemAttribute2ndLimit = 259, + ItemAttribute2ndLevelLimit = 260, + /// 2 weenie attestations. + CharacterTitleId = 261, + /// 1 weenie attestations. + NumCharacterTitles = 262, + /// 93 weenie attestations. + ResistanceModifierType = 263, + FreeTinkersBitfield = 264, + /// 316 weenie attestations. + EquipmentSetId = 265, + PetClass = 266, + /// 119 weenie attestations. + Lifespan = 267, + /// 119 weenie attestations. + RemainingLifespan = 268, + UseCreateQuantity = 269, + /// 62 weenie attestations. + WieldRequirements2 = 270, + /// 62 weenie attestations. + WieldSkilltype2 = 271, + /// 62 weenie attestations. + WieldDifficulty2 = 272, + /// 3 weenie attestations. + WieldRequirements3 = 273, + /// 3 weenie attestations. + WieldSkilltype3 = 274, + /// 3 weenie attestations. + WieldDifficulty3 = 275, + /// 17 weenie attestations. + WieldRequirements4 = 276, + /// 17 weenie attestations. + WieldSkilltype4 = 277, + /// 17 weenie attestations. + WieldDifficulty4 = 278, + /// 14 weenie attestations. + Unique = 279, + /// 365 weenie attestations. + SharedCooldown = 280, + /// 177 weenie attestations. + Faction1Bits = 281, + Faction2Bits = 282, + Faction3Bits = 283, + Hatred1Bits = 284, + Hatred2Bits = 285, + Hatred3Bits = 286, + /// 61 weenie attestations. + SocietyRankCelhan = 287, + /// 60 weenie attestations. + SocietyRankEldweb = 288, + /// 56 weenie attestations. + SocietyRankRadblo = 289, + HearLocalSignals = 290, + HearLocalSignalsRadius = 291, + /// 67 weenie attestations. + Cleaving = 292, + AugmentationSpecializeGearcraft = 293, + AugmentationInfusedCreatureMagic = 294, + AugmentationInfusedItemMagic = 295, + AugmentationInfusedLifeMagic = 296, + AugmentationInfusedWarMagic = 297, + AugmentationCriticalExpertise = 298, + AugmentationCriticalPower = 299, + AugmentationSkilledMelee = 300, + AugmentationSkilledMissile = 301, + AugmentationSkilledMagic = 302, + /// 124 weenie attestations. + ImbuedEffect2 = 303, + /// 124 weenie attestations. + ImbuedEffect3 = 304, + /// 117 weenie attestations. + ImbuedEffect4 = 305, + /// 117 weenie attestations. + ImbuedEffect5 = 306, + /// 1403 weenie attestations. + DamageRating = 307, + /// 729 weenie attestations. + DamageResistRating = 308, + AugmentationDamageBonus = 309, + AugmentationDamageReduction = 310, + ImbueStackingBits = 311, + HealOverTime = 312, + /// 880 weenie attestations. + CritRating = 313, + /// 843 weenie attestations. + CritDamageRating = 314, + /// 713 weenie attestations. + CritResistRating = 315, + /// 732 weenie attestations. + CritDamageResistRating = 316, + HealingResistRating = 317, + DamageOverTime = 318, + /// 79 weenie attestations. + ItemMaxLevel = 319, + /// 79 weenie attestations. + ItemXpStyle = 320, + EquipmentSetExtra = 321, + AetheriaBitfield = 322, + HealingBoostRating = 323, + /// 29 weenie attestations. + HeritageSpecificArmor = 324, + AlternateRacialSkills = 325, + AugmentationJackOfAllTrades = 326, + AugmentationResistanceNether = 327, + AugmentationInfusedVoidMagic = 328, + WeaknessRating = 329, + NetherOverTime = 330, + NetherResistRating = 331, + LuminanceAward = 332, + LumAugDamageRating = 333, + LumAugDamageReductionRating = 334, + LumAugCritDamageRating = 335, + LumAugCritReductionRating = 336, + LumAugSurgeEffectRating = 337, + LumAugSurgeChanceRating = 338, + LumAugItemManaUsage = 339, + LumAugItemManaGain = 340, + LumAugVitality = 341, + LumAugHealingRating = 342, + LumAugSkilledCraft = 343, + LumAugSkilledSpec = 344, + LumAugNoDestroyCraft = 345, + RestrictInteraction = 346, + OlthoiLootTimestamp = 347, + OlthoiLootStep = 348, + UseCreatesContractId = 349, + DotResistRating = 350, + LifeResistRating = 351, + /// 13 weenie attestations. + CloakWeaveProc = 352, + /// 492 weenie attestations. + WeaponType = 353, + MeleeMastery = 354, + RangedMastery = 355, + SneakAttackRating = 356, + RecklessnessRating = 357, + DeceptionRating = 358, + CombatPetRange = 359, + WeaponAuraDamage = 360, + WeaponAuraSpeed = 361, + SummoningMastery = 362, + HeartbeatLifespan = 363, + UseLevelRequirement = 364, + LumAugAllSkills = 365, + /// 259 weenie attestations. + UseRequiresSkill = 366, + /// 259 weenie attestations. + UseRequiresSkillLevel = 367, + /// 36 weenie attestations. + UseRequiresSkillSpec = 368, + /// 271 weenie attestations. + UseRequiresLevel = 369, + /// 869 weenie attestations. + GearDamage = 370, + /// 868 weenie attestations. + GearDamageResist = 371, + /// 854 weenie attestations. + GearCrit = 372, + /// 854 weenie attestations. + GearCritResist = 373, + /// 955 weenie attestations. + GearCritDamage = 374, + /// 953 weenie attestations. + GearCritDamageResist = 375, + /// 610 weenie attestations. + GearHealingBoost = 376, + /// 602 weenie attestations. + GearNetherResist = 377, + /// 602 weenie attestations. + GearLifeResist = 378, + /// 640 weenie attestations. + GearMaxHealth = 379, + Unknown380 = 380, + /// 616 weenie attestations. + PKDamageRating = 381, + /// 602 weenie attestations. + PKDamageResistRating = 382, + /// 643 weenie attestations. + GearPKDamageRating = 383, + /// 640 weenie attestations. + GearPKDamageResistRating = 384, + Unknown385 = 385, + /// 766 weenie attestations. + Overpower = 386, + /// 602 weenie attestations. + OverpowerResist = 387, + /// 602 weenie attestations. + GearOverpower = 388, + /// 602 weenie attestations. + GearOverpowerResist = 389, + /// 2 weenie attestations. + Enlightenment = 390, +} diff --git a/src/AcDream.Core/Properties/PropertyInt64.cs b/src/AcDream.Core/Properties/PropertyInt64.cs new file mode 100644 index 00000000..e6792529 --- /dev/null +++ b/src/AcDream.Core/Properties/PropertyInt64.cs @@ -0,0 +1,43 @@ +// +// Regenerate with the 2026-07-29 enum verification campaign tooling; see +// docs/research/2026-07-29-enum-verification-campaign.md for the oracle set, +// the extraction method, and the open-question ledger. +// Hand edits are pinned by PropertyEnumConformanceTests — change the oracle, +// not the enum. +// + +namespace AcDream.Core.Properties; + +/// +/// AC's PropertyInt64 property table — the numeric keys the server sends in +/// PrivateUpdatePropertyInt64 (0x02D1) +/// and in the property bundles carried by CreateObject / PlayerDescription / +/// IdentifyResponse. The CLR payload for this table is long. +/// +/// Verified 2026-07-29 against two independent oracles: the vendored +/// client-side enum catalog (references/acclientlib/UtilityBelt.Common/Enums/Enums.cs, +/// which names this table Int64Id) and the 38,985-file ACE weenie export corpus +/// (references/weenies/), whose per-stat _comment carries the enum member +/// name beside the numeric key. 3 of these 9 members are attested by BOTH +/// oracles with zero value conflicts; the remainder are single-sourced from the +/// catalog because no weenie in the corpus sets them. +/// +/// This enum is a vocabulary, not a parser contract: the wire carries a raw +/// uint and unknown keys must still round-trip untouched, so never assume a +/// received key is a defined member. +/// +public enum PropertyInt64 : uint +{ + Undef = 0, + TotalExperience = 1, + AvailableExperience = 2, + /// 7 weenie attestations. + AugmentationCost = 3, + /// 79 weenie attestations. + ItemTotalXp = 4, + /// 79 weenie attestations. + ItemBaseXp = 5, + AvailableLuminance = 6, + MaximumLuminance = 7, + InteractionReqs = 8, +} diff --git a/src/AcDream.Core/Properties/PropertyString.cs b/src/AcDream.Core/Properties/PropertyString.cs new file mode 100644 index 00000000..0e2f0b03 --- /dev/null +++ b/src/AcDream.Core/Properties/PropertyString.cs @@ -0,0 +1,112 @@ +// +// Regenerate with the 2026-07-29 enum verification campaign tooling; see +// docs/research/2026-07-29-enum-verification-campaign.md for the oracle set, +// the extraction method, and the open-question ledger. +// Hand edits are pinned by PropertyEnumConformanceTests — change the oracle, +// not the enum. +// + +namespace AcDream.Core.Properties; + +/// +/// AC's PropertyString property table — the numeric keys the server sends in +/// PrivateUpdatePropertyString (0x02DD) / PublicUpdatePropertyString (0x02DE) +/// and in the property bundles carried by CreateObject / PlayerDescription / +/// IdentifyResponse. The CLR payload for this table is string. +/// +/// Verified 2026-07-29 against two independent oracles: the vendored +/// client-side enum catalog (references/acclientlib/UtilityBelt.Common/Enums/Enums.cs, +/// which names this table StringId) and the 38,985-file ACE weenie export corpus +/// (references/weenies/), whose per-stat _comment carries the enum member +/// name beside the numeric key. 28 of these 53 members are attested by BOTH +/// oracles with zero value conflicts; the remainder are single-sourced from the +/// catalog because no weenie in the corpus sets them. +/// +/// This enum is a vocabulary, not a parser contract: the wire carries a raw +/// uint and unknown keys must still round-trip untouched, so never assume a +/// received key is a defined member. +/// +public enum PropertyString : uint +{ + Undef = 0, + /// 38984 weenie attestations. + Name = 1, + Title = 2, + /// 1697 weenie attestations. + Sex = 3, + /// 1693 weenie attestations. + HeritageGroup = 4, + /// 1622 weenie attestations. + Template = 5, + AttackersName = 6, + /// 93 weenie attestations. + Inscription = 7, + /// 93 weenie attestations. + ScribeName = 8, + VendorsName = 9, + /// 1 weenie attestations. + Fellowship = 10, + MonarchsName = 11, + /// 449 weenie attestations. + LockCode = 12, + /// 238 weenie attestations. + KeyCode = 13, + /// 3219 weenie attestations. + Use = 14, + /// 5597 weenie attestations. + ShortDesc = 15, + /// 7107 weenie attestations. + LongDesc = 16, + /// 109 weenie attestations. + ActivationTalk = 17, + /// 10 weenie attestations. + UseMessage = 18, + /// 45 weenie attestations. + ItemHeritageGroupRestriction = 19, + /// 1318 weenie attestations. + PluralName = 20, + MonarchsTitle = 21, + /// 96 weenie attestations. + ActivationFailure = 22, + ScribeAccount = 23, + /// 591 weenie attestations. + TownName = 24, + /// 2 weenie attestations. + CraftsmanName = 25, + /// 4 weenie attestations. + UsePkServerError = 26, + ScoreCachedText = 27, + /// 5 weenie attestations. + ScoreDefaultEntryFormat = 28, + /// 5 weenie attestations. + ScoreFirstEntryFormat = 29, + /// 5 weenie attestations. + ScoreLastEntryFormat = 30, + /// 5 weenie attestations. + ScoreOnlyEntryFormat = 31, + /// 5 weenie attestations. + ScoreNoEntry = 32, + /// 859 weenie attestations. + Quest = 33, + /// 249 weenie attestations. + GeneratorEvent = 34, + PatronsTitle = 35, + HouseOwnerName = 36, + /// 170 weenie attestations. + QuestRestriction = 37, + AppraisalPortalDestination = 38, + TinkerName = 39, + ImbuerName = 40, + HouseOwnerAccount = 41, + DisplayName = 42, + DateOfBirth = 43, + ThirdPartyApi = 44, + KillQuest = 45, + Afk = 46, + AllegianceName = 47, + AugmentationAddQuest = 48, + KillQuest2 = 49, + KillQuest3 = 50, + UseSendsSignal = 51, + GearPlatingName = 52, +} diff --git a/tests/AcDream.Core.Tests/Properties/PropertyEnumConformanceTests.cs b/tests/AcDream.Core.Tests/Properties/PropertyEnumConformanceTests.cs new file mode 100644 index 00000000..f6e7ed03 --- /dev/null +++ b/tests/AcDream.Core.Tests/Properties/PropertyEnumConformanceTests.cs @@ -0,0 +1,1398 @@ +// +// Golden conformance table for the seven Property* enums. Regenerate with the +// 2026-07-29 enum verification campaign tooling; see +// docs/research/2026-07-29-enum-verification-campaign.md. +// +using System; +using System.Collections.Generic; +using System.Linq; +using AcDream.Core.Properties; +using Xunit; + +namespace AcDream.Core.Tests.Properties; + +/// +/// Pins every member of AC's seven property tables to its wire value. The table +/// below is the verbatim output of the 2026-07-29 oracle cross-check, so any hand +/// edit to a Property* enum — a renamed member, a changed value, an added or +/// dropped key — fails here rather than silently mis-reading the wire. +/// +/// is the stronger subset: members whose +/// name/value pairing is independently attested by the ACE weenie export corpus, +/// not just by the client-side enum catalog. +/// +public sealed class PropertyEnumConformanceTests +{ + private static readonly (string Name, uint Value)[] PropertyIntGolden = + [ + ("Undef", 0), + ("ItemType", 1), + ("CreatureType", 2), + ("PaletteTemplate", 3), + ("ClothingPriority", 4), + ("EncumbranceVal", 5), + ("ItemsCapacity", 6), + ("ContainersCapacity", 7), + ("Mass", 8), + ("ValidLocations", 9), + ("CurrentWieldedLocation", 10), + ("MaxStackSize", 11), + ("StackSize", 12), + ("StackUnitEncumbrance", 13), + ("StackUnitMass", 14), + ("StackUnitValue", 15), + ("ItemUseable", 16), + ("RareId", 17), + ("UiEffects", 18), + ("Value", 19), + ("CoinValue", 20), + ("TotalExperience", 21), + ("AvailableCharacter", 22), + ("TotalSkillCredits", 23), + ("AvailableSkillCredits", 24), + ("Level", 25), + ("AccountRequirements", 26), + ("ArmorType", 27), + ("ArmorLevel", 28), + ("AllegianceCpPool", 29), + ("AllegianceRank", 30), + ("ChannelsAllowed", 31), + ("ChannelsActive", 32), + ("Bonded", 33), + ("MonarchsRank", 34), + ("AllegianceFollowers", 35), + ("ResistMagic", 36), + ("ResistItemAppraisal", 37), + ("ResistLockpick", 38), + ("DeprecatedResistRepair", 39), + ("CombatMode", 40), + ("CurrentAttackHeight", 41), + ("CombatCollisions", 42), + ("NumDeaths", 43), + ("Damage", 44), + ("DamageType", 45), + ("DefaultCombatStyle", 46), + ("AttackType", 47), + ("WeaponSkill", 48), + ("WeaponTime", 49), + ("AmmoType", 50), + ("CombatUse", 51), + ("ParentLocation", 52), + ("PlacementPosition", 53), + ("WeaponEncumbrance", 54), + ("WeaponMass", 55), + ("ShieldValue", 56), + ("ShieldEncumbrance", 57), + ("MissileInventoryLocation", 58), + ("FullDamageType", 59), + ("WeaponRange", 60), + ("AttackersSkill", 61), + ("DefendersSkill", 62), + ("AttackersSkillValue", 63), + ("AttackersClass", 64), + ("Placement", 65), + ("CheckpointStatus", 66), + ("Tolerance", 67), + ("TargetingTactic", 68), + ("CombatTactic", 69), + ("HomesickTargetingTactic", 70), + ("NumFollowFailures", 71), + ("FriendType", 72), + ("FoeType", 73), + ("MerchandiseItemTypes", 74), + ("MerchandiseMinValue", 75), + ("MerchandiseMaxValue", 76), + ("NumItemsSold", 77), + ("NumItemsBought", 78), + ("MoneyIncome", 79), + ("MoneyOutflow", 80), + ("MaxGeneratedObjects", 81), + ("InitGeneratedObjects", 82), + ("ActivationResponse", 83), + ("OriginalValue", 84), + ("NumMoveFailures", 85), + ("MinLevel", 86), + ("MaxLevel", 87), + ("LockpickMod", 88), + ("BoosterEnum", 89), + ("BoostValue", 90), + ("MaxStructure", 91), + ("Structure", 92), + ("PhysicsState", 93), + ("TargetType", 94), + ("RadarBlipColor", 95), + ("EncumbranceCapacity", 96), + ("LoginTimestamp", 97), + ("CreationTimestamp", 98), + ("PkLevelModifier", 99), + ("GeneratorType", 100), + ("AiAllowedCombatStyle", 101), + ("LogoffTimestamp", 102), + ("GeneratorDestructionType", 103), + ("ActivationCreateClass", 104), + ("ItemWorkmanship", 105), + ("ItemSpellcraft", 106), + ("ItemCurMana", 107), + ("ItemMaxMana", 108), + ("ItemDifficulty", 109), + ("ItemAllegianceRankLimit", 110), + ("PortalBitmask", 111), + ("AdvocateLevel", 112), + ("Gender", 113), + ("Attuned", 114), + ("ItemSkillLevelLimit", 115), + ("GateLogic", 116), + ("ItemManaCost", 117), + ("Logoff", 118), + ("Active", 119), + ("AttackHeight", 120), + ("NumAttackFailures", 121), + ("AiCpThreshold", 122), + ("AiAdvancementStrategy", 123), + ("Version", 124), + ("Age", 125), + ("VendorHappyMean", 126), + ("VendorHappyVariance", 127), + ("CloakStatus", 128), + ("VitaeCpPool", 129), + ("NumServicesSold", 130), + ("MaterialType", 131), + ("NumAllegianceBreaks", 132), + ("ShowableOnRadar", 133), + ("PlayerKillerStatus", 134), + ("VendorHappyMaxItems", 135), + ("ScorePageNum", 136), + ("ScoreConfigNum", 137), + ("ScoreNumScores", 138), + ("DeathLevel", 139), + ("AiOptions", 140), + ("OpenToEveryone", 141), + ("GeneratorTimeType", 142), + ("GeneratorStartTime", 143), + ("GeneratorEndTime", 144), + ("GeneratorEndDestructionType", 145), + ("XpOverride", 146), + ("NumCrashAndTurns", 147), + ("ComponentWarningThreshold", 148), + ("HouseStatus", 149), + ("HookPlacement", 150), + ("HookType", 151), + ("HookItemType", 152), + ("AiPpThreshold", 153), + ("GeneratorVersion", 154), + ("HouseType", 155), + ("PickupEmoteOffset", 156), + ("WeenieIteration", 157), + ("WieldRequirements", 158), + ("WieldSkilltype", 159), + ("WieldDifficulty", 160), + ("HouseMaxHooksUsable", 161), + ("HouseCurrentHooksUsable", 162), + ("AllegianceMinLevel", 163), + ("AllegianceMaxLevel", 164), + ("HouseRelinkHookCount", 165), + ("SlayerCreatureType", 166), + ("ConfirmationInProgress", 167), + ("ConfirmationTypeInProgress", 168), + ("TsysMutationData", 169), + ("NumItemsInMaterial", 170), + ("NumTimesTinkered", 171), + ("AppraisalLongDescDecoration", 172), + ("AppraisalLockpickSuccessPercent", 173), + ("AppraisalPages", 174), + ("AppraisalMaxPages", 175), + ("AppraisalItemSkill", 176), + ("GemCount", 177), + ("GemType", 178), + ("ImbuedEffect", 179), + ("AttackersRawSkillValue", 180), + ("ChessRank", 181), + ("ChessTotalGames", 182), + ("ChessGamesWon", 183), + ("ChessGamesLost", 184), + ("TypeOfAlteration", 185), + ("SkillToBeAltered", 186), + ("SkillAlterationCount", 187), + ("HeritageGroup", 188), + ("TransferFromAttribute", 189), + ("TransferToAttribute", 190), + ("AttributeTransferCount", 191), + ("FakeFishingSkill", 192), + ("NumKeys", 193), + ("DeathTimestamp", 194), + ("PkTimestamp", 195), + ("VictimTimestamp", 196), + ("HookGroup", 197), + ("AllegianceSwearTimestamp", 198), + ("HousePurchaseTimestamp", 199), + ("RedirectableEquippedArmorCount", 200), + ("MeleedefenseImbuedEffectTypeCache", 201), + ("MissileDefenseImbuedEffectTypeCache", 202), + ("MagicDefenseImbuedEffectTypeCache", 203), + ("ElementalDamageBonus", 204), + ("ImbueAttempts", 205), + ("ImbueSuccesses", 206), + ("CreatureKills", 207), + ("PlayerKillsPk", 208), + ("PlayerKillsPkl", 209), + ("RaresTierOne", 210), + ("RaresTierTwo", 211), + ("RaresTierThree", 212), + ("RaresTierFour", 213), + ("RaresTierFive", 214), + ("AugmentationStat", 215), + ("AugmentationFamilyStat", 216), + ("AugmentationInnateFamily", 217), + ("AugmentationInnateStrength", 218), + ("AugmentationInnateEndurance", 219), + ("AugmentationInnateCoordination", 220), + ("AugmentationInnateQuickness", 221), + ("AugmentationInnateFocus", 222), + ("AugmentationInnateSelf", 223), + ("AugmentationSpecializeSalvaging", 224), + ("AugmentationSpecializeItemTinkering", 225), + ("AugmentationSpecializeArmorTinkering", 226), + ("AugmentationSpecializeMagicItemTinkering", 227), + ("AugmentationSpecializeWeaponTinkering", 228), + ("AugmentationExtraPackSlot", 229), + ("AugmentationIncreasedCarryingCapacity", 230), + ("AugmentationLessDeathItemLoss", 231), + ("AugmentationSpellsRemainPastDeath", 232), + ("AugmentationCriticalDefense", 233), + ("AugmentationBonusXp", 234), + ("AugmentationBonusSalvage", 235), + ("AugmentationBonusImbueChance", 236), + ("AugmentationFasterRegen", 237), + ("AugmentationIncreasedSpellDuration", 238), + ("AugmentationResistanceFamily", 239), + ("AugmentationResistanceSlash", 240), + ("AugmentationResistancePierce", 241), + ("AugmentationResistanceBlunt", 242), + ("AugmentationResistanceAcid", 243), + ("AugmentationResistanceFire", 244), + ("AugmentationResistanceFrost", 245), + ("AugmentationResistanceLightning", 246), + ("RaresTierOneLogin", 247), + ("RaresTierTwoLogin", 248), + ("RaresTierThreeLogin", 249), + ("RaresTierFourLogin", 250), + ("RaresTierFiveLogin", 251), + ("RaresLoginTimestamp", 252), + ("RaresTierSix", 253), + ("RaresTierSeven", 254), + ("RaresTierSixLogin", 255), + ("RaresTierSevenLogin", 256), + ("ItemAttributeLimit", 257), + ("ItemAttributeLevelLimit", 258), + ("ItemAttribute2ndLimit", 259), + ("ItemAttribute2ndLevelLimit", 260), + ("CharacterTitleId", 261), + ("NumCharacterTitles", 262), + ("ResistanceModifierType", 263), + ("FreeTinkersBitfield", 264), + ("EquipmentSetId", 265), + ("PetClass", 266), + ("Lifespan", 267), + ("RemainingLifespan", 268), + ("UseCreateQuantity", 269), + ("WieldRequirements2", 270), + ("WieldSkilltype2", 271), + ("WieldDifficulty2", 272), + ("WieldRequirements3", 273), + ("WieldSkilltype3", 274), + ("WieldDifficulty3", 275), + ("WieldRequirements4", 276), + ("WieldSkilltype4", 277), + ("WieldDifficulty4", 278), + ("Unique", 279), + ("SharedCooldown", 280), + ("Faction1Bits", 281), + ("Faction2Bits", 282), + ("Faction3Bits", 283), + ("Hatred1Bits", 284), + ("Hatred2Bits", 285), + ("Hatred3Bits", 286), + ("SocietyRankCelhan", 287), + ("SocietyRankEldweb", 288), + ("SocietyRankRadblo", 289), + ("HearLocalSignals", 290), + ("HearLocalSignalsRadius", 291), + ("Cleaving", 292), + ("AugmentationSpecializeGearcraft", 293), + ("AugmentationInfusedCreatureMagic", 294), + ("AugmentationInfusedItemMagic", 295), + ("AugmentationInfusedLifeMagic", 296), + ("AugmentationInfusedWarMagic", 297), + ("AugmentationCriticalExpertise", 298), + ("AugmentationCriticalPower", 299), + ("AugmentationSkilledMelee", 300), + ("AugmentationSkilledMissile", 301), + ("AugmentationSkilledMagic", 302), + ("ImbuedEffect2", 303), + ("ImbuedEffect3", 304), + ("ImbuedEffect4", 305), + ("ImbuedEffect5", 306), + ("DamageRating", 307), + ("DamageResistRating", 308), + ("AugmentationDamageBonus", 309), + ("AugmentationDamageReduction", 310), + ("ImbueStackingBits", 311), + ("HealOverTime", 312), + ("CritRating", 313), + ("CritDamageRating", 314), + ("CritResistRating", 315), + ("CritDamageResistRating", 316), + ("HealingResistRating", 317), + ("DamageOverTime", 318), + ("ItemMaxLevel", 319), + ("ItemXpStyle", 320), + ("EquipmentSetExtra", 321), + ("AetheriaBitfield", 322), + ("HealingBoostRating", 323), + ("HeritageSpecificArmor", 324), + ("AlternateRacialSkills", 325), + ("AugmentationJackOfAllTrades", 326), + ("AugmentationResistanceNether", 327), + ("AugmentationInfusedVoidMagic", 328), + ("WeaknessRating", 329), + ("NetherOverTime", 330), + ("NetherResistRating", 331), + ("LuminanceAward", 332), + ("LumAugDamageRating", 333), + ("LumAugDamageReductionRating", 334), + ("LumAugCritDamageRating", 335), + ("LumAugCritReductionRating", 336), + ("LumAugSurgeEffectRating", 337), + ("LumAugSurgeChanceRating", 338), + ("LumAugItemManaUsage", 339), + ("LumAugItemManaGain", 340), + ("LumAugVitality", 341), + ("LumAugHealingRating", 342), + ("LumAugSkilledCraft", 343), + ("LumAugSkilledSpec", 344), + ("LumAugNoDestroyCraft", 345), + ("RestrictInteraction", 346), + ("OlthoiLootTimestamp", 347), + ("OlthoiLootStep", 348), + ("UseCreatesContractId", 349), + ("DotResistRating", 350), + ("LifeResistRating", 351), + ("CloakWeaveProc", 352), + ("WeaponType", 353), + ("MeleeMastery", 354), + ("RangedMastery", 355), + ("SneakAttackRating", 356), + ("RecklessnessRating", 357), + ("DeceptionRating", 358), + ("CombatPetRange", 359), + ("WeaponAuraDamage", 360), + ("WeaponAuraSpeed", 361), + ("SummoningMastery", 362), + ("HeartbeatLifespan", 363), + ("UseLevelRequirement", 364), + ("LumAugAllSkills", 365), + ("UseRequiresSkill", 366), + ("UseRequiresSkillLevel", 367), + ("UseRequiresSkillSpec", 368), + ("UseRequiresLevel", 369), + ("GearDamage", 370), + ("GearDamageResist", 371), + ("GearCrit", 372), + ("GearCritResist", 373), + ("GearCritDamage", 374), + ("GearCritDamageResist", 375), + ("GearHealingBoost", 376), + ("GearNetherResist", 377), + ("GearLifeResist", 378), + ("GearMaxHealth", 379), + ("Unknown380", 380), + ("PKDamageRating", 381), + ("PKDamageResistRating", 382), + ("GearPKDamageRating", 383), + ("GearPKDamageResistRating", 384), + ("Unknown385", 385), + ("Overpower", 386), + ("OverpowerResist", 387), + ("GearOverpower", 388), + ("GearOverpowerResist", 389), + ("Enlightenment", 390), + ]; + + private static readonly (string Name, uint Value)[] PropertyInt64Golden = + [ + ("Undef", 0), + ("TotalExperience", 1), + ("AvailableExperience", 2), + ("AugmentationCost", 3), + ("ItemTotalXp", 4), + ("ItemBaseXp", 5), + ("AvailableLuminance", 6), + ("MaximumLuminance", 7), + ("InteractionReqs", 8), + ]; + + private static readonly (string Name, uint Value)[] PropertyBoolGolden = + [ + ("Undef", 0), + ("Stuck", 1), + ("Open", 2), + ("Locked", 3), + ("RotProof", 4), + ("AllegianceUpdateRequest", 5), + ("AiUsesMana", 6), + ("AiUseHumanMagicAnimations", 7), + ("AllowGive", 8), + ("CurrentlyAttacking", 9), + ("AttackerAi", 10), + ("IgnoreCollisions", 11), + ("ReportCollisions", 12), + ("Ethereal", 13), + ("GravityStatus", 14), + ("LightsStatus", 15), + ("ScriptedCollision", 16), + ("Inelastic", 17), + ("Visibility", 18), + ("Attackable", 19), + ("SafeSpellComponents", 20), + ("AdvocateState", 21), + ("Inscribable", 22), + ("DestroyOnSell", 23), + ("UiHidden", 24), + ("IgnoreHouseBarriers", 25), + ("HiddenAdmin", 26), + ("PkWounder", 27), + ("PkKiller", 28), + ("NoCorpse", 29), + ("UnderLifestoneProtection", 30), + ("ItemManaUpdatePending", 31), + ("GeneratorStatus", 32), + ("ResetMessagePending", 33), + ("DefaultOpen", 34), + ("DefaultLocked", 35), + ("DefaultOn", 36), + ("OpenForBusiness", 37), + ("IsFrozen", 38), + ("DealMagicalItems", 39), + ("LogoffImDead", 40), + ("ReportCollisionsAsEnvironment", 41), + ("AllowEdgeSlide", 42), + ("AdvocateQuest", 43), + ("IsAdmin", 44), + ("IsArch", 45), + ("IsSentinel", 46), + ("IsAdvocate", 47), + ("CurrentlyPoweringUp", 48), + ("GeneratorEnteredWorld", 49), + ("NeverFailCasting", 50), + ("VendorService", 51), + ("AiImmobile", 52), + ("DamagedByCollisions", 53), + ("IsDynamic", 54), + ("IsHot", 55), + ("IsAffecting", 56), + ("AffectsAis", 57), + ("SpellQueueActive", 58), + ("GeneratorDisabled", 59), + ("IsAcceptingTells", 60), + ("LoggingChannel", 61), + ("OpensAnyLock", 62), + ("UnlimitedUse", 63), + ("GeneratedTreasureItem", 64), + ("IgnoreMagicResist", 65), + ("IgnoreMagicArmor", 66), + ("AiAllowTrade", 67), + ("SpellComponentsRequired", 68), + ("IsSellable", 69), + ("IgnoreShieldsBySkill", 70), + ("NoDraw", 71), + ("ActivationUntargeted", 72), + ("HouseHasGottenPriorityBootPos", 73), + ("GeneratorAutomaticDestruction", 74), + ("HouseHooksVisible", 75), + ("HouseRequiresMonarch", 76), + ("HouseHooksEnabled", 77), + ("HouseNotifiedHudOfHookCount", 78), + ("AiAcceptEverything", 79), + ("IgnorePortalRestrictions", 80), + ("RequiresBackpackSlot", 81), + ("DontTurnOrMoveWhenGiving", 82), + ("NpcLooksLikeObject", 83), + ("IgnoreCloIcons", 84), + ("AppraisalHasAllowedWielder", 85), + ("ChestRegenOnClose", 86), + ("LogoffInMinigame", 87), + ("PortalShowDestination", 88), + ("PortalIgnoresPkAttackTimer", 89), + ("NpcInteractsSilently", 90), + ("Retained", 91), + ("IgnoreAuthor", 92), + ("Limbo", 93), + ("AppraisalHasAllowedActivator", 94), + ("ExistedBeforeAllegianceXpChanges", 95), + ("IsDeaf", 96), + ("IsPsr", 97), + ("Invincible", 98), + ("Ivoryable", 99), + ("Dyable", 100), + ("CanGenerateRare", 101), + ("CorpseGeneratedRare", 102), + ("NonProjectileMagicImmune", 103), + ("ActdReceivedItems", 104), + ("Unknown105", 105), + ("FirstEnterWorldDone", 106), + ("RecallsDisabled", 107), + ("RareUsesTimer", 108), + ("ActdPreorderReceivedItems", 109), + ("Afk", 110), + ("IsGagged", 111), + ("ProcSpellSelfTargeted", 112), + ("IsAllegianceGagged", 113), + ("EquipmentSetTriggerPiece", 114), + ("Uninscribe", 115), + ("WieldOnUse", 116), + ("ChestClearedWhenClosed", 117), + ("NeverAttack", 118), + ("SuppressGenerateEffect", 119), + ("TreasureCorpse", 120), + ("EquipmentSetAddLevel", 121), + ("BarberActive", 122), + ("TopLayerPriority", 123), + ("NoHeldItemShown", 124), + ("LoginAtLifestone", 125), + ("OlthoiPk", 126), + ("Account15Days", 127), + ("HadNoVitae", 128), + ("NoOlthoiTalk", 129), + ("AutowieldLeft", 130), + ]; + + private static readonly (string Name, uint Value)[] PropertyFloatGolden = + [ + ("Undef", 0), + ("HeartbeatInterval", 1), + ("HeartbeatTimestamp", 2), + ("HealthRate", 3), + ("StaminaRate", 4), + ("ManaRate", 5), + ("HealthUponResurrection", 6), + ("StaminaUponResurrection", 7), + ("ManaUponResurrection", 8), + ("StartTime", 9), + ("StopTime", 10), + ("ResetInterval", 11), + ("Shade", 12), + ("ArmorModVsSlash", 13), + ("ArmorModVsPierce", 14), + ("ArmorModVsBludgeon", 15), + ("ArmorModVsCold", 16), + ("ArmorModVsFire", 17), + ("ArmorModVsAcid", 18), + ("ArmorModVsElectric", 19), + ("CombatSpeed", 20), + ("WeaponLength", 21), + ("DamageVariance", 22), + ("CurrentPowerMod", 23), + ("AccuracyMod", 24), + ("StrengthMod", 25), + ("MaximumVelocity", 26), + ("RotationSpeed", 27), + ("MotionTimestamp", 28), + ("WeaponDefense", 29), + ("WimpyLevel", 30), + ("VisualAwarenessRange", 31), + ("AuralAwarenessRange", 32), + ("PerceptionLevel", 33), + ("PowerupTime", 34), + ("MaxChargeDistance", 35), + ("ChargeSpeed", 36), + ("BuyPrice", 37), + ("SellPrice", 38), + ("DefaultScale", 39), + ("LockpickMod", 40), + ("RegenerationInterval", 41), + ("RegenerationTimestamp", 42), + ("GeneratorRadius", 43), + ("TimeToRot", 44), + ("DeathTimestamp", 45), + ("PkTimestamp", 46), + ("VictimTimestamp", 47), + ("LoginTimestamp", 48), + ("CreationTimestamp", 49), + ("MinimumTimeSincePk", 50), + ("DeprecatedHousekeepingPriority", 51), + ("AbuseLoggingTimestamp", 52), + ("LastPortalTeleportTimestamp", 53), + ("UseRadius", 54), + ("HomeRadius", 55), + ("ReleasedTimestamp", 56), + ("MinHomeRadius", 57), + ("Facing", 58), + ("ResetTimestamp", 59), + ("LogoffTimestamp", 60), + ("EconRecoveryInterval", 61), + ("WeaponOffense", 62), + ("DamageMod", 63), + ("ResistSlash", 64), + ("ResistPierce", 65), + ("ResistBludgeon", 66), + ("ResistFire", 67), + ("ResistCold", 68), + ("ResistAcid", 69), + ("ResistElectric", 70), + ("ResistHealthBoost", 71), + ("ResistStaminaDrain", 72), + ("ResistStaminaBoost", 73), + ("ResistManaDrain", 74), + ("ResistManaBoost", 75), + ("Translucency", 76), + ("PhysicsScriptIntensity", 77), + ("Friction", 78), + ("Elasticity", 79), + ("AiUseMagicDelay", 80), + ("ItemMinSpellcraftMod", 81), + ("ItemMaxSpellcraftMod", 82), + ("ItemRankProbability", 83), + ("Shade2", 84), + ("Shade3", 85), + ("Shade4", 86), + ("ItemEfficiency", 87), + ("ItemManaUpdateTimestamp", 88), + ("SpellGestureSpeedMod", 89), + ("SpellStanceSpeedMod", 90), + ("AllegianceAppraisalTimestamp", 91), + ("PowerLevel", 92), + ("AccuracyLevel", 93), + ("AttackAngle", 94), + ("AttackTimestamp", 95), + ("CheckpointTimestamp", 96), + ("SoldTimestamp", 97), + ("UseTimestamp", 98), + ("UseLockTimestamp", 99), + ("HealkitMod", 100), + ("FrozenTimestamp", 101), + ("HealthRateMod", 102), + ("AllegianceSwearTimestamp", 103), + ("ObviousRadarRange", 104), + ("HotspotCycleTime", 105), + ("HotspotCycleTimeVariance", 106), + ("SpamTimestamp", 107), + ("SpamRate", 108), + ("BondWieldedTreasure", 109), + ("BulkMod", 110), + ("SizeMod", 111), + ("GagTimestamp", 112), + ("GeneratorUpdateTimestamp", 113), + ("DeathSpamTimestamp", 114), + ("DeathSpamRate", 115), + ("WildAttackProbability", 116), + ("FocusedProbability", 117), + ("CrashAndTurnProbability", 118), + ("CrashAndTurnRadius", 119), + ("CrashAndTurnBias", 120), + ("GeneratorInitialDelay", 121), + ("AiAcquireHealth", 122), + ("AiAcquireStamina", 123), + ("AiAcquireMana", 124), + ("ResistHealthDrain", 125), + ("LifestoneProtectionTimestamp", 126), + ("AiCounteractEnchantment", 127), + ("AiDispelEnchantment", 128), + ("TradeTimestamp", 129), + ("AiTargetedDetectionRadius", 130), + ("EmotePriority", 131), + ("LastTeleportStartTimestamp", 132), + ("EventSpamTimestamp", 133), + ("EventSpamRate", 134), + ("InventoryOffset", 135), + ("CriticalMultiplier", 136), + ("ManaStoneDestroyChance", 137), + ("SlayerDamageBonus", 138), + ("AllegianceInfoSpamTimestamp", 139), + ("AllegianceInfoSpamRate", 140), + ("NextSpellcastTimestamp", 141), + ("AppraisalRequestedTimestamp", 142), + ("AppraisalHeartbeatDueTimestamp", 143), + ("ManaConversionMod", 144), + ("LastPkAttackTimestamp", 145), + ("FellowshipUpdateTimestamp", 146), + ("CriticalFrequency", 147), + ("LimboStartTimestamp", 148), + ("WeaponMissileDefense", 149), + ("WeaponMagicDefense", 150), + ("IgnoreShield", 151), + ("ElementalDamageMod", 152), + ("StartMissileAttackTimestamp", 153), + ("LastRareUsedTimestamp", 154), + ("IgnoreArmor", 155), + ("ProcSpellRate", 156), + ("ResistanceModifier", 157), + ("AllegianceGagTimestamp", 158), + ("AbsorbMagicDamage", 159), + ("CachedMaxAbsorbMagicDamage", 160), + ("GagDuration", 161), + ("AllegianceGagDuration", 162), + ("GlobalXpMod", 163), + ("HealingModifier", 164), + ("ArmorModVsNether", 165), + ("ResistNether", 166), + ("CooldownDuration", 167), + ("WeaponAuraOffense", 168), + ("WeaponAuraDefense", 169), + ("WeaponAuraElemental", 170), + ("WeaponAuraManaConv", 171), + ]; + + private static readonly (string Name, uint Value)[] PropertyStringGolden = + [ + ("Undef", 0), + ("Name", 1), + ("Title", 2), + ("Sex", 3), + ("HeritageGroup", 4), + ("Template", 5), + ("AttackersName", 6), + ("Inscription", 7), + ("ScribeName", 8), + ("VendorsName", 9), + ("Fellowship", 10), + ("MonarchsName", 11), + ("LockCode", 12), + ("KeyCode", 13), + ("Use", 14), + ("ShortDesc", 15), + ("LongDesc", 16), + ("ActivationTalk", 17), + ("UseMessage", 18), + ("ItemHeritageGroupRestriction", 19), + ("PluralName", 20), + ("MonarchsTitle", 21), + ("ActivationFailure", 22), + ("ScribeAccount", 23), + ("TownName", 24), + ("CraftsmanName", 25), + ("UsePkServerError", 26), + ("ScoreCachedText", 27), + ("ScoreDefaultEntryFormat", 28), + ("ScoreFirstEntryFormat", 29), + ("ScoreLastEntryFormat", 30), + ("ScoreOnlyEntryFormat", 31), + ("ScoreNoEntry", 32), + ("Quest", 33), + ("GeneratorEvent", 34), + ("PatronsTitle", 35), + ("HouseOwnerName", 36), + ("QuestRestriction", 37), + ("AppraisalPortalDestination", 38), + ("TinkerName", 39), + ("ImbuerName", 40), + ("HouseOwnerAccount", 41), + ("DisplayName", 42), + ("DateOfBirth", 43), + ("ThirdPartyApi", 44), + ("KillQuest", 45), + ("Afk", 46), + ("AllegianceName", 47), + ("AugmentationAddQuest", 48), + ("KillQuest2", 49), + ("KillQuest3", 50), + ("UseSendsSignal", 51), + ("GearPlatingName", 52), + ]; + + private static readonly (string Name, uint Value)[] PropertyDataIdGolden = + [ + ("Undef", 0), + ("Setup", 1), + ("MotionTable", 2), + ("SoundTable", 3), + ("CombatTable", 4), + ("QualityFilter", 5), + ("PaletteBase", 6), + ("ClothingBase", 7), + ("Icon", 8), + ("EyesTexture", 9), + ("NoseTexture", 10), + ("MouthTexture", 11), + ("DefaultEyesTexture", 12), + ("DefaultNoseTexture", 13), + ("DefaultMouthTexture", 14), + ("HairPalette", 15), + ("EyesPalette", 16), + ("SkinPalette", 17), + ("HeadObject", 18), + ("ActivationAnimation", 19), + ("InitMotion", 20), + ("ActivationSound", 21), + ("PhysicsEffectTable", 22), + ("UseSound", 23), + ("UseTargetAnimation", 24), + ("UseTargetSuccessAnimation", 25), + ("UseTargetFailureAnimation", 26), + ("UseUserAnimation", 27), + ("Spell", 28), + ("SpellComponent", 29), + ("PhysicsScript", 30), + ("LinkedPortalOne", 31), + ("WieldedTreasureType", 32), + ("UnknownGuessedname", 33), + ("UnknownGuessedname2", 34), + ("DeathTreasureType", 35), + ("MutateFilter", 36), + ("ItemSkillLimit", 37), + ("UseCreateItem", 38), + ("DeathSpell", 39), + ("VendorsClassId", 40), + ("ItemSpecializedOnly", 41), + ("HouseId", 42), + ("AccountHouseId", 43), + ("RestrictionEffect", 44), + ("CreationMutationFilter", 45), + ("TsysMutationFilter", 46), + ("LastPortal", 47), + ("LinkedPortalTwo", 48), + ("OriginalPortal", 49), + ("IconOverlay", 50), + ("IconOverlaySecondary", 51), + ("IconUnderlay", 52), + ("AugmentationMutationFilter", 53), + ("AugmentationEffect", 54), + ("ProcSpell", 55), + ("AugmentationCreateItem", 56), + ("AlternateCurrency", 57), + ("BlueSurgeSpell", 58), + ("YellowSurgeSpell", 59), + ("RedSurgeSpell", 60), + ("OlthoiDeathTreasureType", 61), + ]; + + private static readonly (string Name, uint Value)[] PropertyInstanceIdGolden = + [ + ("Undef", 0), + ("Owner", 1), + ("Container", 2), + ("Wielder", 3), + ("Freezer", 4), + ("Viewer", 5), + ("Generator", 6), + ("Scribe", 7), + ("CurrentCombatTarget", 8), + ("CurrentEnemy", 9), + ("ProjectileLauncher", 10), + ("CurrentAttacker", 11), + ("CurrentDamager", 12), + ("CurrentFollowTarget", 13), + ("CurrentAppraisalTarget", 14), + ("CurrentFellowshipAppraisalTarget", 15), + ("ActivationTarget", 16), + ("Creator", 17), + ("Victim", 18), + ("Killer", 19), + ("Vendor", 20), + ("Customer", 21), + ("Bonded", 22), + ("Wounder", 23), + ("Allegiance", 24), + ("Patron", 25), + ("Monarch", 26), + ("CombatTarget", 27), + ("HealthQueryTarget", 28), + ("LastUnlocker", 29), + ("CrashAndTurnTarget", 30), + ("AllowedActivator", 31), + ("HouseOwner", 32), + ("House", 33), + ("Slumlord", 34), + ("ManaQueryTarget", 35), + ("CurrentGame", 36), + ("RequestedAppraisalTarget", 37), + ("AllowedWielder", 38), + ("AssignedTarget", 39), + ("LimboSource", 40), + ("Snooper", 41), + ("TeleportedCharacter", 42), + ("Pet", 43), + ("PetOwner", 44), + ("PetDevice", 45), + ]; + + public static TheoryData Families => + new("PropertyInt", "PropertyInt64", "PropertyBool", "PropertyFloat", "PropertyString", "PropertyDataId", "PropertyInstanceId"); + + private static (Type Enum, (string Name, uint Value)[] Golden) Resolve(string family) => family switch + { + "PropertyInt" => (typeof(PropertyInt), PropertyIntGolden), + "PropertyInt64" => (typeof(PropertyInt64), PropertyInt64Golden), + "PropertyBool" => (typeof(PropertyBool), PropertyBoolGolden), + "PropertyFloat" => (typeof(PropertyFloat), PropertyFloatGolden), + "PropertyString" => (typeof(PropertyString), PropertyStringGolden), + "PropertyDataId" => (typeof(PropertyDataId), PropertyDataIdGolden), + "PropertyInstanceId" => (typeof(PropertyInstanceId), PropertyInstanceIdGolden), + _ => throw new ArgumentOutOfRangeException(nameof(family), family, "unknown property family"), + }; + + [Theory] + [MemberData(nameof(Families))] + public void EnumMatchesGoldenTableExactly(string family) + { + var (type, golden) = Resolve(family); + var actual = Enum.GetNames(type) + .Select(n => (Name: n, Value: Convert.ToUInt32(Enum.Parse(type, n)))) + .OrderBy(e => e.Value).ThenBy(e => e.Name, StringComparer.Ordinal) + .ToArray(); + var expected = golden + .OrderBy(e => e.Value).ThenBy(e => e.Name, StringComparer.Ordinal) + .ToArray(); + Assert.Equal(expected, actual); + } + + [Theory] + [MemberData(nameof(Families))] + public void UnderlyingTypeIsUInt32(string family) + { + var (type, _) = Resolve(family); + Assert.Equal(typeof(uint), Enum.GetUnderlyingType(type)); + } + + [Theory] + [MemberData(nameof(Families))] + public void NoTwoMembersShareAValue(string family) + { + var (_, golden) = Resolve(family); + var dupes = golden.GroupBy(e => e.Value) + .Where(g => g.Count() > 1) + .Select(g => g.Key + ": " + string.Join(", ", g.Select(e => e.Name))) + .ToArray(); + Assert.Empty(dupes); + } + + /// + /// The name/value pairs the ACE weenie export corpus attests directly. These are + /// the two-oracle-confirmed members; the campaign found zero value conflicts + /// between the corpus and the client-side catalog across all seven tables. + /// + public static TheoryData WeenieAttested + { + get + { + var d = new TheoryData(); + d.Add("PropertyInt", "ItemType", 1); + d.Add("PropertyInt", "CreatureType", 2); + d.Add("PropertyInt", "PaletteTemplate", 3); + d.Add("PropertyInt", "ClothingPriority", 4); + d.Add("PropertyInt", "EncumbranceVal", 5); + d.Add("PropertyInt", "ItemsCapacity", 6); + d.Add("PropertyInt", "ContainersCapacity", 7); + d.Add("PropertyInt", "Mass", 8); + d.Add("PropertyInt", "ValidLocations", 9); + d.Add("PropertyInt", "MaxStackSize", 11); + d.Add("PropertyInt", "StackSize", 12); + d.Add("PropertyInt", "StackUnitEncumbrance", 13); + d.Add("PropertyInt", "StackUnitMass", 14); + d.Add("PropertyInt", "StackUnitValue", 15); + d.Add("PropertyInt", "ItemUseable", 16); + d.Add("PropertyInt", "RareId", 17); + d.Add("PropertyInt", "UiEffects", 18); + d.Add("PropertyInt", "Value", 19); + d.Add("PropertyInt", "CoinValue", 20); + d.Add("PropertyInt", "Level", 25); + d.Add("PropertyInt", "AccountRequirements", 26); + d.Add("PropertyInt", "ArmorType", 27); + d.Add("PropertyInt", "ArmorLevel", 28); + d.Add("PropertyInt", "AllegianceRank", 30); + d.Add("PropertyInt", "Bonded", 33); + d.Add("PropertyInt", "ResistMagic", 36); + d.Add("PropertyInt", "ResistItemAppraisal", 37); + d.Add("PropertyInt", "ResistLockpick", 38); + d.Add("PropertyInt", "CombatMode", 40); + d.Add("PropertyInt", "NumDeaths", 43); + d.Add("PropertyInt", "Damage", 44); + d.Add("PropertyInt", "DamageType", 45); + d.Add("PropertyInt", "DefaultCombatStyle", 46); + d.Add("PropertyInt", "AttackType", 47); + d.Add("PropertyInt", "WeaponSkill", 48); + d.Add("PropertyInt", "WeaponTime", 49); + d.Add("PropertyInt", "AmmoType", 50); + d.Add("PropertyInt", "CombatUse", 51); + d.Add("PropertyInt", "ParentLocation", 52); + d.Add("PropertyInt", "PlacementPosition", 53); + d.Add("PropertyInt", "WeaponRange", 60); + d.Add("PropertyInt", "CheckpointStatus", 66); + d.Add("PropertyInt", "Tolerance", 67); + d.Add("PropertyInt", "TargetingTactic", 68); + d.Add("PropertyInt", "CombatTactic", 69); + d.Add("PropertyInt", "FriendType", 72); + d.Add("PropertyInt", "MerchandiseItemTypes", 74); + d.Add("PropertyInt", "MerchandiseMinValue", 75); + d.Add("PropertyInt", "MerchandiseMaxValue", 76); + d.Add("PropertyInt", "MaxGeneratedObjects", 81); + d.Add("PropertyInt", "InitGeneratedObjects", 82); + d.Add("PropertyInt", "ActivationResponse", 83); + d.Add("PropertyInt", "MinLevel", 86); + d.Add("PropertyInt", "MaxLevel", 87); + d.Add("PropertyInt", "LockpickMod", 88); + d.Add("PropertyInt", "BoosterEnum", 89); + d.Add("PropertyInt", "BoostValue", 90); + d.Add("PropertyInt", "MaxStructure", 91); + d.Add("PropertyInt", "Structure", 92); + d.Add("PropertyInt", "PhysicsState", 93); + d.Add("PropertyInt", "TargetType", 94); + d.Add("PropertyInt", "RadarBlipColor", 95); + d.Add("PropertyInt", "EncumbranceCapacity", 96); + d.Add("PropertyInt", "CreationTimestamp", 98); + d.Add("PropertyInt", "PkLevelModifier", 99); + d.Add("PropertyInt", "GeneratorType", 100); + d.Add("PropertyInt", "AiAllowedCombatStyle", 101); + d.Add("PropertyInt", "GeneratorDestructionType", 103); + d.Add("PropertyInt", "ItemWorkmanship", 105); + d.Add("PropertyInt", "ItemSpellcraft", 106); + d.Add("PropertyInt", "ItemCurMana", 107); + d.Add("PropertyInt", "ItemMaxMana", 108); + d.Add("PropertyInt", "ItemDifficulty", 109); + d.Add("PropertyInt", "ItemAllegianceRankLimit", 110); + d.Add("PropertyInt", "PortalBitmask", 111); + d.Add("PropertyInt", "Gender", 113); + d.Add("PropertyInt", "Attuned", 114); + d.Add("PropertyInt", "ItemSkillLevelLimit", 115); + d.Add("PropertyInt", "ItemManaCost", 117); + d.Add("PropertyInt", "Active", 119); + d.Add("PropertyInt", "Age", 125); + d.Add("PropertyInt", "VendorHappyMean", 126); + d.Add("PropertyInt", "VendorHappyVariance", 127); + d.Add("PropertyInt", "MaterialType", 131); + d.Add("PropertyInt", "ShowableOnRadar", 133); + d.Add("PropertyInt", "PlayerKillerStatus", 134); + d.Add("PropertyInt", "ScorePageNum", 136); + d.Add("PropertyInt", "ScoreConfigNum", 137); + d.Add("PropertyInt", "ScoreNumScores", 138); + d.Add("PropertyInt", "AiOptions", 140); + d.Add("PropertyInt", "GeneratorTimeType", 142); + d.Add("PropertyInt", "GeneratorStartTime", 143); + d.Add("PropertyInt", "GeneratorEndTime", 144); + d.Add("PropertyInt", "GeneratorEndDestructionType", 145); + d.Add("PropertyInt", "XpOverride", 146); + d.Add("PropertyInt", "HouseStatus", 149); + d.Add("PropertyInt", "HookPlacement", 150); + d.Add("PropertyInt", "HookType", 151); + d.Add("PropertyInt", "HookItemType", 152); + d.Add("PropertyInt", "HouseType", 155); + d.Add("PropertyInt", "PickupEmoteOffset", 156); + d.Add("PropertyInt", "WeenieIteration", 157); + d.Add("PropertyInt", "WieldRequirements", 158); + d.Add("PropertyInt", "WieldSkilltype", 159); + d.Add("PropertyInt", "WieldDifficulty", 160); + d.Add("PropertyInt", "HouseMaxHooksUsable", 161); + d.Add("PropertyInt", "AllegianceMinLevel", 163); + d.Add("PropertyInt", "SlayerCreatureType", 166); + d.Add("PropertyInt", "TsysMutationData", 169); + d.Add("PropertyInt", "NumItemsInMaterial", 170); + d.Add("PropertyInt", "NumTimesTinkered", 171); + d.Add("PropertyInt", "AppraisalLongDescDecoration", 172); + d.Add("PropertyInt", "AppraisalLockpickSuccessPercent", 173); + d.Add("PropertyInt", "AppraisalPages", 174); + d.Add("PropertyInt", "AppraisalMaxPages", 175); + d.Add("PropertyInt", "AppraisalItemSkill", 176); + d.Add("PropertyInt", "GemCount", 177); + d.Add("PropertyInt", "GemType", 178); + d.Add("PropertyInt", "ImbuedEffect", 179); + d.Add("PropertyInt", "TypeOfAlteration", 185); + d.Add("PropertyInt", "SkillToBeAltered", 186); + d.Add("PropertyInt", "HeritageGroup", 188); + d.Add("PropertyInt", "TransferFromAttribute", 189); + d.Add("PropertyInt", "TransferToAttribute", 190); + d.Add("PropertyInt", "NumKeys", 193); + d.Add("PropertyInt", "HookGroup", 197); + d.Add("PropertyInt", "ElementalDamageBonus", 204); + d.Add("PropertyInt", "ItemAttributeLimit", 257); + d.Add("PropertyInt", "ItemAttributeLevelLimit", 258); + d.Add("PropertyInt", "CharacterTitleId", 261); + d.Add("PropertyInt", "NumCharacterTitles", 262); + d.Add("PropertyInt", "ResistanceModifierType", 263); + d.Add("PropertyInt", "EquipmentSetId", 265); + d.Add("PropertyInt", "Lifespan", 267); + d.Add("PropertyInt", "RemainingLifespan", 268); + d.Add("PropertyInt", "WieldRequirements2", 270); + d.Add("PropertyInt", "WieldSkilltype2", 271); + d.Add("PropertyInt", "WieldDifficulty2", 272); + d.Add("PropertyInt", "WieldRequirements3", 273); + d.Add("PropertyInt", "WieldSkilltype3", 274); + d.Add("PropertyInt", "WieldDifficulty3", 275); + d.Add("PropertyInt", "WieldRequirements4", 276); + d.Add("PropertyInt", "WieldSkilltype4", 277); + d.Add("PropertyInt", "WieldDifficulty4", 278); + d.Add("PropertyInt", "Unique", 279); + d.Add("PropertyInt", "SharedCooldown", 280); + d.Add("PropertyInt", "Faction1Bits", 281); + d.Add("PropertyInt", "SocietyRankCelhan", 287); + d.Add("PropertyInt", "SocietyRankEldweb", 288); + d.Add("PropertyInt", "SocietyRankRadblo", 289); + d.Add("PropertyInt", "Cleaving", 292); + d.Add("PropertyInt", "ImbuedEffect2", 303); + d.Add("PropertyInt", "ImbuedEffect3", 304); + d.Add("PropertyInt", "ImbuedEffect4", 305); + d.Add("PropertyInt", "ImbuedEffect5", 306); + d.Add("PropertyInt", "DamageRating", 307); + d.Add("PropertyInt", "DamageResistRating", 308); + d.Add("PropertyInt", "CritRating", 313); + d.Add("PropertyInt", "CritDamageRating", 314); + d.Add("PropertyInt", "CritResistRating", 315); + d.Add("PropertyInt", "CritDamageResistRating", 316); + d.Add("PropertyInt", "ItemMaxLevel", 319); + d.Add("PropertyInt", "ItemXpStyle", 320); + d.Add("PropertyInt", "HeritageSpecificArmor", 324); + d.Add("PropertyInt", "CloakWeaveProc", 352); + d.Add("PropertyInt", "WeaponType", 353); + d.Add("PropertyInt", "UseRequiresSkill", 366); + d.Add("PropertyInt", "UseRequiresSkillLevel", 367); + d.Add("PropertyInt", "UseRequiresSkillSpec", 368); + d.Add("PropertyInt", "UseRequiresLevel", 369); + d.Add("PropertyInt", "GearDamage", 370); + d.Add("PropertyInt", "GearDamageResist", 371); + d.Add("PropertyInt", "GearCrit", 372); + d.Add("PropertyInt", "GearCritResist", 373); + d.Add("PropertyInt", "GearCritDamage", 374); + d.Add("PropertyInt", "GearCritDamageResist", 375); + d.Add("PropertyInt", "GearHealingBoost", 376); + d.Add("PropertyInt", "GearNetherResist", 377); + d.Add("PropertyInt", "GearLifeResist", 378); + d.Add("PropertyInt", "GearMaxHealth", 379); + d.Add("PropertyInt", "PKDamageRating", 381); + d.Add("PropertyInt", "PKDamageResistRating", 382); + d.Add("PropertyInt", "GearPKDamageRating", 383); + d.Add("PropertyInt", "GearPKDamageResistRating", 384); + d.Add("PropertyInt", "Overpower", 386); + d.Add("PropertyInt", "OverpowerResist", 387); + d.Add("PropertyInt", "GearOverpower", 388); + d.Add("PropertyInt", "GearOverpowerResist", 389); + d.Add("PropertyInt", "Enlightenment", 390); + d.Add("PropertyInt64", "AugmentationCost", 3); + d.Add("PropertyInt64", "ItemTotalXp", 4); + d.Add("PropertyInt64", "ItemBaseXp", 5); + d.Add("PropertyBool", "Stuck", 1); + d.Add("PropertyBool", "Open", 2); + d.Add("PropertyBool", "Locked", 3); + d.Add("PropertyBool", "AiUsesMana", 6); + d.Add("PropertyBool", "AiUseHumanMagicAnimations", 7); + d.Add("PropertyBool", "AllowGive", 8); + d.Add("PropertyBool", "IgnoreCollisions", 11); + d.Add("PropertyBool", "ReportCollisions", 12); + d.Add("PropertyBool", "Ethereal", 13); + d.Add("PropertyBool", "GravityStatus", 14); + d.Add("PropertyBool", "LightsStatus", 15); + d.Add("PropertyBool", "ScriptedCollision", 16); + d.Add("PropertyBool", "Inelastic", 17); + d.Add("PropertyBool", "Visibility", 18); + d.Add("PropertyBool", "Attackable", 19); + d.Add("PropertyBool", "Inscribable", 22); + d.Add("PropertyBool", "DestroyOnSell", 23); + d.Add("PropertyBool", "UiHidden", 24); + d.Add("PropertyBool", "NoCorpse", 29); + d.Add("PropertyBool", "ResetMessagePending", 33); + d.Add("PropertyBool", "DefaultOpen", 34); + d.Add("PropertyBool", "DefaultLocked", 35); + d.Add("PropertyBool", "DealMagicalItems", 39); + d.Add("PropertyBool", "ReportCollisionsAsEnvironment", 41); + d.Add("PropertyBool", "AllowEdgeSlide", 42); + d.Add("PropertyBool", "NeverFailCasting", 50); + d.Add("PropertyBool", "VendorService", 51); + d.Add("PropertyBool", "AiImmobile", 52); + d.Add("PropertyBool", "DamagedByCollisions", 53); + d.Add("PropertyBool", "IsDynamic", 54); + d.Add("PropertyBool", "IsHot", 55); + d.Add("PropertyBool", "AffectsAis", 57); + d.Add("PropertyBool", "LoggingChannel", 61); + d.Add("PropertyBool", "OpensAnyLock", 62); + d.Add("PropertyBool", "UnlimitedUse", 63); + d.Add("PropertyBool", "IgnoreMagicResist", 65); + d.Add("PropertyBool", "IgnoreMagicArmor", 66); + d.Add("PropertyBool", "SpellComponentsRequired", 68); + d.Add("PropertyBool", "IsSellable", 69); + d.Add("PropertyBool", "IgnoreShieldsBySkill", 70); + d.Add("PropertyBool", "NoDraw", 71); + d.Add("PropertyBool", "GeneratorAutomaticDestruction", 74); + d.Add("PropertyBool", "HouseRequiresMonarch", 76); + d.Add("PropertyBool", "AiAcceptEverything", 79); + d.Add("PropertyBool", "RequiresBackpackSlot", 81); + d.Add("PropertyBool", "DontTurnOrMoveWhenGiving", 82); + d.Add("PropertyBool", "NpcLooksLikeObject", 83); + d.Add("PropertyBool", "IgnoreCloIcons", 84); + d.Add("PropertyBool", "AppraisalHasAllowedWielder", 85); + d.Add("PropertyBool", "PortalShowDestination", 88); + d.Add("PropertyBool", "PortalIgnoresPkAttackTimer", 89); + d.Add("PropertyBool", "NpcInteractsSilently", 90); + d.Add("PropertyBool", "Retained", 91); + d.Add("PropertyBool", "IgnoreAuthor", 92); + d.Add("PropertyBool", "Ivoryable", 99); + d.Add("PropertyBool", "Dyable", 100); + d.Add("PropertyBool", "NonProjectileMagicImmune", 103); + d.Add("PropertyBool", "RareUsesTimer", 108); + d.Add("PropertyBool", "AutowieldLeft", 130); + d.Add("PropertyFloat", "HeartbeatInterval", 1); + d.Add("PropertyFloat", "HeartbeatTimestamp", 2); + d.Add("PropertyFloat", "HealthRate", 3); + d.Add("PropertyFloat", "StaminaRate", 4); + d.Add("PropertyFloat", "ManaRate", 5); + d.Add("PropertyFloat", "HealthUponResurrection", 6); + d.Add("PropertyFloat", "StaminaUponResurrection", 7); + d.Add("PropertyFloat", "ManaUponResurrection", 8); + d.Add("PropertyFloat", "ResetInterval", 11); + d.Add("PropertyFloat", "Shade", 12); + d.Add("PropertyFloat", "ArmorModVsSlash", 13); + d.Add("PropertyFloat", "ArmorModVsPierce", 14); + d.Add("PropertyFloat", "ArmorModVsBludgeon", 15); + d.Add("PropertyFloat", "ArmorModVsCold", 16); + d.Add("PropertyFloat", "ArmorModVsFire", 17); + d.Add("PropertyFloat", "ArmorModVsAcid", 18); + d.Add("PropertyFloat", "ArmorModVsElectric", 19); + d.Add("PropertyFloat", "WeaponLength", 21); + d.Add("PropertyFloat", "DamageVariance", 22); + d.Add("PropertyFloat", "MaximumVelocity", 26); + d.Add("PropertyFloat", "RotationSpeed", 27); + d.Add("PropertyFloat", "WeaponDefense", 29); + d.Add("PropertyFloat", "VisualAwarenessRange", 31); + d.Add("PropertyFloat", "PowerupTime", 34); + d.Add("PropertyFloat", "ChargeSpeed", 36); + d.Add("PropertyFloat", "BuyPrice", 37); + d.Add("PropertyFloat", "SellPrice", 38); + d.Add("PropertyFloat", "DefaultScale", 39); + d.Add("PropertyFloat", "LockpickMod", 40); + d.Add("PropertyFloat", "RegenerationInterval", 41); + d.Add("PropertyFloat", "GeneratorRadius", 43); + d.Add("PropertyFloat", "TimeToRot", 44); + d.Add("PropertyFloat", "MinimumTimeSincePk", 50); + d.Add("PropertyFloat", "UseRadius", 54); + d.Add("PropertyFloat", "HomeRadius", 55); + d.Add("PropertyFloat", "WeaponOffense", 62); + d.Add("PropertyFloat", "DamageMod", 63); + d.Add("PropertyFloat", "ResistSlash", 64); + d.Add("PropertyFloat", "ResistPierce", 65); + d.Add("PropertyFloat", "ResistBludgeon", 66); + d.Add("PropertyFloat", "ResistFire", 67); + d.Add("PropertyFloat", "ResistCold", 68); + d.Add("PropertyFloat", "ResistAcid", 69); + d.Add("PropertyFloat", "ResistElectric", 70); + d.Add("PropertyFloat", "ResistHealthBoost", 71); + d.Add("PropertyFloat", "ResistStaminaDrain", 72); + d.Add("PropertyFloat", "ResistStaminaBoost", 73); + d.Add("PropertyFloat", "ResistManaDrain", 74); + d.Add("PropertyFloat", "ResistManaBoost", 75); + d.Add("PropertyFloat", "Translucency", 76); + d.Add("PropertyFloat", "PhysicsScriptIntensity", 77); + d.Add("PropertyFloat", "Friction", 78); + d.Add("PropertyFloat", "Elasticity", 79); + d.Add("PropertyFloat", "AiUseMagicDelay", 80); + d.Add("PropertyFloat", "ItemEfficiency", 87); + d.Add("PropertyFloat", "HealkitMod", 100); + d.Add("PropertyFloat", "ObviousRadarRange", 104); + d.Add("PropertyFloat", "HotspotCycleTime", 105); + d.Add("PropertyFloat", "HotspotCycleTimeVariance", 106); + d.Add("PropertyFloat", "BondWieldedTreasure", 109); + d.Add("PropertyFloat", "BulkMod", 110); + d.Add("PropertyFloat", "SizeMod", 111); + d.Add("PropertyFloat", "FocusedProbability", 117); + d.Add("PropertyFloat", "GeneratorInitialDelay", 121); + d.Add("PropertyFloat", "AiAcquireHealth", 122); + d.Add("PropertyFloat", "AiAcquireStamina", 123); + d.Add("PropertyFloat", "AiAcquireMana", 124); + d.Add("PropertyFloat", "ResistHealthDrain", 125); + d.Add("PropertyFloat", "AiCounteractEnchantment", 127); + d.Add("PropertyFloat", "AiDispelEnchantment", 128); + d.Add("PropertyFloat", "EmotePriority", 131); + d.Add("PropertyFloat", "InventoryOffset", 135); + d.Add("PropertyFloat", "CriticalMultiplier", 136); + d.Add("PropertyFloat", "ManaStoneDestroyChance", 137); + d.Add("PropertyFloat", "SlayerDamageBonus", 138); + d.Add("PropertyFloat", "ManaConversionMod", 144); + d.Add("PropertyFloat", "CriticalFrequency", 147); + d.Add("PropertyFloat", "WeaponMissileDefense", 149); + d.Add("PropertyFloat", "WeaponMagicDefense", 150); + d.Add("PropertyFloat", "IgnoreShield", 151); + d.Add("PropertyFloat", "ElementalDamageMod", 152); + d.Add("PropertyFloat", "IgnoreArmor", 155); + d.Add("PropertyFloat", "ResistanceModifier", 157); + d.Add("PropertyFloat", "AbsorbMagicDamage", 159); + d.Add("PropertyFloat", "ArmorModVsNether", 165); + d.Add("PropertyFloat", "CooldownDuration", 167); + d.Add("PropertyString", "Name", 1); + d.Add("PropertyString", "Sex", 3); + d.Add("PropertyString", "HeritageGroup", 4); + d.Add("PropertyString", "Template", 5); + d.Add("PropertyString", "Inscription", 7); + d.Add("PropertyString", "ScribeName", 8); + d.Add("PropertyString", "Fellowship", 10); + d.Add("PropertyString", "LockCode", 12); + d.Add("PropertyString", "KeyCode", 13); + d.Add("PropertyString", "Use", 14); + d.Add("PropertyString", "ShortDesc", 15); + d.Add("PropertyString", "LongDesc", 16); + d.Add("PropertyString", "ActivationTalk", 17); + d.Add("PropertyString", "UseMessage", 18); + d.Add("PropertyString", "ItemHeritageGroupRestriction", 19); + d.Add("PropertyString", "PluralName", 20); + d.Add("PropertyString", "ActivationFailure", 22); + d.Add("PropertyString", "TownName", 24); + d.Add("PropertyString", "CraftsmanName", 25); + d.Add("PropertyString", "UsePkServerError", 26); + d.Add("PropertyString", "ScoreDefaultEntryFormat", 28); + d.Add("PropertyString", "ScoreFirstEntryFormat", 29); + d.Add("PropertyString", "ScoreLastEntryFormat", 30); + d.Add("PropertyString", "ScoreOnlyEntryFormat", 31); + d.Add("PropertyString", "ScoreNoEntry", 32); + d.Add("PropertyString", "Quest", 33); + d.Add("PropertyString", "GeneratorEvent", 34); + d.Add("PropertyString", "QuestRestriction", 37); + d.Add("PropertyDataId", "Setup", 1); + d.Add("PropertyDataId", "MotionTable", 2); + d.Add("PropertyDataId", "SoundTable", 3); + d.Add("PropertyDataId", "CombatTable", 4); + d.Add("PropertyDataId", "QualityFilter", 5); + d.Add("PropertyDataId", "PaletteBase", 6); + d.Add("PropertyDataId", "ClothingBase", 7); + d.Add("PropertyDataId", "Icon", 8); + d.Add("PropertyDataId", "EyesTexture", 9); + d.Add("PropertyDataId", "NoseTexture", 10); + d.Add("PropertyDataId", "MouthTexture", 11); + d.Add("PropertyDataId", "HairPalette", 15); + d.Add("PropertyDataId", "EyesPalette", 16); + d.Add("PropertyDataId", "SkinPalette", 17); + d.Add("PropertyDataId", "ActivationAnimation", 19); + d.Add("PropertyDataId", "InitMotion", 20); + d.Add("PropertyDataId", "PhysicsEffectTable", 22); + d.Add("PropertyDataId", "UseSound", 23); + d.Add("PropertyDataId", "UseTargetAnimation", 24); + d.Add("PropertyDataId", "UseTargetSuccessAnimation", 25); + d.Add("PropertyDataId", "UseTargetFailureAnimation", 26); + d.Add("PropertyDataId", "UseUserAnimation", 27); + d.Add("PropertyDataId", "Spell", 28); + d.Add("PropertyDataId", "SpellComponent", 29); + d.Add("PropertyDataId", "PhysicsScript", 30); + d.Add("PropertyDataId", "LinkedPortalOne", 31); + d.Add("PropertyDataId", "WieldedTreasureType", 32); + d.Add("PropertyDataId", "UnknownGuessedname", 33); + d.Add("PropertyDataId", "DeathTreasureType", 35); + d.Add("PropertyDataId", "MutateFilter", 36); + d.Add("PropertyDataId", "ItemSkillLimit", 37); + d.Add("PropertyDataId", "UseCreateItem", 38); + d.Add("PropertyDataId", "ItemSpecializedOnly", 41); + d.Add("PropertyDataId", "HouseId", 42); + d.Add("PropertyDataId", "RestrictionEffect", 44); + d.Add("PropertyDataId", "TsysMutationFilter", 46); + d.Add("PropertyDataId", "LinkedPortalTwo", 48); + d.Add("PropertyDataId", "IconOverlay", 50); + d.Add("PropertyDataId", "IconOverlaySecondary", 51); + d.Add("PropertyDataId", "IconUnderlay", 52); + d.Add("PropertyDataId", "ProcSpell", 55); + d.Add("PropertyInstanceId", "ActivationTarget", 16); + d.Add("PropertyInstanceId", "AllowedWielder", 38); + return d; + } + } + + [Theory] + [MemberData(nameof(WeenieAttested))] + public void WeenieAttestedMemberHasExactWireValue(string family, string name, uint value) + { + var (type, _) = Resolve(family); + Assert.True(Enum.IsDefined(type, value), $"{family}.{name} ({value}) is not defined"); + Assert.Equal(name, Enum.GetName(type, value)); + } +}