research: read what a node costs, unlocks and does
The research tree spoke only the node's name and whether you could afford
it. Everything that tells you whether it is worth affording -- the
knowledge cost, the recipes it unlocks, the description -- is drawn in
the hint windows beside the tree and was never spoken, so "cannot afford"
gave no way to find out what was missing or by how much.
states/research.lua now implements details(), the same = / Shift+= hook
the item grids use: cost with the shortfall spelled out, what it unlocks,
then the description, one block each so [ and ] walk them back. Shift+=
adds the name line and the whole knowledge purse across all four types.
The focus line also takes its name from the node's title instead of
humanising the id, so it is "Sewing techniques", not "sewing techniques".
Everything is read from the state's currentNode upvalue -- the display
table updateCurrentNode() assembles for the hint window -- rather than
models/research.lua, whose nodes table is file-local and whose unlocks
are recipe ids, which would have named the recipe instead of the item it
produces. The shortfall is computed against journalModel.knowledge,
required lazily because models.journal drags in much of the game.
The tree has no hotkey and the prologue may hold no writing desk, so the
testbed enters it the way the desk does: ingame.interface("research"),
the exact call in the desk's tryInteractFunction. Require it as
"states/ingame" and not "states.ingame" -- states.lua uses the slash
form, and the dot form loads a second copy of the module whose
levelWindow is nil, which research.draw indexes on its first frame.
98 testbed checks, 0 failures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a1ad7f26c2
commit
ce0f375a10
@@ -7,7 +7,7 @@ fixing what Talon hits. 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, **88/88 checks**.
|
||||
verified by the testbed, **98/98 checks**.
|
||||
|
||||
**Not set up yet, or unsure how the two trees relate?** →
|
||||
[00-dev-setup.md](00-dev-setup.md).
|
||||
@@ -443,10 +443,16 @@ Final two descriptors:
|
||||
selection; `currentlyActiveWindow` says which has focus. Announcing the wrong
|
||||
panel's row would be actively misleading, as the lists are unrelated.
|
||||
- **`research`** — a 2D node graph, not a list. Nodes are icons with **no text
|
||||
label**, so the id is the only identifier; the useful facts are
|
||||
label**, so the focus line must carry the name; the useful facts are
|
||||
researched / locked / cannot afford / available. Without the affordability
|
||||
part the screen is unusable by ear, since enter on an unaffordable node
|
||||
silently does nothing.
|
||||
silently does nothing. Name, cost, unlocks and description all come from the
|
||||
state's **`currentNode`** upvalue — the display table `updateCurrentNode()`
|
||||
builds for the hint window. Read that rather than `models/research.lua`: its
|
||||
`nodes` table is file-local, and its `unlocks` are *recipe* ids, whereas
|
||||
`currentNode.unlocks` is already `{title = <item name>}`. `title` also beats
|
||||
humanising the id ("Alchemical fire", not "alchemical fire"). Cost, unlocks
|
||||
and description are served by `details()` on `=`; see below.
|
||||
|
||||
**Phase 5 — `accessibility/status.lua`:**
|
||||
|
||||
@@ -648,8 +654,10 @@ a **list of blocks**, not one string. Blocks are spoken joined *and* pushed
|
||||
individually into the console history, so `[` / `]` / `\` walk a long
|
||||
description back afterwards — the same trick `states/journal.lua` uses for pages.
|
||||
Driven by `accessibility/details.lua` (`get` / `speak` / `update` / the pure
|
||||
`settleStep`). Implemented so far only by `_itemgrid.lua`; `research`,
|
||||
`ingame_observe` and `journal` are the obvious cheap follow-ups.
|
||||
`settleStep`). Implemented by `_itemgrid.lua` and by `research` (cost with the
|
||||
shortfall spelled out, what it unlocks, the description; verbose adds the name
|
||||
line and the full knowledge purse). `ingame_observe` and `journal` are the
|
||||
obvious cheap follow-ups.
|
||||
|
||||
**The hint panels are the other half, and one reader covers all three.**
|
||||
craft / refine / trade each draw a permanent panel beside the grid that the
|
||||
@@ -844,6 +852,35 @@ testbed check is this descriptor's version-bump canary**.
|
||||
Still unexercised: the **map** popup (needs `worldmap.getLastAreaIcon`, i.e. a
|
||||
discovered area) and the modal **loot** popup from `inventory.lootPopup`.
|
||||
|
||||
### Done — research tree details (Talon request)
|
||||
|
||||
The research screen read only the node name and whether it was affordable. Cost,
|
||||
what it unlocks and the description are all drawn in the hint windows beside the
|
||||
tree and were never spoken, so "cannot afford" gave no way to find out *what* was
|
||||
missing. `states/research.lua` now implements `details()` — the same `=` /
|
||||
`Shift+=` hook the item grids use — and the focus line takes its name from
|
||||
`currentNode.title` instead of humanising the node id.
|
||||
|
||||
Everything comes from the state's **`currentNode`** upvalue, the display table
|
||||
`updateCurrentNode()` assembles for the hint window: `title`, `knowledgeCost`,
|
||||
`unlocks` (already `{title = <item name>}`), `description`. Not from
|
||||
`models/research.lua` — its `nodes` table is file-local and its `unlocks` are
|
||||
*recipe* ids, so it would name the recipe rather than the item. The shortfall is
|
||||
computed against `journalModel.knowledge`, required lazily.
|
||||
|
||||
Verified live: `Sewing techniques, cannot afford` then
|
||||
`Costs 4 practical knowledge, short 4 practical. Unlocks Protective gloves, Tall
|
||||
boots. Simple craft of needle and string, …`; verbose adds the name line and
|
||||
`Knowledge available, 0 practical, 0 ecclesiastic, 0 academic, 0 occult`.
|
||||
|
||||
**98 testbed checks, 0 failures** (was 88). The tree has no hotkey and the
|
||||
prologue may have no writing desk, so the testbed enters it the way the desk
|
||||
does: `ingame.interface("research")`, the exact call in the desk's
|
||||
`tryInteractFunction`. ⚠ Require it as **`states/ingame`**, not `states.ingame` —
|
||||
`states.lua` uses the slash form, and the dot form loads a second copy of the
|
||||
module whose `levelWindow` is nil, which `research.draw` indexes on its first
|
||||
frame.
|
||||
|
||||
### Known gaps (next up)
|
||||
- **Phase 5**: player status key (HP, statuses, current action), popup
|
||||
announcements (`popupStack.add`), damage alerts
|
||||
@@ -908,7 +945,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. **24 state descriptors, 7 patches, 88/88 testbed checks**,
|
||||
Phases 0–5 complete. **24 state descriptors, 7 patches, 98/98 testbed checks**,
|
||||
history unit tests passing, **one line changed in the game** (`main.lua`).
|
||||
|
||||
Everything in the original brief is implemented: console speech with
|
||||
@@ -918,7 +955,7 @@ exploration, wall tones, and keyboard+speech access to every screen.
|
||||
### First thing to do after any change
|
||||
```
|
||||
lua accessibility/tests/test_history.lua # pure Lua, instant
|
||||
bash accessibility/tests/run-testbed.sh # ~4 min, 88 checks
|
||||
bash accessibility/tests/run-testbed.sh # ~4 min, 98 checks
|
||||
git diff --stat vanilla-0.4.2 -- . ':!accessibility' ':!.gitignore' ':!CLAUDE.md' # must stay: main.lua | 1 +
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user