Files
Accessibility ModandClaude Opus 5 50b226620e Phase 4 remainder: crafting screens, slider, config options
Game-file footprint unchanged: still one line in main.lua.

The slider turned out to be genuinely generic: modules/slider.lua is a factory,
so one wrapper on it narrates all four users -- craft, refine, trade and
ingame_wait (the wait-N-turns screen). Same leverage as the console.print and
inventoryCursorPopup patches.

The options screens do NOT share it, though: config_menu changes values through
config.increase/config.decrease, so it needed its own descriptor. It reports tab,
option name and value, and its focus key includes the value so left/right
re-announce even though the focused option has not moved.

states/_itemgrid.lua is now shared by inventory, craft, refine and trade, all of
which build a views/inventoryWindow. It stays silent while
confirmationWindowEnabled is set so the slider owns speech during quantity
selection instead of the two fighting.

testbed gains walkTo(), which navigates using the game's own pathfinder rather
than hardcoded direction sequences -- those drift as soon as anything moves the
player. The config test only adjusts a value when the focused option is
demonstrably safe, and puts it straight back.

The slider patch is applied and confirmed by the self-test but not exercised
live: ingame_wait is unreachable in the prologue because tutorial_bed overrides
bed's tryInteractFunction with an empty function by design, and the crafting
screens need an alchemy table and real items. Recorded as a NOTE rather than a
failing check, since it is a property of the game and not of the mod.

25/25 testbed checks, history unit tests passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 22:12:56 +02:00

68 lines
2.2 KiB
Lua

-- Patch: modules/slider.lua
--
-- The slider is genuinely generic: `modules/slider.lua` is a factory
-- (`newSlider(params)`) and every quantity slider in the game comes from it.
-- Four states use it:
--
-- craft -- how many items to process
-- refine -- same
-- trade -- how many to buy/sell
-- ingame_wait -- how many turns to wait
--
-- So one wrapper on the factory narrates all four, with no per-state work. This
-- is the same leverage as the console.print and inventoryCursorPopup patches.
--
-- NOTE: the options screens (config_menu / settings_menu) do NOT use this. They
-- adjust values through config.increase / config.decrease instead, and are
-- handled by accessibility/states/config_menu.lua.
-- ORDERING: this replaces package.loaded, so it only affects requires that happen
-- AFTER it runs. That is safe here because states are loaded lazily by states.lua
-- (each `require("states/"..name)` happens on first switch), and these four are
-- the only requirers. applyPatches() also runs before the self-test, which is the
-- one thing that loads state files early.
local speech = require("accessibility.speech")
return function()
local newSlider = require("modules.slider")
if type(newSlider) ~= "function" then
error("modules.slider is not a factory function -- game structure changed")
end
package.loaded["modules.slider"] = function(params)
local slider = newSlider(params)
local realSetValue = slider.setValue
if not realSetValue then
return slider
end
-- Announce only on an actual change. setValue is called during
-- construction, on every frame of a mouse drag, and on each repeat of a
-- held key -- speaking unconditionally would stutter badly.
local lastSpoken = slider.currentValue
slider.setValue = function(newValue, noFlip)
local result = realSetValue(newValue, noFlip)
pcall(function()
local current = slider.currentValue
if current == lastSpoken then
return
end
lastSpoken = current
-- Interrupt: the value is the answer to the key just pressed, and
-- a backlog of intermediate numbers is worse than useless.
speech.say(tostring(current), true)
end)
return result
end
return slider
end
end