-- itemdetails.lua — turn an item into speakable detail blocks. -- -- The game already composes the whole of an item's detail text in one place: -- `item.getPopupMessage()` (modules/item.lua:199). It returns a list of -- `{text =, icon =, font =}` lines that the cursor popup renders: -- -- a torch. <- name, with (quantity) if stackable -- It is a tool. <- category, from item/categories.lua -- It is pretty worn (43% condition).<- only when canDegrade -- -- Yields: <- only when the item can be refined -- x1 when ground in a mortar. <- one per refinement type -- Contained knowledge: <- only when containedLore -- (2/5 fragments learned so far) -- -- That is exactly what a player needs to evaluate an item, including "what does -- this turn into", and it is already assembled -- so we read it rather than -- re-deriving any of it from templates. -- -- The icons are dropped: every icon line's `text` already names the thing in -- words ("x1 when ground in a mortar"), so nothing is lost by ear. -- -- Pure formatting, no LÖVE and no game state, so the testbed can exercise it -- against a synthetic item. local itemdetails = {} -- The game wraps its own text and joins the wrapped lines with "\n", so those -- newlines are pure layout. Left in, the reader pauses mid-sentence at every -- wrap point. Same treatment as journal pages (states/journal.lua). local function flatten(text) return (tostring(text):gsub("%s*\n%s*", " "):gsub("^%s+", ""):gsub("%s+$", "")) end itemdetails.flatten = flatten -- Does this popup line merely repeat the name the focus announcement just said? -- getPopupMessage's first line is "." or " (3)." -- speaking it again -- immediately after "a torch, slot 1" is pure repetition. local function isNameLine(text, item) local name = item and item.name if type(name) ~= "string" then return false end return text:sub(1, #name) == name end -- Returns a list of speakable blocks for `item`, or nil if there is nothing to -- say. `verbose` keeps the leading name line as well. function itemdetails.blocks(item, verbose) if type(item) ~= "table" then return nil end local blocks = {} local ok, lines = pcall(function() return item.getPopupMessage and item.getPopupMessage() end) if ok and type(lines) == "table" then for index, line in ipairs(lines) do local text = type(line) == "table" and line.text or (type(line) == "string" and line) if type(text) == "string" then text = flatten(text) if text ~= "" and not (index == 1 and not verbose and isNameLine(text, item)) then blocks[#blocks + 1] = text end end end elseif type(item.description) == "string" then -- getPopupMessage missing or raising means the game changed shape. Degrade -- to the raw description rather than going silent. local text = flatten(item.description) if text ~= "" then blocks[#blocks + 1] = text end end if #blocks == 0 then return nil end return blocks end return itemdetails