The item grids said which item you were on ("a torch, slot 3") but nothing
about what it was -- no description, no condition, and no "what does this
refine into", which is the whole of alchemy.
The game already composes all of it in one place: item.getPopupMessage()
(modules/item.lua:199) returns the cursor popup's line list, so read that
rather than re-deriving anything from templates.
It also already gates it behind a dwell -- the popup only fades in after
examinationPopupFadeInDuration (0.4s), so a sighted player who arrows past a
slot never sees the details either. Mirror that instead of inventing a
modality: stop on an item for 0.6s and the details speak themselves, queued.
"=" reads them on demand, Shift+= keeps the name line too. ("r" was the
obvious mnemonic but is a game-claimed scancode, and getCommand() dispatches
on scancode ignoring modifiers.)
New generic hook descriptor.details() returning a LIST of blocks, so each is
also pushed into the console history and [ ] \ walk a long description back
afterwards -- the journal page trick. Only _itemgrid.lua implements it so far.
The other half is the hint panel craft/refine/trade draw permanently beside
the grid, which the popup never contains: recipe components, and price, which
appears nowhere else in the game. The three panels share a shape, so one
reader covers them. Affordability survives only as a red colour in the hint
table and decides whether enter does anything, so it is decoded and spoken.
59 testbed checks, 0 failures: a synthetic ivy_leaves item as the version-bump
canary for getPopupMessage, hasUpvalue over every hint-panel local, four
assertions on the pure settleStep, and an end-to-end "=" press. Not yet
exercised against a live item -- the prologue inventory is empty.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
242 lines
9.6 KiB
Markdown
242 lines
9.6 KiB
Markdown
# Accessibility mod — Sulphur Memories: Alchemist
|
||
|
||
Blind-accessibility mod adding screen-reader speech, an object tracker, tile
|
||
exploration and directional wall tones.
|
||
|
||
Speech goes through **Tolk**, so it uses your running screen reader (NVDA, JAWS,
|
||
System Access) and falls back to SAPI 5 if none is running.
|
||
|
||
## Running
|
||
|
||
```
|
||
"C:\Program Files\LOVE\love.exe" "D:\code\Sulphur Memories Alchemist 0.4.2 sanctified"
|
||
```
|
||
|
||
Use `lovec.exe` instead of `love.exe` to get a console window — every spoken line
|
||
is mirrored there, which is useful for reporting bugs.
|
||
|
||
The TTS libraries live in `accessibility/lib/` and are loaded by absolute path,
|
||
so nothing needs installing or copying into Program Files.
|
||
|
||
If speech does not work, check the console for the startup self-test:
|
||
|
||
```
|
||
[accessibility] TTS: available
|
||
[accessibility] speech channel: yes
|
||
```
|
||
|
||
`speech channel: NO` means Tolk loaded but found no screen reader and no SAPI.
|
||
|
||
---
|
||
|
||
## Keys added by the mod
|
||
|
||
All of these are **in addition to** the game's own controls, and none of them
|
||
replace a key the game uses.
|
||
|
||
### Reading the message log
|
||
|
||
| Key | Action |
|
||
|---|---|
|
||
| `[` | Previous message |
|
||
| `]` | Next message |
|
||
| `Shift+[` | Oldest message |
|
||
| `Shift+]` | Newest message (and resume following new messages) |
|
||
| `\` | Repeat the current message |
|
||
| `Shift+\` | Copy the current message to the clipboard |
|
||
|
||
New messages are spoken automatically. Pressing any key that does something in
|
||
the game cancels whatever is still queued, so you are never stuck listening to a
|
||
backlog. While you are moving through the history, new messages do **not** drag
|
||
the cursor away — press `Shift+]` to return to the newest.
|
||
|
||
### Looking around
|
||
|
||
| Key | Action |
|
||
|---|---|
|
||
| `/` | Scan all eight neighbouring tiles, clockwise from north |
|
||
| `Shift+/` | Cycle automatic announcements of what comes in and out of view |
|
||
| `;` | Where am I — area name, in-game date and time, coordinates |
|
||
| `Ctrl` + numpad `1`–`9` | Describe the tile in that direction without moving |
|
||
| `Ctrl` + numpad `5` | Describe the tile you are standing on |
|
||
|
||
#### Announcing things as they come into view (`Shift+/`)
|
||
|
||
`/` tells you what is around you *now*. `Shift+/` decides how much of that
|
||
happens by itself as you walk, cycling three settings:
|
||
|
||
- **View announcements when you stop** *(the default)* — changes pile up while
|
||
you are moving and are read out once you have stood still for a moment. A
|
||
single step reports as soon as the step lands. A ten-tile walk gives you **one
|
||
combined summary at the end** rather than ten reports on top of each other,
|
||
and it is a *net* change: something that came into view halfway along and went
|
||
out again before you stopped is not mentioned.
|
||
- **View announcements on every step** — each step reports its own change. Best
|
||
when you are creeping along carefully; too talkative for crossing a room.
|
||
- **View announcements off**.
|
||
|
||
You hear things arriving — `In view: a rat, 4 tiles north-east. barrel, 3,
|
||
nearest 2 tiles east` — and creatures leaving: `Out of view: a rat`. Only
|
||
creatures are reported when they leave. Furniture drops out of sight constantly
|
||
as walls come between you and it, and being told the bed is out of view every
|
||
other step would bury everything useful; a creature you can no longer see is
|
||
worth knowing about.
|
||
|
||
These announcements are queued rather than urgent, so anything you asked for
|
||
yourself is spoken first, and any key that acts in the game clears them.
|
||
|
||
Nothing outside your current field of view is ever reported.
|
||
|
||
The game's own examine mode (**`x`**) is also fully spoken: the arrow keys move a
|
||
cursor around the map and each tile is described with its distance and direction
|
||
from you. Press `f` in examine mode to jump between exits.
|
||
|
||
### Object tracker
|
||
|
||
Finds everything you have seen, sorted by distance.
|
||
|
||
| Key | Action |
|
||
|---|---|
|
||
| `Ctrl+PageUp` / `Ctrl+PageDown` | Previous / next **category** |
|
||
| `PageUp` / `PageDown` | Previous / next **kind** of thing in that category |
|
||
| `Shift+PageUp` / `Shift+PageDown` | Previous / next **instance** of that kind |
|
||
| `Home` | Distance, direction, and number of steps by path |
|
||
| `Ctrl+Home` | Walk to it |
|
||
|
||
Categories: Creatures, Items, Alchemy, Interactables, Exits, Terrain features.
|
||
|
||
So `Ctrl+PageDown` to reach "Creatures", `PageDown` to move between rat / beetle
|
||
/ guard, and `Shift+PageDown` to step through the individual rats. `Home` gives
|
||
you the walking distance, which indoors is often very different from the
|
||
straight-line distance.
|
||
|
||
`Ctrl+Home` does exactly what left-clicking the tile does with a mouse: it queues
|
||
a walk along the game's own path. If the thing itself cannot be stood on — a
|
||
creature, a chest, a bed — you walk to the nearest tile beside it instead, and
|
||
the announcement says "next to" rather than "to". As with a mouse click, the walk
|
||
stops early if something interrupts you, and while an enemy is in view the game
|
||
only ever commits one step at a time.
|
||
|
||
Your selection sticks. The list is rebuilt and re-sorted by distance every turn,
|
||
but the tracker follows the thing you picked rather than the slot it was in, so a
|
||
rat you are tracking stays selected as it moves around. It is only let go when it
|
||
genuinely stops being visible.
|
||
|
||
The tracker only ever reports things you have actually seen.
|
||
|
||
### The journal (`j`)
|
||
|
||
The journal has three parts, and all three are spoken:
|
||
|
||
| Key | Moves |
|
||
|---|---|
|
||
| `q` / `e` | Between tabs — Quests, Lore, Bestiary, Components, Recipes, Tutorials |
|
||
| Up / Down | Between entries in the current tab |
|
||
| Left / Right | Between pages of the selected entry |
|
||
|
||
Selecting an entry reads its title, its position in the list, and then the text
|
||
of the page itself. The tab name is only spoken when you change tabs, and the
|
||
title only when you change entry, so flipping pages doesn't make you sit through
|
||
the heading again.
|
||
|
||
Long entries run to several pages; you are told `page 2 of 3` when there is more
|
||
than one. The page text also goes into the message history, so `[` and `]` will
|
||
walk back through it and `\` re-reads a line — useful for a long lore entry you
|
||
want to take in a piece at a time.
|
||
|
||
### The inventory (`i`)
|
||
|
||
Moving the cursor reads the item under it, or `empty`, plus the slot number:
|
||
`a torch, slot 3`. `q` / `e` change tab, and the tab name is spoken when it
|
||
changes. An item you are currently wearing, wielding or have switched on is read
|
||
as `equipped`.
|
||
|
||
Pressing enter (or `z`) on an item opens a small menu of the things you can do
|
||
with *that* item right now — the list is different for every item, and changes
|
||
with its state. It is read as, for example:
|
||
|
||
```
|
||
a torch, actions, Switch on, 1 of 2
|
||
```
|
||
|
||
Up and Down move through the actions, enter performs the selected one, and any
|
||
other key closes the menu without doing anything. After the action runs you hear
|
||
the item again, so `Switch on` is followed by `a torch, equipped, slot 3` — that
|
||
is your confirmation it worked.
|
||
|
||
Some items have no actions at all (plain crafting reagents, for instance). For
|
||
those, enter does nothing whatsoever in the base game — not even a click — so the
|
||
mod says `a pinch of sulphur, no actions` rather than leaving you wondering
|
||
whether the key registered.
|
||
|
||
Common actions include Activate, Wield, Unwield, Wear, Take off, Switch on,
|
||
Switch off, Drink, Eat, Apply, Read, Open, and Prepare for throwing / Pack away.
|
||
**Equipping is done from here** — there is no separate equipment screen.
|
||
|
||
### Item details (`=`)
|
||
|
||
| Key | Action |
|
||
|---|---|
|
||
| `=` | Read the full details of the item under the cursor |
|
||
| `Shift+=` | The same, including the item's name |
|
||
|
||
Reading the cursor only tells you *which* item you are on. The details tell you
|
||
what it is: what kind of thing it is, its condition if it can wear out, its
|
||
description, and — the useful part for alchemy — **what it turns into**, listed
|
||
per refinement method:
|
||
|
||
```
|
||
It is a raw material. Some fresh green leaves from ivy. They contain weak
|
||
poison. Yields: x1 when ground in a mortar. x0.2 when distilled.
|
||
```
|
||
|
||
On the crafting, refining and trading screens the details also read the panel
|
||
beside the grid, which is where the game keeps the things you most need before
|
||
committing: a recipe's components and **whether you can afford them**, what a
|
||
refinement produces and how much of it you already have, and — in a shop — the
|
||
**price**, which appears nowhere else.
|
||
|
||
You do not have to press `=` every time. **Stop on an item for about half a
|
||
second and the details are read to you automatically**, which is what the game
|
||
does for a sighted player: its own detail popup only appears after you have
|
||
hovered a slot for a moment. Arrow through a tab quickly and you hear only the
|
||
names, exactly as a sighted player sees only the icons.
|
||
|
||
Details also go into the message history, so `[` and `]` walk back through a
|
||
long description a piece at a time and `\` re-reads a line.
|
||
|
||
### Your character
|
||
|
||
| Key | Action |
|
||
|---|---|
|
||
| `'` | Health and active effects |
|
||
| `,` | Currently selected action |
|
||
|
||
You are also told automatically when you take damage or are healed.
|
||
|
||
### Wall tones
|
||
|
||
Each step you take, a tone sounds from the direction of any wall within five
|
||
tiles, positioned in 3D so you can hear where it is. Further walls are louder.
|
||
|
||
---
|
||
|
||
## Reporting problems
|
||
|
||
Run with `lovec.exe` and include the console output. Lines beginning `[speech]`
|
||
show exactly what was spoken and when:
|
||
|
||
- `[speech]!` — interrupted whatever was being said
|
||
- `[speech]*` — urgent alert, spoken immediately
|
||
- `[speech] ` — queued normally
|
||
|
||
If something is **silent that should not be**, that is the most useful thing to
|
||
report, together with the screen you were on and the key you pressed.
|
||
|
||
---
|
||
|
||
## For developers
|
||
|
||
See `accessibility/docs/` — start with `docs/README.md`, and read
|
||
`docs/scratch.md` first if you are picking the work up mid-stream.
|