Binds LayoutDesc 0x2100005C through OP2's template-list mechanism and OP3's per-page OptionPage model: the General Options header + two DualHash-linked opacity sliders (Option_DefaultOpacity_Property 0x10000080 / Option_ActiveOpacity_Property 0x10000081, live-apply on drag through RetailWindowOpacityController, defaults read from the installed DAT's DBProperties collection at DID 0x78000001 via ChatOptionsDatDefaults), and the five per-window text-filter blocks (main window 12 rows minus Gameplay, four floaties 13 rows each — the byte-verified authored order cross-checked against the raw gmChatOptionsUI::InitOptions/AddCheckboxBitfield64Option pseudo-C, not just the research doc's own table) writing AcDream.Core.Chat. ChatWindowState directly, the same state CH6's chat windows already read. AP-195 retired: ported both halves left open at the OP2 re-review — the ALL-set LED media swap (new UiButton.FaceFileOverride, driven by the block-level P0x10000082/P0x10000083 sprites now threaded through ElementInfo/DatWidgetFactory) and the CreateChildren self-sizing tail (UiCheckboxBitfield64.Height grows with its stacked row content; the enclosing ListBox reflows around the block's FINAL height via the new UiTemplateListBox.AddPrebuiltRow, reusing the ListBox's own stacking rather than a third stacking path). AP-187 broadened to cover the main window's own filter (previously only the four floaties) and the new live-editing write path. The main chat window's filter (retail window id 8, ChatWindowState id 0) gains its own settings.json persistence (ChatSettings. ChatWindowMainFilter) alongside the pre-existing floaty 1-4 fields; opacity persistence is now wired on every live slider change, not only through the old dev-scaffold Settings panel. Fixture regeneration (ACDREAM_REGENERATE_UI_FIXTURES=1) picked up the new ElementInfo.LedCheckedSprite/LedUncheckedSprite fields across all 19 committed layout fixtures — purely additive, confirmed against the live installed DAT (0x10000520's own 0x82/0x83 properties resolve to 0x06004D17/0x06004D19 exactly as AP-195 documented). Conformance: FilterRows/FilterBlocks pinned against the byte-verified authored order and ChatWindowState's own default constants; the AP-195 LED swap and self-sizing behavior; the DAT opacity-default extraction against the live installed DAT; live filter/opacity writes reaching ChatWindowState/RetailWindowOpacityController; OnShown re-seed and Reset/Defaults ghosting per the OP4 binding-pattern discipline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
662 lines
36 KiB
Markdown
662 lines
36 KiB
Markdown
# Campaign OP connected-gate test script
|
|
|
|
**Status:** OP3, OP4, OP5, and OP7 sections. Later slices (OP6, OP8) append
|
|
their own sections here as they land; the campaign's OP9 closeout gate is
|
|
this document complete plus every slice code-complete.
|
|
|
|
This document is the script the user runs against the live connected
|
|
client (`ACDREAM_LIVE=1` against the local ACE server) to accept each
|
|
slice. Each item states what to do and what retail-faithful behavior to
|
|
expect. Anything marked **INERT** is authored and clickable but
|
|
deliberately does nothing yet — that is the correct, contracted behavior
|
|
for this slice, not a bug.
|
|
|
|
---
|
|
|
|
## OP3 — panel shell, open paths, Gameplay tab
|
|
|
|
### Opening and closing the panel
|
|
|
|
1. **Press F11.** The Options panel opens — a floating, resizable window
|
|
titled by its own chrome (no title-bar text is authored; the window
|
|
itself is the visual identity). The **Gameplay Options** tab is
|
|
selected by default (leftmost tab, matching the user's own retail
|
|
screenshot).
|
|
2. **Press F11 again.** The panel closes.
|
|
3. **Click the toolbar's Options button** (the icon at the right end of
|
|
the shortcut row, next to Inventory). The panel opens. If a DIFFERENT
|
|
`gmPanelUI`-family panel was already open (Character Info, Skills,
|
|
Vitae, Inventory, etc.), opening Options closes it first — this is
|
|
retail's real "one active panel" behavior (`gmPanelUI`'s shared
|
|
geometry/exclusive-child model), not new to this panel. **Note the
|
|
button's STATE change, not just its behavior:** before this slice this
|
|
button was greyed out/disabled (panel id 10 was not in the catalog) and
|
|
clicking it did nothing. It should now be fully enabled, AND it should
|
|
highlight (same visual as the Inventory/Character/Magic buttons) while
|
|
the Options panel is open, un-highlighting when it closes.
|
|
4. **Click the panel's own close (X) button**, top-right of the window
|
|
chrome. The panel closes — same action as F11.
|
|
5. **Drag the window by its border/chrome; resize it from the BOTTOM
|
|
edge only.** Options shares its geometry policy with every other
|
|
`gmPanelUI` sibling (Character/Inventory/Spellbook/the indicator-detail
|
|
panels): draggable, resizable from the bottom edge only (NOT the top,
|
|
left, or right edges, and NOT a corner — the panel does not resize
|
|
horizontally at all), and it remembers its HEIGHT across a close/reopen
|
|
within the same session, same as every sibling. This is a correction
|
|
from OP3-as-landed, which briefly gave Options all-four-edge/horizontal
|
|
resize that no sibling has and that silently reverted to 300px wide the
|
|
next time a sibling panel was shown.
|
|
|
|
### Tab switching
|
|
|
|
6. **Click each of the four tabs** (Gameplay Options, Character, Chat,
|
|
Config). Each switches the visible page; exactly one page is visible
|
|
at a time. Character/Chat/Config show their AUTHORED content (row
|
|
templates, Apply/Reset/Defaults buttons, scrollbars) but nothing on
|
|
those three tabs is wired to live data yet — that is OP4/OP5/OP6's
|
|
scope, not a bug in this slice. Only the currently-selected tab's
|
|
button highlights as "open"; the others read "closed".
|
|
7. **Switch away from Gameplay and back.** No crash, no stuck state.
|
|
|
|
### The seven Gameplay-tab buttons
|
|
|
|
8. **Exit Game.** Click it. The client logs off and closes gracefully —
|
|
same behavior as pressing Escape then confirming, or closing the
|
|
window. **No confirmation dialog** (retail has none on this path).
|
|
9. **Exit to Character Selection.** Click it. A confirmation dialog
|
|
appears ("Are you sure you want to end this character session?" or
|
|
the DAT-resolved retail equivalent). Click **Yes** while standing on
|
|
solid ground: the client logs off and closes — **today this behaves
|
|
identically to Exit Game**, NOT a return to a character-select
|
|
screen (acdream has no pre-world character-select flow yet — register
|
|
row AD-74). Click **No**: nothing happens, panel stays open.
|
|
10. **Exit to Character Selection while airborne** (jump and click the
|
|
button mid-air, or confirm while still in the air). Expect the chat
|
|
line **"Cannot log off while in mid-air."** in the SpewBox/chat
|
|
scroll instead of logging off — this is retail's own byte-verified
|
|
refusal, faithfully ported.
|
|
11. **Configure Keyboard.** Click it. **INERT — nothing happens.** This
|
|
is the contracted behavior for OP3; OP8 wires the real Configure
|
|
Keyboard screen, and OP8's own gate re-tests this exact button. Do
|
|
not report this as a bug for OP3.
|
|
12. **In-Game Help Files.** Click it. **INERT — nothing happens.**
|
|
Retail's own help viewer is a third-party plugin
|
|
(`plugins\ACHelpPlugin.dll`) acdream does not have; retail itself
|
|
fails silently with the plugin absent, and this button mirrors that
|
|
(register row AD-76).
|
|
13. **Urgent Assistance.** Click it. Expect a chat line explaining the
|
|
web browser could not be launched and pointing at
|
|
`http://support.turbine.com/ics/support/ticketnewwizard.asp?style=classic`
|
|
— retail's own byte-verified failure text, always shown (the URL is
|
|
dead in 2026, so acdream never attempts to open a browser — register
|
|
row AD-75). **No native browser window opens, no OS dialog box.**
|
|
**Legibility check (blast review SHOULD-FIX 4):** this is a
|
|
THREE-LINE, ~110-character-URL body landing in the SpewBox overlay,
|
|
which auto-expires after 5 seconds. Read the whole body BEFORE it
|
|
disappears — if you cannot finish reading it (especially the URL) in
|
|
that window, report it as a legibility problem; the honest fix would
|
|
be routing it to the scrolling chat transcript (which stays and
|
|
scrolls back) instead of shortening the timeout.
|
|
14. **Report Abuse.** Click it. Same shape as Urgent Assistance
|
|
(including the same legibility check), with its own retail text
|
|
("...to submit an abuse report...").
|
|
15. **Use Mouse Turning Settings.** Click it. Expect one retail chat
|
|
line per changed value among: Camera Stiffness, Camera Adjustment,
|
|
Mouse Sensitivity, Align To Slope, Invert Mouselook Axes, Turn to
|
|
Face Camera — a FRESH character (never touched these settings) sees
|
|
all six lines; clicking the button a second time in the same
|
|
session sees zero lines (everything already at the macro's target).
|
|
**These six lines are byte-verified `RetailLogTextType.Magic` (0x07),
|
|
NOT the client-local refusal type** — expect LIGHT BLUE text in the
|
|
SCROLLING CHAT TRANSCRIPT (not the transient SpewBox overlay). Do
|
|
NOT expect a timestamp prefix: acdream renders no chat timestamps
|
|
yet (the Display Timestamps consumer is OP4 scope, and there is no
|
|
chat-log file — TS-69), so a bare light-blue line is CORRECT here
|
|
(OP3 re-review R1). If you see bright red text in a transient
|
|
5-second overlay instead (the ClientLocal/SpewBox look used by the
|
|
mid-air refusal and UA/RA above), that is the pre-fix-round bug —
|
|
report it.
|
|
**Known, registered gap (TS-74): acdream has no persistent
|
|
"turn to face camera" mouse-turning MODE yet, so this button changes
|
|
stored preferences and sends the wire bit, but you will not see the
|
|
camera actually start turning with mouse movement** — that consumer
|
|
does not exist yet. Verify the CHAT LINES and that the button is
|
|
clickable/does not crash; do not expect a camera-behavior change.
|
|
|
|
### Cross-session persistence (mechanism review S6)
|
|
|
|
16. **Relog the SAME character** (log off through Exit Game, or
|
|
disconnect/reconnect, then log back in) after step 15 has already
|
|
shown all six lines once. Open the Options panel and click "Use
|
|
Mouse Turning Settings" again. Expect **zero** chat lines this time —
|
|
`UseMouseTurning` is an auto-save id (`SetSingleCharacterOption
|
|
0x0005`), so the bit reached ACE on the first click and the fresh
|
|
post-relog `PlayerDescription` echoes it back as already-on. Seeing
|
|
the "Turn to Face Camera was changed..." line AGAIN after a clean
|
|
relog means the bit did not actually persist server-side — report it.
|
|
17. **Fully relaunch the client** (close the window, start a new
|
|
process) after step 15. Reopen the Options panel — no button click
|
|
needed. The five CLIENT-LOCAL preferences (Camera Stiffness,
|
|
Adjustment Speed, Mouse Sensitivity, Align To Slope, Invert Mouselook
|
|
Axes) persisted to `settings.json`'s `cameraTurning` section should
|
|
still read at the macro's target values from the PREVIOUS session —
|
|
click "Use Mouse Turning Settings" once more and confirm you again
|
|
see zero lines (proving the five client-local prefs, not just the
|
|
one server bit, survived the relaunch).
|
|
|
|
### What to report
|
|
|
|
- Any of the above NOT matching (wrong text, wrong tab default, window
|
|
not draggable/resizable, close button not working, F11/toolbar not
|
|
opening the panel, opening Options not closing a sibling panel, toolbar
|
|
button not highlighting while the panel is open).
|
|
- Any exception/crash on any of the 17 steps.
|
|
- Whether the confirmation dialog's exact wording looks retail-correct
|
|
(it resolves from the DAT string table at runtime; a fallback English
|
|
string only appears if that resolution fails, which would itself be
|
|
worth reporting).
|
|
|
|
### Explicitly NOT in scope for this gate
|
|
|
|
- Character/Chat/Config tab content (rows, checkboxes, sliders, live
|
|
data) — OP4/OP5/OP6.
|
|
- Configure Keyboard's actual screen — OP8.
|
|
- Any observable camera change from "Use Mouse Turning Settings" — no
|
|
acdream consumer exists yet (TS-74).
|
|
|
|
---
|
|
|
|
## OP4 — the Character tab
|
|
|
|
The Character tab (`0x21000028`) is the biggest single tab: 6 authored
|
|
group headers and 50 toggle rows (49 from the 2013 build + D3's "Listen to
|
|
PK death messages"), each bound by its retail `PlayerOption` id through
|
|
`CharacterOptionTable` and the shared `RuntimeCharacterOptionsState.
|
|
TrySetOption` seam every other Options-panel consumer already uses.
|
|
|
|
### Opening the tab and reading the rows
|
|
|
|
1. **Open the Options panel (F11) and click the Character tab.** Six
|
|
group headers appear top-to-bottom: **User Interface Behavior** (3
|
|
rows), **User Interface Display** (15 rows), **Grouping** (6 rows),
|
|
**Other Players** (11 rows), **Character Behavior** (7 rows), **Chat**
|
|
(8 rows — 7 from retail plus "Listen to PK death messages"). Every row
|
|
has a label; hover a few and confirm a tooltip appears. If ANY row
|
|
shows no label at all, that is a DAT string-resolution miss worth
|
|
reporting (the code deliberately renders nothing rather than invented
|
|
English when a string fails to resolve — a blank row is the correct
|
|
FAILURE shape, not a crash, but still worth flagging which row).
|
|
2. **Scroll the list** via the scrollbar. All 50+6 rows are reachable;
|
|
the list does not clip or overlap the Apply/Reset/Defaults buttons at
|
|
the bottom.
|
|
3. **Confirm the checkboxes reflect your character's actual state** —
|
|
e.g. if you have `IgnoreAllegianceRequests` on from a prior session,
|
|
its row should show checked on open (seeded from the live server bit
|
|
at panel-mount time, not always-off).
|
|
|
|
### Auto-save rows — immediate `0x0005`
|
|
|
|
4. **Toggle "Listen to General Chat" off, then on again**, without
|
|
clicking Apply. Confirm the effect is IMMEDIATE and matches the
|
|
existing Settings-panel Hear\*Chat behavior: turning it off silently
|
|
drops you from general chat (no more `/g` messages appear); turning it
|
|
back on restores them. This id is auto-save — the wire send happens on
|
|
the click itself, not on Apply.
|
|
5. **Toggle "Automatically Repeat Attacks" or "Accept Corpse Looting
|
|
Permissions"** (both auto-save). These previously flipped ONLY a
|
|
client-local flag and never reached the wire (an unfiled divergence
|
|
this slice closes) — verify the *behavior* actually changes in
|
|
combat/looting, not just the checkbox art.
|
|
6. **Relog the same character** after toggling a couple of auto-save
|
|
rows. Reopen the panel — the rows should still read whatever you left
|
|
them at (server echo), confirming the send actually reached ACE and
|
|
persisted, not just the local bit.
|
|
|
|
### Batched rows — the `0x01A1` blob via Apply
|
|
|
|
7. **Toggle a BATCHED row** (e.g. "Side By Side Vitals" or "Display Date
|
|
of Birth" — anything NOT in the auto-save set) and click **Apply**.
|
|
Relog and reopen the panel: the row should still read your new value
|
|
(Apply flushed the `0x01A1` blob, ACE persisted it, the fresh
|
|
`PlayerDescription` echoes it back).
|
|
8. **Close the Options panel (F11) FIRST, then toggle a batched row
|
|
WITHOUT clicking Apply**, then relog. The row should revert to its
|
|
PRE-toggle value on reopen — an un-flushed batched change never
|
|
reached the wire (the 480 s auto-save timer is a Runtime-level
|
|
mechanism tested at OP1; do not wait 8 minutes for this gate — just
|
|
don't click Apply). **Closing the panel first is load-bearing, not
|
|
optional**: logout flushes the dirty blob (`CPlayerSystem::
|
|
LogOffCharacter` calls `SaveToServer`), so "relog without Apply
|
|
reverts" only holds because reaching Exit Game requires switching to
|
|
the Gameplay tab first — retail's own `OnVisibilityChanged(false) ->
|
|
RestoreSavedValues` — which reverts the uncommitted edit BEFORE
|
|
logout's flush ever sees it. A user who force-quits the client (or any
|
|
route that skips hiding the Character page) will see the OPPOSITE:
|
|
the un-Applied toggle DOES persist, because logout still flushes
|
|
whatever is dirty at that moment. Both are retail-correct; this step
|
|
exercises the panel-close path specifically.
|
|
|
|
### Apply / Reset / Defaults semantics
|
|
|
|
9. **Toggle several rows (mix of auto-save and batched), then click
|
|
Reset.** Every row you touched reverts to its pre-edit value; rows you
|
|
didn't touch are unaffected. Auto-save rows you toggled will have
|
|
ALREADY sent their change on the click — Reset sends the REVERTED
|
|
value as a fresh change (a second `0x0005`), which is retail-correct
|
|
(Reset re-applies live, it does not "undo" a wire message that already
|
|
happened).
|
|
10. **Click Defaults.** Every row jumps to its retail default value
|
|
LIVE — auto-save rows whose default differs from current send
|
|
immediately; batched rows just dirty the module. Apply/Reset stay (or
|
|
become) ENABLED afterward if anything actually changed — Defaults
|
|
does NOT commit a new baseline by itself.
|
|
11. **After clicking Defaults, click Apply.** The defaulted batched rows'
|
|
values now flush via `0x01A1`; the new state becomes the baseline
|
|
(Reset can no longer undo past this point).
|
|
12. **Switch to another tab (e.g. Gameplay) without clicking Apply after
|
|
an edit.** Uncommitted edits silently revert — switching tabs is a
|
|
Reset, not a save. Switch back to Character and confirm the
|
|
reverted state.
|
|
|
|
### Group B consumers — presentation bindings
|
|
|
|
13. **Toggle "Display Timestamps" on, then send/receive a new chat
|
|
line** (e.g. `/who` or any inbound tell/say). The NEW line should be
|
|
prefixed with a timestamp like `14:32:07 ` (no leading zero on the
|
|
hour). Lines already in the transcript before you toggled the option
|
|
do NOT retroactively gain a timestamp. Toggle it back off — new lines
|
|
stop getting the prefix.
|
|
14. **Toggle "Disable Distance Fog" on** while outdoors somewhere with
|
|
visible atmospheric fog at a distance (dusk/dawn or an overcast
|
|
keyframe shows this most clearly). Distant terrain/objects should
|
|
stop fading into the fog color — toggle back off and the fog returns.
|
|
15. **Toggle "Run as Default Movement" off.** Press W (or your bound
|
|
forward-movement key) alone, with no modifier held: your character
|
|
should now WALK by default instead of run. Hold the walk-mode
|
|
modifier key while this option is off: it should now temporarily make
|
|
you RUN (the modifier always inverts whichever default is active).
|
|
Toggle the option back on and confirm W-alone runs again (today's
|
|
pre-OP4 behavior).
|
|
16. **"Display 3D Tooltips", "Side By Side Vitals", "Display Spell
|
|
Durations", "Advanced Combat Interface", "Stay in Chat Mode",
|
|
"Disable Most Weather Effects", "Always Daylight Outdoors", "Filter
|
|
Language", "Use Main Pack as Default for Picking Up Items" — verify
|
|
these are TOGGLEABLE and PERSIST (store+wire only, per the plan's own
|
|
contract), but do NOT expect any observable client behavior change
|
|
from them yet.** acdream has no existing consumer surface for these
|
|
(no side-by-side vitals layout, no 3D tooltip rendering, no discrete
|
|
weather-particle system to gate, no client-side pickup-container
|
|
preference, no profanity filter) — this is an honest, registered gap,
|
|
not a bug to report. "Always Daylight Outdoors" specifically does NOT
|
|
force daytime lighting yet; do not confuse it with the unrelated
|
|
weather-VARIETY forcing mechanism already in the codebase.
|
|
|
|
### Group C — re-pointed to server truth
|
|
|
|
17. **Toggle "Auto Target", "Automatically Repeat Attacks", "Keep Combat
|
|
Targets in View", "Vivid Targeting Indicator", "Show Coordinates By
|
|
the Radar", or "Accept Corpse Looting Permissions" and confirm the
|
|
EXISTING behavior for each (auto-targeting in combat, the combat
|
|
camera tracking your target, the vivid target overlay, radar
|
|
coordinate labels, corpse-loot consent) still works exactly as
|
|
before — these now read the SERVER bit instead of the local
|
|
`settings.json` copy, so the observable behavior should be unchanged
|
|
UNLESS your character's server-side value differs from whatever
|
|
`settings.json` had (in which case the NEW, server-driven behavior is
|
|
correct and the old local-only behavior was the bug).
|
|
18. **Relog and confirm all six Group-C options above read their
|
|
server-persisted value**, not a locally-cached default.
|
|
|
|
### Apply/Reset enable-gating (MUST-FIX 2, OP4 review-fix round)
|
|
|
|
19. **On first open of the Character tab, Apply and Reset are greyed out**
|
|
(disabled — retail's `PostInit` runs `OnOptionChanged(0)` so the pair
|
|
starts disabled). **Click any LED and they light up** (enabled).
|
|
**Click Apply and they grey out again.** **Defaults is never greyed
|
|
out** — before a change, immediately after clicking it, or after
|
|
Apply — at any point in this sequence.
|
|
|
|
### Combat panel — the SAME LEDs, a second surface (MUST-FIX 3 / blast M2)
|
|
|
|
20. **Open the Combat window (its own toolbar button, not the Options
|
|
panel) and confirm its own Repeat Attacks / Auto Target / Keep in
|
|
View checkboxes match the Character tab's rows for the SAME three
|
|
options** (Automatically Repeat Attacks / Auto Target / Keep Combat
|
|
Targets in View) — both surfaces now read the identical server bit,
|
|
so toggling one and reopening/refreshing the other must show the
|
|
SAME state. Before this fix round the Combat panel read a separate,
|
|
disconnected client-local copy that could silently disagree with the
|
|
Character tab and never reached the wire for two of the three.
|
|
|
|
### What to report
|
|
|
|
- Any row with a missing label/tooltip (note which one).
|
|
- Any auto-save row whose behavior doesn't persist across a relog.
|
|
- Any batched row that persists WITHOUT clicking Apply, or reverts
|
|
DESPITE clicking Apply.
|
|
- Any Reset/Defaults button that stays permanently disabled, or Defaults
|
|
that becomes disabled (it must never be).
|
|
- Any crash, freeze, or scroll glitch anywhere in the 56-row list.
|
|
- Timestamps, fog toggling, or run-as-default NOT working as described in
|
|
13-15.
|
|
- Any Group-C option (17-18) behaving DIFFERENTLY than it did before this
|
|
slice, other than "now reads the correct server value instead of a
|
|
stale local one."
|
|
|
|
### Explicitly NOT in scope for this gate
|
|
|
|
- Chat tab / Config tab content — OP5/OP6.
|
|
- Configure Keyboard — OP8.
|
|
- Any observable change from Group A rows (privacy flags, fellowship
|
|
grouping, missile/charge-attack options, helm/cloak visibility, and
|
|
similar) beyond the checkbox itself toggling and persisting — retail's
|
|
OWN client has no local consumer for most of these either; the server
|
|
is the only place their effect is visible (and largely invisible to the
|
|
player triggering them).
|
|
- "Always Daylight Outdoors" and "Disable Most Weather Effects" actually
|
|
changing the sky/weather — no acdream consumer exists yet (see item 16
|
|
and this slice's register rows).
|
|
- "Use Main Pack as Default for Picking Up Items" actually changing
|
|
pickup routing — no client-side preferred-container consumer exists.
|
|
- "Filter Language" actually filtering profanity — no filter subsystem
|
|
exists.
|
|
|
|
---
|
|
|
|
## OP5 — the Chat tab
|
|
|
|
The Chat tab (`0x2100005C`) has six sections: **General Options** (the two
|
|
linked window-opacity sliders) and five per-window text-filter blocks — the
|
|
**Main Chat Window** (12 checkboxes, no "Gameplay" row) and four **Floaty
|
|
Chat Window 1-4** blocks (13 checkboxes each). All five blocks write
|
|
`AcDream.Core.Chat.ChatWindowState` directly — the SAME state CH6's floating
|
|
chat windows already read when deciding which lines to show.
|
|
|
|
### Opening the tab
|
|
|
|
1. **Open the Options panel (F11) and click the Chat tab.** Six group
|
|
headers appear top-to-bottom: **General Options**, **Main Chat Window**,
|
|
**Floaty Chat Window 1**, **Floaty Chat Window 2**, **Floaty Chat Window
|
|
3**, **Floaty Chat Window 4**. Under General Options, two horizontal
|
|
sliders; the second one has "Transparent"/"Opaque" range captions at its
|
|
ends. Under each window section, a block of checkboxes with labels
|
|
(Gameplay, Combat, Magic, Area Speech, Tells, Allegiance, Fellowship,
|
|
General, Trade, LFG, Roleplay, Society, Error) — the Main Chat Window
|
|
block is missing the **Gameplay** row (12 rows, not 13); every floaty
|
|
block has all 13.
|
|
2. **Scroll the list.** All six sections are reachable; the block heights
|
|
visibly differ from a flat 100px box — each block is exactly tall enough
|
|
to show all of its own rows with no clipping and no dead space below the
|
|
last row (AP-195's self-sizing).
|
|
3. **Look closely at a row whose mask covers MULTIPLE underlying message
|
|
types** (Gameplay, Combat, Allegiance, or Fellowship — the composite-mask
|
|
rows per the research doc) versus a single-bit row (e.g. "Error" or
|
|
"General"). If your character's chat history has caused a PARTIAL match
|
|
on one of those composite rows (some but not all of its underlying types
|
|
currently enabled), the checkbox's own LED art should look visibly
|
|
different (dimmer/"ghosted") from a row that is FULLY on — this is
|
|
AP-195's LED media swap. On a fresh character every row is likely either
|
|
fully on or fully off, so this may not be observable without deliberately
|
|
creating a partial-match state via repeated single clicks inside a
|
|
composite row's underlying bits (not directly clickable per-bit through
|
|
this UI — a visual nice-to-have to note, not a blocking check).
|
|
|
|
### Opacity sliders — live drag, linked, never clamping
|
|
|
|
4. **Drag the FIRST slider (Default Opacity) most of the way to the right**
|
|
while the Options panel itself is NOT focused/hovered by your mouse (so
|
|
you can see another registered window, e.g. the toolbar or a floating
|
|
chat window, at its UNFOCUSED opacity). Watch that OTHER window's
|
|
transparency change LIVE, continuously, as you drag — not just on
|
|
release. This is retail's `SetCurrentValue -> Apply(1)` immediate-apply
|
|
semantic.
|
|
5. **Drag the first slider (Default) ABOVE the second slider's (Active)
|
|
current position.** Retail's link drags the SECOND slider's thumb UP to
|
|
match — watch it move on its own as you drag the first. Neither slider
|
|
should ever let Default end up above Active.
|
|
6. **Drag the second slider (Active) BELOW the first slider's (Default)
|
|
current position.** The first slider's thumb should get dragged DOWN to
|
|
match, symmetric to step 5.
|
|
7. **Focus a chat window (click into its text entry) and watch its opacity
|
|
change to the Active value; click away and watch it ease back toward
|
|
Default.** (The easing itself is AP-190's existing behavior, not new to
|
|
this slice — this step just confirms the sliders are actually driving
|
|
the SAME live opacity controller every other window already uses.)
|
|
|
|
### Filter checkboxes — live routing, per-window independence
|
|
|
|
8. **Open a floating chat window (Alt+1 through Alt+4, or the toolbar
|
|
indicator buttons) and uncheck "Combat" in that SAME window's filter
|
|
block on the Chat tab** (e.g. Floaty Chat Window 1's block if you opened
|
|
window 1). Trigger a combat message (attack a monster, or have someone
|
|
attack you) — it should STOP appearing in that floating window while
|
|
still appearing in the MAIN chat window (whose own filter is untouched).
|
|
Re-check the box — combat messages resume in that window.
|
|
9. **Uncheck a filter row in the MAIN CHAT WINDOW's own block** (e.g.
|
|
"Trade") and generate a matching message (a `/trade` broadcast, or
|
|
whatever is easiest to trigger). It should stop appearing in the main
|
|
window specifically, while a floating window with Trade still checked
|
|
keeps showing it — proving the main window's filter is genuinely
|
|
consulted now (CH6a/b's own fixed bug: broadcast lines used to
|
|
short-circuit true for the main window regardless of its filter).
|
|
10. **Verify the five blocks are independent**: toggling a row in Floaty
|
|
Chat Window 2's block must not affect Floaty Chat Window 1, 3, 4, or the
|
|
Main window's own same-named row.
|
|
|
|
### Apply/Reset/Defaults
|
|
|
|
11. **Toggle a couple of filter checkboxes AND drag both opacity sliders,
|
|
then click Reset.** Every row you touched (checkboxes, both sliders)
|
|
reverts to its value from the last Apply/OnShown — filter writes revert
|
|
live (you should see the reverted checkbox state immediately, and the
|
|
corresponding message routing revert too).
|
|
12. **Click Defaults.** The two opacity sliders jump to their DAT-extracted
|
|
values (0.5 default / 1.0 active — the same values you'd see on a
|
|
NEVER-touched install) LIVE; every filter block reverts to its OWN
|
|
window's retail default (Main: 0xFBFFFFFF's rows — everything checked
|
|
except Error; each floaty: its own narrower default set, per the
|
|
research doc's table) — Apply/Reset light up afterward if anything
|
|
actually changed (Defaults never commits by itself).
|
|
13. **Switch to another tab (e.g. Gameplay) without clicking Apply after an
|
|
edit.** Uncommitted slider/checkbox edits silently revert — switching
|
|
tabs is a Reset, not a save. Switch back to Chat and confirm the
|
|
reverted state (both the slider positions AND the filter checkboxes).
|
|
|
|
### Persistence — local-only, survives relog AND relaunch
|
|
|
|
14. **Set a distinctive combination** (e.g. Default Opacity ~30%, Active
|
|
Opacity ~90%, Main window's "LFG" row OFF, Floaty 3's "Fellowship" row
|
|
OFF) and click Apply (or just leave the panel open — filter writes and
|
|
slider drags apply live and persist to `settings.json` on every change,
|
|
not just on Apply).
|
|
15. **Fully relaunch the client** (close the window, start a new process;
|
|
a simple relog is not required since this is LOCAL-only state, unlike
|
|
the Character tab's server-authoritative rows). Reopen the Options
|
|
panel's Chat tab — the two sliders should read back at your set values,
|
|
and the Main/Floaty-3 checkboxes should read back unchecked for the
|
|
rows you turned off. **This is expected to be LOCAL-only persistence**:
|
|
retail's own wire mechanism for this data (the `0x1000008C`
|
|
GameplayOptions blob) is explicitly out of scope for this campaign
|
|
(register row AP-187, broadened at this slice — the blob stays
|
|
unsent); acdream persists through `settings.json` instead, which is
|
|
why a relaunch (not a server round trip) is the correct way to prove
|
|
it survived.
|
|
|
|
### What to report
|
|
|
|
- Any section/row/label missing, or the Main window showing a Gameplay row
|
|
(or a floaty missing one).
|
|
- A slider that does not apply live while dragging, or that lets Default
|
|
end up above Active (or vice versa) after a drag.
|
|
- A filter checkbox whose toggle does not change live message routing in
|
|
the window it belongs to, or that leaks into a DIFFERENT window.
|
|
- Reset/Defaults not behaving as described in 11-12.
|
|
- Any block whose height looks clipped or has a large empty gap below its
|
|
last row (a self-sizing regression).
|
|
- Any setting that reverts to default after a full relaunch (a persistence
|
|
regression) — remember this is local-only, so a SERVER-side relog is not
|
|
the right test here (see item 15's note).
|
|
|
|
### Explicitly NOT in scope for this gate
|
|
|
|
- Config tab content — OP6.
|
|
- The retail `0x1000008C` wire format for this same data — explicitly
|
|
deferred (see the plan's "What is explicitly OUT of scope" section and
|
|
this slice's own register citation).
|
|
- The composite-mask LED "partial vs full" visual distinction (step 3) is a
|
|
nice-to-have confirmation, not a blocking pass/fail item — it requires a
|
|
specific partial-match state that a fresh character is unlikely to be in.
|
|
|
|
---
|
|
|
|
## OP7 — headless `characterOptions`
|
|
|
|
Unlike OP3-OP6, this is not a graphical-client gate: no window is launched.
|
|
The coordinator runs `acdream-headless run` against local ACE with a config
|
|
declaring a small `characterOptions` block, and inspects the ACE-side
|
|
persisted `CharacterOptions1`/`CharacterOptions2` (and, for the
|
|
`ListenTo*Chat` ids, the actual Turbine room membership) before and after.
|
|
Automated coverage (schema rejection, the diff-and-send engine, the wiring
|
|
from a real `PlayerDescription` game event through to a captured wire
|
|
action, and dedicated-update-thread affinity) already runs in
|
|
`tests/AcDream.Headless.Tests/HeadlessConfigurationLoaderTests.cs`,
|
|
`HeadlessCharacterOptionsSeederTests.cs`, and
|
|
`HeadlessCharacterOptionsSeederWiringTests.cs` — this script is for the ONE
|
|
thing those tests cannot prove: that a REAL ACE server actually accepts and
|
|
persists the sends.
|
|
|
|
### Recipe
|
|
|
|
1. **Confirm the character's starting state.** Before running the bot,
|
|
note (or reset) the target character's `IgnoreAllegianceRequests`
|
|
(0x01, auto-save, `SetSingleCharacterOption 0x0005`) and
|
|
`ListenToTradeChat` (0x24, auto-save, also `0x0005` — additionally
|
|
joins/leaves the Turbine trade room) options — e.g. via an existing
|
|
graphical login, or by inspecting ACE's stored `CharacterOptions1`/
|
|
`CharacterOptions2` for the character row directly. Pick a THIRD,
|
|
batched (non-auto-save) id for the blob path — `SalvageMultiple`
|
|
(0x22, tier 2) is a safe choice: it has no observable server-side
|
|
effect beyond the stored bit, so a mismatch is purely a persistence
|
|
question, not a behavior one.
|
|
2. **Author a headless config** with all three declared at values that
|
|
DIFFER from the character's current stored state, e.g.:
|
|
```json
|
|
{
|
|
"version": 1,
|
|
"sessions": [{
|
|
"id": "op7-bot",
|
|
"endpoint": { "host": "127.0.0.1", "port": 9000 },
|
|
"account": "testaccount",
|
|
"character": { "name": "+Acdream" },
|
|
"policy": { "id": "idle" },
|
|
"credential": { "provider": "environment", "reference": "OP7_BOT_PASSWORD" },
|
|
"characterOptions": {
|
|
"IgnoreAllegianceRequests": true,
|
|
"ListenToTradeChat": true,
|
|
"SalvageMultiple": true
|
|
}
|
|
}]
|
|
}
|
|
```
|
|
(Flip each `true` to `false` instead if the character already has that
|
|
bit set — the point is a genuine diff in both directions, not
|
|
specifically "everything ON".)
|
|
3. **Run it**: `acdream-headless run --config op7-bot.json` with
|
|
`OP7_BOT_PASSWORD` set in the environment. Let it sit in-world a few
|
|
seconds, then stop it (Ctrl+C — the process scheduler's graceful-
|
|
shutdown path already sends a real logoff).
|
|
|
|
### Expected wire sends on first connect
|
|
|
|
- One `SetSingleCharacterOption (0x0005)` for `IgnoreAllegianceRequests`
|
|
(id `0x01`) — immediately, no batching.
|
|
- One `SetSingleCharacterOption (0x0005)` for `ListenToTradeChat` (id
|
|
`0x24`) — immediately, and ACE's handler additionally joins the
|
|
Turbine trade-chat room server-side for this session (observable via
|
|
ACE's own Turbine-chat membership logging if available).
|
|
- **No** `SetSingleCharacterOption (0x0005)` for `SalvageMultiple` (id
|
|
`0x22`) — it is batched, not auto-save, so `TrySetOption` only marks
|
|
the module dirty and never sends `0x0005` for it. The single
|
|
`SetCharacterOptions (0x01A1)` blob flush is the ONLY wire evidence of
|
|
this id changing (OP7's diff-and-send calls the explicit `SaveOptions`
|
|
verb once, after every declared id has been diffed, never interleaved
|
|
— so this same `0x01A1` also carries whatever the loop already wrote
|
|
locally for `IgnoreAllegianceRequests`/`ListenToTradeChat`, even though
|
|
those two ALSO got their own immediate `0x0005`).
|
|
- **No other option bits change.** ACE's stored `CharacterOptions1`/
|
|
`CharacterOptions2` for every UNDECLARED id stay exactly what they
|
|
were before the run.
|
|
- **No 0x01A1 blob before the client's own `GameActionLoginComplete`.**
|
|
If ACE logs a refusal ("SetCharacterOptions received before
|
|
FirstEnterWorldDone" or equivalent), that is a real OP7 defect — the
|
|
diff-and-send is contracted to run only after both LoginComplete has
|
|
been sent AND a real `PlayerDescription` has seeded local state
|
|
(`HeadlessCharacterOptionsSeeder`'s own two-precondition latch).
|
|
|
|
### Expected silence on reconnect
|
|
|
|
4. **Run the SAME config a second time** (a fresh process, or the
|
|
process's own reconnect path if it fires) without changing anything
|
|
on the ACE side in between. Expect **zero** `0x0005`/`0x01A1` sends
|
|
for the three declared ids — the fresh `PlayerDescription` now echoes
|
|
back exactly what the first run persisted, so the declared-vs-actual
|
|
diff finds nothing (idempotent by construction: a bot that already
|
|
has what it wants sends nothing, matching retail's own "re-set to the
|
|
current value produces nothing" rule — set-character-options-wire.md
|
|
§3.1/§3.5).
|
|
5. **Flip one declared value** in the config (e.g. `SalvageMultiple` back
|
|
to `false`) and run again. `SalvageMultiple` is batched, so expect
|
|
exactly ONE `0x01A1` blob flush and **no** `0x0005` for it — the other
|
|
two declared ids, still matching, produce nothing at all (not even the
|
|
blob).
|
|
|
|
### What to report
|
|
|
|
- Any declared id that does NOT persist across a fresh reconnect (ACE
|
|
either rejected it silently, or the diff-and-send never actually ran).
|
|
- Any UNDECLARED id whose stored value changed — a sign the blob echoed
|
|
something it shouldn't have (wire research §5.3's "echo real values,
|
|
never zero them" rule, or a stale/incorrect snapshot read).
|
|
- Any 0x0005/0x01A1 send observed BEFORE the client's own LoginComplete
|
|
action on the wire (a WireMCP capture on loopback `127.0.0.1:9000`
|
|
settles this precisely if ACE's own log line is ambiguous).
|
|
- Whether `ListenToTradeChat` actually joined the Turbine trade room
|
|
server-side (not just the stored bit) — the one declared id in the
|
|
sample config with a real behavioral consumer.
|
|
|
|
### Explicitly NOT in scope for this gate
|
|
|
|
- Every other tier-1/tier-2 option name — the three above exercise both
|
|
wire paths (auto-save `0x0005`-only and batched `0x0005`+`0x01A1`);
|
|
the remaining 23 names share the same two code paths and are already
|
|
covered by the id-ascending completeness assertions in
|
|
`CharacterOptionTableTests` (OP1) and the schema tests here (OP7).
|
|
- Any presentation-only (tier-3) option — `HeadlessConfigurationLoader`
|
|
refuses to load a config that declares one; there is nothing to run.
|
|
- The graphical Options panel's own Character tab — OP4.
|
|
|
|
### OP7 gate result — PASSED (coordinator, 2026-08-11)
|
|
|
|
Three live runs against local ACE (`127.0.0.1:9000`, `+Acdream`,
|
|
`lifecycle-smoke` policy, temporary seeder diagnostics since reverted):
|
|
|
|
- **Run 1 (declared: IgnoreAllegianceRequests=true, ListenToTradeChat=true,
|
|
SalvageMultiple=true):** the seeder sent exactly two `SetSingleOption`
|
|
diffs (`IgnoreAllegianceRequests` false→true auto-save;
|
|
`SalvageMultiple` false→true batched) plus ONE `SaveOptions (0x01A1)`
|
|
flush; `ListenToTradeChat` was already true and sent nothing. After the
|
|
policy's own portal AND a genuine mid-run reconnect (fresh ACE
|
|
`PlayerDescription`), all three reported `already ..., no send` —
|
|
proving ACE accepted and persisted both wire paths within the session.
|
|
- **Run 3 (fresh process, SalvageMultiple flipped to false):** the fresh
|
|
seed echoed `SalvageMultiple=true` from run 1 — a value ONLY the run-1
|
|
`0x01A1` blob could have carried (batched id, never `0x0005`), which is
|
|
the cross-process ACE-persistence proof. The flip sent one
|
|
`SetSingleOption` + one `SaveOptions` and nothing for the other two
|
|
ids; post-portal and post-reconnect re-diffs were silent.
|
|
- Both runs: no pre-LoginComplete sends observed, no ACE refusals,
|
|
graceful zero-code exits, `disposed` with converged runtime and zero
|
|
leases. Pre-existing noise unrelated to OP7, noted for the record: an
|
|
unmapped `[weenie-error] code=0x051D`, and the K4 resource envelope's
|
|
`handle-count` violation (the `k4-linux-30-session` Linux profile
|
|
evaluated on Windows).
|