# Campaign CC connected-gate test script **Status: the campaign is CODE-COMPLETE (CC1-CC7) and this script is its connected-gate contract.** Every step below is the user's own eyes on the running client — nothing here was run automatically. **No automated live character creation has been run against ACE** (see §CC-Not-Automated) — the first LIVE create is deliberately left to this gate. This script covers TWO ways to reach the chargen screen: the real launcher flow (Campaign LA's product path) and the developer shortcut (`ACDREAM_RETAIL_UI=1` + `ACDREAM_OPEN_CHARGEN=1`, still available and still useful for a fast create-only iteration loop). Both land on the exact same screen and Runtime owner — there is no second code path being tested. Local ACE connection details (per `CLAUDE.md`): host `127.0.0.1`, port `9000`, account `testaccount` / `testpassword`. Use a FRESH character name per attempt (ACE does not forget names within a session) — `CC--` is a good scheme, e.g. `CCAB1`, `CCAB2`. --- ## §CC1 — reaching the screen ### Path A — the launcher (product path) 1. Launch `AcDream.Launcher` (already installed/updated per Campaign LA's own gates — this script does not re-run first-run setup or the update flow; see `docs/research/2026-08-14-campaign-la-test-script.md` if either is in question). 2. Open **Check for updates**. Confirm it reports the client already current (no install prompt) — Campaign LA's own gates already proved the install/update mechanics; this step just confirms nothing is stale before the character-creation gate. 3. Confirm (or create) a profile pointed at `127.0.0.1:9000`, `testaccount` / `testpassword`. 4. Click **GUI — character select**. The retail character-management screen (`gmCharacterManagementUI`) opens — the flat character list, World name, Enter/Delete/Restore buttons, and the **Create** button. ### Path B — the developer shortcut ```powershell $env:ACDREAM_DAT_DIR = "$env:USERPROFILE\Documents\Asheron's Call" $env:ACDREAM_RETAIL_UI = "1" $env:ACDREAM_LIVE = "1" $env:ACDREAM_TEST_HOST = "127.0.0.1" $env:ACDREAM_TEST_PORT = "9000" $env:ACDREAM_TEST_USER = "testaccount" $env:ACDREAM_TEST_PASS = "testpassword" dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Release ``` Confirm the SAME character-management screen appears. `ACDREAM_OPEN_CHARGEN=1` (add it to the block above) is the CC4-era interim seam that opens the chargen screen directly on startup, skipping the Create click — still useful for a fast create-only loop, but Path A/B above is now the REAL path and should be exercised at least once per gate. ### The Create button 1. With at least one free character slot (roster count below the account's allowed slot count — most test accounts have several free slots), confirm **Create** is ENABLED (not greyed out). 2. **Click Create.** The chargen screen (`gmCharGenMainUI`) opens directly on the **Heritage** page — no confirmation, no loading screen. The character-management screen you were just on is not closed or hidden; it simply sits behind the new screen (this matters for the Exit step below). 3. **If your account's roster is completely full** (rare on a fresh test account — every slot occupied), confirm Create is instead GREYED OUT and does nothing when clicked. This is retail's own gate (`gmCharacterManagementUI::UpdateButtons`) — a full roster ghosts Create exactly like Enter/Delete grey out for an unselected row. **A fresh test account is unlikely to be full on its own** (ACE's default `max_chars_per_account` is 11) — force this state instead of waiting for it: 1. From the ACE server console (or a GM-privileged in-game `@` command), run `@modifylong max_chars_per_account 2` to lower the ceiling below your current roster count. 2. Reconnect (a fresh `CharacterList` only arrives on a new connection — the client does not re-fetch it live) and confirm Create is now GREYED OUT. 3. Restore the default afterward: `@modifylong max_chars_per_account 11`, then reconnect again and confirm Create is enabled once more. 4. **The count includes pending-delete (greyed) characters** — a character mid-deletion still occupies a roster slot both in ACE's `GameMessageCharacterList` and in acdream's own gate (`RuntimeCharacterSelectionState.BuildButtons`'s `_entries.Length < _slotCount`, which counts every roster entry regardless of pending-delete state) — matching retail's own `RebuildCharacterList`, which walks the same full set. If you have a pending-delete character sitting around, it still counts toward the ceiling above. ### Leaving the screen (Back-at-Heritage and Exit) 1. On the **Heritage** page (the first page), click **Back**. Confirm a confirmation dialog appears asking whether to leave character creation (same text/shape as the Exit button below — Back-at-Heritage and Exit share retail's one `DoExit` confirmation). 2. Click **Exit** (top of the screen, available on every page). Confirm the SAME confirmation dialog appears. 3. **Confirm the dialog (accept).** The chargen screen closes. You are back at the character-management screen you started from — roster, World name, and any prior selection are exactly as you left them (character management was never hidden, so there is nothing to "restore"). 4. Click **Cancel** on a repeat Exit attempt instead — confirm the dialog closes and chargen stays open, untouched. ### What to report for §CC1 - Create's enabled/greyed state matching the free-slot count you actually have. - Whether clicking Create opens chargen with no lag/flash/black frame. - Whether returning from Exit shows the character list exactly as it was (no re-flicker, no lost highlight, no stale World name). --- ## §CC2 — the six-page create flow **The screen does NOT open blank.** `gmCharGenMainUI`'s own constructor rolls a full random character (heritage, gender, appearance, clothing, template, start area) before the Heritage page ever draws — acdream ports this faithfully (AP-214, retired). **Expected retail quirk: the gender shown on the Appearance page is the FLIP of the roll** — the Appearance page's own init code reads the just-rolled gender and immediately swaps it to the opposite one. If you open chargen and see (say) a female Aluvian with the Appearance page showing "Male" selected, that is CORRECT, not a bug — do not report it. ### Heritage page 1. Confirm one of the 13 heritage buttons is already highlighted (the opening roll) — Human heritages (Aluvian/Gharu'ndim/Sho/Viamontian), Tumerok, Gearknight, Lugian, Empyrean, Penumbraen, Shadowbound, Undead, Olthoi, and OlthoiAcid should all be selectable and each show its own description text (starting skills, bonus-skills paragraph where retail has one — Lugian/Olthoi/OlthoiAcid have none, that's retail-correct). 2. Click **Random**. Confirm the highlighted heritage changes to a uniformly-picked one of the 13 — this is AP-212's documented approximation (retail's own Heritage-page Random rolls with retail's own distribution; acdream picks uniformly over every installed heritage). A uniform pick over 13 can land back on the heritage you already have — click a few times if the first click looks like a no-op; occasional repeats are expected, not a bug. Not a bug to report unless the button does nothing or crashes across several clicks. 3. Select **Olthoi** or **OlthoiAcid**. Confirm the Profession, Skills, and Town tabs are hidden (Olthoi variants skip straight to a fixed Custom template with no attribute/skill/town choices) and the screen auto-advances past them. ### Profession page 1. Select a NON-Olthoi heritage. Confirm 7 template buttons (Custom + 6 presets) and 6 attribute sliders (Strength/Endurance/Coordination/ Quickness/Focus/Self). 2. Drag a slider. Confirm the numeric readout updates live and the Available-credits counter decreases/increases correspondingly. 3. Click a preset template (not Custom). Confirm all 6 sliders jump to that preset's values and Available credits updates to match. 4. Click **Random**. Confirm heritage/template selection changes (AP-212 — uniform pick, not retail's own weighted roll). ### Skills page 1. Confirm ONE flat listbox of skills, each row showing name, current level, and train/specialize costs (AP-213 — retail groups these into four sorted buckets; acdream's flat list is a presentation simplification, not a rules difference — do not report the flat ordering as a bug). 2. Click a trainable row. Confirm it advances (Untrained -> Trained -> Specialized) and the skill-credits meter decreases; a second click on an already-Specialized row does nothing further (no fourth state). 3. Confirm **Random** is disabled/greyed on this page (retail's `RandomizeSkills` primitive is unported — AP-212's own documented gap). ### Appearance page 1. Confirm **Face** and **Clothes** sub-tabs, nine spin controls (hair, eyes, nose, mouth, skin under Face; headgear, shirt, trousers, footwear under Clothes), nine color swatches, a shade scrollbar, zoom/rotate buttons, and a live 3D preview playing an idle animation loop. 2. Click a spin's left/right arrow zones. Confirm the selected style index advances/retreats and the preview model updates. 3. Click a color swatch. Confirm the swatch shows a highlighted "selected" ring/border (AP-215 — acdream's own selection indicator, not retail's overlay mechanism; functionally equivalent). 4. Click **Zoom In**. Confirm the preview freezes its pose (idle animation stops) and the camera tweens closer over about half a second. Click **Zoom Out** — animation resumes, camera tweens back out. 5. Click **Rotate Clockwise**/**Counter-Clockwise**. Confirm the model spins continuously at a steady rate (about 3 seconds per full turn); clicking the SAME direction again stops it, clicking the OPPOSITE direction reverses it. 6. Click **Random** (on either sub-tab). Confirm hair/eyes/nose/mouth/skin (Face) or headgear/shirt/trousers/footwear (Clothes) all re-roll together — this IS retail's real `RandomizeAppearance`/ `RandomizeClothing` primitive (CC5 ported it verbatim, not approximated). 7. Select **Gearknight**, **Olthoi**, or **OlthoiAcid** on the Heritage page, then return to Appearance. Confirm the Clothes sub-tab and its four spins are unreachable, Nose/Mouth spins are hidden, and Eyes' arrows are disabled (fixed eyes for these forms). Known cosmetic gaps on this page — expected, do not report as bugs unless noticeably worse than described: swatches show static art rather than the actual color they represent (AP-216); the gradient circle art next to the swatches never repaints to reflect the current color (AP-217); the four icon-only spins (hair/eyes/nose/mouth) show a plain number instead of an icon thumbnail, while the four clothing spins show real names (AP-215/ AP-218); on Olthoi/OlthoiAcid/Gearknight the Skin spin does not slide up to close the gap left by the hidden Nose/Mouth spins (AP-219); switching heritage INTO or OUT OF Gearknight does not automatically re-roll appearance/clothing the way retail does on that exact transition (AP-220); the currently-selected spin shows no distinct highlighted state versus the other eight (AP-222 — this is a MEASURED gap in acdream's own art, not yet attributed to a specific missing asset; report clearly if you can visually compare with retail here). **Known session-permanent gap (AP-221) — check the console before reporting a dead preview.** On an unlucky frame where the DAT/GPU resource read backing the 3D preview isn't ready at the client's single composition pass, the Appearance page's zoom/rotate controls can go dead for the rest of the session (or the Summary page's preview can simply never render), with no on-screen error — the only evidence is a console line: `[UI] chargen preview viewport unavailable at composition time...` (or the Summary-page sibling, `[UI] summary preview viewport unavailable at composition time...`). If zoom/rotate stop responding or a preview stays blank, check the console for one of these lines FIRST. If it's there, restart the client and retry before reporting a bug — this is a known, already-registered gap, not a new one. ### Town page 1. Confirm four town buttons: Holtburg, Shoushi, Yaraq, Sanamar (not id order — that's retail's own literal ordering, ported faithfully), each with descriptive text. 2. Click a town. Confirm it highlights and the description text updates. ### Summary page 1. Confirm a listbox showing Profession, Gender, Heritage, and Starting Town lines, an "Attributes" header, then Strength/Endurance/ Coordination/Quickness/Focus/Self/Health/Stamina/Mana/Skill Credits as paired rows, then Specialized and Trained skill name lists (retail also lists the two Untrained buckets; acdream's Summary omits them — AP-224, same class of cut as the Skills page's own AP-213). 2. Confirm a static 3D preview of the character (no zoom/rotate controls on this page — retail has none here either). 3. Click the **name field** and type a name. Confirm only letters, spaces, apostrophes, and hyphens are accepted (other characters are silently rejected keystroke-by-keystroke). 4. Click **Random** on this page. Confirm a confirmation dialog appears first ("are you sure you want to randomize?"); confirming it re-rolls the ENTIRE character (heritage through name) using retail's real `RandomizeCharacter` primitive — the same one the screen-open roll uses. ### What to report for §CC2 - Any page that fails to render a control listed above, or where a control visibly does nothing when clicked. - Anything from the "known cosmetic gaps" list that looks MORE broken than described (e.g. a spin that doesn't advance at all, not just a missing highlight). - Any crash, freeze, or console error while navigating pages or the tabs. --- ## §CC3 — Finish and its dialogs Use a fresh, never-before-used character name for the happy path. For every scenario below, watch the console/log for `[UI]`/`[CC]`-prefixed lines — they help distinguish "nothing happened because the click didn't register" from "the request went out and ACE is thinking about it." ### Happy path 1. Complete a legal character (heritage, gender, template with credits fully spent, at least a default set of skills, a town, a fresh name). 2. Click **Finish** on the Summary page. Confirm the screen closes almost immediately (no visible "please wait" dialog for a normal accept — ACE's Ok reply is fast) and you land DIRECTLY in the world as the new character — no return to character management, no fresh character list, matching retail's own "log straight in" behavior. 3. If you back out to character management instead (e.g. via a later logout), confirm the new character now appears in the roster alongside any pre-existing ones, in the correct slot. ### NameInUse (duplicate name) 1. Create a SECOND character using the EXACT name you just used above. 2. Click Finish. Confirm the `ID_Character_Err_NameReserved` dialog appears ("that name is in use" / similar text) and you stay on the chargen screen — Finish is clickable again afterward. 3. **Expected log noise (register AD-100):** ACE sends the NameInUse rejection TWICE for the same request (a real ACE double-send bug, not an acdream defect). The FIRST reply drives the dialog above; the SECOND logs something like `unexpected CharacterGenerationVerificationResponse` in the console. That log line is EXPECTED here — do not report it as an error. ### The credit-warning confirm flow 1. Select the **Custom** template on the Profession page (leaves several attribute credits unspent) and complete the rest of the character. 2. Click Finish. Confirm a warning dialog appears about unspent attribute credits, and Finish does NOT send anything yet. 3. Confirm the dialog. Confirm the request now sends anyway, with the unspent credits — this is retail-correct (`DoFinish`'s own confirm-arm skips the credit check entirely; ACE accepts an under-spent build). ### The randomize warning flow Already covered in §CC2's Summary-page step 4 above — confirm the warning appears BEFORE any randomization happens, and Cancel leaves the character completely untouched. ### The exit warning flow Already covered in §CC1's "Leaving the screen" section above. ### NameTooLong 1. On the Summary page, type or paste a name longer than 32 characters and commit it (press Enter, or click elsewhere to move focus away from the field). 2. Confirm the `ID_CharGen_NameTooLong` dialog appears and the field reverts to its previous (shorter) value — the field itself does not cap your typing at 32 characters as you go; the rejection only fires on commit. That is retail-correct, not a bug. ### Empty name (AP-227, an acdream/retail divergence — expected) 1. On the Summary page, select all the text in the name field and delete it entirely, then blur the field (click elsewhere) without typing a replacement. 2. Click **Finish**. Confirm the `NoName`/`ID_CharGen_NoNameWarning` dialog appears — acdream clears its internal name state the instant the field is emptied, so Finish sees an empty name and refuses. **This is NOT what retail does**: retail's own commit handler only acts when the field's length is greater than 1 (NUL-inclusive, so an empty field's length is exactly 1) — an emptied-then-blurred field is a silent no-op in retail, and the character's internal name stays whatever it was BEFORE you cleared the field, even though the field visually shows empty. A real retail client would create the character under that old, uncleared name here instead of showing a dialog. Expect acdream's dialog, not retail's silent keep-old-name behavior — register AP-227. ### What to report for §CC3 - Whether the happy path truly lands you in-world with no intermediate screen. - The exact dialog text shown for each rejection (useful for a later string-table audit even if it looks right). - Any case where Finish appears to do nothing at all (no dialog, no console line, no world entry) — that would be a real regression, not one of the documented cosmetic gaps above. --- ## §CC4 — ACE-side landmines (not acdream defects) - **Heritage-priced skill over-deduction — LATENT, will not fire with the installed EoR DAT.** ACE's `PlayerFactory.CreatePlayer` has a real overcharge bug when specializing a skill priced by the active heritage's own skill list (versus the global skill table). It was measured against the installed EoR data and found unreachable — every heritage's one priced skill (Arcane Lore) has a heritage NormalCost of 0, which makes ACE's overcharge exactly zero. You should NOT be able to trigger a `FailedToSpecializeSkill` rejection from a retail-legal build during this gate. If you somehow do, that is worth flagging immediately — it would mean the installed DAT's costs differ from what was measured. - **Disabled-Olthoi create -> Pending -> NameDBDown dialog is retail-correct.** If your local ACE has Olthoi character creation disabled (a server config option), attempting to create an Olthoi/ OlthoiAcid character will surface the `ID_Character_Err_NameDBDown` dialog via a `Pending` response code. This is retail's OWN behavior (ACE's `olthoi_play_disabled` branch sends `Pending`, and retail's dispatch has no silent branch for it) — not a "the client swallowed my request" bug. --- ## §CC-Not-Automated No automated test in this repository has created a character against a LIVE ACE server. Every field-shape and response-code assertion in Campaign CC's test suite runs against a real `WorldSession` and hand-built response packets (see `tests/AcDream.Runtime.Tests/Session/LiveSessionControllerCharacterCreationTests.cs`) — the wire bytes and the state machine are proven byte-for-byte, but the FIRST character ever created against a real, running ACE process is whatever you create during this gate. Server state (what names exist, what heritages are enabled, what the account's slot count is) is entirely yours to observe; this script deliberately does not assume any of it in advance.