journal: speak the page text, not just the entry title
Opening the journal and selecting an entry announced its title and stopped, which is an index into content the player could never reach. Page flipping was silent too. The screen is three widgets at once: the tab row (q/e), the list of entry titles down the left (up/down), and the page on the right holding the actual text (left/right). The descriptor read only the first two. It now reads options[selectedOption].pages[selectedPageId] and speaks its text blocks. A page is bounded by what fits on screen, so it is safe as a single utterance. Layout newlines are flattened first -- splitTextByPages joins the game's own wrapped lines with \n, so left in they make the reader pause mid-sentence at every wrap point. Page position is announced only when there is more than one page, and the blocks are pushed into the console history so [ and ] walk back through a long lore entry after the utterance has gone by. The tab leads only when the tab changed and the title only when the entry changed, so flipping pages does not bury the new page under a repeated heading. That suppression made read() stateful, which is a trap: it is called for the same focus from four places -- the per-frame poll, the post-keypress announce, repeatFocus, and the testbed's before/after probes -- so a poll would consume the "changed" flag and the real announcement would come out headless. The descriptor now caches its last (key, text) and replays it whenever the key is unchanged, making read() idempotent; the suppression state advances exactly once per genuine focus change. Adds a generic descriptor.reset hook, called from menus.announceScreen. The memory lives in file-locals that outlive the screen, so without it reopening the journal on the entry you left it on would read the page with no title. Testbed asserts the spoken text contains the page body rather than merely being non-nil. 29 checks, 0 failures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
81a209b600
commit
e1d9995c9f
@@ -7,7 +7,7 @@ playtesting.** Remaining work is polish, mod settings and distribution.
|
||||
|
||||
**Game is playable start-to-finish by ear** from main menu through the intro
|
||||
conversation into gameplay, plus journal, character, actions and inventory —
|
||||
verified by the testbed, **26/26 checks**.
|
||||
verified by the testbed, **29/29 checks**.
|
||||
|
||||
### Run the testbed (do this after any change)
|
||||
```
|
||||
@@ -463,6 +463,48 @@ so it also bypassed the flush-time logger — meaning damage alerts fired but we
|
||||
invisible in the testbed transcript. Log prefixes: `!` interrupt, `*` immediate,
|
||||
` ` queued.
|
||||
|
||||
### Done — journal page text (bug fix, reported by Talon)
|
||||
|
||||
**Symptom:** open the journal with `j`, select an entry, hear nothing useful.
|
||||
|
||||
**Cause:** the journal is three widgets at once — the tab row, the list of entry
|
||||
titles on the left, and the **page** on the right that holds the actual text.
|
||||
The descriptor read only the first two. So it announced
|
||||
`Quests, A simple commission, 1 of 1` and stopped, which is an index into
|
||||
content you could never reach. Page flipping (`left`/`right`) was silent too.
|
||||
|
||||
**Fix** — `accessibility/states/journal.lua`:
|
||||
- Reads `options[selectedOption].pages[selectedPageId]`, a list of text blocks,
|
||||
and speaks their `text`. Page size is bounded by what fits on screen, so a
|
||||
page is safe to speak as one utterance.
|
||||
- **Flattens the newlines** in each block. `journalModel.splitTextByPages`
|
||||
concatenates the game's own wrapped lines with `\n`, so those are pure layout —
|
||||
left in, the reader pauses mid-sentence at every wrap point.
|
||||
- Says `page 2 of 3` only when there is more than one page.
|
||||
- Pushes the blocks into the console history, so `[` / `]` / `\` re-read the
|
||||
page after the utterance has gone by — the same trick `_textscreen.lua` uses
|
||||
for the manual.
|
||||
- Title leads only when the *entry* changed, tab only when the *tab* changed, so
|
||||
flipping pages doesn't bury the page you just turned to under a repeated title.
|
||||
|
||||
⚠ **`read()` must be idempotent.** It is called for the same focus from four
|
||||
places: the per-frame poll, the post-keypress announce, `menus.repeatFocus`, and
|
||||
the testbed's before/after probes. Any "only say this when it changed" state
|
||||
inside a descriptor is therefore a trap — the poll consumes the flag and the
|
||||
real announcement comes out headless. The journal descriptor caches its last
|
||||
`(key, text)` and replays it whenever the key is unchanged, so the suppression
|
||||
state advances exactly once per genuine focus change.
|
||||
|
||||
**New generic hook: `descriptor.reset`**, called by `menus.announceScreen`.
|
||||
Change-suppression memory lives in file-locals that outlive the screen, so
|
||||
without it, reopening the journal on the entry you left it on would read the
|
||||
page with no title in front of it.
|
||||
|
||||
Verified live: `Journal. Quests, A simple commission, 1 of 1, Someone's banging
|
||||
at my door. Whoever it is, this person is very persistent and doesn't know about
|
||||
doorbells.` **29/29 testbed checks**, including a new one that asserts the spoken
|
||||
text actually contains the page body rather than merely being non-nil.
|
||||
|
||||
### Known gaps (next up)
|
||||
- **Phase 5**: player status key (HP, statuses, current action), popup
|
||||
announcements (`popupStack.add`), damage alerts
|
||||
@@ -527,7 +569,7 @@ utterance — speech is verifiable from the log, not only by ear. `!` after
|
||||
## HANDOFF — read this if you are resuming
|
||||
|
||||
### State of play
|
||||
Phases 0–5 complete. **23 state descriptors, 5 patches, 26/26 testbed checks**,
|
||||
Phases 0–5 complete. **23 state descriptors, 5 patches, 29/29 testbed checks**,
|
||||
history unit tests passing, **one line changed in the game** (`main.lua`).
|
||||
|
||||
Everything in the original brief is implemented: console speech with
|
||||
@@ -538,7 +580,7 @@ exploration, wall tones, and keyboard+speech access to every screen.
|
||||
```
|
||||
lua accessibility/tests/test_history.lua # pure Lua, instant
|
||||
rm -rf ~/AppData/Roaming/LOVE/Alchemist # clean save
|
||||
"C:/Program Files/LOVE/lovec.exe" . --a11y-test # ~4 min, 26 checks
|
||||
"C:/Program Files/LOVE/lovec.exe" . --a11y-test # ~4 min, 29 checks
|
||||
git diff --stat vanilla-0.4.2 -- . ':!accessibility' ':!.gitignore' # must stay: main.lua | 1 +
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user