-- Shared descriptor for the full-screen prose states: menu_text (manual, -- credits), ingame_message and menu_message. -- -- These have no focus cursor -- the whole screen is one block of text. Long ones -- (the manual runs to thousands of words) are unusable as a single utterance, so -- the text is ALSO pushed into the console history. That makes the existing -- review keys ([ and ]) work on it: you can walk the manual paragraph by -- paragraph, jump to the start with Shift+[, and re-read with \. local history = require("accessibility.history") -- Split on blank lines first, falling back to single newlines. Paragraph-sized -- chunks read far better than either one huge utterance or line-by-line -- fragments broken mid-sentence by the game's own wrapping. local function paragraphs(text) local chunks = {} for chunk in (text .. "\n\n"):gmatch("(.-)\n%s*\n") do chunk = chunk:gsub("^%s+", ""):gsub("%s+$", "") if chunk ~= "" then chunks[#chunks + 1] = chunk end end if #chunks == 0 then for line in text:gmatch("[^\n]+") do line = line:gsub("^%s+", ""):gsub("%s+$", "") if line ~= "" then chunks[#chunks + 1] = line end end end return chunks end local lastText return { read = function(stateTable, menus) local text = menus.getAnyUpvalue(stateTable, "messageText") if type(text) ~= "string" or text == "" then return nil, nil end if text == lastText then return nil, nil end lastText = text -- Feed the review buffer so [ and ] can walk it. local chunks = paragraphs(text) for _, chunk in ipairs(chunks) do pcall(history.append, chunk, "text") end local summary = #chunks > 1 and string.format("%s. %d paragraphs, use review keys to read.", chunks[1], #chunks) or chunks[1] return summary, text end, }