merge(core): the enum verification campaign, onto the post-deletion tree

Brings `github/overnight/enums` (`c19680fd`) forward onto the V11 tree. The
branch was cut at `b70b9832`, before the OpenGL deletion, and the two lines of
work turned out to be disjoint: the enum campaign lives entirely in
`AcDream.Core` and its tests, while V11 emptied `AcDream.App`. The merge is
clean — no conflicting file on either side.

What it carries: names for AC's seven property tables verified against two
oracles, a correction to `DamageType`'s rotated bits and `ItemType`'s shifted
craft ladder, the retail members the equipment and physics enums were missing,
and names for `AmmoType`, `CombatUse` and `ItemUseable`. Five commits, seventeen
files, +3,767 / -27 lines.

Verified on the merge result rather than on the branch: Release build 0 errors,
no new warning attributable to any file the branch touches, and
`AcDream.Core.Tests` at 3,893 passed / 2 skipped / 3,895. The campaign's
claimed +597 is exact — the `Properties` namespace alone runs 597 tests, all
passing.

The campaign's open decision items — whether to adopt `WeenieError` wholesale,
whether the `SoundId` subset is the right cut, and the re-clone of the ACE and
Chorizite references that `references/` no longer holds — are not settled here.
They are carried into the morning report as questions for the user.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-29 03:29:16 +02:00
commit cd2f3feae2
17 changed files with 3767 additions and 27 deletions

View file

@ -398,22 +398,24 @@ public static class ItemAppraisalTextFormatter
if (ammoType == 0u)
return;
uint baseAmmoType = ammoType switch
// Retail gives the crystal and chorizite variants their own bits
// (acclient.h:4221); each folds back to the base kind for this sentence.
AmmoType baseAmmoType = (AmmoType)ammoType switch
{
0x08u or 0x40u => 1u,
0x10u or 0x80u => 2u,
0x20u or 0x100u => 4u,
_ => ammoType,
AmmoType.ArrowCrystal or AmmoType.ArrowChorizite => AmmoType.Arrow,
AmmoType.BoltCrystal or AmmoType.BoltChorizite => AmmoType.Bolt,
AmmoType.AtlatlCrystal or AmmoType.AtlatlChorizite => AmmoType.Atlatl,
var other => other,
};
bool launcher = (validLocations & (uint)EquipMask.MissileWeapon) != 0;
string? description = (launcher, baseAmmoType) switch
{
(true, 1u) => "Uses arrows as ammunition.",
(true, 2u) => "Uses quarrels as ammunition.",
(true, 4u) => "Uses atlatl darts as ammunition.",
(false, 1u) => "Used as ammunition by bows.",
(false, 2u) => "Used as ammunition by crossbows.",
(false, 4u) => "Used as ammunition by atlatls.",
(true, AmmoType.Arrow) => "Uses arrows as ammunition.",
(true, AmmoType.Bolt) => "Uses quarrels as ammunition.",
(true, AmmoType.Atlatl) => "Uses atlatl darts as ammunition.",
(false, AmmoType.Arrow) => "Used as ammunition by bows.",
(false, AmmoType.Bolt) => "Used as ammunition by crossbows.",
(false, AmmoType.Atlatl) => "Used as ammunition by atlatls.",
_ => null,
};
if (description is not null)