Module:ItemList

local IL = require('Module:IL') local Hat = mw.loadData('Module:Sandbox/Adnoam/Hats') local Boots = mw.loadData('Module:Sandbox/Adnoam/Boots') local Transport = mw.loadData('Module:Sandbox/Adnoam/Transport')

local fancy = false

local item_class = { ["Hat"] = Hat, ["Boots"] = Boots, ["Transport"] = Transport, --   ["Clothing"] = Clothing,    ["Gloves"] = Gloves,    ["Weapon"] = Weapon    ["Companion"] = Companion,    ["Destiny"] = Destiny,    ["Affiliation"] = Affiliation,    ["Transportation"] = Transportation,    ["Home Comfort"] = Home Comfort,    ["Ship"] = Ship,    ["Spouse"] = Spouse,    ["Club"] = Club }

local negative_q = { ["Nightmares"] = true, ["Scandal"] = true, ["Suspicion"] = true, ["Wounds"] = true }

-- Detect and deal with negative qualities (i.e. menaces). For the purpose of sorting, flip the value's sign local function deal_with_negative_q(quality, value) if (negative_q[quality]) then value = value * (-1) end

return value end

-- This function formats an effect's value for display. For positive numbers, '+' is added up front local function qvalue(v) local str = "" if (v > 0) then str = "+" end return str .. v end

--[[ This function is used to compare two effects to determine which should be displayed first.

Each input effect (a or b) is a table with: q = quality name (e.g. "Persuasive") v = the quality's value (e.g. 2) If the two effects have the same value, then: - Menaces will appear after other qualities. - If both are menaces (or both are not), sort lexicographically by effect name. ]] local function compare_effects(a, b)   if (a.v == b.v) then if (negative_q[a.q] and not negative_q[b.q]) then return false elseif (negative_q[b.q] and not negative_q[a.q]) then return true end return (a.q < b.q)   else return (a.v > b.v)   end end

local special_fonts = { ["Fate"] = "FontFate", ["Retired"] = "FontRetired", ["Rose"] = "FontRose", ["Christmas"] = "FontChristmas", ["Hallowmas"] = "FontHallowmas", ["Fruits"] = "FontFruits", ["Election"] = "FontElection", ["Sunless Sea"] = "FontSunless", ["Sunless Skies"] = "FontSkies", ["Silver Tree"] = "FontSilver", ["Mysteries"] = "FontMysteries" }

local function special_font(id) local frame = mw.getCurrentFrame if (special_fonts[id] == nil) then return id .. "Category:Site maintenance" end --return special_fonts[id] return frame:expandTemplate{ title = special_fonts[id] } end

local function display_mood return "Mood" end

local function display_ambition(ambition) return ("Ambition: " .. ambition .. " Item") end

local function display_profession(profession) return ("Profession: " .. profession .. " Item") end

local function display_protege return ("The Protégé of a Mysterious Benefactor Item") end

local function display_faction(faction) return ("" .. faction .. " Faction Item") end

-- A hash table for the proper function(s) which know how to create the display text for each possible qualifier. local display_qualifier = { ["Fate"] = special_font, ["Retired"] = special_font, ["Rose"] = special_font, ["Christmas"] = special_font, ["Hallowmas"] = special_font, ["Fruits"] = special_font, ["Election"] = special_font, ["Mood"] = display_mood, ["Sunless Sea"] = special_font, ["Sunless Skies"] = special_font, ["Silver Tree"] = special_font, ["Mysteries"] = special_font, ["Nemesis"] = display_ambition, ["Bag a Legend!"] = display_ambition, ["Heart's Desire!"] = display_ambition, ["Light Fingers!"] = display_ambition, ["Campaigner"] = display_profession, ["Mystic"] = display_profession, ["Glassman"] = display_profession, ["Enforcer"] = display_profession, ["Murderer"] = display_profession, ["Licentiate"] = display_profession, ["Journalist"] = display_profession, ["Author"] = display_profession, ["Correspondent"] = display_profession, ["Rat-Catcher"] = display_profession, ["Stalker"] = display_profession, ["Monster-Hunter"] = display_profession, ["Trickster"] = display_profession, ["Conjurer"] = display_profession, ["Crooked-Cross"] = display_profession, ["Watcher"] = display_profession, ["Agent"] = display_profession, ["Midnighter"] = display_profession, ["Protege"] = display_protege, ["Bohemians"] = display_faction, ["Constables"] = display_faction, ["Criminals"] = display_faction, ["Hell"] = display_faction, ["Revolutionaries"] = display_faction, ["Rubbery Men"] = display_faction, ["Society"] = display_faction, ["The Church"] = display_faction, ["The Docks"] = display_faction, ["The Great Game"] = display_faction, ["Tomb-Colonies"] = display_faction, ["Urchins"] = display_faction, }

-- This function formats an item's name for display local function display_item_name(name)

if (fancy) then return "* " .. name .. "" else local frame = mw.getCurrentFrame return "* " .. frame:expandTemplate{ title = "IL", args = { name, Size="40px" } } end end

-- Transform a qualifier to its canonical case-sensitive form (for lookup in tables). 1. Set all letter to lowercase. 2. Toggle first letter to uppercase. 3. Toggle letters following a space (e.g. "The Docks") or a '-' (e.g. "Rat-Catcher") to uppercase 4. Toggle a single " A " back to lowercase (for "Bag a Legend!") local function canonical_q_name(qualifier) qualifier = string.lower(qualifier) qualifier = string.gsub(qualifier, "^%l", string.upper) qualifier = string.gsub(qualifier, "[%s-]%l", string.upper) qualifier = string.gsub(qualifier, " A ", string.lower)

return qualifier end

-- Concatenate a new item to the list string. If this is the first item, add a "(" up front. Otherwise, add a separator (" " by default) in front of it. local function add_separator(list, new, is_first)    local separator = " "    if (is_first) then        --separator = "(" is_first = false end

list = list .. separator .. new

return list, is_first end

--[[ Format for display the list of optional qualifiers which are to be added to the item line, after all the effects.

The optional "FATE", followed by the optional "RETIRED" are to be shown last. ]] local function display_qualifiers(qualifiers) local qualifier_list = "" local is_fate = false local is_retired = false local is_first = true for _, vv in ipairs(qualifiers) do     vv = canonical_q_name(vv) if (vv == "Fate") then is_fate = true elseif (vv == "Retired") then is_retired = true; else local new_item = vv         if (display_qualifier[vv]) then new_item = display_qualifier[vv](vv) end

qualifier_list, is_first = add_separator(qualifier_list, new_item, is_first) end end

if (is_fate) then local new_item = special_font("Fate") qualifier_list, is_first = add_separator(qualifier_list, new_item, is_first) end

if (is_retired) then local new_item = special_font("Retired") qualifier_list, is_first = add_separator(qualifier_list, new_item, is_first) end

--qualifier_list = qualifier_list .. ")"   return qualifier_list end

--[[ This function is used to create the display line for a given item, with the list of its effects, and optional qualifiers at the end.

Input parameters: @name = the item's name @item = the table holding the item's qualities (effects and qualifiers) @quality = the quality to place first in the effects list

Example created line: "Lemurian's Mask (Bizarre +1) FEAST OF THE ROSE

The function returns two elements: @item_line = the generated line of item effect list and qualifiers @sorted = a sorted array holding all of the items effects, with the specified quality (if provided) at the top. Each element of this sorted array is itself a pair of the format: { q="quality", v=value) } ]] local function create_item_line(name, item, quality)   local effect_value = item.effects[quality]    local item_line = display_item_name(name) .. " (" .. quality .. " " .. qvalue(effect_value)

local sorted = {} -- Ensure that the selected quality stays at front of effects list -- after the upcoming sort table.insert(sorted, {q=quality, v=(effect_value + 1000)}) for i, e in pairs(item.effects) do       i = canonical_q_name(i) if (i ~= quality) then e = deal_with_negative_q(i, e)           table.insert(sorted, {q=i, v=e}) end end table.sort(sorted, compare_effects)

-- Now that the effects list is sorted, remove the artificial bump -- in value for the selected quality. -- This will allo wproper sort *between* item lines sorted[1].v = sorted[1].v - 1000 for _, vv in ipairs(sorted) do       if (vv.q ~= quality) then local value = deal_with_negative_q(vv.q, vv.v)           item_line = item_line .. ", " .. vv.q .. " " .. qvalue(value) end end item_line = item_line .. ")"   if (item.qualifiers) then        item_line = item_line .. " " .. display_qualifiers(item.qualifiers)        if (fancy) then            item_line = item_line .. " "        end    else        if (item.source) then            if (display_qualifier[item.source]) then                item_line = item_line .. " " .. display_qualifier[item.source](item.source)            else                item_line = item_line .. " " .. item.source            end        end        if (item.fate) then            item_line = item_line .. " " .. display_qualifier["Fate"]("Fate")        end        if (item.retired) then            item_line = item_line .. " " .. display_qualifier["Retired"]("Retired")        end    end    return item_line, sorted end

-- This function is used to compare two item lines, for the purpose of sorting. Each input item (a or b) is a table with:   l = (the item line, e.g. "Mask of the Rose (Persuasive +1)")    k = sorting key, which is itself a sorted array of item effects.        Each array element of 'k' is a pair: { q="quality", v=value) } The function compares each of the input items' sorting key array elements, one by one. So, for example, if one item's highest quality is +10, and the other's highest quality is +9, the first item will be sorted first. If both have the same level for their highest quality, the second highest quality is compared, and so on.  local function compare_lines(a, b)    -- Go over item a's sorting key's effects one by one, and compare each    -- to b's corresponding sorting key's effect    for i = 1, #a.k do        if (i > #b.k) then            -- No more effectes listed for item b.            -- Just check if what's left for 'a' is positive or negative. if (a.k[i].v > 0) then return true else return false end end if (a.k[i].v > b.k[i].v) then return true elseif (a.k[i].v < b.k[i].v) then return false end end

-- We've checked all of a's listed effects. If there are more effects listed -- for item 'b', then we'll just check if they are positive or negative. if (#b.k > #a.k) then if (b.k[#a.k + 1].v > 0) then return false else return true end end -- Both of the items' effect levels are equivallent. -- Sort lexicographically by item name. return a.l < b.l end

local function create_list(class, quality) quality = canonical_q_name(quality) local sorted_lines = {} for i, v in pairs(class) do       if (v.effects and v.effects[quality]) then local line, sort_key = create_item_line(i, v, quality) table.insert(sorted_lines, {l=line, k=sort_key}) end end

table.sort(sorted_lines, compare_lines)

local full_list = "" for _, vv in ipairs(sorted_lines) do       --print (vv.l)        full_list = full_list .. vv.l .. "\n" end

return full_list end

local p = {} function p.create_list(frame) local full_list = "" local class = frame.args[1] or frame:getParent.args[1] local quality = frame.args[2] or frame:getParent.args[2] if (frame.args.fancy) then fancy = true end if (class == "") then class = nil end if (quality == "") then quality = nil end if (class and quality and item_class[class]) then full_list = create_list(item_class[class], quality) else full_list = "Category:Site maintenance" end

return full_list end

function p.list_size(frame) local class = frame.args[1] or frame:getParent.args[1] local quality = frame.args[2] or frame:getParent.args[2] if (class == "") then class = nil end if (quality == "") then quality = nil end

local count = 0 if (class and quality and item_class[class]) then for i, v in pairs(item_class[class]) do           if (v.effects and v.effects[quality]) then count = count + 1 end end end

if (count > 0) then return count else return "" end end

return p