acdream carried 16 status codes, curated by hand out of the CMotionInterp and MoveToManager decompilation passes. The other 362 were unnamed, which made every one of them a cast site waiting to happen. This slice takes the whole table: 372 values under 378 names. The oracle set is finally complete. All six vendored reference repos were empty when the 2026-07-29 enum campaign ran, which is why it deferred this decision; they are re-cloned now, so ACE's WeenieError could be read directly instead of leaning on the UtilityBelt catalog alone. The two agree without a single conflict. ACE has 369 members, no internal value collisions. The catalog has 372, shares all 369 ACE names, and disagrees on none of their values. Its three extras -- IsNowOpenFellowship (0x050B), IsNowClosedFellowship (0x050C), LockedFellowshipCannotRecruit (0x0518) -- each turn up in ACE's separate WeenieErrorWithString enum with a `_` marking the interpolated name, so the catalog is just the less-split view of the same client enum. All three are adopted on agreement between two oracles, not on one. Retail cannot arbitrate any of this. acclient.h has no counterpart enum; its charError (26) is character-creation only. Recorded, not guessed around. Six values keep two names. acdream's NotGrounded, CrouchInCombatStance, SitInCombatStance, SleepInCombatStance, ChatEmoteOutsideNonCombat and ActionDepthExceeded are each anchored to a retail decompilation site, where ACE's names for those values are server-side coinages. Rather than pick, both are declared, acdream's first so ToString() is untouched. Behaviour is unchanged, and there is no way for it not to be: nothing in the tree branches on a WeenieError member. MotionInterpreter's switch is on a motion type and merely returns one of these; WeenieErrorText.For switches on a raw uint; the chat translation table WeenieErrorMessages is keyed on uint throughout, so naming a code does not make it render. The one site that moved is RemoteTeleportHook, where the (WeenieError)0x3Cu cast becomes the now-named WeenieError.ITeleported at the same value. Register row AP-15 is narrowed rather than retired. Its code-catalog caveat is superseded -- an unnamed code is no longer a way for it to bite -- but the sentences are still ACE's doc comments rather than retail's string_table.bin, and that part stands. The enum moved out of MotionInterpreter.cs into its own file at the same namespace. At 372 members it does not belong inside a physics class file. Core tests 3903 passed / 2 skipped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
331 lines
19 KiB
Markdown
331 lines
19 KiB
Markdown
# Enum verification campaign — 2026-07-29
|
|
|
|
Bucket B item 1 of [`docs/plans/2026-07-29-post-vulkan-work-intake.md`](../plans/2026-07-29-post-vulkan-work-intake.md).
|
|
Successor to the (missing — see Open question 1) 2026-06-04 property-enum
|
|
divergence note. Run unattended against base `b70b9832`.
|
|
|
|
**Headline: the campaign found two real value bugs and one wrong comment, all in
|
|
enums nothing currently reads.** They were traps armed for the next person to
|
|
write a comparison, not live defects. Everything else diffs clean.
|
|
|
|
---
|
|
|
|
## 1. The oracle set actually used
|
|
|
|
CLAUDE.md's reference hierarchy names six vendored repos. In this environment
|
|
**`references/ACE`, `references/Chorizite.ACProtocol`, `references/holtburger`,
|
|
`references/ACViewer`, `references/AC2D` and `references/DatReaderWriter` are all
|
|
empty directories** (`references/*` is gitignored; only WorldBuilder is checked
|
|
in). The campaign therefore re-anchored on the oracles that *are* present, which
|
|
is no loss of rigour — CLAUDE.md ranks the first of them above ACE anyway:
|
|
|
|
| # | Oracle | What it is | Weight |
|
|
|---|---|---|---|
|
|
| 1 | `docs/research/named-retail/acclient.h` | The Sept 2013 EoR retail header, verbatim. 348 parseable `enum` blocks. | **Decides.** CLAUDE.md: "beats every other reference for what the real client does." |
|
|
| 2 | `references/acclientlib/UtilityBelt.Common/Enums/Enums.cs` | 18,313-line client-side enum catalog, shipped beside a vendored `ACE.Entity` tree. Holds the seven property tables as `IntId`/`BoolId`/`FloatId`/… | Strong, **not infallible** — see §2. |
|
|
| 3 | `references/weenies/**/*.json` | 38,985 ACE weenie exports. Every stat entry carries the numeric key *and* the enum member name in its `_comment`; enum-valued ints also name the value member after `=`. | Independent mechanical attestation, limited to values some weenie actually sets. |
|
|
| 4 | `references/WorldBuilder/.../ACEnums.cs` | 233 lines, a handful of property members. | Spot check only. |
|
|
|
|
Retail does **not** name the seven property tables anywhere in `acclient.h`
|
|
(searched as `SType*`, `Property*`, and by member name). The client receives
|
|
property keys as opaque `u32`, so oracles 2 and 3 carry those alone.
|
|
|
|
**Why having more than one oracle mattered:** on `ItemType.CraftFletchingBase`
|
|
the *catalog* is wrong (says `0x02000000`) and acdream was right (`0x01000000`,
|
|
matching retail). Had the campaign trusted the catalog the way the mission brief
|
|
assumed it would trust ACE, it would have introduced a bug. No single source was
|
|
taken on faith; retail's header decided every disagreement, with the weenie
|
|
corpus as tiebreak.
|
|
|
|
---
|
|
|
|
## 2. Bugs found and fixed
|
|
|
|
### 2.1 `DamageType` — four bits rotated (`f3e95a3e`)
|
|
|
|
acdream assigned `Nether/Mana/Health/Stamina` to `0x80/0x100/0x200/0x400`.
|
|
Retail `DAMAGE_TYPE` (acclient.h:3788) assigns `Health/Stamina/Mana/Nether`.
|
|
|
|
| value | acdream (before) | retail | catalog | weenie corpus |
|
|
|---|---|---|---|---|
|
|
| 0x80 | Nether | **Health** | — | — |
|
|
| 0x100 | Mana | **Stamina** | — | Stamina (n=2) |
|
|
| 0x200 | Health | **Mana** | — | Mana (n=8) |
|
|
| 0x400 | Stamina | **Nether** | — | Nether (n=9) |
|
|
|
|
`BASE_DAMAGE_TYPE = 0x10000000` was also absent. Both of acdream's live
|
|
damage-type name tables — `CombatChatTranslator.FormatDamageType` (ported from
|
|
holtburger) and `ItemAppraisalTextFormatter.TryDamageTypeName` — already used
|
|
retail's order reading the raw wire `uint`, and `CombatChatTranslator` already
|
|
knew about `base`. The enum was the only thing in the tree that was wrong, and
|
|
nothing consumed the rotated members. **No live mislabel; latent trap removed.**
|
|
|
|
### 2.2 `ItemType` — shifted craft ladder + locally recomputed composites (`f3e95a3e`)
|
|
|
|
Retail `ITEM_TYPE` (acclient.h:3300) leaves `0x02000000` unused and puts
|
|
`CRAFT_ALCHEMY_INTERMEDIATE` on `0x04000000`. acdream had alchemy-intermediate
|
|
on `0x02000000` and an **invented `CraftCookingIntermediate`** squatting on
|
|
`0x04000000`. The weenie corpus attests `0x04000000` as
|
|
`Craft_Alchemy_Intermediate` 235 times and contains no cooking-intermediate at
|
|
all — there is no such item type.
|
|
|
|
Separately the composite masks were derived from the local primitives instead of
|
|
transcribed, which is how the ladder drifted in the first place:
|
|
|
|
| member | acdream (before) | retail |
|
|
|---|---|---|
|
|
| `Weapon` | `0x8101` (= melee\|missile\|caster) | `0x101` — melee\|missile, **no caster** |
|
|
| `WeaponOrCaster` | `0x8101` (alias of `Weapon`) | `0x8101` |
|
|
| `Item` | `0x830F` | `0x2DFBEF` |
|
|
|
|
Five retail composites acdream never had (`PortalMagicTarget`,
|
|
`LockableMagicTarget`, `ItemEnchantableTarget`,
|
|
`RedirectableItemEnchantmentTarget`, `VendorShopkeep`, `VendorGrocer`) came
|
|
along. Only one site in the tree referenced any changed member — a test that
|
|
wants a nonzero `HookItemTypes` and does not care which — so **no branch changed.**
|
|
|
|
### 2.3 `EquipMask` — a wrong type remark (`8ccaf72a`)
|
|
|
|
A remark claimed retail's `CLOTHING_LOC` composite "also sets bit 31,
|
|
0x80000000, which is not a named INVENTORY_LOC primitive". It does not.
|
|
`CLOTHING_LOC` is `0x080001FF`: the nine wear slots plus **bit 27**, which is the
|
|
perfectly well-named `Cloak` slot. No `INVENTORY_LOC` member touches bit 31 at
|
|
all — `ALL_LOC` stops at bit 30. Caught by writing the composite test.
|
|
|
|
---
|
|
|
|
## 3. Per-family end state
|
|
|
|
### 3.1 The seven `Property*` tables (`251dd68a`)
|
|
|
|
acdream had **no** `Property*` enums at all — property IDs were bare `uint`s with
|
|
the meaning carried in prose (`private const uint EncumbranceValProperty = 5u`
|
|
duplicated across two files, `UiEffects` as "ACE enum value 18" in a doc comment).
|
|
All seven are now created under `AcDream.Core.Properties`.
|
|
|
|
| family | members adopted | attested by both oracles | single-sourced |
|
|
|---|---|---|---|
|
|
| `PropertyInt` | 391 | 189 | 202 |
|
|
| `PropertyFloat` | 172 | 86 | 86 |
|
|
| `PropertyBool` | 131 | 59 | 72 |
|
|
| `PropertyDataId` | 62 | 41 | 21 |
|
|
| `PropertyString` | 53 | 28 | 25 |
|
|
| `PropertyInstanceId` | 46 | 2 | 44 |
|
|
| `PropertyInt64` | 9 | 3 | 6 |
|
|
| **total** | **864** | **408** | **456** |
|
|
|
|
Zero value conflicts between the two oracles across all seven, and the corpus
|
|
contained no key the catalog lacked — the catalog is a strict superset of
|
|
everything 38,985 weenies set. Three members differ in *spelling* only; acdream
|
|
took ACE's (`ItemType`/`HookItemType`/`MerchandiseItemTypes` over the catalog's
|
|
`ObjectType`/…), which is what the corpus emits and what acdream's own `ItemType`
|
|
already called it.
|
|
|
|
### 3.2 Existing wire-adjacent enums, diffed against retail
|
|
|
|
Legend: **closed** = every retail member present at retail's value.
|
|
|
|
| acdream enum | retail enum | end state |
|
|
|---|---|---|
|
|
| `ItemType` | `ITEM_TYPE` | **closed** (2 fixed) — retail's `TYPE_UNDEF`/`TYPE_SELF` are both 0; acdream spells the single 0 `None` |
|
|
| `DamageType` | `DAMAGE_TYPE` | **closed** (4 fixed, 1 added) |
|
|
| `EquipMask` | `INVENTORY_LOC` | **closed** — 43/43, 11 composites adopted |
|
|
| `TransientStateFlags` | `TransientState` | **closed** — `WaterContact`, `CheckEthereal` adopted |
|
|
| `PhysicsStateFlags` | `PhysicsState` | **closed** — `ReservedUnused1/2` adopted |
|
|
| `ObjectInfoState` | `ObjectInfoEnum` | **closed** — was already exact (`None` = `DEFAULT_OI`) |
|
|
| `AttackHeight` | `ATTACK_HEIGHT` | **closed** — `Undef` adopted; `NUM_ATTACK_HEIGHTS` is a count, deliberately not a member |
|
|
| `HoldKey` | `HoldKey` | **closed** — `Num_HoldKeys` is a count |
|
|
| `AttackType` | `AttackType` | **already correct**, incl. both composites (`Unarmed` 0x19, `MultiStrike` 0x79E0) |
|
|
| `RadarBlipShape` | `RadarBlipShape` | already exact (14/14) |
|
|
| `RadarBehavior` | `RadarEnum` | already exact (5/5) |
|
|
| `MovementType` | `MovementTypes::Type` | already exact (10/10) |
|
|
| `ParticleType` | `ParticleType` | already exact (14/14) |
|
|
| `PhysicsDescriptionFlag` | `PhysicsDesc::PhysicsDescInfo` | already exact (naming only: `AnimationFrame`/`ANIMFRAME_ID`) |
|
|
|
|
### 3.3 New enums for wire fields acdream parsed but never named (`3efa266a`)
|
|
|
|
| enum | retail source | members | why |
|
|
|---|---|---|---|
|
|
| `AmmoType` | acclient.h:4221 | 10 | parsed via `PublicWeenieDesc._ammo_type`; the appraisal sentence matched raw hex |
|
|
| `CombatUse` | acclient.h:6523 | 6 | `PropertyInt.CombatUse` (51) |
|
|
| `ItemUseable` | acclient.h:6478 | 39 | `PropertyInt.ItemUseable` (16); two 16-bit halves, ~30 named combinations |
|
|
|
|
`ItemAppraisalTextFormatter`'s ammunition fold now reads through `AmmoType`. Its
|
|
crystal/chorizite → base collapse was verified correct against retail's bit
|
|
layout before the change; behaviour is unchanged.
|
|
|
|
### 3.4 Verified correct, no change needed
|
|
|
|
- `ItemAppraisalTextFormatter` ammo fold (§3.3) against `AMMO_TYPE`.
|
|
- `CombatChatTranslator.FormatDamageType` and
|
|
`ItemAppraisalTextFormatter.TryDamageTypeName` against `DAMAGE_TYPE` — both
|
|
already retail-correct, which is what exposed §2.1.
|
|
|
|
---
|
|
|
|
## 4. Open questions
|
|
|
|
Each is something the campaign could **not** settle from an oracle. Per
|
|
CLAUDE.md these are recorded rather than guessed.
|
|
|
|
1. **The 2026-06-04 research drop is missing.** `claude-memory/MEMORY.md` indexes
|
|
`research/2026-06-04-property-enum-divergence.md` (the "929 values across 7
|
|
enums" ledger) and `research/2026-06-04-magic-number-audit.md`. Neither exists
|
|
in the working tree, under any ref (`git log --all --diff-filter=A`), or in the
|
|
memory directory — which has no `research/` subfolder at all. The 929 figure
|
|
could not be reproduced or audited; this campaign regenerated from scratch and
|
|
arrived at 864 property members. **Blocker:** source documents absent. Either
|
|
they were never committed or they lived in a discarded worktree. Suggest
|
|
fixing the MEMORY.md index entries to point at this doc.
|
|
2. ~~**Five of six reference repos are empty**~~ **RESOLVED 2026-07-29.** All six
|
|
were re-cloned from their upstreams into the main checkout's `references/`
|
|
(still gitignored). See §7. The 456 single-sourced property members (§3.1) can
|
|
now be promoted to two-oracle confirmed by a follow-up pass; that pass has not
|
|
been run.
|
|
3. **456 of 864 property members are single-sourced.** They are transcribed from
|
|
the catalog, not invented, but no weenie in the corpus sets them so there is no
|
|
independent attestation. **Blocker:** needs ACE source, or the client DAT's own
|
|
`EnumMapper` file type (`acclientlib` has a reader for it — a genuinely retail
|
|
oracle, and the most promising unexplored lead).
|
|
4. ~~**`WeenieError` — 362 unadopted status codes.**~~ **RESOLVED 2026-07-29** by
|
|
user decision: all 362 adopted. See §8.1. What remains open is only the
|
|
*sentences* — retail's `string_table.bin` — which stays as register row
|
|
**AP-15**, now narrowed to the translation table alone.
|
|
5. **`CombatMode` has no located retail counterpart.** acdream's 7 members match
|
|
the catalog's `CombatMode` (`Magic = 8`). Retail's `CombatStyle` (25 members,
|
|
`Magic_CombatStyle = 512`) is a different enum — weapon-style, not combat mode.
|
|
A retail `COMBAT_MODE` was not found in `acclient.h`. **Blocker:** oracle not
|
|
located; acdream is probably right but is single-sourced.
|
|
6. **`PublicWeenieFlags` counterpart unidentified.** acdream's 17 members
|
|
(`Attackable`, `Door`, `Vendor`, …) share exactly one name with retail's
|
|
`PublicWeenieDescPackHeader` (34), which is the *pack-header* bitfield — a
|
|
different thing. `PublicWeenieDesc::BitfieldIndex` (31 members) is the likely
|
|
real counterpart. **Blocker:** pairing unconfirmed; not diffed.
|
|
7. **`SoundId` is a curated 23-member local subset** of retail's `SoundType`
|
|
(206), with acdream-local names (`FootstepGrass`, `BuffApplied`) that do not
|
|
correspond 1:1 to retail members. **Blocker:** needs a decision — adopt
|
|
retail's table wholesale, or record the subset as an intentional divergence
|
|
with a register row. Neither was done.
|
|
8. **`ChatType` / `BlobType` / `DispatchType`** (TurbineChat) share no members
|
|
with retail's `eChatTypes` (26) or `ChatTypeEnum` (12); they describe chat
|
|
*channels*, not text-display types. **Blocker:** correct counterpart not
|
|
identified. Relevant to the Bucket C chatbox cleanup.
|
|
9. **`GameEventType` (103 members) was not verified.** No counterpart found under
|
|
a matching name in either retail or the catalog. **Blocker:** needs the wire
|
|
catalog (Bucket B item 2) to supply the pairing.
|
|
10. **`MaterialType` not adopted.** acdream parses it as raw `uint` from
|
|
`PublicWeenieDesc`; the catalog has 108 members; no retail counterpart located
|
|
in `acclient.h`. **Blocker:** single-sourced, and unused so far.
|
|
11. **`SpellTargetType`, `ItemPrimaryUseResult`, `PositionFlags`,
|
|
`EnchantmentMask`/`EnchantmentBucket`, `GameMessageGroup`, `InventoryRequestKind`
|
|
are acdream-local** with no retail counterpart at the same semantics. Confirmed
|
|
for `EnchantmentMask`/`EnchantmentBucket`: they are PlayerDescription wire
|
|
*trailer bucket* flags (ACE's `EnchantmentMask`), not retail's
|
|
`EnchantmentTypeEnum` — the apparent value conflict is a false pairing. The
|
|
others were not individually run down.
|
|
12. **Tooling limitation, for whoever re-runs this.** The extractor reads one line
|
|
per enum member, so a member whose value spans multiple lines is truncated.
|
|
This produced a false `AttackType.MultiStrike` conflict (read as `0x1E0`,
|
|
actually `0x79E0`). Any automated re-run must join continuation lines before
|
|
trusting a reported conflict.
|
|
|
|
---
|
|
|
|
## 5. Reproducing
|
|
|
|
Extraction and diff scripts were scratch tooling, not committed (they hardcode
|
|
absolute paths into `references/`). The method, in order:
|
|
|
|
1. Parse `acclient.h` for `enum NAME {` blocks; resolve member expressions
|
|
(hex, digit separators, references to earlier members).
|
|
2. Parse the UtilityBelt catalog the same way.
|
|
3. Walk `references/weenies/**/*.json`, pulling `(key, value, _comment)` from each
|
|
`*Stats` array; the comment's left side is the property name, the right side
|
|
(after `=`) names the value member for enum-typed ints.
|
|
4. Normalise names across conventions (retail `SCREAMING_SNAKE` with family
|
|
prefix/suffix ↔ acdream `PascalCase`) and diff on the normalised key, comparing
|
|
values exactly.
|
|
5. Any disagreement: retail decides, corpus breaks ties, and anything still
|
|
unresolved becomes an open question above rather than a guess.
|
|
|
|
## 6. Commits
|
|
|
|
| commit | slice |
|
|
|---|---|
|
|
| `251dd68a` | the seven `Property*` tables (864 members, 429 tests) |
|
|
| `f3e95a3e` | `DamageType` rotation + `ItemType` craft ladder and composites |
|
|
| `8ccaf72a` | `EquipMask` composites, `TransientState`, `PhysicsState`, `AttackHeight` |
|
|
| `3efa266a` | `AmmoType`, `CombatUse`, `ItemUseable` |
|
|
|
|
---
|
|
|
|
## 7. The reference tree, restored (2026-07-29)
|
|
|
|
Open question 2 is closed. All six vendored repos were re-cloned from their
|
|
upstreams into the main checkout at
|
|
`C:\Users\erikn\source\repos\acdream\references\`, which every worktree shares.
|
|
`references/*` is gitignored (only `WorldBuilder` is checked in as a gitlink), so
|
|
none of this enters our history.
|
|
|
|
Each candidate URL was cross-checked against the description in CLAUDE.md and
|
|
`memory/reference_repos.md` before cloning, and the clone was verified to contain
|
|
the files those descriptions name.
|
|
|
|
| repo | upstream | commit | size | how the URL was confirmed |
|
|
|---|---|---|---|---|
|
|
| ACE | `https://github.com/ACEmulator/ACE.git` | `65f092dd` | 56 MB | `git remote -v` of the recovered copy at `repos/client/ACE`; the three enum files this slice reads are byte-identical between the two |
|
|
| ACViewer | `https://github.com/ACEmulator/ACViewer.git` | `c5c54fb3` | 97 MB | cited by URL in `docs/research/2026-07-13-retail-projectile-vfx-pseudocode.md`; also the remote of `repos/ACViewer`. Cloned `--recurse-submodules`, so its `ACE.DatLoader` submodule (`382edb23`) is present as the docs describe |
|
|
| Chorizite.ACProtocol | `https://github.com/Chorizite/Chorizite.ACProtocol` | `ff7dffd6` | 4.5 MB | Chorizite org + exact repo name; contains the `Chorizite.ACProtocol` + `.SourceGen` projects CLAUDE.md describes as XML-generated |
|
|
| holtburger | `https://github.com/merklejerk/holtburger` | `a7e806cb` | 25 MB | named by URL in `docs/research/2026-05-10-holtburger-network-stack-study.md`; also the remote of `repos/holtburger` |
|
|
| AC2D | `https://github.com/deregtd/AC2D` | `3451f0d2` | 17 MB | no URL was recorded anywhere in the repo, so the candidate was verified by content: it is C++, and it holds `cNetwork.cpp`, `cInterface.cpp`, `cPictureBox.h`/`cStaticText.h`/`cEditBox.h`, and `FSplitNESW` in `Landblocks.cpp` — every file the docs attribute to AC2D |
|
|
| DatReaderWriter | `https://github.com/Chorizite/DatReaderWriter` | `c5359870` | 4.2 MB | cited by URL in `docs/research/2026-04-26-datreaderwriter-reference.md`. Not on the restore list, but it was empty for the same reason and is unambiguously identified |
|
|
|
|
---
|
|
|
|
## 8. Adoptions made on the restored oracle set
|
|
|
|
### 8.1 `WeenieError` — the full 372-code table
|
|
|
|
Open question 4, closed by user decision. acdream carried 16 members; it now
|
|
carries 372 values under 378 names.
|
|
|
|
The oracles agree completely. ACE's `WeenieError` has 369 members with no
|
|
internal value collisions; the UtilityBelt catalog's `StatusMessage` has 372,
|
|
shares all 369 ACE names, and disagrees on none of their values — it is a strict
|
|
superset. Its three extra codes are `IsNowOpenFellowship` (0x050B),
|
|
`IsNowClosedFellowship` (0x050C) and `LockedFellowshipCannotRecruit` (0x0518),
|
|
and each is independently present in ACE's *separate* `WeenieErrorWithString`
|
|
enum carrying a `_` where the interpolated name goes. So the catalog is simply
|
|
the less-split view of what ACE keeps as two enums, and the three are adopted on
|
|
two-oracle agreement rather than on the catalog alone.
|
|
|
|
Retail cannot arbitrate any of this: `acclient.h` has no counterpart enum, and
|
|
its `charError` (26 members) is character-creation only. That is recorded, not
|
|
guessed around.
|
|
|
|
Ten of acdream's 16 members matched an ACE name at an identical value. The other
|
|
six sit at values ACE names differently, and acdream's names are the better ones
|
|
— each is anchored to a retail decompilation site from the A10/R4 passes, where
|
|
ACE's is a server-side coinage. Rather than choose, the six values carry both
|
|
names, acdream's declared first:
|
|
|
|
| value | acdream (decomp-anchored) | ACE / catalog |
|
|
|---|---|---|
|
|
| 0x0024 | `NotGrounded` | `YouCantJumpWhileInTheAir` |
|
|
| 0x003F | `CrouchInCombatStance` | `CantCrouchInCombat` |
|
|
| 0x0040 | `SitInCombatStance` | `CantSitInCombat` |
|
|
| 0x0041 | `SleepInCombatStance` | `CantLieDownInCombat` |
|
|
| 0x0042 | `ChatEmoteOutsideNonCombat` | `CantChatEmoteInCombat` |
|
|
| 0x0045 | `ActionDepthExceeded` | `TooManyActions` |
|
|
|
|
**Behaviour: unchanged.** Nothing in the tree branches on a `WeenieError`
|
|
member. The two switches that mention the type switch on something else —
|
|
`MotionInterpreter.cs:971` switches on a motion type and *returns* a
|
|
`WeenieError`, and `WeenieErrorText.For` switches on a raw `uint`. The chat
|
|
translation table `WeenieErrorMessages` is keyed on `uint` throughout, so
|
|
naming a code does not make it render. The only site touched is
|
|
`RemoteTeleportHook`, whose `(WeenieError)0x3Cu` cast could become the now-named
|
|
`WeenieError.ITeleported` — same value, no behavioural edge.
|
|
|
|
The enum also moved out of `MotionInterpreter.cs` into its own file at the same
|
|
namespace; at 372 members it no longer belongs inside a physics class file.
|