-- states/journal.lua — quests, lore, bestiary, knowledge, research, tutorials. -- -- Two axes move independently: the tab (left/right) and the entry within it -- (up/down). Both must be announced, and the tab header must lead when it -- changes, since "Quests" and "Bestiary" list very different things. -- -- Uses getAnyUpvalue because activeTabIndex, options and selectedOption are -- touched by different functions here (gotoTab, refreshOptions, keypressed). local lastTab return { read = function(stateTable, menus) local tabIndex = menus.getAnyUpvalue(stateTable, "activeTabIndex") local tabsList = menus.getAnyUpvalue(stateTable, "tabsList") local options = menus.getAnyUpvalue(stateTable, "options") local selected = menus.getAnyUpvalue(stateTable, "selectedOption") if type(tabIndex) ~= "number" or type(tabsList) ~= "table" then return nil, nil end local tab = tabsList[tabIndex] local tabName = tab and tab.header or ("tab " .. tabIndex) local parts = {} -- Lead with the tab only when it just changed, so stepping through a long -- quest list doesn't repeat "Quests" on every line. if tabIndex ~= lastTab then lastTab = tabIndex parts[#parts + 1] = tabName end if type(options) == "table" and type(selected) == "number" and options[selected] then local entry = options[selected] parts[#parts + 1] = entry.title or entry.header or entry.name or "?" parts[#parts + 1] = selected .. " of " .. #options elseif type(options) == "table" and #options == 0 then parts[#parts + 1] = "empty" end if #parts == 0 then return nil, nil end return table.concat(parts, ", "), tostring(tabIndex) .. ":" .. tostring(selected) .. ":" .. tostring(options and #options) end, }