feat(core): adopt retail's full WeenieError code table
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>
This commit is contained in:
parent
6530585309
commit
f27ad9ee43
6 changed files with 1149 additions and 149 deletions
|
|
@ -130,7 +130,7 @@ AP-94..AP-112 for the confirmed retail-UI completion gaps.
|
|||
| AP-12 | Enchantment family-stacking tiebreak by largest SpellId; retail picks highest Generation, tie-broken by latest cast | `src/AcDream.Core/Spells/EnchantmentMath.cs:89` | `ActiveEnchantmentRecord` doesn't carry Generation; SpellId correlates with generation level in practice | Where spell ids don't track power within a family (or same-generation re-cast), the wrong buff wins — vital-max / stat values diverge from retail | `CEnchantmentRegistry::EnchantAttribute` 0x00594570 (pc:416110) |
|
||||
| AP-13 | `ComputeDamage` is a simplified retail damage formula (no augmentations/ratings) — verified DEAD CODE as of 2026-06-04, M2 scaffolding | `src/AcDream.Core/Combat/CombatModel.cs:184` | Not on the critical path; stubbed from r02 §5 + ACE CombatManager for the future M2 predictive display | If wired into the M2 attack-bar estimate as-is, predicted numbers diverge whenever augs/ratings apply | r02 §5; ACE CombatManager |
|
||||
| AP-14 | Encumbrance multiplier is a rough piecewise-linear stand-in (1.0→50%, ~0.7@100%, 0.1@300%) for retail's exact curve | `src/AcDream.Core/Items/ItemInstance.cs:187` | Hand-fit segments capture the curve's shape for scaffolding | Client-side burden-scaled effects (speed prediction) differ from retail at most burden ratios when loaded | r06 §6 (retail encumbered multiplier curve) |
|
||||
| AP-15 | WeenieError translation table covers only ~30 common codes (from ACE enum docs, not retail string_table.bin); unknown codes render raw hex | `src/AcDream.Core/Chat/WeenieErrorMessages.cs:26` | Untranslated codes are rare, fall back losslessly, 30-second add when reported | Server messages outside the table show as raw hex instead of the retail sentence | retail string_table.bin; ACE WeenieError*.cs |
|
||||
| AP-15 | WeenieError **sentence** table covers only ~30 common codes (from ACE enum docs, not retail string_table.bin); unknown codes render raw hex. The row's older *code-catalog* caveat is superseded: `WeenieError` carried a curated 16-member subset until 2026-07-29 and now holds the full 372-code table, so a code being unnamed is no longer a way for this to bite | `src/AcDream.Core/Chat/WeenieErrorMessages.cs:26` | Untranslated codes are rare, fall back losslessly, 30-second add when reported | Server messages outside the table show as raw hex instead of the retail sentence | retail string_table.bin; ACE WeenieError*.cs; `src/AcDream.Core/Physics/WeenieError.cs` |
|
||||
| AP-16 | Point/spot lights selected per-object / per-cell as the **8 nearest reaching lights** (sphere-overlap, nearest-first) via `LightManager.SelectForObject`, capped at `MaxLightsPerObject=8`; called from `WbDrawDispatcher.ComputeEntityLightSet` (objects) and `EnvCellRenderer.GetCellLightSet` (cell shells). Retail's bake (`SetStaticLightingVertexColors`) sums ALL reaching static lights per vertex with no count cap. Retail's *hardware* path (`minimize_object_lighting` 0x0054d480) DOES cap at 8 per object, so the cap is faithful to retail's hardware path — not to its bake path. The `LightManager.Tick` UBO path survives for DIRECTIONAL (sun) lights only; `mesh_modern.vert`'s UBO loop skips point/spot entries (`posAndKind.w != 0 → continue`) — point lights reach the shader exclusively via the per-object SSBO (binding 5) | `src/AcDream.Core/Lighting/LightManager.cs:234` (`SelectForObject`); `MaxLightsPerObject` ~line 174; call sites `WbDrawDispatcher.ComputeEntityLightSet` + `EnvCellRenderer.GetCellLightSet` | Matches retail's hardware constraint (8 lights per object/cell); selection is nearest-sphere-overlap which faithfully allocates lights to the surfaces that actually see them | Surfaces reached by >8 point lights are dimmer than retail's uncapped bake — rare (a dungeon room has a handful of torches), but real; see AP-35 for the bake-vs-GPU-evaluate architecture difference | `minimize_object_lighting` 0x0054d480 (retail's 8-light hardware cap); `SetStaticLightingVertexColors` 0x0059cfe0 (retail's bake, no count cap) |
|
||||
| ~~AP-18~~ | **RETIRED 2026-07-10 — faithful retail radar port.** Exact `RGBAColor_Radar*` floats were recovered from named static data and `gmRadarUI::GetBlipColor` was re-ported with `_blipColor` overrides plus portal/vendor/attackable-creature/admin/PK/PKLite/free-PK/fellowship precedence. The old implementation was not merely hue-tuned: it also had wrong portal/vendor colors and an incomplete dispatch matrix. | `src/AcDream.Core/Ui/RadarBlipColors.cs` + radar classification tests | — | — | `gmRadarUI::GetBlipColor` 0x004d76f0; static RGBA initializers at named decomp pc:1089736-1089804 |
|
||||
| AP-19 | `PortalSideEpsilon` 0.01 (≈1 cm) instead of retail F_EPSILON ≈ 0.0002 — a documented render-root-lag tolerance, NOT a retail constant. DO-NOT-RETRY: T2 (BR-4) tried the retail value; CornerFloodReplay refuted it | `src/AcDream.App/Rendering/PortalVisibilityBuilder.cs:49` | Retail's tight epsilon only works with eye-exact swept curr_cell tracking; our viewer cell lags the eye by up to ~1 cm at pressed corners. Tighten after the #108-membership family + cdstW near-clip pin land | A 1 cm misclassification band at portal planes can flood or cull a portal the eye hasn't crossed — one-frame leaks / grey flashes at knife-edge doorway/corner positions | F_EPSILON @0x007c8c70; `PView::InitCell` 0x005a4b70 |
|
||||
|
|
|
|||
|
|
@ -177,22 +177,20 @@ CLAUDE.md these are recorded rather than guessed.
|
|||
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** (§1). Everything sourced here came
|
||||
from retail + the UtilityBelt catalog + the weenie corpus. **Blocker:** repos
|
||||
not cloned in this environment. Re-cloning ACE and Chorizite would let the 456
|
||||
single-sourced property members (§3.1) be promoted to two-oracle confirmed.
|
||||
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.** acdream has 16 members; the
|
||||
catalog's `StatusMessage` has 372, with 10 shared and zero conflicts. Retail's
|
||||
`charError` (26) is a *different* enum — character-creation errors only — so
|
||||
retail cannot arbitrate. Register row **AP-15** already tracks that acdream's
|
||||
translation table covers only ~30 common codes. **Blocker:** needs a decision
|
||||
on importing 362 server-side codes wholesale, and ideally retail's
|
||||
`string_table.bin` for the real sentences. Deliberately not done here.
|
||||
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.
|
||||
|
|
@ -258,3 +256,76 @@ absolute paths into `references/`). The method, in order:
|
|||
| `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.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ namespace AcDream.App.Physics;
|
|||
/// </summary>
|
||||
public static class RemoteTeleportHook
|
||||
{
|
||||
private const WeenieError TeleportCancelContext = (WeenieError)0x3Cu;
|
||||
// 0x3C had no name until the 2026-07-29 WeenieError adoption; the cast it
|
||||
// needed is gone, the value is unchanged.
|
||||
private const WeenieError TeleportCancelContext = WeenieError.ITeleported;
|
||||
|
||||
public static bool Execute(
|
||||
RemoteTeleportHookActions actions,
|
||||
|
|
|
|||
|
|
@ -157,142 +157,9 @@ public enum MovementType
|
|||
TurnToHeading = 9,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WeenieError-shaped codes returned by CMotionInterp methods. Values are
|
||||
/// the hex constants used directly in the decompiled C code.
|
||||
///
|
||||
/// <para>
|
||||
/// <b>R3-W1 renumber (closes J16-codes/A10).</b> Prior to this slice, the
|
||||
/// names were shuffled relative to retail's actual numeric semantics
|
||||
/// (<c>GeneralMovementFailure</c> was assigned 0x24 and used at the
|
||||
/// airborne-jump gate, but retail's 0x24 means "not grounded / no contact"
|
||||
/// and retail's 0x47 is the general-movement-failure code; 0x48 meant
|
||||
/// "cannot jump while in the air" here, but retail's 0x48 means "jump
|
||||
/// blocked by the CURRENT MOTION OR POSITION" — a blocklist check
|
||||
/// (<c>motion_allows_jump</c>), not an airborne check). Renumbered per the
|
||||
/// definitive, exhaustively-swept table in
|
||||
/// <c>docs/research/2026-07-02-r3-motioninterp/W0-pins.md</c> §A10 (19
|
||||
/// return sites + 1 store site over raw 304908-306277 + 300150-300540).
|
||||
/// These codes are LOCAL-ONLY — never serialized to the wire — so the
|
||||
/// renumber is safe (verified: no consumer outside
|
||||
/// <c>MotionInterpreter.cs</c> pattern-matches on the numeric value).
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public enum WeenieError : uint
|
||||
{
|
||||
/// <summary>0x00 — success.</summary>
|
||||
None = 0x00,
|
||||
/// <summary>
|
||||
/// 0x08 — no <c>physics_obj</c>. Sites (A10): StopCompletely @305214;
|
||||
/// DoInterpretedMotion @305579; StopInterpretedMotion @305639;
|
||||
/// StopMotion @305680; jump @305798; DoMotion @306165.
|
||||
/// </summary>
|
||||
NoPhysicsObject = 0x08,
|
||||
/// <summary>
|
||||
/// 0x0B — NoMotionInterpreter. R4-V1 addition (M12), per
|
||||
/// docs/research/2026-07-03-r4-moveto/r4-moveto-decomp.md §12 constants
|
||||
/// inventory (<c>8, 0xb, 0x36, 0x37, 0x38, 0x3d, 0x47</c>). ACE name;
|
||||
/// the retail sites that store this code were not individually
|
||||
/// extracted in the R4 pass (no MoveToManager consumer in this slice —
|
||||
/// V1 pins the numeric value only).
|
||||
/// </summary>
|
||||
NoMotionInterpreter = 0x0B,
|
||||
/// <summary>
|
||||
/// 0x24 — not grounded / no contact. Sites (A10):
|
||||
/// <c>jump_is_allowed</c> @305570 (gravity-active creature without
|
||||
/// Contact+OnWalkable; also the <c>physics_obj == null</c> case, which
|
||||
/// falls out to this same code per the A10 note — NOT 8);
|
||||
/// <c>DoInterpretedMotion</c> @305622-305623 (action-class motion
|
||||
/// blocked by <c>contact_allows_move</c>).
|
||||
/// </summary>
|
||||
NotGrounded = 0x24,
|
||||
/// <summary>
|
||||
/// 0x3f — Crouch (0x41000012) rejected while in combat stance. Site:
|
||||
/// DoMotion @306196.
|
||||
/// </summary>
|
||||
CrouchInCombatStance = 0x3f,
|
||||
/// <summary>
|
||||
/// 0x40 — Sitting (0x41000013) rejected while in combat stance. Site:
|
||||
/// DoMotion @306199.
|
||||
/// </summary>
|
||||
SitInCombatStance = 0x40,
|
||||
/// <summary>
|
||||
/// 0x41 — Sleeping (0x41000014) rejected while in combat stance. Site:
|
||||
/// DoMotion @306202.
|
||||
/// </summary>
|
||||
SleepInCombatStance = 0x41,
|
||||
/// <summary>
|
||||
/// 0x42 — <c>motion & 0x2000000</c> (the chat-emote bit) rejected
|
||||
/// outside NonCombat (0x8000003d). Site: DoMotion @306205.
|
||||
/// </summary>
|
||||
ChatEmoteOutsideNonCombat = 0x42,
|
||||
/// <summary>
|
||||
/// 0x36 — ActionCancelled. R4-V1 addition (M12). Site:
|
||||
/// <c>MoveToManager::PerformMovement</c> (r4-moveto-decomp.md §3a
|
||||
/// @0052a901) — every new moveto cancels the previous one with this
|
||||
/// code before dispatching; also <c>CPhysicsObj::interrupt_current_movement</c>
|
||||
/// → <c>MovementManager::CancelMoveTo(0x36)</c> (§9e — the TS-36 cancel
|
||||
/// entry). Per §7c, <c>MoveToManager::CancelMoveTo</c>'s WeenieError arg
|
||||
/// is NEVER READ in this build's body — kept for parity/logging only.
|
||||
/// </summary>
|
||||
ActionCancelled = 0x36,
|
||||
/// <summary>
|
||||
/// 0x37 — ObjectGone. R4-V1 addition (M12). Site:
|
||||
/// <c>MoveToManager::HandleUpdateTarget</c> (§6d @307866-307867) — a
|
||||
/// RETARGET delivery arrives with a non-OK target status (the target
|
||||
/// object was already being tracked, then went away).
|
||||
/// </summary>
|
||||
ObjectGone = 0x37,
|
||||
/// <summary>
|
||||
/// 0x38 — NoObject. R4-V1 addition (M12). Site:
|
||||
/// <c>MoveToManager::HandleUpdateTarget</c> (§6d @307857-307858) — the
|
||||
/// FIRST target callback arrives with a non-OK status (the target never
|
||||
/// resolved in the first place).
|
||||
/// </summary>
|
||||
NoObject = 0x38,
|
||||
/// <summary>
|
||||
/// 0x45 — action-queue depth cap: an action-class motion (bit
|
||||
/// 0x10000000) with <c>GetNumActions() >= 6</c> pending. Site:
|
||||
/// DoMotion @306209.
|
||||
/// </summary>
|
||||
ActionDepthExceeded = 0x45,
|
||||
/// <summary>
|
||||
/// 0x47 — general movement failure. Sites (A10):
|
||||
/// <c>jump_is_allowed</c> @305525 (<c>IsFullyConstrained</c>);
|
||||
/// @305549+305556 (<c>JumpStaminaCost</c> refusal);
|
||||
/// <c>CMotionInterp::PerformMovement</c> @306227 (dispatch type-1 > 4);
|
||||
/// <c>MovementManager::PerformMovement</c> @300201 (dispatch type-1 > 8).
|
||||
/// </summary>
|
||||
GeneralMovementFailure = 0x47,
|
||||
/// <summary>
|
||||
/// 0x48 — jump BLOCKED by the current motion or position (A1: the
|
||||
/// <c>motion_allows_jump</c> literal-range blocklist — NOT an airborne
|
||||
/// check; airborne is 0x24). Sites (A10):
|
||||
/// <c>motion_allows_jump</c> @304930; <c>jump_charge_is_allowed</c>
|
||||
/// @304948 (Fallen or Crouch..Sleeping); <c>charge_jump</c> @305459
|
||||
/// (same predicate); STORED (not returned) as the queue node's
|
||||
/// <c>jump_error_code</c> in <c>DoInterpretedMotion</c> @305605 when
|
||||
/// <c>disable_jump_during_link</c> is set.
|
||||
/// </summary>
|
||||
YouCantJumpFromThisPosition = 0x48,
|
||||
/// <summary>
|
||||
/// 0x49 — the weenie's <c>CanJump(jump_extent)</c> virtual refused
|
||||
/// (e.g. stamina/burden gate). Sites: <c>jump_charge_is_allowed</c>
|
||||
/// @304941; <c>charge_jump</c> @305454.
|
||||
/// </summary>
|
||||
CantJumpLoadedDown = 0x49,
|
||||
/// <summary>
|
||||
/// 0x3D — YouChargedTooFar. R4-V1 addition (M12). Site:
|
||||
/// <c>MoveToManager::HandleMoveToPosition</c> Phase 2 arrival check
|
||||
/// (r4-moveto-decomp.md §6b) — the <c>fail_distance</c> progress gate
|
||||
/// exceeded (<c>CheckProgressMade</c> §5b failing for >1s AND the
|
||||
/// mover overshot <c>fail_distance</c>). NOTE: numerically out of A10's
|
||||
/// increasing order (0x3D < 0x3F/0x40/0x41/0x42/0x45) because it was
|
||||
/// not part of the CMotionInterp jump-family sweep this code sits
|
||||
/// beside — it belongs to the MoveToManager family instead (§7c, §12).
|
||||
/// </summary>
|
||||
YouChargedTooFar = 0x3D,
|
||||
}
|
||||
// The WeenieError catalog moved to its own file on 2026-07-29 when it grew
|
||||
// from the 16-member CMotionInterp/MoveToManager subset to retail's full
|
||||
// 372-code table: src/AcDream.Core/Physics/WeenieError.cs (same namespace).
|
||||
|
||||
// ── Motion state structs ───────────────────────────────────────────────────────
|
||||
|
||||
|
|
|
|||
563
src/AcDream.Core/Physics/WeenieError.cs
Normal file
563
src/AcDream.Core/Physics/WeenieError.cs
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
// <auto-adopted from the oracle set — see the summary below. Hand edits are
|
||||
// fine; keep members ordered by value and keep the conformance test in sync.>
|
||||
namespace AcDream.Core.Physics;
|
||||
|
||||
/// <summary>
|
||||
/// Retail's single client-side status-code enum, as carried on the wire by
|
||||
/// <c>WeenieError</c> (0x028A) and <c>WeenieErrorWithString</c> (0x028B), and
|
||||
/// returned locally by <c>CMotionInterp</c> / <c>MoveToManager</c> methods.
|
||||
///
|
||||
/// <para>
|
||||
/// <b>2026-07-29 full adoption.</b> The catalog was a curated 16-member subset
|
||||
/// until this slice; it now carries all 372 codes. Oracles, in the order they
|
||||
/// decided: ACE <c>ACE.Entity.Enum.WeenieError</c> (369 members) and the
|
||||
/// UtilityBelt client-side catalog <c>StatusMessage</c> (372) — the two agree
|
||||
/// on every one of the 369 names ACE has, with zero value conflicts, and the
|
||||
/// catalog is a strict superset. The catalog's three extra codes (0x050B,
|
||||
/// 0x050C, 0x0518) are confirmed against ACE's separate
|
||||
/// <c>WeenieErrorWithString</c> enum, which holds them with a <c>_</c>
|
||||
/// placeholder marking the interpolated name. Retail <c>acclient.h</c> has no
|
||||
/// counterpart to arbitrate — its <c>charError</c> (26 members) is
|
||||
/// character-creation only — so the two C# oracles carry these alone.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// Six values additionally keep an acdream-local name alongside the ACE one,
|
||||
/// because the local name is anchored to a retail decompilation site and the
|
||||
/// ACE name is not. Both names denote the same value; the local name is
|
||||
/// declared first so <c>ToString()</c> is unchanged by this adoption.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This enum is the code catalog only. The human-readable sentences live in
|
||||
/// <c>AcDream.Core.Chat.WeenieErrorMessages</c>, which is keyed on the raw
|
||||
/// <c>uint</c> and is unaffected by the members named here; register row
|
||||
/// AP-15 tracks that table's coverage separately.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// The paragraph that follows is the original R3-W1 note, written when this
|
||||
/// enum held nothing but the <c>CMotionInterp</c> / <c>MoveToManager</c>
|
||||
/// family. Its "these codes" means that family, which is still local-only.
|
||||
/// The 362 codes adopted on 2026-07-29 are wire codes and are not covered by
|
||||
/// it.
|
||||
/// </para>
|
||||
///
|
||||
/// WeenieError-shaped codes returned by CMotionInterp methods. Values are
|
||||
/// the hex constants used directly in the decompiled C code.
|
||||
///
|
||||
/// <para>
|
||||
/// <b>R3-W1 renumber (closes J16-codes/A10).</b> Prior to this slice, the
|
||||
/// names were shuffled relative to retail's actual numeric semantics
|
||||
/// (<c>GeneralMovementFailure</c> was assigned 0x24 and used at the
|
||||
/// airborne-jump gate, but retail's 0x24 means "not grounded / no contact"
|
||||
/// and retail's 0x47 is the general-movement-failure code; 0x48 meant
|
||||
/// "cannot jump while in the air" here, but retail's 0x48 means "jump
|
||||
/// blocked by the CURRENT MOTION OR POSITION" — a blocklist check
|
||||
/// (<c>motion_allows_jump</c>), not an airborne check). Renumbered per the
|
||||
/// definitive, exhaustively-swept table in
|
||||
/// <c>docs/research/2026-07-02-r3-motioninterp/W0-pins.md</c> §A10 (19
|
||||
/// return sites + 1 store site over raw 304908-306277 + 300150-300540).
|
||||
/// These codes are LOCAL-ONLY — never serialized to the wire — so the
|
||||
/// renumber is safe (verified: no consumer outside
|
||||
/// <c>MotionInterpreter.cs</c> pattern-matches on the numeric value).
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public enum WeenieError : uint
|
||||
{
|
||||
/// <summary>0x00 — success.</summary>
|
||||
None = 0x0000,
|
||||
NoMem = 0x0001,
|
||||
BadParam = 0x0002,
|
||||
DivZero = 0x0003,
|
||||
SegV = 0x0004,
|
||||
Unimplemented = 0x0005,
|
||||
UnknownMessageType = 0x0006,
|
||||
NoAnimationTable = 0x0007,
|
||||
|
||||
/// <summary>
|
||||
/// 0x08 — no <c>physics_obj</c>. Sites (A10): StopCompletely @305214;
|
||||
/// DoInterpretedMotion @305579; StopInterpretedMotion @305639;
|
||||
/// StopMotion @305680; jump @305798; DoMotion @306165.
|
||||
/// </summary>
|
||||
NoPhysicsObject = 0x0008,
|
||||
NoBookieObject = 0x0009,
|
||||
NoWslObject = 0x000A,
|
||||
|
||||
/// <summary>
|
||||
/// 0x0B — NoMotionInterpreter. R4-V1 addition (M12), per
|
||||
/// docs/research/2026-07-03-r4-moveto/r4-moveto-decomp.md §12 constants
|
||||
/// inventory (<c>8, 0xb, 0x36, 0x37, 0x38, 0x3d, 0x47</c>). ACE name;
|
||||
/// the retail sites that store this code were not individually
|
||||
/// extracted in the R4 pass (no MoveToManager consumer in this slice —
|
||||
/// V1 pins the numeric value only).
|
||||
/// </summary>
|
||||
NoMotionInterpreter = 0x000B,
|
||||
UnhandledSwitch = 0x000C,
|
||||
DefaultConstructorCalled = 0x000D,
|
||||
InvalidCombatManeuver = 0x000E,
|
||||
BadCast = 0x000F,
|
||||
MissingQuality = 0x0010,
|
||||
MissingDatabaseObject = 0x0012,
|
||||
NoCallbackSet = 0x0013,
|
||||
CorruptQuality = 0x0014,
|
||||
BadContext = 0x0015,
|
||||
NoEphseqManager = 0x0016,
|
||||
BadMovementEvent = 0x0017,
|
||||
CannotCreateNewObject = 0x0018,
|
||||
NoControllerObject = 0x0019,
|
||||
CannotSendEvent = 0x001A,
|
||||
PhysicsCantTransition = 0x001B,
|
||||
PhysicsMaxDistanceExceeded = 0x001C,
|
||||
YoureTooBusy = 0x001D,
|
||||
CannotSendMessage = 0x001F,
|
||||
IllegalInventoryTransaction = 0x0020,
|
||||
ExternalWeenieObject = 0x0021,
|
||||
InternalWeenieObject = 0x0022,
|
||||
MotionFailure = 0x0023,
|
||||
|
||||
/// <summary>
|
||||
/// 0x24 — not grounded / no contact. Sites (A10):
|
||||
/// <c>jump_is_allowed</c> @305570 (gravity-active creature without
|
||||
/// Contact+OnWalkable; also the <c>physics_obj == null</c> case, which
|
||||
/// falls out to this same code per the A10 note — NOT 8);
|
||||
/// <c>DoInterpretedMotion</c> @305622-305623 (action-class motion
|
||||
/// blocked by <c>contact_allows_move</c>).
|
||||
/// </summary>
|
||||
NotGrounded = 0x0024,
|
||||
/// <summary>ACE/catalog name for 0x0024; alias of <see cref="NotGrounded"/>.</summary>
|
||||
YouCantJumpWhileInTheAir = 0x0024,
|
||||
InqCylSphereFailure = 0x0025,
|
||||
ThatIsNotAValidCommand = 0x0026,
|
||||
CarryingItem = 0x0027,
|
||||
Frozen = 0x0028,
|
||||
Stuck = 0x0029,
|
||||
YouAreTooEncumbered = 0x002A,
|
||||
BadContain = 0x002C,
|
||||
BadParent = 0x002D,
|
||||
BadDrop = 0x002E,
|
||||
BadRelease = 0x002F,
|
||||
MsgBadMsg = 0x0030,
|
||||
MsgUnpackFailed = 0x0031,
|
||||
MsgNoMsg = 0x0032,
|
||||
MsgUnderflow = 0x0033,
|
||||
MsgOverflow = 0x0034,
|
||||
MsgCallbackFailed = 0x0035,
|
||||
|
||||
/// <summary>
|
||||
/// 0x36 — ActionCancelled. R4-V1 addition (M12). Site:
|
||||
/// <c>MoveToManager::PerformMovement</c> (r4-moveto-decomp.md §3a
|
||||
/// @0052a901) — every new moveto cancels the previous one with this
|
||||
/// code before dispatching; also <c>CPhysicsObj::interrupt_current_movement</c>
|
||||
/// → <c>MovementManager::CancelMoveTo(0x36)</c> (§9e — the TS-36 cancel
|
||||
/// entry). Per §7c, <c>MoveToManager::CancelMoveTo</c>'s WeenieError arg
|
||||
/// is NEVER READ in this build's body — kept for parity/logging only.
|
||||
/// </summary>
|
||||
ActionCancelled = 0x0036,
|
||||
|
||||
/// <summary>
|
||||
/// 0x37 — ObjectGone. R4-V1 addition (M12). Site:
|
||||
/// <c>MoveToManager::HandleUpdateTarget</c> (§6d @307866-307867) — a
|
||||
/// RETARGET delivery arrives with a non-OK target status (the target
|
||||
/// object was already being tracked, then went away).
|
||||
/// </summary>
|
||||
ObjectGone = 0x0037,
|
||||
|
||||
/// <summary>
|
||||
/// 0x38 — NoObject. R4-V1 addition (M12). Site:
|
||||
/// <c>MoveToManager::HandleUpdateTarget</c> (§6d @307857-307858) — the
|
||||
/// FIRST target callback arrives with a non-OK status (the target never
|
||||
/// resolved in the first place).
|
||||
/// </summary>
|
||||
NoObject = 0x0038,
|
||||
CantGetThere = 0x0039,
|
||||
Dead = 0x003A,
|
||||
ILeftTheWorld = 0x003B,
|
||||
ITeleported = 0x003C,
|
||||
|
||||
/// <summary>
|
||||
/// 0x3D — YouChargedTooFar. R4-V1 addition (M12). Site:
|
||||
/// <c>MoveToManager::HandleMoveToPosition</c> Phase 2 arrival check
|
||||
/// (r4-moveto-decomp.md §6b) — the <c>fail_distance</c> progress gate
|
||||
/// exceeded (<c>CheckProgressMade</c> §5b failing for >1s AND the
|
||||
/// mover overshot <c>fail_distance</c>). NOTE: numerically out of A10's
|
||||
/// increasing order (0x3D < 0x3F/0x40/0x41/0x42/0x45) because it was
|
||||
/// not part of the CMotionInterp jump-family sweep this code sits
|
||||
/// beside — it belongs to the MoveToManager family instead (§7c, §12).
|
||||
/// </summary>
|
||||
YouChargedTooFar = 0x003D,
|
||||
YouAreTooTiredToDoThat = 0x003E,
|
||||
|
||||
/// <summary>
|
||||
/// 0x3f — Crouch (0x41000012) rejected while in combat stance. Site:
|
||||
/// DoMotion @306196.
|
||||
/// </summary>
|
||||
CrouchInCombatStance = 0x003F,
|
||||
/// <summary>ACE/catalog name for 0x003F; alias of <see cref="CrouchInCombatStance"/>.</summary>
|
||||
CantCrouchInCombat = 0x003F,
|
||||
|
||||
/// <summary>
|
||||
/// 0x40 — Sitting (0x41000013) rejected while in combat stance. Site:
|
||||
/// DoMotion @306199.
|
||||
/// </summary>
|
||||
SitInCombatStance = 0x0040,
|
||||
/// <summary>ACE/catalog name for 0x0040; alias of <see cref="SitInCombatStance"/>.</summary>
|
||||
CantSitInCombat = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// 0x41 — Sleeping (0x41000014) rejected while in combat stance. Site:
|
||||
/// DoMotion @306202.
|
||||
/// </summary>
|
||||
SleepInCombatStance = 0x0041,
|
||||
/// <summary>ACE/catalog name for 0x0041; alias of <see cref="SleepInCombatStance"/>.</summary>
|
||||
CantLieDownInCombat = 0x0041,
|
||||
|
||||
/// <summary>
|
||||
/// 0x42 — <c>motion & 0x2000000</c> (the chat-emote bit) rejected
|
||||
/// outside NonCombat (0x8000003d). Site: DoMotion @306205.
|
||||
/// </summary>
|
||||
ChatEmoteOutsideNonCombat = 0x0042,
|
||||
/// <summary>ACE/catalog name for 0x0042; alias of <see cref="ChatEmoteOutsideNonCombat"/>.</summary>
|
||||
CantChatEmoteInCombat = 0x0042,
|
||||
NoMtableData = 0x0043,
|
||||
CantChatEmoteNotStanding = 0x0044,
|
||||
|
||||
/// <summary>
|
||||
/// 0x45 — action-queue depth cap: an action-class motion (bit
|
||||
/// 0x10000000) with <c>GetNumActions() >= 6</c> pending. Site:
|
||||
/// DoMotion @306209.
|
||||
/// </summary>
|
||||
ActionDepthExceeded = 0x0045,
|
||||
/// <summary>ACE/catalog name for 0x0045; alias of <see cref="ActionDepthExceeded"/>.</summary>
|
||||
TooManyActions = 0x0045,
|
||||
Hidden = 0x0046,
|
||||
|
||||
/// <summary>
|
||||
/// 0x47 — general movement failure. Sites (A10):
|
||||
/// <c>jump_is_allowed</c> @305525 (<c>IsFullyConstrained</c>);
|
||||
/// @305549+305556 (<c>JumpStaminaCost</c> refusal);
|
||||
/// <c>CMotionInterp::PerformMovement</c> @306227 (dispatch type-1 > 4);
|
||||
/// <c>MovementManager::PerformMovement</c> @300201 (dispatch type-1 > 8).
|
||||
/// </summary>
|
||||
GeneralMovementFailure = 0x0047,
|
||||
|
||||
/// <summary>
|
||||
/// 0x48 — jump BLOCKED by the current motion or position (A1: the
|
||||
/// <c>motion_allows_jump</c> literal-range blocklist — NOT an airborne
|
||||
/// check; airborne is 0x24). Sites (A10):
|
||||
/// <c>motion_allows_jump</c> @304930; <c>jump_charge_is_allowed</c>
|
||||
/// @304948 (Fallen or Crouch..Sleeping); <c>charge_jump</c> @305459
|
||||
/// (same predicate); STORED (not returned) as the queue node's
|
||||
/// <c>jump_error_code</c> in <c>DoInterpretedMotion</c> @305605 when
|
||||
/// <c>disable_jump_during_link</c> is set.
|
||||
/// </summary>
|
||||
YouCantJumpFromThisPosition = 0x0048,
|
||||
|
||||
/// <summary>
|
||||
/// 0x49 — the weenie's <c>CanJump(jump_extent)</c> virtual refused
|
||||
/// (e.g. stamina/burden gate). Sites: <c>jump_charge_is_allowed</c>
|
||||
/// @304941; <c>charge_jump</c> @305454.
|
||||
/// </summary>
|
||||
CantJumpLoadedDown = 0x0049,
|
||||
YouKilledYourself = 0x004A,
|
||||
MsgResponseFailure = 0x004B,
|
||||
ObjectIsStatic = 0x004C,
|
||||
InvalidPkStatus = 0x004D,
|
||||
InvalidXpAmount = 0x03E9,
|
||||
InvalidPpCalculation = 0x03EA,
|
||||
InvalidCpCalculation = 0x03EB,
|
||||
UnhandledStatAnswer = 0x03EC,
|
||||
HeartAttack = 0x03ED,
|
||||
TheContainerIsClosed = 0x03EE,
|
||||
InvalidInventoryLocation = 0x03F0,
|
||||
ChangeCombatModeFailure = 0x03F1,
|
||||
FullInventoryLocation = 0x03F2,
|
||||
ConflictingInventoryLocation = 0x03F3,
|
||||
ItemNotPending = 0x03F4,
|
||||
BeWieldedFailure = 0x03F5,
|
||||
BeDroppedFailure = 0x03F6,
|
||||
YouAreTooFatiguedToAttack = 0x03F7,
|
||||
YouAreOutOfAmmunition = 0x03F8,
|
||||
YourAttackMisfired = 0x03F9,
|
||||
YouveAttemptedAnImpossibleSpellPath = 0x03FA,
|
||||
MagicIncompleteAnimList = 0x03FB,
|
||||
MagicInvalidSpellType = 0x03FC,
|
||||
MagicInqPositionAndVelocityFailure = 0x03FD,
|
||||
YouDontKnowThatSpell = 0x03FE,
|
||||
IncorrectTargetType = 0x03FF,
|
||||
YouDontHaveAllTheComponents = 0x0400,
|
||||
YouDontHaveEnoughManaToCast = 0x0401,
|
||||
YourSpellFizzled = 0x0402,
|
||||
YourSpellTargetIsMissing = 0x0403,
|
||||
YourProjectileSpellMislaunched = 0x0404,
|
||||
MagicSpellbookAddSpellFailure = 0x0405,
|
||||
MagicTargetOutOfRange = 0x0406,
|
||||
YourSpellCannotBeCastOutside = 0x0407,
|
||||
YourSpellCannotBeCastInside = 0x0408,
|
||||
MagicGeneralFailure = 0x0409,
|
||||
YouAreUnpreparedToCastASpell = 0x040A,
|
||||
YouveAlreadySwornAllegiance = 0x040B,
|
||||
CantSwearAllegianceInsufficientXp = 0x040C,
|
||||
AllegianceIgnoringRequests = 0x040D,
|
||||
AllegianceSquelched = 0x040E,
|
||||
AllegianceMaxDistanceExceeded = 0x040F,
|
||||
AllegianceIllegalLevel = 0x0410,
|
||||
AllegianceBadCreation = 0x0411,
|
||||
AllegiancePatronBusy = 0x0412,
|
||||
YouAreNotInAllegiance = 0x0414,
|
||||
AllegianceRemoveHierarchyFailure = 0x0415,
|
||||
FellowshipIgnoringRequests = 0x0417,
|
||||
FellowshipSquelched = 0x0418,
|
||||
FellowshipMaxDistanceExceeded = 0x0419,
|
||||
FellowshipMember = 0x041A,
|
||||
FellowshipIllegalLevel = 0x041B,
|
||||
FellowshipRecruitBusy = 0x041C,
|
||||
YouMustBeLeaderOfFellowship = 0x041D,
|
||||
YourFellowshipIsFull = 0x041E,
|
||||
FellowshipNameIsNotPermitted = 0x041F,
|
||||
LevelTooLow = 0x0420,
|
||||
LevelTooHigh = 0x0421,
|
||||
ThatChannelDoesntExist = 0x0422,
|
||||
YouCantUseThatChannel = 0x0423,
|
||||
YouAreAlreadyOnThatChannel = 0x0424,
|
||||
YouAreNotOnThatChannel = 0x0425,
|
||||
AttunedItem = 0x0426,
|
||||
YouCannotMergeDifferentStacks = 0x0427,
|
||||
YouCannotMergeEnchantedItems = 0x0428,
|
||||
YouMustControlAtLeastOneStack = 0x0429,
|
||||
CurrentlyAttacking = 0x042A,
|
||||
MissileAttackNotOk = 0x042B,
|
||||
TargetNotAcquired = 0x042C,
|
||||
ImpossibleShot = 0x042D,
|
||||
BadWeaponSkill = 0x042E,
|
||||
UnwieldFailure = 0x042F,
|
||||
LaunchFailure = 0x0430,
|
||||
ReloadFailure = 0x0431,
|
||||
UnableToMakeCraftReq = 0x0432,
|
||||
CraftAnimationFailed = 0x0433,
|
||||
YouCantCraftWithThatNumberOfItems = 0x0434,
|
||||
CraftGeneralErrorUiMsg = 0x0435,
|
||||
CraftGeneralErrorNoUiMsg = 0x0436,
|
||||
YouDoNotPassCraftingRequirements = 0x0437,
|
||||
YouDoNotHaveAllTheNecessaryItems = 0x0438,
|
||||
NotAllTheItemsAreAvailable = 0x0439,
|
||||
YouMustBeInPeaceModeToTrade = 0x043A,
|
||||
YouAreNotTrainedInThatTradeSkill = 0x043B,
|
||||
YourHandsMustBeFree = 0x043C,
|
||||
YouCannotLinkToThatPortal = 0x043D,
|
||||
YouHaveSolvedThisQuestTooRecently = 0x043E,
|
||||
YouHaveSolvedThisQuestTooManyTimes = 0x043F,
|
||||
QuestUnknown = 0x0440,
|
||||
QuestTableCorrupt = 0x0441,
|
||||
QuestBad = 0x0442,
|
||||
QuestDuplicate = 0x0443,
|
||||
QuestUnsolved = 0x0444,
|
||||
ItemRequiresQuestToBePickedUp = 0x0445,
|
||||
QuestSolvedTooLongAgo = 0x0446,
|
||||
TradeIgnoringRequests = 0x044C,
|
||||
TradeSquelched = 0x044D,
|
||||
TradeMaxDistanceExceeded = 0x044E,
|
||||
TradeAlreadyTrading = 0x044F,
|
||||
TradeBusy = 0x0450,
|
||||
TradeClosed = 0x0451,
|
||||
TradeExpired = 0x0452,
|
||||
TradeItemBeingTraded = 0x0453,
|
||||
TradeNonEmptyContainer = 0x0454,
|
||||
TradeNonCombatMode = 0x0455,
|
||||
TradeIncomplete = 0x0456,
|
||||
TradeStampMismatch = 0x0457,
|
||||
TradeUnopened = 0x0458,
|
||||
TradeEmpty = 0x0459,
|
||||
TradeAlreadyAccepted = 0x045A,
|
||||
TradeOutOfSync = 0x045B,
|
||||
PKsMayNotUsePortal = 0x045C,
|
||||
NonPKsMayNotUsePortal = 0x045D,
|
||||
HouseAbandoned = 0x045E,
|
||||
HouseEvicted = 0x045F,
|
||||
HouseAlreadyOwned = 0x0460,
|
||||
HouseBuyFailed = 0x0461,
|
||||
HouseRentFailed = 0x0462,
|
||||
Hooked = 0x0463,
|
||||
MagicInvalidPosition = 0x0465,
|
||||
YouMustHaveDarkMajestyToUsePortal = 0x0466,
|
||||
InvalidAmmoType = 0x0467,
|
||||
SkillTooLow = 0x0468,
|
||||
YouHaveUsedAllTheHooks = 0x0469,
|
||||
TradeAiDoesntWant = 0x046A,
|
||||
HookHouseNotOwned = 0x046B,
|
||||
YouMustCompleteQuestToUsePortal = 0x0474,
|
||||
HouseNoAllegiance = 0x047E,
|
||||
YouMustOwnHouseToUseCommand = 0x047F,
|
||||
YourMonarchDoesNotOwnAMansionOrVilla = 0x0480,
|
||||
YourMonarchsHouseIsNotAMansionOrVilla = 0x0481,
|
||||
YourMonarchHasClosedTheMansion = 0x0482,
|
||||
YouMustBeMonarchToPurchaseDwelling = 0x048A,
|
||||
AllegianceTimeout = 0x048D,
|
||||
YourOfferOfAllegianceWasIgnored = 0x048E,
|
||||
ConfirmationInProgress = 0x048F,
|
||||
YouMustBeAMonarchToUseCommand = 0x0490,
|
||||
YouMustSpecifyCharacterToBoot = 0x0491,
|
||||
YouCantBootYourself = 0x0492,
|
||||
ThatCharacterDoesNotExist = 0x0493,
|
||||
ThatPersonIsNotInYourAllegiance = 0x0494,
|
||||
CantBreakFromPatronNotInAllegiance = 0x0495,
|
||||
YourAllegianceHasBeenDissolved = 0x0496,
|
||||
YourPatronsAllegianceHasBeenBroken = 0x0497,
|
||||
YouHaveMovedTooFar = 0x0498,
|
||||
TeleToInvalidPosition = 0x0499,
|
||||
MustHaveDarkMajestyToUse = 0x049A,
|
||||
YouFailToLinkWithLifestone = 0x049B,
|
||||
YouWanderedTooFarToLinkWithLifestone = 0x049C,
|
||||
YouSuccessfullyLinkWithLifestone = 0x049D,
|
||||
YouMustLinkToLifestoneToRecall = 0x049E,
|
||||
YouFailToRecallToLifestone = 0x049F,
|
||||
YouFailToLinkWithPortal = 0x04A0,
|
||||
YouSuccessfullyLinkWithPortal = 0x04A1,
|
||||
YouFailToRecallToPortal = 0x04A2,
|
||||
YouMustLinkToPortalToRecall = 0x04A3,
|
||||
YouFailToSummonPortal = 0x04A4,
|
||||
YouMustLinkToPortalToSummonIt = 0x04A5,
|
||||
YouFailToTeleport = 0x04A6,
|
||||
YouHaveBeenTeleportedTooRecently = 0x04A7,
|
||||
YouMustBeAnAdvocateToUsePortal = 0x04A8,
|
||||
PortalAisNotAllowed = 0x04A9,
|
||||
PlayersMayNotUsePortal = 0x04AA,
|
||||
YouAreNotPowerfulEnoughToUsePortal = 0x04AB,
|
||||
YouAreTooPowerfulToUsePortal = 0x04AC,
|
||||
YouCannotRecallPortal = 0x04AD,
|
||||
YouCannotSummonPortal = 0x04AE,
|
||||
LockAlreadyUnlocked = 0x04AF,
|
||||
YouCannotLockOrUnlockThat = 0x04B0,
|
||||
YouCannotLockWhatIsOpen = 0x04B1,
|
||||
KeyDoesntFitThisLock = 0x04B2,
|
||||
LockUsedTooRecently = 0x04B3,
|
||||
YouArentTrainedInLockpicking = 0x04B4,
|
||||
AllegianceInfoEmptyName = 0x04B5,
|
||||
AllegianceInfoSelf = 0x04B6,
|
||||
AllegianceInfoTooRecent = 0x04B7,
|
||||
AbuseNoSuchCharacter = 0x04B8,
|
||||
AbuseReportedSelf = 0x04B9,
|
||||
AbuseComplaintHandled = 0x04BA,
|
||||
YouDoNotOwnThatSalvageTool = 0x04BD,
|
||||
YouDoNotOwnThatItem = 0x04BE,
|
||||
MaterialCannotBeCreated = 0x04C1,
|
||||
ItemsAttemptingToSalvageIsInvalid = 0x04C2,
|
||||
YouCannotSalvageItemsInTrading = 0x04C3,
|
||||
YouMustBeHouseGuestToUsePortal = 0x04C4,
|
||||
YourAllegianceRankIsTooLowToUseMagic = 0x04C5,
|
||||
YourArcaneLoreIsTooLowToUseMagic = 0x04C7,
|
||||
ItemDoesntHaveEnoughMana = 0x04C8,
|
||||
YouHaveBeenInPKBattleTooRecently = 0x04CC,
|
||||
TradeAiRefuseEmote = 0x04CD,
|
||||
YouFailToAlterSkill = 0x04D0,
|
||||
FellowshipDeclined = 0x04DB,
|
||||
FellowshipTimeout = 0x04DC,
|
||||
YouHaveFailedToAlterAttributes = 0x04DD,
|
||||
CannotTransferAttributesWhileWieldingItem = 0x04E0,
|
||||
YouHaveSucceededTransferringAttributes = 0x04E1,
|
||||
HookIsDuplicated = 0x04E2,
|
||||
ItemIsWrongTypeForHook = 0x04E3,
|
||||
HousingChestIsDuplicated = 0x04E4,
|
||||
HookWillBeDeleted = 0x04E5,
|
||||
HousingChestWillBeDeleted = 0x04E6,
|
||||
CannotSwearAllegianceWhileOwningMansion = 0x04E7,
|
||||
YouCantDoThatWhileInTheAir = 0x04EB,
|
||||
CannotChangePKStatusWhileRecovering = 0x04EC,
|
||||
AdvocatesCannotChangePKStatus = 0x04ED,
|
||||
LevelTooLowToChangePKStatusWithObject = 0x04EE,
|
||||
LevelTooHighToChangePKStatusWithObject = 0x04EF,
|
||||
YouFeelAHarshDissonance = 0x04F0,
|
||||
YouArePKAgain = 0x04F1,
|
||||
YouAreTemporarilyNoLongerPK = 0x04F2,
|
||||
PKLiteMayNotUsePortal = 0x04F3,
|
||||
YouArentTrainedInHealing = 0x04FC,
|
||||
YouDontOwnThatHealingKit = 0x04FD,
|
||||
YouCantHealThat = 0x04FE,
|
||||
YouArentReadyToHeal = 0x0500,
|
||||
YouCanOnlyHealPlayers = 0x0501,
|
||||
LifestoneMagicProtectsYou = 0x0502,
|
||||
PortalEnergyProtectsYou = 0x0503,
|
||||
YouAreNonPKAgain = 0x0504,
|
||||
YoureTooCloseToYourSanctuary = 0x0505,
|
||||
CantDoThatTradeInProgress = 0x0506,
|
||||
OnlyNonPKsMayEnterPKLite = 0x0507,
|
||||
YouAreNowPKLite = 0x0508,
|
||||
IsNowOpenFellowship = 0x050B,
|
||||
IsNowClosedFellowship = 0x050C,
|
||||
YouDoNotBelongToAFellowship = 0x050F,
|
||||
UsingMaxHooksSilent = 0x0511,
|
||||
YouAreNowUsingMaxHooks = 0x0512,
|
||||
YouAreNoLongerUsingMaxHooks = 0x0513,
|
||||
YouAreNotPermittedToUseThatHook = 0x0516,
|
||||
LockedFellowshipCannotRecruit = 0x0518,
|
||||
LockedFellowshipCannotRecruitYou = 0x0519,
|
||||
ActivationNotAllowedNotOwner = 0x051A,
|
||||
TurbineChatIsEnabled = 0x051D,
|
||||
YouCannotAddPeopleToHearList = 0x0520,
|
||||
YouAreNowDeafTo_Screams = 0x0523,
|
||||
YouCanHearAllPlayersOnceAgain = 0x0524,
|
||||
YouChickenOut = 0x0526,
|
||||
YouCanPossiblySucceed = 0x0527,
|
||||
FellowshipIsLocked = 0x0528,
|
||||
TradeComplete = 0x0529,
|
||||
NotASalvageTool = 0x052A,
|
||||
CharacterNotAvailable = 0x052B,
|
||||
YouMustWaitToPurchaseHouse = 0x0532,
|
||||
YouDoNotHaveAuthorityInAllegiance = 0x0535,
|
||||
YouHaveMaxAccountsBanned = 0x0540,
|
||||
YouHaveMaxAllegianceOfficers = 0x0545,
|
||||
YourAllegianceOfficersHaveBeenCleared = 0x0546,
|
||||
YouCannotJoinChannelsWhileGagged = 0x0548,
|
||||
YouAreNoLongerAllegianceOfficer = 0x054A,
|
||||
YourAllegianceDoesNotHaveHometown = 0x054C,
|
||||
HookItemNotUsable_CannotOpen = 0x054E,
|
||||
HookItemNotUsable_CanOpen = 0x054F,
|
||||
MissileOutOfRange = 0x0550,
|
||||
MustPurchaseThroneOfDestinyToUseFunction = 0x0552,
|
||||
MustPurchaseThroneOfDestinyToUseItem = 0x0553,
|
||||
MustPurchaseThroneOfDestinyToUsePortal = 0x0554,
|
||||
MustPurchaseThroneOfDestinyToAccessQuest = 0x0555,
|
||||
YouFailedToCompleteAugmentation = 0x0556,
|
||||
AugmentationUsedTooManyTimes = 0x0557,
|
||||
AugmentationTypeUsedTooManyTimes = 0x0558,
|
||||
AugmentationNotEnoughExperience = 0x0559,
|
||||
ExitTrainingAcademyToUseCommand = 0x055D,
|
||||
OnlyPKsMayUseCommand = 0x055F,
|
||||
OnlyPKLiteMayUseCommand = 0x0560,
|
||||
MaxFriendsExceeded = 0x0561,
|
||||
ThatCharacterNotOnYourFriendsList = 0x0563,
|
||||
OnlyHouseOwnerCanUseCommand = 0x0564,
|
||||
InvalidAllegianceNameCantBeEmpty = 0x0565,
|
||||
InvalidAllegianceNameTooLong = 0x0566,
|
||||
InvalidAllegianceNameBadCharacters = 0x0567,
|
||||
InvalidAllegianceNameInappropriate = 0x0568,
|
||||
InvalidAllegianceNameAlreadyInUse = 0x0569,
|
||||
AllegianceNameCleared = 0x056B,
|
||||
InvalidAllegianceNameSameName = 0x056C,
|
||||
InvalidOfficerLevel = 0x056F,
|
||||
AllegianceOfficerTitleIsNotAppropriate = 0x0570,
|
||||
AllegianceNameIsTooLong = 0x0571,
|
||||
AllegianceOfficerTitlesCleared = 0x0572,
|
||||
AllegianceTitleHasIllegalChars = 0x0573,
|
||||
YouHaveNotPreApprovedVassals = 0x0579,
|
||||
YouHaveClearedPreApprovedVassal = 0x057C,
|
||||
CharIsAlreadyGagged = 0x057D,
|
||||
CharIsNotCurrentlyGagged = 0x057E,
|
||||
YourAllegianceChatPrivilegesRestored = 0x0581,
|
||||
TooManyUniqueItems = 0x0584,
|
||||
HeritageRequiresSpecificArmor = 0x0585,
|
||||
ArmorRequiresSpecificHeritage = 0x0586,
|
||||
OlthoiCannotInteractWithThat = 0x0587,
|
||||
OlthoiCannotUseLifestones = 0x0588,
|
||||
OlthoiVendorLooksInHorror = 0x0589,
|
||||
OlthoiCannotJoinFellowship = 0x058B,
|
||||
OlthoiCannotJoinAllegiance = 0x058C,
|
||||
YouCannotUseThatItem = 0x058D,
|
||||
ThisPersonWillNotInteractWithYou = 0x058E,
|
||||
OnlyOlthoiMayUsePortal = 0x058F,
|
||||
OlthoiMayNotUsePortal = 0x0590,
|
||||
YouMayNotUsePortalWithVitae = 0x0591,
|
||||
YouMustBeTwoWeeksOldToUsePortal = 0x0592,
|
||||
OlthoiCanOnlyRecallToLifestone = 0x0593,
|
||||
ContractError = 0x0594,
|
||||
}
|
||||
|
|
@ -0,0 +1,497 @@
|
|||
// <auto-generated-source>
|
||||
// Golden conformance table for WeenieError. Regenerated by the 2026-07-29
|
||||
// full-adoption slice; see docs/research/2026-07-29-enum-verification-campaign.md.
|
||||
// </auto-generated-source>
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AcDream.Core.Physics;
|
||||
using Xunit;
|
||||
|
||||
namespace AcDream.Core.Tests.Properties;
|
||||
|
||||
/// <summary>
|
||||
/// Pins every member of <see cref="WeenieError"/> to its wire value. The table is
|
||||
/// the verbatim cross-check of ACE <c>ACE.Entity.Enum.WeenieError</c> (369 members)
|
||||
/// against the UtilityBelt client-side catalog <c>StatusMessage</c> (372) — the two
|
||||
/// agree on every shared name with zero value conflicts, and the catalog is a strict
|
||||
/// superset whose three extra codes are confirmed against ACE's separate
|
||||
/// <c>WeenieErrorWithString</c>. Retail <c>acclient.h</c> has no counterpart enum, so
|
||||
/// it cannot arbitrate; that is recorded rather than guessed around.
|
||||
///
|
||||
/// <para>Six values carry two names: the acdream-local name anchored to a retail
|
||||
/// decompilation site, plus the ACE/catalog name. Both are pinned.</para>
|
||||
/// </summary>
|
||||
public sealed class WeenieErrorConformanceTests
|
||||
{
|
||||
private static readonly (string Name, uint Value)[] Golden =
|
||||
[
|
||||
("None", 0x0000),
|
||||
("NoMem", 0x0001),
|
||||
("BadParam", 0x0002),
|
||||
("DivZero", 0x0003),
|
||||
("SegV", 0x0004),
|
||||
("Unimplemented", 0x0005),
|
||||
("UnknownMessageType", 0x0006),
|
||||
("NoAnimationTable", 0x0007),
|
||||
("NoPhysicsObject", 0x0008),
|
||||
("NoBookieObject", 0x0009),
|
||||
("NoWslObject", 0x000A),
|
||||
("NoMotionInterpreter", 0x000B),
|
||||
("UnhandledSwitch", 0x000C),
|
||||
("DefaultConstructorCalled", 0x000D),
|
||||
("InvalidCombatManeuver", 0x000E),
|
||||
("BadCast", 0x000F),
|
||||
("MissingQuality", 0x0010),
|
||||
("MissingDatabaseObject", 0x0012),
|
||||
("NoCallbackSet", 0x0013),
|
||||
("CorruptQuality", 0x0014),
|
||||
("BadContext", 0x0015),
|
||||
("NoEphseqManager", 0x0016),
|
||||
("BadMovementEvent", 0x0017),
|
||||
("CannotCreateNewObject", 0x0018),
|
||||
("NoControllerObject", 0x0019),
|
||||
("CannotSendEvent", 0x001A),
|
||||
("PhysicsCantTransition", 0x001B),
|
||||
("PhysicsMaxDistanceExceeded", 0x001C),
|
||||
("YoureTooBusy", 0x001D),
|
||||
("CannotSendMessage", 0x001F),
|
||||
("IllegalInventoryTransaction", 0x0020),
|
||||
("ExternalWeenieObject", 0x0021),
|
||||
("InternalWeenieObject", 0x0022),
|
||||
("MotionFailure", 0x0023),
|
||||
("NotGrounded", 0x0024),
|
||||
("YouCantJumpWhileInTheAir", 0x0024),
|
||||
("InqCylSphereFailure", 0x0025),
|
||||
("ThatIsNotAValidCommand", 0x0026),
|
||||
("CarryingItem", 0x0027),
|
||||
("Frozen", 0x0028),
|
||||
("Stuck", 0x0029),
|
||||
("YouAreTooEncumbered", 0x002A),
|
||||
("BadContain", 0x002C),
|
||||
("BadParent", 0x002D),
|
||||
("BadDrop", 0x002E),
|
||||
("BadRelease", 0x002F),
|
||||
("MsgBadMsg", 0x0030),
|
||||
("MsgUnpackFailed", 0x0031),
|
||||
("MsgNoMsg", 0x0032),
|
||||
("MsgUnderflow", 0x0033),
|
||||
("MsgOverflow", 0x0034),
|
||||
("MsgCallbackFailed", 0x0035),
|
||||
("ActionCancelled", 0x0036),
|
||||
("ObjectGone", 0x0037),
|
||||
("NoObject", 0x0038),
|
||||
("CantGetThere", 0x0039),
|
||||
("Dead", 0x003A),
|
||||
("ILeftTheWorld", 0x003B),
|
||||
("ITeleported", 0x003C),
|
||||
("YouChargedTooFar", 0x003D),
|
||||
("YouAreTooTiredToDoThat", 0x003E),
|
||||
("CrouchInCombatStance", 0x003F),
|
||||
("CantCrouchInCombat", 0x003F),
|
||||
("SitInCombatStance", 0x0040),
|
||||
("CantSitInCombat", 0x0040),
|
||||
("SleepInCombatStance", 0x0041),
|
||||
("CantLieDownInCombat", 0x0041),
|
||||
("ChatEmoteOutsideNonCombat", 0x0042),
|
||||
("CantChatEmoteInCombat", 0x0042),
|
||||
("NoMtableData", 0x0043),
|
||||
("CantChatEmoteNotStanding", 0x0044),
|
||||
("ActionDepthExceeded", 0x0045),
|
||||
("TooManyActions", 0x0045),
|
||||
("Hidden", 0x0046),
|
||||
("GeneralMovementFailure", 0x0047),
|
||||
("YouCantJumpFromThisPosition", 0x0048),
|
||||
("CantJumpLoadedDown", 0x0049),
|
||||
("YouKilledYourself", 0x004A),
|
||||
("MsgResponseFailure", 0x004B),
|
||||
("ObjectIsStatic", 0x004C),
|
||||
("InvalidPkStatus", 0x004D),
|
||||
("InvalidXpAmount", 0x03E9),
|
||||
("InvalidPpCalculation", 0x03EA),
|
||||
("InvalidCpCalculation", 0x03EB),
|
||||
("UnhandledStatAnswer", 0x03EC),
|
||||
("HeartAttack", 0x03ED),
|
||||
("TheContainerIsClosed", 0x03EE),
|
||||
("InvalidInventoryLocation", 0x03F0),
|
||||
("ChangeCombatModeFailure", 0x03F1),
|
||||
("FullInventoryLocation", 0x03F2),
|
||||
("ConflictingInventoryLocation", 0x03F3),
|
||||
("ItemNotPending", 0x03F4),
|
||||
("BeWieldedFailure", 0x03F5),
|
||||
("BeDroppedFailure", 0x03F6),
|
||||
("YouAreTooFatiguedToAttack", 0x03F7),
|
||||
("YouAreOutOfAmmunition", 0x03F8),
|
||||
("YourAttackMisfired", 0x03F9),
|
||||
("YouveAttemptedAnImpossibleSpellPath", 0x03FA),
|
||||
("MagicIncompleteAnimList", 0x03FB),
|
||||
("MagicInvalidSpellType", 0x03FC),
|
||||
("MagicInqPositionAndVelocityFailure", 0x03FD),
|
||||
("YouDontKnowThatSpell", 0x03FE),
|
||||
("IncorrectTargetType", 0x03FF),
|
||||
("YouDontHaveAllTheComponents", 0x0400),
|
||||
("YouDontHaveEnoughManaToCast", 0x0401),
|
||||
("YourSpellFizzled", 0x0402),
|
||||
("YourSpellTargetIsMissing", 0x0403),
|
||||
("YourProjectileSpellMislaunched", 0x0404),
|
||||
("MagicSpellbookAddSpellFailure", 0x0405),
|
||||
("MagicTargetOutOfRange", 0x0406),
|
||||
("YourSpellCannotBeCastOutside", 0x0407),
|
||||
("YourSpellCannotBeCastInside", 0x0408),
|
||||
("MagicGeneralFailure", 0x0409),
|
||||
("YouAreUnpreparedToCastASpell", 0x040A),
|
||||
("YouveAlreadySwornAllegiance", 0x040B),
|
||||
("CantSwearAllegianceInsufficientXp", 0x040C),
|
||||
("AllegianceIgnoringRequests", 0x040D),
|
||||
("AllegianceSquelched", 0x040E),
|
||||
("AllegianceMaxDistanceExceeded", 0x040F),
|
||||
("AllegianceIllegalLevel", 0x0410),
|
||||
("AllegianceBadCreation", 0x0411),
|
||||
("AllegiancePatronBusy", 0x0412),
|
||||
("YouAreNotInAllegiance", 0x0414),
|
||||
("AllegianceRemoveHierarchyFailure", 0x0415),
|
||||
("FellowshipIgnoringRequests", 0x0417),
|
||||
("FellowshipSquelched", 0x0418),
|
||||
("FellowshipMaxDistanceExceeded", 0x0419),
|
||||
("FellowshipMember", 0x041A),
|
||||
("FellowshipIllegalLevel", 0x041B),
|
||||
("FellowshipRecruitBusy", 0x041C),
|
||||
("YouMustBeLeaderOfFellowship", 0x041D),
|
||||
("YourFellowshipIsFull", 0x041E),
|
||||
("FellowshipNameIsNotPermitted", 0x041F),
|
||||
("LevelTooLow", 0x0420),
|
||||
("LevelTooHigh", 0x0421),
|
||||
("ThatChannelDoesntExist", 0x0422),
|
||||
("YouCantUseThatChannel", 0x0423),
|
||||
("YouAreAlreadyOnThatChannel", 0x0424),
|
||||
("YouAreNotOnThatChannel", 0x0425),
|
||||
("AttunedItem", 0x0426),
|
||||
("YouCannotMergeDifferentStacks", 0x0427),
|
||||
("YouCannotMergeEnchantedItems", 0x0428),
|
||||
("YouMustControlAtLeastOneStack", 0x0429),
|
||||
("CurrentlyAttacking", 0x042A),
|
||||
("MissileAttackNotOk", 0x042B),
|
||||
("TargetNotAcquired", 0x042C),
|
||||
("ImpossibleShot", 0x042D),
|
||||
("BadWeaponSkill", 0x042E),
|
||||
("UnwieldFailure", 0x042F),
|
||||
("LaunchFailure", 0x0430),
|
||||
("ReloadFailure", 0x0431),
|
||||
("UnableToMakeCraftReq", 0x0432),
|
||||
("CraftAnimationFailed", 0x0433),
|
||||
("YouCantCraftWithThatNumberOfItems", 0x0434),
|
||||
("CraftGeneralErrorUiMsg", 0x0435),
|
||||
("CraftGeneralErrorNoUiMsg", 0x0436),
|
||||
("YouDoNotPassCraftingRequirements", 0x0437),
|
||||
("YouDoNotHaveAllTheNecessaryItems", 0x0438),
|
||||
("NotAllTheItemsAreAvailable", 0x0439),
|
||||
("YouMustBeInPeaceModeToTrade", 0x043A),
|
||||
("YouAreNotTrainedInThatTradeSkill", 0x043B),
|
||||
("YourHandsMustBeFree", 0x043C),
|
||||
("YouCannotLinkToThatPortal", 0x043D),
|
||||
("YouHaveSolvedThisQuestTooRecently", 0x043E),
|
||||
("YouHaveSolvedThisQuestTooManyTimes", 0x043F),
|
||||
("QuestUnknown", 0x0440),
|
||||
("QuestTableCorrupt", 0x0441),
|
||||
("QuestBad", 0x0442),
|
||||
("QuestDuplicate", 0x0443),
|
||||
("QuestUnsolved", 0x0444),
|
||||
("ItemRequiresQuestToBePickedUp", 0x0445),
|
||||
("QuestSolvedTooLongAgo", 0x0446),
|
||||
("TradeIgnoringRequests", 0x044C),
|
||||
("TradeSquelched", 0x044D),
|
||||
("TradeMaxDistanceExceeded", 0x044E),
|
||||
("TradeAlreadyTrading", 0x044F),
|
||||
("TradeBusy", 0x0450),
|
||||
("TradeClosed", 0x0451),
|
||||
("TradeExpired", 0x0452),
|
||||
("TradeItemBeingTraded", 0x0453),
|
||||
("TradeNonEmptyContainer", 0x0454),
|
||||
("TradeNonCombatMode", 0x0455),
|
||||
("TradeIncomplete", 0x0456),
|
||||
("TradeStampMismatch", 0x0457),
|
||||
("TradeUnopened", 0x0458),
|
||||
("TradeEmpty", 0x0459),
|
||||
("TradeAlreadyAccepted", 0x045A),
|
||||
("TradeOutOfSync", 0x045B),
|
||||
("PKsMayNotUsePortal", 0x045C),
|
||||
("NonPKsMayNotUsePortal", 0x045D),
|
||||
("HouseAbandoned", 0x045E),
|
||||
("HouseEvicted", 0x045F),
|
||||
("HouseAlreadyOwned", 0x0460),
|
||||
("HouseBuyFailed", 0x0461),
|
||||
("HouseRentFailed", 0x0462),
|
||||
("Hooked", 0x0463),
|
||||
("MagicInvalidPosition", 0x0465),
|
||||
("YouMustHaveDarkMajestyToUsePortal", 0x0466),
|
||||
("InvalidAmmoType", 0x0467),
|
||||
("SkillTooLow", 0x0468),
|
||||
("YouHaveUsedAllTheHooks", 0x0469),
|
||||
("TradeAiDoesntWant", 0x046A),
|
||||
("HookHouseNotOwned", 0x046B),
|
||||
("YouMustCompleteQuestToUsePortal", 0x0474),
|
||||
("HouseNoAllegiance", 0x047E),
|
||||
("YouMustOwnHouseToUseCommand", 0x047F),
|
||||
("YourMonarchDoesNotOwnAMansionOrVilla", 0x0480),
|
||||
("YourMonarchsHouseIsNotAMansionOrVilla", 0x0481),
|
||||
("YourMonarchHasClosedTheMansion", 0x0482),
|
||||
("YouMustBeMonarchToPurchaseDwelling", 0x048A),
|
||||
("AllegianceTimeout", 0x048D),
|
||||
("YourOfferOfAllegianceWasIgnored", 0x048E),
|
||||
("ConfirmationInProgress", 0x048F),
|
||||
("YouMustBeAMonarchToUseCommand", 0x0490),
|
||||
("YouMustSpecifyCharacterToBoot", 0x0491),
|
||||
("YouCantBootYourself", 0x0492),
|
||||
("ThatCharacterDoesNotExist", 0x0493),
|
||||
("ThatPersonIsNotInYourAllegiance", 0x0494),
|
||||
("CantBreakFromPatronNotInAllegiance", 0x0495),
|
||||
("YourAllegianceHasBeenDissolved", 0x0496),
|
||||
("YourPatronsAllegianceHasBeenBroken", 0x0497),
|
||||
("YouHaveMovedTooFar", 0x0498),
|
||||
("TeleToInvalidPosition", 0x0499),
|
||||
("MustHaveDarkMajestyToUse", 0x049A),
|
||||
("YouFailToLinkWithLifestone", 0x049B),
|
||||
("YouWanderedTooFarToLinkWithLifestone", 0x049C),
|
||||
("YouSuccessfullyLinkWithLifestone", 0x049D),
|
||||
("YouMustLinkToLifestoneToRecall", 0x049E),
|
||||
("YouFailToRecallToLifestone", 0x049F),
|
||||
("YouFailToLinkWithPortal", 0x04A0),
|
||||
("YouSuccessfullyLinkWithPortal", 0x04A1),
|
||||
("YouFailToRecallToPortal", 0x04A2),
|
||||
("YouMustLinkToPortalToRecall", 0x04A3),
|
||||
("YouFailToSummonPortal", 0x04A4),
|
||||
("YouMustLinkToPortalToSummonIt", 0x04A5),
|
||||
("YouFailToTeleport", 0x04A6),
|
||||
("YouHaveBeenTeleportedTooRecently", 0x04A7),
|
||||
("YouMustBeAnAdvocateToUsePortal", 0x04A8),
|
||||
("PortalAisNotAllowed", 0x04A9),
|
||||
("PlayersMayNotUsePortal", 0x04AA),
|
||||
("YouAreNotPowerfulEnoughToUsePortal", 0x04AB),
|
||||
("YouAreTooPowerfulToUsePortal", 0x04AC),
|
||||
("YouCannotRecallPortal", 0x04AD),
|
||||
("YouCannotSummonPortal", 0x04AE),
|
||||
("LockAlreadyUnlocked", 0x04AF),
|
||||
("YouCannotLockOrUnlockThat", 0x04B0),
|
||||
("YouCannotLockWhatIsOpen", 0x04B1),
|
||||
("KeyDoesntFitThisLock", 0x04B2),
|
||||
("LockUsedTooRecently", 0x04B3),
|
||||
("YouArentTrainedInLockpicking", 0x04B4),
|
||||
("AllegianceInfoEmptyName", 0x04B5),
|
||||
("AllegianceInfoSelf", 0x04B6),
|
||||
("AllegianceInfoTooRecent", 0x04B7),
|
||||
("AbuseNoSuchCharacter", 0x04B8),
|
||||
("AbuseReportedSelf", 0x04B9),
|
||||
("AbuseComplaintHandled", 0x04BA),
|
||||
("YouDoNotOwnThatSalvageTool", 0x04BD),
|
||||
("YouDoNotOwnThatItem", 0x04BE),
|
||||
("MaterialCannotBeCreated", 0x04C1),
|
||||
("ItemsAttemptingToSalvageIsInvalid", 0x04C2),
|
||||
("YouCannotSalvageItemsInTrading", 0x04C3),
|
||||
("YouMustBeHouseGuestToUsePortal", 0x04C4),
|
||||
("YourAllegianceRankIsTooLowToUseMagic", 0x04C5),
|
||||
("YourArcaneLoreIsTooLowToUseMagic", 0x04C7),
|
||||
("ItemDoesntHaveEnoughMana", 0x04C8),
|
||||
("YouHaveBeenInPKBattleTooRecently", 0x04CC),
|
||||
("TradeAiRefuseEmote", 0x04CD),
|
||||
("YouFailToAlterSkill", 0x04D0),
|
||||
("FellowshipDeclined", 0x04DB),
|
||||
("FellowshipTimeout", 0x04DC),
|
||||
("YouHaveFailedToAlterAttributes", 0x04DD),
|
||||
("CannotTransferAttributesWhileWieldingItem", 0x04E0),
|
||||
("YouHaveSucceededTransferringAttributes", 0x04E1),
|
||||
("HookIsDuplicated", 0x04E2),
|
||||
("ItemIsWrongTypeForHook", 0x04E3),
|
||||
("HousingChestIsDuplicated", 0x04E4),
|
||||
("HookWillBeDeleted", 0x04E5),
|
||||
("HousingChestWillBeDeleted", 0x04E6),
|
||||
("CannotSwearAllegianceWhileOwningMansion", 0x04E7),
|
||||
("YouCantDoThatWhileInTheAir", 0x04EB),
|
||||
("CannotChangePKStatusWhileRecovering", 0x04EC),
|
||||
("AdvocatesCannotChangePKStatus", 0x04ED),
|
||||
("LevelTooLowToChangePKStatusWithObject", 0x04EE),
|
||||
("LevelTooHighToChangePKStatusWithObject", 0x04EF),
|
||||
("YouFeelAHarshDissonance", 0x04F0),
|
||||
("YouArePKAgain", 0x04F1),
|
||||
("YouAreTemporarilyNoLongerPK", 0x04F2),
|
||||
("PKLiteMayNotUsePortal", 0x04F3),
|
||||
("YouArentTrainedInHealing", 0x04FC),
|
||||
("YouDontOwnThatHealingKit", 0x04FD),
|
||||
("YouCantHealThat", 0x04FE),
|
||||
("YouArentReadyToHeal", 0x0500),
|
||||
("YouCanOnlyHealPlayers", 0x0501),
|
||||
("LifestoneMagicProtectsYou", 0x0502),
|
||||
("PortalEnergyProtectsYou", 0x0503),
|
||||
("YouAreNonPKAgain", 0x0504),
|
||||
("YoureTooCloseToYourSanctuary", 0x0505),
|
||||
("CantDoThatTradeInProgress", 0x0506),
|
||||
("OnlyNonPKsMayEnterPKLite", 0x0507),
|
||||
("YouAreNowPKLite", 0x0508),
|
||||
("IsNowOpenFellowship", 0x050B),
|
||||
("IsNowClosedFellowship", 0x050C),
|
||||
("YouDoNotBelongToAFellowship", 0x050F),
|
||||
("UsingMaxHooksSilent", 0x0511),
|
||||
("YouAreNowUsingMaxHooks", 0x0512),
|
||||
("YouAreNoLongerUsingMaxHooks", 0x0513),
|
||||
("YouAreNotPermittedToUseThatHook", 0x0516),
|
||||
("LockedFellowshipCannotRecruit", 0x0518),
|
||||
("LockedFellowshipCannotRecruitYou", 0x0519),
|
||||
("ActivationNotAllowedNotOwner", 0x051A),
|
||||
("TurbineChatIsEnabled", 0x051D),
|
||||
("YouCannotAddPeopleToHearList", 0x0520),
|
||||
("YouAreNowDeafTo_Screams", 0x0523),
|
||||
("YouCanHearAllPlayersOnceAgain", 0x0524),
|
||||
("YouChickenOut", 0x0526),
|
||||
("YouCanPossiblySucceed", 0x0527),
|
||||
("FellowshipIsLocked", 0x0528),
|
||||
("TradeComplete", 0x0529),
|
||||
("NotASalvageTool", 0x052A),
|
||||
("CharacterNotAvailable", 0x052B),
|
||||
("YouMustWaitToPurchaseHouse", 0x0532),
|
||||
("YouDoNotHaveAuthorityInAllegiance", 0x0535),
|
||||
("YouHaveMaxAccountsBanned", 0x0540),
|
||||
("YouHaveMaxAllegianceOfficers", 0x0545),
|
||||
("YourAllegianceOfficersHaveBeenCleared", 0x0546),
|
||||
("YouCannotJoinChannelsWhileGagged", 0x0548),
|
||||
("YouAreNoLongerAllegianceOfficer", 0x054A),
|
||||
("YourAllegianceDoesNotHaveHometown", 0x054C),
|
||||
("HookItemNotUsable_CannotOpen", 0x054E),
|
||||
("HookItemNotUsable_CanOpen", 0x054F),
|
||||
("MissileOutOfRange", 0x0550),
|
||||
("MustPurchaseThroneOfDestinyToUseFunction", 0x0552),
|
||||
("MustPurchaseThroneOfDestinyToUseItem", 0x0553),
|
||||
("MustPurchaseThroneOfDestinyToUsePortal", 0x0554),
|
||||
("MustPurchaseThroneOfDestinyToAccessQuest", 0x0555),
|
||||
("YouFailedToCompleteAugmentation", 0x0556),
|
||||
("AugmentationUsedTooManyTimes", 0x0557),
|
||||
("AugmentationTypeUsedTooManyTimes", 0x0558),
|
||||
("AugmentationNotEnoughExperience", 0x0559),
|
||||
("ExitTrainingAcademyToUseCommand", 0x055D),
|
||||
("OnlyPKsMayUseCommand", 0x055F),
|
||||
("OnlyPKLiteMayUseCommand", 0x0560),
|
||||
("MaxFriendsExceeded", 0x0561),
|
||||
("ThatCharacterNotOnYourFriendsList", 0x0563),
|
||||
("OnlyHouseOwnerCanUseCommand", 0x0564),
|
||||
("InvalidAllegianceNameCantBeEmpty", 0x0565),
|
||||
("InvalidAllegianceNameTooLong", 0x0566),
|
||||
("InvalidAllegianceNameBadCharacters", 0x0567),
|
||||
("InvalidAllegianceNameInappropriate", 0x0568),
|
||||
("InvalidAllegianceNameAlreadyInUse", 0x0569),
|
||||
("AllegianceNameCleared", 0x056B),
|
||||
("InvalidAllegianceNameSameName", 0x056C),
|
||||
("InvalidOfficerLevel", 0x056F),
|
||||
("AllegianceOfficerTitleIsNotAppropriate", 0x0570),
|
||||
("AllegianceNameIsTooLong", 0x0571),
|
||||
("AllegianceOfficerTitlesCleared", 0x0572),
|
||||
("AllegianceTitleHasIllegalChars", 0x0573),
|
||||
("YouHaveNotPreApprovedVassals", 0x0579),
|
||||
("YouHaveClearedPreApprovedVassal", 0x057C),
|
||||
("CharIsAlreadyGagged", 0x057D),
|
||||
("CharIsNotCurrentlyGagged", 0x057E),
|
||||
("YourAllegianceChatPrivilegesRestored", 0x0581),
|
||||
("TooManyUniqueItems", 0x0584),
|
||||
("HeritageRequiresSpecificArmor", 0x0585),
|
||||
("ArmorRequiresSpecificHeritage", 0x0586),
|
||||
("OlthoiCannotInteractWithThat", 0x0587),
|
||||
("OlthoiCannotUseLifestones", 0x0588),
|
||||
("OlthoiVendorLooksInHorror", 0x0589),
|
||||
("OlthoiCannotJoinFellowship", 0x058B),
|
||||
("OlthoiCannotJoinAllegiance", 0x058C),
|
||||
("YouCannotUseThatItem", 0x058D),
|
||||
("ThisPersonWillNotInteractWithYou", 0x058E),
|
||||
("OnlyOlthoiMayUsePortal", 0x058F),
|
||||
("OlthoiMayNotUsePortal", 0x0590),
|
||||
("YouMayNotUsePortalWithVitae", 0x0591),
|
||||
("YouMustBeTwoWeeksOldToUsePortal", 0x0592),
|
||||
("OlthoiCanOnlyRecallToLifestone", 0x0593),
|
||||
("ContractError", 0x0594),
|
||||
];
|
||||
|
||||
/// <summary>The 16 members that predate the 2026-07-29 full adoption. Their
|
||||
/// values are load-bearing for the CMotionInterp / MoveToManager port and must
|
||||
/// not move when the catalog grows.</summary>
|
||||
private static readonly (string Name, uint Value)[] PreAdoption =
|
||||
[
|
||||
("None", 0x0000),
|
||||
("NoPhysicsObject", 0x0008),
|
||||
("NoMotionInterpreter", 0x000B),
|
||||
("NotGrounded", 0x0024),
|
||||
("ActionCancelled", 0x0036),
|
||||
("ObjectGone", 0x0037),
|
||||
("NoObject", 0x0038),
|
||||
("YouChargedTooFar", 0x003D),
|
||||
("CrouchInCombatStance", 0x003F),
|
||||
("SitInCombatStance", 0x0040),
|
||||
("SleepInCombatStance", 0x0041),
|
||||
("ChatEmoteOutsideNonCombat", 0x0042),
|
||||
("ActionDepthExceeded", 0x0045),
|
||||
("GeneralMovementFailure", 0x0047),
|
||||
("YouCantJumpFromThisPosition", 0x0048),
|
||||
("CantJumpLoadedDown", 0x0049),
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void EveryGoldenMemberHasItsExactValue()
|
||||
{
|
||||
foreach (var (name, value) in Golden)
|
||||
{
|
||||
Assert.True(Enum.IsDefined(typeof(WeenieError), name),
|
||||
$"WeenieError.{name} is missing");
|
||||
Assert.Equal(value, (uint)Enum.Parse<WeenieError>(name));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeclaresNothingOutsideTheGoldenTable()
|
||||
{
|
||||
var expected = Golden.Select(g => g.Name).OrderBy(n => n, StringComparer.Ordinal);
|
||||
var actual = Enum.GetNames<WeenieError>().OrderBy(n => n, StringComparer.Ordinal);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CatalogHoldsTheFullRetailCodeSpace()
|
||||
{
|
||||
Assert.Equal(378, Enum.GetNames<WeenieError>().Length);
|
||||
Assert.Equal(372, Enum.GetValues<WeenieError>().Cast<uint>().Distinct().Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreAdoptionMembersKeepTheirValues()
|
||||
{
|
||||
foreach (var (name, value) in PreAdoption)
|
||||
Assert.Equal(value, (uint)Enum.Parse<WeenieError>(name));
|
||||
}
|
||||
|
||||
/// <summary>The six values that carry both an acdream-local and an ACE name.
|
||||
/// Nothing else may be aliased — a duplicate value elsewhere means the adoption
|
||||
/// picked up a name collision.</summary>
|
||||
[Fact]
|
||||
public void OnlyTheSixDecompAnchoredValuesAreAliased()
|
||||
{
|
||||
(uint Value, string Local, string Ace)[] expected =
|
||||
[
|
||||
(0x0024, "NotGrounded", "YouCantJumpWhileInTheAir"),
|
||||
(0x003F, "CrouchInCombatStance", "CantCrouchInCombat"),
|
||||
(0x0040, "SitInCombatStance", "CantSitInCombat"),
|
||||
(0x0041, "SleepInCombatStance", "CantLieDownInCombat"),
|
||||
(0x0042, "ChatEmoteOutsideNonCombat", "CantChatEmoteInCombat"),
|
||||
(0x0045, "ActionDepthExceeded", "TooManyActions"),
|
||||
];
|
||||
|
||||
var actual = Enum.GetValues<WeenieError>()
|
||||
.Cast<uint>()
|
||||
.Distinct()
|
||||
.Where(v => Golden.Count(g => g.Value == v) > 1)
|
||||
.OrderBy(v => v)
|
||||
.ToArray();
|
||||
Assert.Equal(expected.Select(e => e.Value).OrderBy(v => v), actual);
|
||||
|
||||
foreach (var (value, local, ace) in expected)
|
||||
{
|
||||
Assert.Equal(value, (uint)Enum.Parse<WeenieError>(local));
|
||||
Assert.Equal(value, (uint)Enum.Parse<WeenieError>(ace));
|
||||
// Enum.GetName is documented to return an arbitrary one of the
|
||||
// names sharing a value, so only membership is pinned here.
|
||||
Assert.Contains(Enum.GetName(typeof(WeenieError), value), new[] { local, ace });
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue