# acdream — strategic roadmap **Status:** Living document. Updated 2026-04-11 after Phase 6, 7.1, 9.1, 9.2 landed. **Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file. --- ## Phases already shipped | Phase | What landed | Verification | |---|---|---| | 1 | Terrain rendering, plugin host scaffold | Visual ✓ | | 2a | Static stabs/buildings (126 entities) | Visual ✓ | | 2b | Textured 3×3 landblock grid + FlyCamera + IGameState | Visual ✓ | | 2c | Procedural scenery (419 trees/rocks/bushes) | Visual ✓ | | 2d | Interior EnvCell walker (475 static interior objects) | Visual ✓ | | 3a/3b | Directional sun lighting + per-vertex terrain normals | Visual ✓ | | 3c | Per-cell terrain texture blending (alpha atlas) | Visual ✓ | | 4 | Full UDP codec + handshake + character login + WorldSession | Live ✓ | | 5 | ObjDesc: AnimPartChange + TextureChanges + SubPalettes + ObjScale + Placement.Resting | Live ✓ | | 6.1 | Idle motion frame resolution (MotionResolver MVP) | Live ✓ | | 6.2 | Server-sent `MovementData` stance + forward command honored | Live ✓ | | 6.3 | Server-supplied `MotionTableId` override (fixes drudge statue) | Live ✓ | | 6.4 | Per-frame animation playback (breathing, idle cycles) | Live ✓ | | 6.5 | Slerp between keyframes for smooth animation | Live ✓ | | 6.6 | `UpdateMotion` (0xF74C) parser + dispatch to animation tick | Live ✓ | | 6.7 | `UpdatePosition` (0xF748) parser + position reseating | Live ✓ | | 7.1 | EnvCell room geometry — walls/floors/ceilings via CellStruct + Environment dats | Visual ✓ | | 9.1 | Translucent render pass (AlphaBlend / Additive / InvAlpha + per-kind blend funcs) | Visual ✓ | | 9.2 | Back-face culling in translucent pass (fixes lifestone crystal) | Visual ✓ | | A.1 | Streaming landblock loader — runtime-configurable visible window (default 5×5, `ACDREAM_STREAM_RADIUS`), camera-centered offline / player-centered live, hysteresis-based unloads, pending-spawn list for late CreateObject events | Live ✓ | | A.2 | Frustum culling — per-landblock AABB test (Gribb-Hartmann), terrain + static-mesh renderers skip culled landblocks, perf overlay in window title | Visual ✓ | | A.3 | Background net receive thread — dedicated daemon thread buffers UDP into Channel, render thread drains | Visual ✓ | | B.3 | Physics collision engine — TerrainSurface (heightmap Z), CellSurface (indoor floor polygon projection), PhysicsEngine (resolver with step-height + cell transitions). Populated from streaming pipeline. | Tests ✓ | | B.2 | Player movement mode — Tab-toggled WASD ground walking, walk/run/idle animations, third-person chase camera, MoveToState + AutonomousPosition outbound, portal entry. Outdoor-only MVP. | Live ✓ | | D.1 | 2D ortho overlay + font rendering (StbTrueTypeSharp atlas + TextRenderer + DebugOverlay) | Visual ✓ | | E.1 | Motion-hook expansion — AnimationSequencer fires all 27 hook types per crossed frame; PosFrames root motion + vel/omega exposure; IAnimationHookSink + AnimationHookRouter fan-out | Tests ✓ | | E.2 | Audio engine — OpenAL 16-voice 3D pool with retail-faithful quieter-slot eviction, SoundTable cookbook (probability-weighted variant picking), Wave PCM decoder, AudioHookSink wiring | Tests ✓ | | E.3 | Particle system (data layer) — ParticleSystem with 13 motion integrators, EmitterDescRegistry, ParticleHookSink wiring all CreateParticle / DestroyParticle / StopParticle hooks | Tests ✓ | | E.4 | Combat notifications + outbound — AttackTargetRequest (0x0008), 7 combat notification parsers (Victim/Defender/Attacker/Evasion/AttackDone/UpdateHealth), CombatState per-entity health tracker | Tests ✓ | | E.5 | Spell cast wire — CastSpellRequest targeted (0x004A) + untargeted (0x0048), Spellbook (learned spells + active-enchantment layers), 5 enchantment GameEvent parsers | Tests ✓ | | F.1 | GameEvent (0xF7B0) envelope dispatcher — all 94 sub-opcodes routed, exception-isolated handler registry, unhandled-count diagnostic bag; 18 event-payload parsers | Tests ✓ | | F.2 | Item model + Appraise — ItemRepository with move/equip/property events, AppraiseRequest (0x00C8), IdentifyObjectResponse header, WieldObject + InventoryPutObjInContainer | Tests ✓ | | G.1 | Sky + day/night — DerethDateTime (retail-exact 7620-tick calendar + 16-hour names + PY year), SkyStateProvider (4-keyframe default with angular-wrap lerp), WorldTimeService (server-synced clock with real-time advance) | Tests ✓ | | G.2 | Dynamic lighting (selection) — LightSource + LightManager with retail 8-light cap, range-squared with 1.1× slack, slot 0 reserved for Sun, OwnerId-keyed unregister | Tests ✓ | | G.1+ | Full sky visuals + weather + dynamic-light shader — SkyDescLoader parses Region 0x13000000 dat keyframes with retail fog fields (start/end/mode); WeatherSystem picks Clear/Overcast/Rain/Snow/Storm deterministically per in-game day with 10s fade; SkyRenderer draws far-plane-1e6 celestial meshes with UV scroll; SceneLightingUbo binds at std140 location=1 with 8 Light slots + fog + lightning flash; terrain.vert + mesh.frag + mesh_instanced.frag + sky.frag all consume the shared UBO; LightingHookSink auto-registers Setup.Lights per entity + flips IsLit on SetLightHook; ParticleRenderer renders rain/snow billboards; F7 cycles day time override, F10 cycles weather; WorldSession surfaces server time via ServerTimeUpdated (ConnectRequest + TimeSync flag) | Tests ✓ | | H.1 | Chat window — wire layer + panel + outbound input + holtburger inbound parity all shipped (I.1-I.7). Talk (0x0015) / Tell (0x005D) / ChatChannel (0x0147) outbound + EmoteText (0x01E0) / SoulEmote (0x01E2) / ServerMessage (0xF7E0) / PlayerKilled (0x019E) / TurbineChat (0xF7DE) / SetTurbineChatChannels (0x0295) inbound; `ChatPanel` with Enter-to-submit input + slash commands; `CombatChatTranslator` posts combat events as chat lines. | Live ✓ | | Glue | GameEventWiring.WireAll — single-call registration mapping parsed GameEvents → Core state classes (ChatLog, CombatState, Spellbook, ItemRepository); GameWindow exposes state classes + wires them to live session | Tests ✓ | | D.2a | UI scaffold — `AcDream.UI.Abstractions` stable contract (`IPanel` / `IPanelHost` / `IPanelRenderer` / `ICommandBus` + `VitalsVM` / `VitalsPanel`); `AcDream.UI.ImGui` backend on ImGui.NET + `Silk.NET.OpenGL.Extensions.ImGui` (pivoted from Hexa.NET.ImGui on 2026-04-25 — Hexa's native OpenGL3 backend resolves GL via GLFW/SDL and crashed 0xC0000005 without them); VitalsPanel wired into GameWindow behind `ACDREAM_DEVTOOLS=1` with `ImGui.WantCaptureKeyboard` WASD suppression. 11 new tests. | Live ✓ | | I.1 | `IPanelRenderer` widget extension — TextColored / Checkbox / Combo / InputTextSubmit / BeginTable + ~9 more widget signatures on `IPanelRenderer`; matching `ImGuiPanelRenderer` impls. Foundation for I.2 + I.4. | Tests ✓ | | I.2 | DebugPanel migration — replaced 473-LOC StbTrueTypeSharp `DebugOverlay` with `AcDream.UI.Abstractions/Panels/Debug/DebugPanel` (collapsing-headers + diagnostics checkboxes + combat-event tail). `DebugOverlay.cs` deleted; `TextRenderer` + `BitmapFont` retained for the future world-space HUD (D.6). | Live ✓ | | I.3 | `LiveCommandBus` + `WorldSession.SendTalk` / `SendTell` / `SendChannel` — replaces `NullCommandBus.Instance` with a real handler-registry `ICommandBus`. New `SendChatCmd` record + `ChannelResolver` legacy-id mapping (per holtburger). 3-line wrappers around existing `ChatRequests.BuildTalk/Tell/ChatChannel`. | Tests ✓ | | I.4 | `ChatPanel` input field + slash commands — Enter-to-submit input field; `ChatInputParser` recognises `/say` `/t` `/tell` `/r` `/g` `/f` `/a` `/m` `/p` `/v` `/cv` `/lfg` `/trade` `/role` `/society` `/olthoi`; `ChatVM.LastIncomingTellSender` tracks for `/r` reply. `ImGui.WantCaptureKeyboard` already suppresses WASD on focus. | Live ✓ | | I.5 | Holtburger inbound chat parity + Windows-1252 codec — `EmoteText (0x01E0)`, `SoulEmote (0x01E2)`, `ServerMessage (0xF7E0)`, `PlayerKilled (0x019E)` parsers + `WeenieError` routing through `GameEventWiring`. Global string codec switch from `Encoding.ASCII` to `Encoding.GetEncoding(1252)` so accented names round-trip per retail + holtburger. | Tests ✓ | | I.6 | TurbineChat codec + `ChatChannelInfo` — full `0xF7DE` codec with three payload variants (`EventSendToRoom`, `RequestSendToRoomById`, `Response`), UTF-16LE strings with variable-length prefix, `SetTurbineChatChannels (0x0295)` parser, unified `ChatChannelInfo` (Legacy + Turbine variants), `TurbineChatState`. **ACE doesn't host a TurbineChat server — codec is ready when retail-emulating servers exist.** | Tests ✓ | | I.7 | `CombatChatTranslator` — retail-faithful combat-text formatters into `ChatLog` ("You hit drudge for 50 slashing damage (87%)"). Subscribes to `CombatState`'s `DamageTaken` / `DamageDealtAccepted` / `EvadedIncoming` / `MissedOutgoing` / `AttackDone` / `KillLanded`; templates ported verbatim from holtburger `panels/chat.rs:221-308`. | Tests ✓ | | K | Input architecture — `Action` enum, `KeyChord`, `KeyBindings`, multicast `InputDispatcher` with scope-stack + modal capture, retail-default keymap (152 bindings), `keybinds.json` persistence, F11 Settings panel with click-to-rebind + conflict detection, main menu bar + View menu | Live ✓ | | L.0 | Full retail-style Settings interface — F11 tabbed panel with 6 tabs (Keybinds + Display + Audio + Gameplay + Chat + Character). `settings.json` at `%LOCALAPPDATA%\acdream\`, per-toon `Character` keying (swapped on EnterWorld). Display GL knobs (Resolution / Fullscreen / VSync / FOV / ShowFps) + Audio (Master / SFX) live-wired; Gameplay / Chat / Character settings persist for server-sync wiring later. Tab API extension to `IPanelRenderer`; chat Copy mode (read-only multi-line); per-panel layout reset; FramebufferResize handler keeps GL viewport + camera aspect + panel positions in sync. | Live ✓ | Plus polish that doesn't get its own phase number: - FlyCamera default speed lowered + Shift-to-boost - SurfaceDecoder: PFID_P8 / PFID_R8G8B8 / PFID_X8R8G8B8 decoders - GfxObjMesh: emit both pos and neg sides of double-sided polygons - EnvCell mesh Z-lift to fix ground-floor / terrain flicker --- ## Phases ahead — agreed order ### Phase A — Foundation (in progress) **Goal:** walk across 10+ landblocks without crashes, without hitches at landblock boundaries, and without framerate cratering. **Sub-pieces:** - **✓ SHIPPED — A.1 — Streaming landblock loader.** Runtime-configurable visible window (default 5×5, `ACDREAM_STREAM_RADIUS` env var override). Center follows the fly camera offline and the server-sent player position in live mode. Currently runs **synchronously** on the render thread — the original async-worker design hit DatCollection's lack of thread safety and was reverted for correctness. The Channel-based outbox API is preserved so async loading can return cleanly when `Phase A.3` introduces a thread-safe dat wrapper. Pending-spawn list in `GpuWorldState` parks live `CreateObject` events whose target landblock hasn't been streamed in yet and back-fills them when it arrives, so spawn-vs-streaming races are no longer racy at all. `MaxCompletionsPerFrame=4` spreads the 5×5 first-frame load over ~7 frames (~116ms) to avoid GPU OOM. - **✓ SHIPPED — A.2 — Frustum culling.** Per-landblock AABB test (Gribb-Hartmann plane extraction + positive-vertex AABB test) in both `TerrainRenderer.Draw` and `StaticMeshRenderer.Draw`. Per-entity culling deferred. LOD deferred to Phase C. Performance overlay in window title shows FPS, frame time, visible/total landblock ratio, entity count, animated count. ~160fps uncapped at 5×5 radius. - **✓ SHIPPED — A.3 — Background net receive thread.** Dedicated daemon thread continuously pulls raw UDP datagrams from the kernel buffer into a `Channel`. Render thread's `Tick()` drains the channel. All decode, fragment assembly, ISAAC crypto, event dispatch, and ack-sending remain on the render thread — minimal change that prevents packet drops during frame stalls. Thread starts after `EnterWorld()` completes; `PumpOnce()` during handshake still reads the socket directly. - **A.4 — Async dat decoding.** Folded into the streaming worker — it's the worker's read path, not a separate subsystem. Called out here because regressions in dat caching could land on this surface. **Acceptance:** - Walk across 10+ landblocks in any direction, no crashes, no empty voids. - Landblock-boundary crossings produce no visible hitch. - Runtime window radius toggleable via environment variable. **Detailed spec:** `docs/superpowers/specs/2026-04-11-foundation-phase-design.md` --- ### Phase B — Gameplay / interaction **Goal:** actually play the game — walk the character on the server, click NPCs, pick up items, chat, basic combat loop. **Sub-pieces:** - **✓ SHIPPED — B.1 — Outbound ack pump.** Shipped as Phase 4.9 — per-packet ACK_SEQUENCE, not periodic. Server no longer drops idle clients. - **✓ SHIPPED — B.2 — Player movement mode.** Tab-toggled WASD ground walking with collision-resolved outdoor terrain, walk/run/idle/turn-right animations, third-person chase camera, outbound MoveToState (0xF61C) + AutonomousPosition (0xF753) server messages, portal entry works. Outdoor→indoor transition disabled for MVP (CellSurface floor polygons too aggressive without portal-based detection). Minor polish remaining: strafe animation, turn-left animation. Spec: `docs/superpowers/specs/2026-04-12-player-movement-design.md`. - **✓ SHIPPED — B.3 — Physics collision engine.** TerrainSurface (heightmap bilinear Z), CellSurface (indoor floor polygon projection via barycentric interpolation), PhysicsEngine (top-level resolver with step-height enforcement, outdoor↔indoor cell transitions, gravity reporting). Populated from streaming pipeline. 16 unit tests with fake data. Spec: `docs/superpowers/specs/2026-04-12-physics-collision-engine-design.md`. - **B.4 — `Use` / `UseWithTarget` / `PickUp`.** Outbound interaction messages. Drives opening doors, looting, talking to vendors. - **B.5 — Chat.** `SendTell`, `SendChat` outbound + receive/display inbound (display side depends on Phase D.1). **References:** - `references/ACE/Source/ACE.Server/Network/Handlers/MovementHandler.cs` - `references/ACE/Source/ACE.Server/Network/Handlers/UseObjectHandler.cs` - `references/holtburger/src/session/send.rs` for outbound packet-building patterns **Acceptance:** walk on-server with your character, open a door, talk to an NPC, send a chat message and see the echo. --- ### Phase C — Polish / visuals **Goal:** close the visible gaps that make the world read as "old / broken" compared to retail. **Sub-pieces:** - **C.1 — VFX / particle system.** `PhysicsScript` parser, per-entity `ParticleEmitter` state, billboarded-quad particle renderer that lives in the Phase 9.1/9.2 translucent pass. Delivers **portal swirls, chimney smoke, and fireplace flames** in one implementation. - **C.2 — Dynamic point lights.** Fireplaces and lamps need local lighting; small upgrade to the mesh shader to accumulate N (e.g., 4) nearest point lights per draw. Uniform-buffer or UBO-friendly layout. - **C.3 — Palette range tuning.** Small per-range offset/length tweaks to match retail skin/hair/eye colors. Mostly diff and verify work, no architecture change. - **C.4 — Double-sided translucent polys.** Edge case left by Phase 9.2: neg-side translucent polys are culled because cull is always BACK. Fix by tracking per-sub-mesh `CullMode` and flipping GL state per draw (or drawing twice with opposite cull). Minor. - **C.5 — Shadow mapping (optional).** Deferred unless it becomes a bottleneck in screenshots — dynamic shadows are a known complexity trap. **References:** - `references/ACE/Source/ACE.DatLoader/FileTypes/PhysicsScript.cs` for the emitter schema - `references/ACViewer/ACViewer/Physics/Particles/` for the visual model - `references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/ParticleBatcher.cs` for the Silk.NET-flavored implementation **Acceptance:** portals look like swirly gates, chimneys smoke, fireplaces burn, character skin matches retail screenshots. --- ### Phase D — UI / HUD + Sound **Goal:** chat window, nameplates, inventory, and audio. Can run concurrently with Phase B or C because it doesn't touch gameplay/net/rendering surfaces. > **Updated 2026-04-24 — staged backend strategy.** We split Phase D into > two stages so game logic can be validated quickly without waiting for > the full retail-look custom toolkit. See > [`docs/plans/2026-04-24-ui-framework.md`](2026-04-24-ui-framework.md) > for the full design. Short version: > > 1. **D.2a — ImGui as the short-term backend.** Wire up in days, > iterate game logic (chat-send, inventory actions, vitals HUD reading > real state) in weeks. Looks like a debugger; that's fine. *(Shipped > 2026-04-25 on ImGui.NET + `Silk.NET.OpenGL.Extensions.ImGui` after a > day-one pivot away from Hexa.NET.ImGui; see shipped table.)* > 2. **Stable `AcDream.UI.Abstractions` layer** — ViewModels + Commands + > `IPanel` / `IPanelRenderer` interfaces. Backend-agnostic. Plugin API > publishes against this layer and never sees ImGui. > 3. **D.2b onward — custom retail-look backend** using dat assets (icons, > panels, fonts). Swap one panel at a time; ImGui stays forever as the > `ACDREAM_DEVTOOLS=1` overlay for packet trace / state dump / dat browser. > > Every sub-piece below (D.3 AcFont, D.4 dat sprites, D.5 core panels, > D.6 HUD, D.7 cursors) ships against the abstraction layer, so it > doesn't matter which backend is drawing when the port lands. **Sub-pieces:** - **D.1 — 2D ortho overlay + font rendering.** ✅ SHIPPED 2026-04-17 as the dev-facing debug overlay (StbTrueTypeSharp system-font atlas + `TextRenderer` + `DebugOverlay`). - **✓ SHIPPED — D.2a — ImGui scaffold + `AcDream.UI.Abstractions` layer.** Shipped 2026-04-25. Wires ImGui as the short-term backend behind `ACDREAM_DEVTOOLS=1`. Defines `IPanel` / `IPanelHost` / `IPanelRenderer` / `ICommandBus` + the first ViewModel (`VitalsVM`) in the new `AcDream.UI.Abstractions` project. First real panel: `VitalsPanel` reading HP from `CombatState.GetHealthPercent`. **Backend pivoted Hexa.NET.ImGui → ImGui.NET + `Silk.NET.OpenGL.Extensions.ImGui` during integration** — Hexa's native OpenGL3 backend does its own GL function resolution via GLFW/SDL and crashed with `0xC0000005` in `ImGuiImplOpenGL3.InitNative` against Silk.NET (no GLFW/SDL present). The Silk.NET extension is purpose-built for this scenario and is the `ImGui.NET` mitigation path that `docs/plans/2026-04-24-ui-framework.md` already called out as a "one-morning operation". Stam/Mana return `float?` null in D.2a because absolute values need `LocalPlayerState` + `PlayerDescription (0x0013)` parsing (filed post-D.2a). 11 new `AcDream.UI.Abstractions.Tests` green. - **D.2b — Custom retail-look backend.** Implements the same `IPanel` / `IPanelRenderer` contracts using a custom retained-mode toolkit sourced from retail dat assets. Requires D.2a shipped. Panels get reskinned one at a time; ImGui stays as the `ACDREAM_DEVTOOLS=1` overlay forever. The original 2026-04-17 scaffold research (`UiRoot` / `UiElement` / `UiPanel` / `UiHost` + retail event codes + focus / drag-drop state machine + `WorldMouseFallThrough`) is the implementation foundation here — see `docs/research/retail-ui/`. - **D.3 — AcFont from portal.dat.** Replace stb_truetype system font with retail `Font` DBObjs (`0x40000000..0x40000FFF`) baked from `RenderSurface` source sheets — see research slice 03 §4. Preserves retail visual identity. **(D.2b dependency — needs the custom renderer.)** - **D.4 — Dat sprites + 9-slice panel backgrounds.** Load `RenderSurface` (`0x06xxxxxx`) as GL textures; add `DrawSprite` to `UiRenderContext`. Enables retail panel art. **(D.2b dependency.)** - **D.5 — Core panels.** Attributes (`chunk_00470000.c:FUN_0047ba70`), Skills (same), Paperdoll (`chunk_004A0000.c:FUN_004A5200`), Inventory, Spellbook (`chunk_004C0000.c`), Fellowship, Allegiance. Each uses the port sketches in slice 05. **(Targets `AcDream.UI.Abstractions` — ships with D.2a using ImGui-rendered widgets; reskinned by D.2b.)** The *chat* panel originally listed under D.5 shipped early in Phase I (I.4 input + I.7 combat translator superseded the chat-panel design here); this entry now covers Attributes / Skills / Paperdoll / Inventory / Spellbook / Fellowship / Allegiance only. - **D.6 — HUD.** Vital orbs (scissor-rect partial fill, dat sprites `0x060013B2`), radar (`0x06001388` / `0x06004CC1`, 1.18× range factor), compass strip (scrolling U), target name plate, damage floaters, selection indicator. See slice 06. **(Targets `AcDream.UI.Abstractions` — ships with D.2a; reskinned by D.2b.)** Phase I.2 retired the StbTrueTypeSharp `DebugOverlay` but kept `TextRenderer` + `BitmapFont` alive specifically for D.6's world-space HUD elements (damage floaters, name plates) — they need raw GL text drawing that ImGui can't reach into the 3D scene. - **D.7 — Cursor manager.** OS + dat-sourced custom cursors (`FUN_0043c1c0` GDI HCURSOR builder pattern from slice 03). **(D.2b dependency.)** - ~~**D.8 — Sound.**~~ **Superseded — shipped as Phase E.2** (`SoundTable`/`Sound` dat decode, OpenAL 16-voice engine, per-entity 3D positional audio via `AudioHookSink`). Entry kept here for history; see the shipped table. **Reference docs:** `docs/research/retail-ui/00-master-synthesis.md` + slices 01-06. Every AC-specific behavior has a decompiled FUN_ / DAT_ citation. **Acceptance:** chat messages display in a retail-style panel, health/stamina/mana orbs fill correctly, attributes panel shows player stats, inventory opens with drag-drop working, and sound plays on hit/footstep. --- ### Phase E — "Feel alive" — motion hooks + audio + VFX Unlocks the sensory layer: footsteps, swing whooshes, impact sparks, spell auras. All three systems share animation-hook delivery as the trigger source — motion hooks are the blocker. Research backing: `docs/research/deepdives/00-master-synthesis.md` + R3 + R4 + R5. - **E.1 — Motion-hook expansion.** Extend MotionInterpreter + AnimationSequencer to deliver all 27 AnimationHookType values (Sound=1, SoundTable=2, CreateParticle=18, AttackFrame=20, SoundTweaked=21, …) during frame advance. See `r03-motion-animation.md`. - **E.2 — Audio engine.** `AudioEngine` via `Silk.NET.OpenAL`, inverse-square CPU falloff, 16-voice pool. SoundTable + Wave dat decoders. Motion-hook wiring for footsteps + attacks. See `r05-audio-sound.md`. - **E.3 — Particle system.** `ParticleSystem` on Silk.NET GL (port WorldBuilder's `ParticleBatcher`). 13 motion-type integrators. `PhysicsScript` dispatcher tied to motion-hooks. See `r04-vfx-particles.md`. **Acceptance:** walk around, footstep sounds per material; swing a weapon, hear whoosh; combat impact shows sparks + hit sound. ### Phase F — Fight + cast + gear Core gameplay loop on top of Phase E. Research: R1 + R2 + R6 + R8 + UI slices 04/05. - **F.1 — GameEvent envelope dispatcher.** 94 sub-opcodes in `0xF7B0`. Zero handled today. Start with `PlayerDescription (0x0013)` + property-update events. See `r08-network-protocol-atlas.md`. - **F.2 — Item + inventory model.** `ItemInstance` / `Container` / `PropertyBundle`. Appraise round-trip (`0x00C8` → `0x00C9`). Burden math. See `r06-items-inventory.md` + `src/AcDream.Core/Items/`. - **F.3 — Combat math + damage flow.** Damage formula, per-body-part AL, crit, hit-chance sigmoid. Server broadcasts damage events; client displays + HP bar. See `r02-combat-system.md` + `src/AcDream.Core/Combat/`. - **F.4 — Spell cast state machine.** `SpellCastStateMachine` + active buff tracking. Buffs + recalls first, projectile spells later. Fizzle sigmoid + mana conversion. See `r01-spell-system.md` + `src/AcDream.Core/Spells/`. - **F.5 — Core panels.** Attributes / Skills / Paperdoll / Inventory / Spellbook — using the retail-ui framework from Phase D.2. See `05-panels.md` under retail-ui. **(Targets `AcDream.UI.Abstractions`; unblocked by D.2a — ships with ImGui widgets — and reskinned when D.2b lands.)** **Acceptance:** equip a weapon, swing at a monster, see damage numbers, buff yourself, recall to the lifestone. ### Phase G — World systems Research: R9 + R12 + R13. - **✓ SHIPPED — G.1 — Sky + weather + day-night.** Deterministic client-side from Portal Year time. Sky dome geometry + keyframe gradients + rain/snow particles. See `r12-weather-daynight.md`. Full data + visual stack shipped: Region dat loader, keyframe interp, WeatherSystem with 5-kind PDF + transitions + storm flashes, WorldSession→WorldTimeService sync via ConnectRequest+TimeSync, SkyRenderer with sky-object arcs + UV scroll, rain/snow billboard renderer, F7/F10 debug cycle keys. - **✓ SHIPPED — G.2 — Dynamic lighting.** 8-light D3D-style fixed pipeline. Hard-cutoff at Range, no attenuation inside. Cell ambient. Shader UBO per frame. See `r13-dynamic-lighting.md`. SceneLightingUbo std140 at binding=1 feeds terrain + mesh + mesh_instanced + sky shaders. LightingHookSink auto-registers Setup.Lights at entity stream-in, flips IsLit on SetLightHook, unregisters on landblock unload. - **G.3 — Dungeon streaming + portal space.** `EnvCellStreamer`, portal-visibility BFS, `PlayerTeleport (0xF751)` handling with `LoginComplete` re-send, "pink bubble" loading state. See `r09-dungeon-portal-space.md`. **Acceptance:** walk outside at dusk, see the sky gradient + sun moving; enter a torch-lit dungeon via portal; leave back to daylight. ### Phase H — Social + progression Research: R7 + R10 + R11 + UI slice 05. - **✓ SHIPPED — H.1 — Chat window.** UI panel + all 6 wire opcodes (Channel, Tell, System, HearSpeech, HearRangedSpeech, TurbineChat). Wire layer + panel + outbound input + holtburger inbound parity + combat translator all shipped across I.1-I.7 on 2026-04-25. Targets `AcDream.UI.Abstractions`; will be reskinned when D.2b's custom retail-look toolkit lands. - **H.2 — Allegiance.** Tree model + XP pass-up math + 5 allegiance chat channels + MOTD. See `r11-allegiance.md`. - **H.3 — Emote scripts + quests + dialogs.** 122 EmoteType × 39 Trigger mini-VM. Contract tracker UI. NPC dialog rendered via chat with `` markup. See `r10-quest-dialogs.md`. - **H.4 — Character creation.** `0xE000002 CharGen` dat + 13 heritages + templates + appearance picker + preview renderer. See `r07-character-creation.md`. **Acceptance:** create a character from scratch, talk to an NPC, get + complete a quest, gain XP that passes up to the patron. ### Phase I — UI consolidation + complete chat system **Goal:** retire the dual UI stack (custom StbTrueTypeSharp DebugOverlay + ImGui) in favour of ImGui hosting *all* dev/debug surfaces, then finish the chat system end-to-end (input, slash commands, holtburger inbound parity, combat translator). After this phase, dev tools live in one place and chat works the way retail + holtburger expect. **Sub-pieces (all ✓ SHIPPED 2026-04-25):** - **✓ SHIPPED — I.1 — `IPanelRenderer` widget extension.** Adds `TextColored`, `Checkbox`, `Combo`, `InputTextSubmit`, `BeginTable` + ~9 more widget signatures to `IPanelRenderer` and matching `ImGuiPanelRenderer` impls. Foundation for I.2 (DebugPanel) and I.4 (chat input). Commit `b131514`. - **✓ SHIPPED — I.2 — DebugPanel migration.** Replaces the 473-LOC StbTrueTypeSharp `DebugOverlay` with `AcDream.UI.Abstractions/Panels/Debug/DebugPanel` (collapsing-headers + diagnostics checkboxes + combat-event tail). `DebugOverlay.cs` deleted; `TextRenderer` + `BitmapFont` retained for the future world-space HUD (D.6 — damage floaters, name plates). Commit `56037a4`. - **✓ SHIPPED — I.3 — `LiveCommandBus` + `WorldSession.Send{Talk,Tell,Channel}`.** Replaces `NullCommandBus.Instance` with a real handler-registry `ICommandBus`. New `SendChatCmd` record + `ChatChannelKind` enum + `ChannelResolver` legacy-id mapping (per holtburger). `WorldSession.SendTalk` / `SendTell` / `SendChannel` are 3-line wrappers around existing `ChatRequests.BuildTalk/Tell/ChatChannel`. Commit `8e6e5a0`. - **✓ SHIPPED — I.4 — `ChatPanel` input field + slash commands.** Enter-to-submit input field on `ChatPanel`; `ChatInputParser` recognises `/say` `/t` `/tell` `/r` `/g` `/f` `/a` `/m` `/p` `/v` `/cv` `/lfg` `/trade` `/role` `/society` `/olthoi`; `ChatVM.LastIncomingTellSender` tracks for `/r` reply. `ImGui.WantCaptureKeyboard` already suppresses WASD on input focus. Commit `f14296c`. - **✓ SHIPPED — I.5 — Holtburger inbound chat parity + Windows-1252.** `EmoteText (0x01E0)`, `SoulEmote (0x01E2)`, `ServerMessage (0xF7E0)`, `PlayerKilled (0x019E)` parsers + `WeenieError` routing through `GameEventWiring`. Global string codec switch from `Encoding.ASCII` to `Encoding.GetEncoding(1252)` so accented names round-trip per retail + holtburger. Commit `ff5ed9e`. - **✓ SHIPPED — I.6 — TurbineChat codec + `ChatChannelInfo`.** Full `0xF7DE` codec with three payload variants (`EventSendToRoom`, `RequestSendToRoomById`, `Response`), UTF-16LE strings with variable-length prefix, `SetTurbineChatChannels (0x0295)` parser, unified `ChatChannelInfo` (Legacy + Turbine variants), `TurbineChatState`. **ACE doesn't host a TurbineChat server — codec is ready when retail-emulating servers exist.** Commit `ca968fc`. - **✓ SHIPPED — I.7 — `CombatChatTranslator`.** Retail-faithful combat-text formatters into `ChatLog` ("You hit drudge for 50 slashing damage (87%)"). Subscribes to `CombatState`'s `DamageTaken` / `DamageDealtAccepted` / `EvadedIncoming` / `MissedOutgoing` / `AttackDone` / `KillLanded`; templates ported verbatim from holtburger `panels/chat.rs:221-308`. Commit `3d26c8e`. - **✓ SHIPPED — I.8 — Docs alignment.** Roadmap (this file) + `docs/ISSUES.md` issues #14-#20 closed + `memory/project_chat_pipeline.md` crib + `MEMORY.md` index entry + `CLAUDE.md` UI strategy paragraph all updated to reflect Phase I shipped state. Commit `(this commit)`. **Acceptance (verified 2026-04-25):** - All ImGui dev panels open with `ACDREAM_DEVTOOLS=1`: VitalsPanel + ChatPanel + DebugPanel. - Old `DebugOverlay.cs` is deleted; `TextRenderer` / `BitmapFont` still compile for D.6. - `/say hello` in chat sends a Talk packet; local echo lands in the panel. - Attacking a creature produces "You hit Drudge for 12 slashing damage (87%)" lines in chat. - Accented character names round-trip through the wire correctly (CP1252). **Memory crib:** `memory/project_chat_pipeline.md`. --- ### Phase K — Input architecture + retail bindings + Settings panel **Goal:** retire the hardcoded WASD-style scheme; ship retail-faithful bindings as the default; let users remap any action via an in-game Settings panel; auto-enter player mode at login; replace mouse-X-yaw with retail's MMB-hold mouse-look. **Sub-pieces (all ✓ SHIPPED 2026-04-26):** - **✓ SHIPPED — K.1a — Input architecture skeleton.** Action enum, multicast `InputDispatcher` with scope stack, `KeyChord` / `Binding` / `KeyBindings`, Silk.NET adapters, parallel to existing handlers — no behavior change. Commit `84512d3`. - **✓ SHIPPED — K.1b — Cut handlers over to dispatcher.** Drop the legacy mouse-X-character-yaw path, fix `WantCaptureMouse` gating, single input path. Commit `256e962`. - **✓ SHIPPED — K.1c — Retail-default keymap + JSON persistence.** ~149 bindings matching `docs/research/named-retail/retail-default.keymap.txt` + JSON load/save with merge-over-defaults migration at `%LOCALAPPDATA%\acdream\keybinds.json`. Acdream debug F-keys relocated to `Ctrl+F*` to avoid retail conflicts. Commit `da18910`. - **✓ SHIPPED — K.2 — Login flow + MMB mouse-look + free-fly button.** Auto-enter player mode at login (one-shot guard reusing the existing Tab handler), MMB-hold mouse-look (retail's `CameraInstantMouseLook` — cursor-locked camera + character yaw drive together), `DebugPanel` "Toggle Free-Fly Mode" button, `Tab → ToggleChatEntry → ChatPanel.FocusInput()`. Commit `af74eac`. - **✓ SHIPPED — K.3 — Settings panel + Keybindings UI + roadmap/issues update.** `SettingsPanel` with click-to-rebind UX (modal capture via `InputDispatcher.BeginCapture`, Esc cancels, conflict-detection- with-confirmation prompt, draft / Save / Cancel semantics), F11 toggle + ImGui MainMenuBar entry, per-action / per-section / reset-all-defaults buttons. Roadmap + ISSUES + memory crib + CLAUDE.md updated in this commit. Commit `(this commit)`. **Acceptance (verified 2026-04-26):** - Login → spawn at the character's actual world position in chase camera (NOT Holtburg orbit). Tab not required. - W = run forward; X = run back; A/D = turn; Z/C = strafe; Alt+A/D/Left/Right = strafe (alternate); Q = autorun; Space = jump; Shift = walk modifier; S = stop; Y/G/H/B = postures. - Mouse alone does NOT drive character yaw. MMB-hold = cursor-locked camera + character yaw drive together. RMB and LMB are `SelectRight` / `SelectLeft` per retail. - F11 / View → Settings opens panel. Click "Rebind" next to any action → press a key → if conflict, prompt. Save writes `%LOCALAPPDATA%\acdream\keybinds.json`. Restart preserves customizations. - Mode-dependent combat keys (Insert/PgUp/Delete/End/PgDn) bound but dormant — light up in Phase L when `CombatState.CurrentMode` is wired (issue #L.3). **Memory crib:** `memory/project_input_pipeline.md`. --- ### Phase J — Long-tail (deferred / low-priority) Not detailed here; each gets its own brainstorm when it becomes relevant. - Player character full rig (held weapons, spell effects, death/revive animation) - Group/fellowship UI - Trade window (multi-player confirms) - Salvage + tinker UI - House ownership + hooks - Society UI - GM visible tools (we explicitly don't build GM powers; but DEV-mode tools like teleport anywhere are useful) --- ### Phase R — Retail research infrastructure **Goal:** sustainable, scalable access to retail-client decompilation — named symbols, struct layouts, wire schemas — so every future port is a 5-second grep instead of 30-minute archaeology. **Sub-pieces:** - **✓ SHIPPED — R.1 — Named-retail corpus committed.** Shipped 2026-04-25 (commit `a9a01d8`). `docs/research/named-retail/{acclient_2013_pseudo_c.txt, acclient.h, acclient.c}` + `docs/research/data/spells.csv` + vendored `references/actestclient/`. 1.4 M lines of named pseudo-C (99.6% function naming) + 70K lines of verbatim retail headers + 3,956 spells with `Family` for buff stacking + machine-readable wire schema in `messages.xml`. - **✓ SHIPPED — R.2 — pdb-extract tool + JSON sidecars.** Shipped 2026-04-25 (commit `69d884a`). `tools/pdb-extract/pdb_extract.py` reads `refs/acclient.pdb` (Sept 2013 EoR build) and emits `symbols.json` (18,366 named functions) + `types.json` (5,371 named struct types) to `docs/research/named-retail/`. Pure Python, no deps, runs in <1 s. - **✓ SHIPPED — R.3 — actestclient vendored.** Shipped 2026-04-25 alongside R.1. `references/actestclient/` (covered by `references/` gitignore) includes the canonical `messages.xml` AC-protocol wire schema. **Acceptance:** Step 0 of `CLAUDE.md`'s development workflow points at `named-retail/` first; subsequent issue closures (#6 / #7 / #9 / #11) all consume this foundation. **Effects on other phases:** Issue closures unblocked by Phase R land under their existing letter phases (#6 enchantment buffs → Phase D / F.5 maintenance; #7 PlayerDescription trailer → Phase H.1 / F.2 maintenance). The PDB symbols + headers also accelerate any future port in any phase — no separate listing here. --- ## Cross-cutting work tracked in parallel - **Test coverage.** Each phase lands with unit + integration tests in `tests/`. Current count: 98 Core + 96 Core.Net = 194. Keep the ratio as new phases land. - **Memory files.** Project state under `memory/project_phase_*_state.md` is updated when a phase ships. `MEMORY.md` is the index. - **`CLAUDE.md` discipline.** Check all four references (ACE, ACViewer, WorldBuilder, Chorizite) before committing to an approach. WorldBuilder is the closest stack match and should be checked first. --- ## Explicitly out of scope - **Server emulation** — we use ACE for server, never reimplement. - **Account creation** — direct user to ACE tooling. - **Anti-cheat / GM tools / live-ops** — irrelevant for personal use. - **Cross-platform support** — Windows-only; the dat path assumptions depend on retail Windows install layout. Silk.NET is cross-platform but we don't promise. - **Custom game content** — this is a client for existing AC data, not a toolchain. --- ## "When will my specific complaint be fixed?" — quick lookup | Observation | Phase | |---|---| | Drudge statue in wrong pose | **6.3 FIXED** ✓ | | Characters in T-pose / wrong idle | **6.1 FIXED** ✓ | | No breathing on NPCs | **6.4 + sentinel fix FIXED** ✓ | | Lifestone crystal has one side missing | **9.2 FIXED** ✓ | | Ground floor flickering with terrain | **7.1 FIXED** ✓ | | Houses missing second floors / walls | **7.1 FIXED** ✓ (interior mesh landed) | | Character clothing missing / wrong | **5 FIXED** ✓ | | Statue wrong color / wrong scale | **5 FIXED** ✓ | | Holtburg sign half-buried | **5 FIXED** ✓ | | Can't walk past the loaded 3×3 window | **A.1 FIXED** ✓ (5×5 default, `ACDREAM_STREAM_RADIUS` to tune) | | Frame hitch crossing landblock boundary | **Phase A.3** (synchronous loader for now; async returns when DatCollection is thread-safe) | | Walking around doesn't move me on the server | **Phase B.3 FIXED** ✓ | | Can't talk to NPCs | **Phase H.3** (emote scripts + dialogs) | | Can't open a door | **Phase F** (object-use action) | | Portals render as a rotating black disk | **Phase E.3** (particle system) | | Chimneys have no smoke | **Phase E.3** | | Houses have no fireplace fire | **Phase E.3** | | No fireplace / torch lighting | **Phase G.2** (shipped; Setup.Lights auto-register, 8-light cap with hard-cutoff) | | Skin/hair color slightly off | **Phase C.3** | | No chat window | **Phase H.1 / I.1-I.7 FIXED** ✓ | | Chat? You can finally type and send messages | **I.4 FIXED** ✓ (shipped 2026-04-25) | | Combat doesn't show in the chat log | **I.7 FIXED** ✓ | | Accented character names show as `?` or garbled | **I.5 FIXED** ✓ (Windows-1252 codec) | | No sound | **Phase E.2** | | Dungeons / foundry interior missing | **Phase G.3** | | Can't fight monsters | **Phase F.3** (combat math + damage) | | Can't cast spells | **Phase F.4** | | No inventory panel | **Phase F.2 + F.5** | | No character creation — must use ACE admin | **Phase H.4** | | Sky is a flat color | **Phase G.1** (shipped; F7 cycles time, F10 cycles weather) | | Can't join allegiance | **Phase H.2** | | No quest tracker | **Phase H.3** | If you see something not on this list, add it here and assign a phase.