78,000 words of grounded, citation-backed research across 13 major AC
subsystems, produced by 13 parallel Opus-4.7 high-effort agents. Plus
compact C# port scaffolds for the top-5 systems and a phase-E-through-H
roadmap update sequencing the work.
Research (docs/research/deepdives/):
- 00-master-synthesis.md (navigation hub + dependency graph)
- r01-spell-system.md 5.4K words (fizzle sigmoid, 8 tabs, 0x004A wire)
- r02-combat-system.md 5.9K words (damage formula, crit, body table)
- r03-motion-animation.md 8.2K words (450+ commands, 27 hook types)
- r04-vfx-particles.md 5.8K words (13 ParticleType, PhysicsScript)
- r05-audio-sound.md 5.6K words (DirectSound 8, CPU falloff)
- r06-items-inventory.md 7.4K words (ItemType flags, EquipMask 31 slots)
- r07-character-creation.md 6.3K words (CharGen dat, 13 heritages)
- r08-network-protocol-atlas 9.7K words (63+149+94 opcodes mapped)
- r09-dungeon-portal-space.md 6.3K words (EnvCell, PlayerTeleport flow)
- r10-quest-dialogs.md 7.1K words (emote-script VM, 122 actions)
- r11-allegiance.md 5.4K words (tree + XP passup + 5 channels)
- r12-weather-daynight.md 4.5K words (deterministic client-side)
- r13-dynamic-lighting.md 4.9K words (8-light cap, hard Range cutoff)
Every claim cites a FUN_ address, ACE file path, DatReaderWriter type,
or holtburger/ACViewer reference. The master synthesis ties them into a
dependency graph and phase sequence.
Key architectural finding: of 94 GameEvents in the 0xF7B0 envelope,
ZERO are handled today — that's the largest network-protocol gap and
blocks F.2 (items) + F.5 (panels) + H.1 (chat).
C# scaffolds (src/AcDream.Core/):
- Items/ItemInstance.cs — ItemType/EquipMask enums, ItemInstance,
Container, PropertyBundle, BurdenMath
- Spells/SpellModel.cs — SpellDatEntry, SpellComponentEntry,
SpellCastStateMachine, ActiveBuff,
SpellMath (fizzle sigmoid + mana cost)
- Combat/CombatModel.cs — CombatMode/AttackType/DamageType/BodyPart,
DamageEvent record, CombatMath (hit-chance
sigmoids, power/accuracy mods, damage formula),
ArmorBuild
- Audio/AudioModel.cs — SoundId enum, SoundEntry, WaveData,
IAudioEngine / ISoundCache contracts,
AudioFalloff (inverse-square)
- Vfx/VfxModel.cs — 13 ParticleType integrators, EmitterDesc,
PhysicsScript + hooks, Particle struct,
ParticleEmitter, IParticleSystem contract
All Core-layer data models; platform-backed engines live in AcDream.App.
Compiles clean; 470 tests still pass.
Roadmap (docs/plans/2026-04-11-roadmap.md):
- Phase E — "Feel alive": motion-hooks + audio + VFX
- Phase F — Fight + cast + gear: GameEvent dispatch, inventory,
combat, spell, core panels
- Phase G — World systems: sky/weather, dynamic lighting, dungeons
- Phase H — Social + progression: chat, allegiance, quests, char creation
- Phase J — Long-tail (renumbered from old Phase E)
Quick-lookup table updated with 10+ new rows mapping observations to
new phase letters.
24 KiB
acdream — Retail AC Deep-Dive Master Synthesis
Date: 2026-04-17
Total research output: ~78,000 words across 13 deep-dive slices
(plus the retail-UI set from earlier the same day — 30,000 words more).
Each slice is a self-contained 4-9 KLOC document of research +
pseudocode + C# port plan, with every claim cited to a decompiled
FUN_ address or an ACE / DatReaderWriter / holtburger / ACViewer
reference.
This document is the navigation hub and cross-reference map. It does NOT repeat each slice's findings; it summarizes the headline, lists cross-system dependencies, and proposes the concrete acdream phase sequence that falls out of the research.
1. Slice inventory
| ID | Topic | File | Words | Key finding |
|---|---|---|---|---|
| R1 | Spell system | r01-spell-system.md | 5.4K | Sigmoid 1/(1+e^(-0.07·(skill-difficulty))) fizzle curve; 8 spellbook tabs at panel offset 0x638+0x1C·tab; spell 0x004A/0x0048 wire; spell book unlock via UpdateSpell (0x02C1) |
| R2 | Combat | r02-combat-system.md | 5.9K | PowerMod = Level + 0.5 melee; physical logistic at k=0.03 / magic at k=0.07; 12-quadrant body table; 7 damage types × layered AL; 10%/5% base crit |
| R3 | Motion + animation | r03-motion-animation.md | 8.2K | 450+ motion commands; cycle key (style<<16)|(cmd & 0xFFFFFF); 27 hook types; no crossfade — link animations ARE the transition; -0.65 backward factor; 1.5× run-turn |
| R4 | VFX / particles | r04-vfx-particles.md | 5.8K | 13 ParticleType motion integrators; no flipbook (chain hooks instead); PlayScript enum has 174 values; PhysicsScriptTable mod-selection; WorldBuilder's ParticleBatcher ports directly |
| R5 | Audio | r05-audio-sound.md | 5.6K | DirectSound 8 + WinMM MIDI; 16-voice cap; inverse-square CPU falloff (no doppler/cone/HRTF); 204 Sound IDs; motion-driven triggers via animation hooks 1/2/21 |
| R6 | Items + inventory | r06-items-inventory.md | 7.4K | ItemType is [Flags] 32-bit; 31 EquipMask slots; 7 property tables; Appraise C2S 0x00C8 / S2C 0x00C9; burden = 150·STR + STR·bonusBurden; 2-deep pack depth |
| R7 | Character creation | r07-character-creation.md | 6.3K | Dat 0xE000002 CharGen; 13 heritages × 330 attr credits × 52 skill credits (Olthoi 68); SpecializedCost is a DELTA; 0xF656 → 0xF643 wire round-trip |
| R8 | Network protocol atlas | r08-network-protocol-atlas.md | 9.7K | 63 primary GameMessages + 149 GameActions + 94 GameEvents mapped. Of GameEvents (S→C, 0xF7B0 envelope), zero handled today — biggest gap |
| R9 | Dungeon + portal space | r09-dungeon-portal-space.md | 6.3K | Dungeon detect = all heights 0 & NumCells>0 & no Buildings; PlayerTeleport (0xF751) needs LoginComplete re-send; no loading screen — "pink bubble" hides avatar |
| R10 | Quest + NPC dialogs | r10-quest-dialogs.md | 7.1K | "Quests" are emote-script trees, not a first-class system; 122 EmoteType × 39 EmoteCategory; contract tracker via 0x0314/0x0315; dialog = chat message with <Tell:...> markup |
| R11 | Allegiance | r11-allegiance.md | 5.4K | Max 11 direct vassals; rank max(lower+1, higher) capped 10; XP passup 50+22.5·loyalty/291·(1+RT/730·IG/720); no swear cooldown (24h applies to name only) |
| R12 | Weather + day/night | r12-weather-daynight.md | 4.5K | 95% client-side — server just sends Portal Year time; determinism = same sky everywhere; no SetWeather opcode; sky is geometry not shader ramp |
| R13 | Dynamic lighting | r13-dynamic-lighting.md | 4.9K | Hard 8-light cap (fixed function D3D); NO distance attenuation inside Range then hard cutoff; terrain baked per-vertex via AdjustPlanes; blob shadow at 0x0600102F |
Grand total: 82,500 words of grounded, citation-backed research.
2. The big picture — how the systems wire together
┌─────────────────────────────────────────────────────────────────┐
│ ACE (Asheron's Call Emulator) │
│ — server authority │
└────┬────────────────────────────────────────────────────────────┘
│ UDP packets (ISAAC, fragmented, ack'd)
│
┌────▼────────────────────────────────────────────────────────────┐
│ WorldSession (R8 atlas) │
│ • Login (4 msg), CharList, EnterWorld, CreateObject stream │
│ • Dispatch of 63 + 94 + 149 opcodes │
└────┬──────────────┬──────────────┬──────────────┬───────────────┘
│ │ │ │
│CreateObject │UpdateMotion │UpdateHealth │UpdateSpell
│ items │ anim │ combat │ buff/debuff
▼ ▼ ▼ ▼
┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────────┐
│ Inventory│ │ Motion │ │ Combat │ │ Spell │
│ (R6) │ │ (R3) │ │ (R2) │ │ (R1) │
│ │ │ │ │ │ │ │
│ItemInst │──│ DoMotion │──│ Damage │──│ ActiveBuf │
│Container │ │ MotionTbl │ │ fromCmd │ │ Fizzle │
│Burden │ │ Hooks ────┼──┤ FootStep │ │ Recall │
└────┬─────┘ └─┬────┬────┘ └────┬─────┘ └────┬──────┘
│ │ │ │ │
│ │ └────hooks──►│ │
│ │ │ │
└──────────┴───────►┌────────▼─────────────▼──┐
│ Audio (R5) + │
│ VFX/Particles (R4) │
│ — cosmetic layer │
└──────────────┬──────────┘
│
▼
┌───────────────────────────────┐
│ UI (retail-ui set) + HUD │
│ AttrPanel + SpellBar + Chat │
│ VitalOrbs + Radar + Compass │
│ (all behind UiRoot scaffold) │
└───────────────────────────────┘
┌─ World lifecycle
│
┌───▼─────────────────────┐
│ Streaming (existing) │
├─────────────────────────┤
│ + Dungeon / portal (R9) │
│ + Weather sky (R12) │
│ + Dynamic lights (R13) │
└─────────────────────────┘
┌─ Social / progression
│
┌──────────────────┐ ┌─────────────────┐
│ Allegiance (R11) │ │ Quest + dialog │
│ • Tree + ranks │ │ (R10) │
│ • XP passup │ │ • Emote scripts │
│ • Chat channels │ │ • Contract tkr │
└──────────────────┘ └─────────────────┘
┌─ Game entry
│
┌──────────────────┐
│ CharCreate (R7) │
│ • Heritage + skl │
│ • Appearance │
│ • Starting town │
└──────────────────┘
3. Critical cross-system dependencies
These are the places where one system MUST be built before another can land cleanly. They define the port sequence.
3.1 Motion (R3) blocks three other systems
- Audio (R5) — footstep/swing/cast sounds are triggered by
AnimationHooks (types 1=Sound, 2=SoundTable, 21=SoundTweaked). Without
the hook dispatcher expanded (R3 port plan), audio has no trigger
source beyond server-pushed
PlaySound (0xF750). - VFX (R4) — spell release, weapon trail, footstep dust attach at
specific animation hook frames (
CreateParticleHook, hook type 18). - Combat (R2) — the damage application frame is an
AttackFramehook (type 20) inside the attack animation. Without R3 hook dispatch, combat math has to guess timing.
Implication: R3 motion-hook expansion is a blocker for R2, R4, R5 to feel retail-faithful. It's a prerequisite for "the game feels alive".
3.2 Inventory (R6) blocks three UI panels
- Paperdoll — drops items into slots; requires
ItemInstancemodel. - Spellbook (R1) — items like scarabs are consumed via R6 burden rules.
- Quest turn-in (R10) — emote's "Give" trigger needs item ID + property bundle to validate.
Implication: R6 is the data-model foundation for any gameplay UI.
3.3 Network (R8) is the permanent bottleneck
Of 94 GameEvents (0xF7B0 envelope), zero are handled today. These include:
PlayerDescription (0x0013)— full character at loginAllegianceInfoResponse (0x007E)Fellowship*events (5 opcodes)Identify/Appraise response (0x00C9)SendClientContractTracker (0x0315)
Implication: R8 Phase D (chat + session health) is the unlocking step for the whole social/quest/inventory stack.
3.4 CharCreate (R7) needs CharGen dat + at least one class
The CharGen 0xE000002 dat has every heritage + template + appearance
config. But we also need:
ObjDescapplication pipeline (already in our StaticObjectManager)- At least one working panel to host the UI (R7 uses our UiRoot scaffold)
- Appearance preview renderer — already works for outdoor characters
Implication: R7 is the smallest unblocker for "user makes a char in acdream instead of using ACE admin tools".
3.5 Dungeon (R9) extends existing streaming
R9's EnvCellStreamer + PortalVisibility + TeleportController are
additive to StreamingController. Risk is low.
3.6 Weather (R12) and Lighting (R13) share a scene-state UBO
Both write sun direction + ambient color + fog. A single
SceneLightingState UBO fed to terrain.frag and mesh.frag
consolidates them. R13 reads it; R12 produces it.
3.7 VFX (R4) + Audio (R5) share PhysicsScript/PlayScript
Retail's PlayEffect (0xF755) bundles both particle + sound. Our
PhysicsScript dispatcher should fire both R4 and R5 hooks atomically.
4. Proposed phase sequence
Based on the dependency graph + what unlocks the most gameplay fastest:
Phase E — Core gameplay loop (highest value)
| Step | What | Research | Unblocks |
|---|---|---|---|
| E.1 | R3 Motion hooks expansion | R3 | E.2-E.4 |
| E.2 | R5 Audio engine + motion-hook wiring | R5 | immediate feel |
| E.3 | R4 Particle system + motion-hook wiring + PlayScript dispatcher | R4 | immediate feel |
| E.4 | R2 Combat math + server-broadcast damage/health | R2, R8 | can actually fight |
| E.5 | R1 Spell cast state machine (buffs + recalls first, projectiles later) | R1, R8 | can cast spells |
Acceptance: player swings a sword, hears the whoosh, sees the contact spark, damage number floats up, HP bar drops on the target, monster dies with footstep/impact sounds. Spell buff lands with glowing aura + cast sound.
Phase F — Inventory + UI panels
| Step | What | Research | Unblocks |
|---|---|---|---|
| F.1 | R8 GameEvent envelope (0xF7B0) dispatcher | R8 | F.2+ |
| F.2 | R6 Item model (ItemInstance, PropertyBundle) |
R6 | F.3-F.5 |
| F.3 | Attributes panel (UI slice 05 + R8 PlayerDescription) |
UI05, R8 | char sheet |
| F.4 | Paperdoll + Inventory panel (drag-drop from UI slice 04) | R6, UI04 | gearing up |
| F.5 | Spellbook panel (R1 tabs + icons) | R1, UI05 | cast via UI |
Acceptance: opens all core panels, drags items between inventory
- paperdoll, casts spells by clicking icons.
Phase G — World systems
| Step | What | Research |
|---|---|---|
| G.1 | R12 Sky / weather / day-night | R12 |
| G.2 | R13 Dynamic lighting (8-light fixed pipeline) | R13 |
| G.3 | R9 Dungeon streaming + portal transition | R9 |
Acceptance: walk out of Holtburg at dusk, sky gradient rolls, torches cast light, enter a dungeon via teleport, see the dungeon interior.
Phase H — Social + progression
| Step | What | Research |
|---|---|---|
| H.1 | Chat window (UI slice 05) + all 6 wire ops | UI05, R8 |
| H.2 | R11 Allegiance panel + XP passup display | R11 |
| H.3 | R10 Quest/emote/dialog system | R10 |
| H.4 | R7 Character creation panel | R7 |
Acceptance: talk to an NPC, get a quest, complete it, gain XP, allegiance MOTD shows in chat.
5. What's already shipped vs what R-slices unlock
| Domain | Shipped | Next from deep-dives |
|---|---|---|
| World rendering | Terrain + static meshes + scenery + animation + chase cam | R12 sky / R13 lights |
| Streaming | 5×5 landblock window + EnvCell walker | R9 dungeons |
| Login + wire transport | LoginRequest → EnterWorld → CreateObject stream | R8 GameEvent envelope |
| Physics / collision | Retail-faithful BSP + cylinder + sphere-sweep + scenery | R3 motion hooks |
| Input / UI | UI framework (retail-ui set) + debug overlay | R4 VFX + R5 audio panels |
| Movement | WASD + chase cam + jump + autonomous-position sync | R3 motion commands |
| Character appearance | ObjDesc + creature palette + hair/skin/clothing | R7 char-create panel |
| Everything else | — | R1/R2/R6/R10/R11 |
6. Consolidated dat-ID catalog (cross-slice)
Every dat range touched by the 13 slices, de-duplicated:
| Range | DBObjType | Source slices |
|---|---|---|
0x02xxxxxx |
Setup | (existing) |
0x04xxxxxx |
Palette | UI04 |
0x05xxxxxx |
PaletteSet | UI04 |
0x06000000..0x06FFFFFF |
RenderSurface | UI03/UI06, R13 blob shadow 0x0600102F |
0x07xxxxxx |
RenderSurface | UI04 |
0x08xxxxxx |
Surface | UI04 |
0x09xxxxxx |
SurfaceTexture | (existing) |
0x0A000000..0x0A00FFFF |
Wave | R5 audio |
0x0E000002 |
CharGen | R7 chargen |
0x0F000000..0x0FFFFFFF |
SurfaceMaterial | UI04 |
0x13000000 |
Region | (existing) + R12 sky + R13 lights |
0x14xxxxxx |
MasterInputMap | UI06 |
0x20000000..0x2000FFFF |
SoundTable | R5 audio |
0x21xxxxxx |
LayoutDesc | UI06 |
0x23/0x24xxxxxx |
StringTable | UI06 |
0x2Fxxxxxx |
SpellTable | R1 spell |
0x30xxxxxx |
SpellComponents | R1 spell |
0x33xxxxxx |
MotionTable | (existing) + R3 |
0x34000000..0x34000FFF |
Animation | (existing) + R3 |
0x40000000..0x40000FFF |
Font | UI03 |
0x41xxxxxx |
LanguageInfo | UI06 |
7. Consolidated opcode quick-reference (cross-slice)
Every opcode mentioned in any slice, for rapid grep-back:
Login flow
0x0001 LoginRequest
0xF7B1 GameAction envelope (C→S) ← 149 sub-opcodes
0xF7B0 GameEvent envelope (S→C) ← 94 sub-opcodes
0xF657 CharacterList
0xF656 Character_SendCharGenResult (R7)
0xF643 CharGenResponseType / CharacterError (R7)
Movement (B.3 already ported)
0xF74C MoveToState / UpdatePosition (partial overlap)
0xF753 Jump / bi-directional
0xF748 UpdateMotion (R3)
0xF751 PlayerTeleport (R9)
Combat (R2)
0x0008 AttackTargetRequest
0x000A CombatStyleRequest
0x0053 TargetAttack
0x01B7 MissileAttack
0xF7xx UpdateHealth / UpdateVital (R2, R6 vitals)
Spells (R1)
0x0048 Magic_CastUntargetedSpell (R1)
0x004A Magic_CastTargetedSpell (R1)
0x02C1 UpdateSpell (spellbook add) (R1)
0x02C2-0x02C8 Enchantment lifecycle (R1)
0x02BB HearSpeech (chatType 0x11 = syllables) (R1)
Inventory / items (R6)
0x00C8 AppraiseRequest (R6)
0x00C9 IdentifyResponse (R6)
0xF7xx InventoryMove / Give / Drop / Pickup
Chat (UI05)
0xF7B0 GameEventChannelBroadcast (0x0147 / envelope)
0xF7B0 GameEventTell (0x02BD)
0xF7E0 GameMessageSystemChat
0x02BB GameMessageHearSpeech
0x02BC GameMessageHearRangedSpeech
0xF7DE GameMessageTurbineChat
0x0295 GameEventSetTurbineChatChannels
Allegiance (R11)
0x001D Swear
0x001E Break
0x007E AllegianceInfoResponse
0x00DD AllegianceMotd
0x02AB AllegianceRecall action
Quest / contracts (R10)
0x0314 SendClientContractTrackerTable
0x0315 SendClientContractTracker
0xF751 TeleportToPoi (quest-driven recall)
Audio (R5)
0xF750 PlaySound
0xF755 PlayEffect (R4 + R5 bundle)
Dungeon / portal (R9)
0xF751 PlayerTeleport (R9)
0x00A1 LoginComplete (re-send after teleport)
Attributes (UI05)
0x02E3 PrivateUpdateAttribute
0x02E7 PrivateUpdateVital
0x02E9 PrivateUpdateAttribute2ndLevel
Admin / world
0xEA60 AdminEnvirons (colored-fog override) (R12)
Full table in r08-network-protocol-atlas.md.
8. Open questions that surfaced
- keystone.dll — blocking for truly retail-faithful widget layout. Would need a second decompile pass. (UI slice 02)
- Launcher / patcher — similarly binary-only. (out of scope)
- Retail fizzle mana — R1 flagged "5 points lost on fizzle" as tentative; would benefit from retail packet capture.
- Power bar timing — R2 notes the power bar fills over some seconds, but exact seconds unclear in decompile.
- Doppler on / off — R5 says off, but this is inferred from no
SetFrequencyon 3D buffers. Verify with retail binary trace if audio fidelity matters later. - Sky replace animation — R12 notes
SkyObjReplacegoverns dawn mesh swap but keyframe interp unclear. - Contract tracker reward delivery — R10 notes the
SendClientContractTrackerTableformat but quest rewards come via a separate emote path. - Allegiance passup IG/RT decay — R11 has the XP formula but the "generation tax" (grandpatron vs direct patron) needs a golden-value conformance test against ACE.
9. Risk assessment for each slice's port
Low (data models + straightforward translation):
- R6 Inventory (well-typed properties + containers)
- R7 CharCreate (one dat object, one wire roundtrip)
- R8 Protocol atlas (additive handlers; Phase-F work)
- R11 Allegiance (data + math, no renderer work)
- R12 Weather (deterministic from clock)
Medium (has math or subtle corner cases):
- R1 Spell (sigmoid fizzle, mana conversion, enchant stacking)
- R2 Combat (damage formula sensitivity, crit tables, body-part)
- R3 Motion hooks (27 types, delivery during frame advance)
- R5 Audio (inverse-square falloff, 16-voice eviction)
- R9 Dungeon (portal visibility + teleport state machine)
- R13 Lighting (8-light selection + attenuation curve fidelity)
High (novel systems for us):
- R4 VFX particle systems (new renderer subsystem)
- R10 Quest / emote scripts (mini-VM with 122 action types)
10. Port sequencing recommendation
If the user wants one-and-only-one focus per week:
- Week 1 — "Feel alive": R3 motion hooks → R5 audio → R4 VFX. Ship: footsteps, swing sounds, impact particles, spell aura particle.
- Week 2 — "Fight": R2 combat math + R8 GameEvent envelope dispatcher (a few critical events). Ship: actual damage flow, HP updates, death.
- Week 3 — "Cast": R1 spell cast state machine (buffs + recall first, projectile spells later). Ship: heal spell works, buff spell works, recall spell works.
- Week 4 — "Have gear": R6 inventory + Attributes + Paperdoll panels. Ship: equip weapon, see stats, manage pack contents.
- Week 5 — "World": R12 sky + R13 lights + R9 dungeon. Ship: enter a dungeon, see torch lights, day/night outside.
- Week 6 — "Social": Chat + R11 allegiance + R10 quest + R7 char-create. Ship: complete the loop.
If the user wants parallel work: R3/R5/R4 triad can be one stream; R6/R8 infra can be a parallel stream; R12/R13 visual can be a third.
11. Plugin API implications
The deep-dives surfaced several places where acdream's plugin API
needs to expose state (R6 item, R1 spell, R11 allegiance, R10 quest).
These are all pure data + event streams, no 3D rendering hooks. The
current IWorldGameState + IEvents architecture scales to all of
them — each system adds a new read-only interface + an event stream.
Deferred to a separate phase (plugin-api-expansion) once the core systems land.