tracker: sticky selection and Ctrl+Home walk-to; walltones: conventional volume

Tracker selection now survives a rescan. The scan is rebuilt every turn and
both lists are distance-sorted, so holding a bare index meant one step by the
player silently re-pointed the selection at a different rat. The tracker now
remembers identity instead -- the actor table for creatures, coordinates for
tiles -- and re-derives the indices in reanchor() after each rescan. Selection
is dropped only when the thing genuinely stops being reported (out of FoV,
killed, picked up), and the existing clamp then falls back to the nearest.

Ctrl+Home walks to the selection, reusing the exact shape of the game's own
click-to-path in ingame.mousepressed: calculatePathFromPlayer, then either
bufferInput or playerInput for a one-step path. Interruptions and threatened-
player truncation therefore behave the way a mouse click does. Most things
worth tracking stand on impassable tiles, which calculatePathFromPlayer refuses
outright, so we fall back to the cheapest of the 8 neighbours and say "next to"
rather than "to". Guarded on states.getCurrent() == "ingame": elsewhere the
input buffer belongs to another state and feeding it moves would be a bug.

Wall tones now follow the usual proximity convention -- a near wall is loud,
one out at radius is quiet. It was inverted, which read backwards in play since
a nearby wall is the more urgent fact. config.louderWhenFurther still flips it.

Testbed covers both: selection identity across a forced rescan, and that
Ctrl+Home moves the player without breaking out of the map.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Accessibility Mod
2026-08-02 01:00:25 +02:00
co-authored by Claude Opus 5
parent 6380998376
commit 81a209b600
5 changed files with 293 additions and 21 deletions
+32
View File
@@ -404,6 +404,37 @@ local function scenario()
press("pagedown", "tracker: next instance", {shift = true})
press("home", "tracker: announce location")
-- Selection stickiness: the scan is rebuilt from scratch and re-sorted by
-- distance every turn, so re-deriving the selection by index would silently
-- land on a different object. Force a rescan and check we are still on the
-- same one.
local beforeSelection = tracker.currentSelection()
if beforeSelection then
tracker.rescan(true)
local afterSelection = tracker.currentSelection()
check("tracker keeps its selection across a rescan",
afterSelection ~= nil
and afterSelection.kind == beforeSelection.kind
and afterSelection.x == beforeSelection.x
and afterSelection.y == beforeSelection.y,
beforeSelection.kind .. " at " .. beforeSelection.x .. "," .. beforeSelection.y)
-- Ctrl+Home walks to the selection, the way a left click does.
local _, trackerWorld = pcall(require, "models.world")
local level = trackerWorld and trackerWorld.currentLevel
local walkFrom = level and level.playerActor
local fromX, fromY = walkFrom and walkFrom.x, walkFrom and walkFrom.y
press("home", "tracker: walk to selection", {ctrl = true})
wait(20)
check("ctrl+home did not break out of the map", currentState() == "ingame",
"state is " .. tostring(currentState()))
if fromX then
local now = level.playerActor
print(string.format("[testbed] ctrl+home moved player %d,%d -> %d,%d",
fromX, fromY, now.x, now.y))
end
end
-- Phase 4: the menu screens reachable from gameplay.
--
-- Each is opened, navigated once, and closed. `back` is bound to x/escape/
@@ -428,6 +459,7 @@ local function scenario()
end
check(screen.state .. " describes focus", focusText() ~= nil,
"focus=" .. tostring(focusText()))
press("escape", "close " .. screen.state)
wait(15)
end