Game-file footprint unchanged: still one line in main.lua. - describe.lua: shared spatial formatting. 8-point compass and Chebyshev distance, since the game moves 8-directionally and Euclidean would overstate diagonal travel. Verbosity setting, because sweeping eight neighbours and inspecting a single tile want different amounts of detail. - states/ingame_observe.lua: narrates the game's existing examine cursor. - surroundings.lua: probe one direction, scan all eight, or report location, without moving anything or touching game state. - patches/popups.lua: wraps inventoryCursorPopup.set, covering inventory, craft, refine and trade in a single patch. Q3 resolved as augment rather than relay: the game's descriptions carry no position, which is fine on screen and useless by ear, so distance and direction are appended. Examine mode is polled rather than driven by levelCursorPopup. That popup is set from an animation-completion callback, so unless the player has enabled the game's quickExaminationPopup option the text arrives a full keypress late -- in testing you heard the previous tile while standing on the next. Polling level.cursorX/Y is same-frame and setting-independent. hotkeys.isCtrlDown/isShiftDown are now overridable fields rather than direct love.keyboard calls: real hardware state cannot be faked by love.event.push, so without that seam every modifier-gated hotkey would be untestable. 11/11 testbed checks, history unit tests passing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Accessibility mod — documentation
Research and planning for making Sulphur Memories: Alchemist 0.4.2 blind-accessible.
| Doc | Contents |
|---|---|
| 01-architecture.md | How the game is built: states, console, level model, keybindings, where text already exists. |
| 02-hooking-strategy.md | How to attach the mod with (near) zero edits to game files. |
| 03-implementation-plan.md | Six phases, each independently testable. |
| 04-open-questions.md | Decisions needed before/while building. |
| 05-decisions.md | Answers given so far, and what they imply. Supersedes Q1/Q2/Q7/Q10. |
The short version
Three findings shape everything:
-
The game is already keyboard-complete. All 28 states implement
keypressed; there's a full rebindable-keys system with contexts. The accessibility gap is that nothing announces what is focused — not that things are unreachable. This makes the job much smaller than a typical mouse-driven game. -
The game already writes the text we need to speak.
console.printis a single chokepoint for all log messages.level.getCursorMessage()returns tile/creature descriptions.getCursorPopupStats()feeds the item popups in five screens. We are mostly re-routing existing strings to speech, not writing a description engine. -
Everything is a
required singleton, anddebug.getupvalueworks. Module functions can be monkey-patched in place, and the file-localselectedOptionvariables in menu states are readable from outside. A one-line bootstrap inmain.luais the only unavoidable edit.
Proposed footprint: 1–3 lines added to main.lua, everything else new files under accessibility/. A git baseline tagged vanilla-0.4.2 makes re-application on future versions a rebase.