Files
alchemist-accessibility/accessibility/docs/04-open-questions.md
T
Accessibility ModandClaude Opus 5 e57350ded3 Phase 0: accessibility mod bootstrap and TTS
Establishes the mod skeleton and gets speech working end to end.

Game-file footprint: one line in main.lua.

- accessibility/init.lua: sole entry point. Patch registry, hooks states.switch
  (announces screen changes) and states.update (per-frame speech flush, avoiding
  an edit to love.update). Startup self-test prints what resolved -- the canary
  for when a future game version moves something we hook.
- accessibility/speech.lua: TTS wrapper. pcall-guarded so a missing DLL degrades
  to silence instead of crashing. Queues utterances within a frame and joins them,
  since one game turn emits several console.print calls and speaking each with
  interrupt would leave only the last audible.
- accessibility/stateNames.lua: spoken names for the 28 states.
- accessibility/vendor/love2talk: vendored TTS library, see VENDORED.md.
  Loads Tolk.dll by absolute path via love.filesystem.getSource() and adds that
  directory via SetDllDirectory, so the DLLs live in the project instead of
  needing an elevated copy into Program Files.

Verified with lovec against NVDA: TTS available, speech channel yes,
'Main menu' spoken on startup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 20:28:30 +02:00

6.8 KiB
Raw Blame History

Open questions

Ordered roughly by how much they block work. Q1–Q3 affect the design; the rest are preferences I can pick defaults for if you'd rather not decide up front.


Q1 — Tolk DLL placement and how you launch the game (blocking Phase 0)

ffi.load("Tolk") goes through the Windows loader, so Tolk.dll + the screen-reader clients (nvdaControllerClient64.dll, SAAPI64.dll, …) must be next to the executable or on PATH — they can't live inside a .love archive.

Copies already exist on this machine at D:\code\cafe, D:\code\dragonrpg-mapmaker, D:\code\DragonWarriorAccess.

  • How are you running the game right now — love.exe "D:\code\Sulphur Memories..." from a shortcut, or something else?
  • Is the end goal a fused .exe (via build.lua / love-build, DLLs shipped alongside) or a source folder + system LÖVE?
  • Are you happy for me to copy the DLLs into the project (or a dist/ staging folder), or do you want them kept out of the tree?

Q2 — Object tracker semantics (blocking Phase 3)

I've assumed a three-level hierarchy:

  • Category (Ctrl+PgUp/PgDn) → "Creatures", "Items", "Exits", …
  • Item within category (PgUp/PgDn) → distinct kinds: "rat", "beetle", "guard"
  • Instance (Shift+PgUp/PgDn) → the specific rat: "rat 2 of 3, 5 tiles north-west"

Is that the model you have in mind? The alternative reading is that PgUp/PgDn walks a flat distance-sorted list of every object in the category, and Shift only kicks in for same-named ones. Both are defensible; the first is more structured, the second faster to sweep.

Also: my proposed categories are Creatures / Items / Exits / Interactables / Terrain features / Alchemy. Anything you'd add, drop, or split? (Alchemy ingredient nodes are broken out separately because the game is built around harvesting them — tell me if that's over-thinking it.)


Q3 — Verbosity and how much to add vs. relay

The game already produces good description text (getCursorMessage, the popup lines). I can either:

  • (a) Relay only — speak exactly what a sighted player reads. Faithful, low risk of the mod drifting from the game.
  • (b) Relay + augment — add distance, direction, passability, visible-vs-remembered, "has loot", etc.

I've assumed (b) for tile examination, since bare descriptions without spatial context aren't much use non-visually. Confirm? And should augmentation be a verbosity setting (terse / normal / verbose) rather than fixed?


Q4 — Auto-speak policy for the console

A single game turn can emit several log lines (combat flavour, status changes, ambient flavour). Options:

  • Speak everything, queued, in order — thorough but can lag behind fast play.
  • Speak everything except colorTemplate == "flavor" (the greyed-out ambient text), which stays review-only.
  • Speak everything, but let a new keypress interrupt the pending queue.

I lean toward: speak everything, queued; a new player action interrupts leftover queue; with a config toggle to mute flavour. Sound right?

Related: the game coalesces repeated identical messages into "message (x3)". Should speech do the same, or announce each occurrence?


Q5 — Wall tones: when do they fire?

You've supplied walltone_{north,south,east,west}.wav. Candidate triggers:

  • On bump — the player tries to move into a wall and can't. Unambiguous, low noise.
  • On adjacency — a tone whenever a wall is directly adjacent, as an ambient orientation cue. Richer, but potentially constant in a corridor.
  • On the surroundings-scan key only — explicit, never intrusive.

What were you picturing? And should they be positioned audio (LÖVE's TEsound.playPositioned, panned by direction — the game already sets an inverse distance model) or flat stereo?


Q6 — Keybindings: integrate or stay separate?

The game has a proper rebindable-keys system with contexts and a keybindings_menu screen, persisted to keybindings.json.

  • Integrate: register our commands into models/keybindings.lua's tables so they show up in the game's own rebinding UI and get conflict detection for free. Nicer for the player; more coupling, and it writes our commands into the player's keybindings.json.
  • Separate: our own accessibility/keys.json and our own (spoken) rebinding flow. Fully decoupled; duplicates a system that already exists.

I lean separate for decoupling, but reusing keybindings.checkForConflicts to warn about clashes. Preference?


Q7 — How much game-file editing is acceptable, really?

debug.getupvalue lets us read menu focus with zero game edits, at the cost of depending on internal variable names (selectedOption, optionsList) that could be renamed in any future version. The alternative is ~13 small patches — one access.announce(...) call per state — which are far more robust but must be re-applied on every version bump (manageable via the git-rebase workflow in 02-hooking-strategy.md).

My recommendation: upvalue probing by default + a startup self-test that loudly reports any probe that stopped resolving, so a broken version bump is obvious immediately. But if you'd rather have boring-and-robust over clever-and-fragile, say so now — it changes Phase 4's shape substantially.


Q8 — Scope of "everything mouse-only"

Good news from the research: all 28 states already implement keypressed, and the ones I read (inventory, craft, ingame, ingame_observe, ingame_dialogue, main_menu) are genuinely fully keyboard-driven. So the gap is narration, not reachability.

I haven't yet exhaustively verified every state for mouse-only corners — likely suspects are the slider in craft/refine, the worldmap travel targets, and keybindings_menu's key-capture flow. Do you want me to do a full keyboard-reachability audit of all 28 states as an explicit deliverable (adds a doc, moderate time), or handle gaps opportunistically as they surface during Phase 4?


Q9 — Testing and target screen reader

  • Which screen reader do you use (NVDA, JAWS, SAPI)? Affects interrupt behaviour and punctuation handling.
  • Do you want me to actually run the game with lovec.exe during development to verify hooks fire (I can, LÖVE 11.5 is installed), or would you rather drive testing yourself and have me work from the source?
  • Is there an existing save file I can load to reach a populated level quickly, or should I plan around the tutorial start?

Q10 — Upstream intent

Is this purely a personal/community mod, or do you intend to offer it to the developer (Spellweaver) for upstreaming? If upstreaming is plausible, that argues for the clean-patches approach over upvalue probing, and for integrating with the game's own keybindings and settings systems rather than running parallel ones.