Module:Items navbox
Appearance
Documentation for this module may be created at Module:Items navbox/doc
local p = {}
local function has(values, wanted)
for _, value in ipairs(values or {}) do
if value == wanted then return true end
end
return false
end
local function currentGroup(entry)
local presentation = entry.presentation or {}
local boost = presentation.boostTier
if boost then return 'boosts', boost.category end
if entry.effect then
if entry.effect.type == 'actionBoost' then
local actions = {fish='Fish', hunt='Hunt', mine='Mine', explore='Explore', work='Work'}
return 'boosts', actions[entry.effect.action] or 'Other'
end
return 'boosts', 'Rare loot'
end
if entry.petAdventureBoostEffect then return 'boosts', 'Pet' end
if entry.farmPlotBoostEffect then return 'boosts', 'Farm' end
if entry.augmentProperties then return 'boosts', 'Tool' end
if presentation.loot and presentation.loot[1] then return 'boxes', '' end
if entry.damage or entry.damageMultiplier then return 'weapons', '' end
if has(entry.attributes, 'equippable') then return 'equipment', '' end
if entry.growTime then return 'crops', '' end
if entry.petEnergy then return 'food', '' end
if entry.worthPerGainedFromBurn then return 'pyre', '' end
if has(entry.attributes, 'relayItem') then return 'relay', '' end
if has(entry.lootSources, 'rare') then return 'rare', '' end
for _, source in ipairs({'explore', 'fish', 'hunt', 'mine'}) do
if has(entry.lootSources, source) then return 'materials', source end
end
if not entry.uncraftable then return 'materials', 'crafted' end
return 'materials', 'other'
end
local function worth(entry)
local value = tonumber(entry.cost)
-- Unknown final worth is placed after known values, without inventing zero.
return value and value >= 0 and value or math.huge
end
local function less(a, b)
if a.worth ~= b.worth then return a.worth < b.worth end
local left, right = mw.ustring.lower(a.name), mw.ustring.lower(b.name)
if left ~= right then return left < right end
return a.article < b.article
end
-- Values and current Item membership are supplied by the existing reference
-- poller. The registry selects canonical removed concepts from the frozen archive;
-- it intentionally does not infer identity from reused numeric Item slots.
function p.groups(reference, archive, registry)
local grouped, seen = {}, {}
local function add(group, subgroup, entry, article)
local title = article or entry.article or entry.name
if seen[title] then error('Duplicate Item navigation article: ' .. title) end
seen[title] = true
grouped[group] = grouped[group] or {}
grouped[group][subgroup] = grouped[group][subgroup] or {}
table.insert(grouped[group][subgroup], {
article=title, name=article or entry.name, worth=worth(entry)
})
end
for _, entry in pairs(reference.items) do
if not entry.retired then
local group, subgroup = currentGroup(entry)
add(group, subgroup, entry)
end
end
for key, article in pairs(registry.removedItems) do
local entry = archive.items[key]
if not entry or entry.status ~= 'removed' then
error('Missing removed Item navigation record: ' .. key)
end
add('removed', registry.removedTypes[entry.type] or 'utilities', entry, article)
end
for _, subgroups in pairs(grouped) do
for _, entries in pairs(subgroups) do table.sort(entries, less) end
end
return grouped
end
local function links(cell, entries)
local list = cell:tag('ul'):addClass('bc-release-links')
for _, entry in ipairs(entries) do
list:tag('li'):wikitext('[[' .. mw.text.nowiki(entry.article) .. '|' .. mw.text.nowiki(entry.name) .. ']]')
end
end
function p.render()
local reference = mw.loadJsonData('GameData:Reference.json')
local archive = mw.loadJsonData('GameData:Historical items.json')
local registry = mw.loadJsonData('GameData:Item navigation.json')
local groups = p.groups(reference, archive, registry)
local root = mw.html.create('table'):addClass('bc-navbox-table bc-item-nav-table')
for _, definition in ipairs(registry.groups) do
local group = groups[definition.key]
if group then
local row = root:tag('tr')
row:tag('th'):attr('scope', 'row'):addClass('bc-item-nav-group'):wikitext(mw.text.nowiki(definition.label))
local body = row:tag('td')
if definition.subgroups then
body:addClass('bc-item-nav-body')
local nested = body:tag('table'):addClass('bc-navbox-months bc-item-nav-subgroups')
local emitted = {}
local function subgroup(key, label)
if not group[key] or #group[key] == 0 then return end
emitted[key] = true
local subrow = nested:tag('tr')
subrow:tag('th'):attr('scope', 'row'):wikitext(mw.text.nowiki(label))
links(subrow:tag('td'), group[key])
end
for _, sub in ipairs(definition.subgroups) do subgroup(sub.key, sub.label) end
-- New feed classifications remain visible pending editorial labels.
local unknown = {}
for key in pairs(group) do if not emitted[key] then table.insert(unknown, key) end end
table.sort(unknown)
for _, key in ipairs(unknown) do subgroup(key, key == '' and 'Other' or key) end
else
links(body, group[''] or {})
end
end
end
return tostring(root)
end
return p