Module:Item sets

From Idlescape Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Item sets/doc

local p = {}
local enchantmentData = require("Module:Enchantment/data")
local itemsData = mw.loadData("Module:Items/data")


---@param tbl table
---@param element any
---@return boolean
local function includes(tbl, element)
    for _, v in pairs(tbl) do
        if v == element then
            return true
        end
    end
    return false
end

local function getValuesByKey(array, key)
    local values = {}
    for _, item in ipairs(array) do
        if item[key] ~= nil then
            table.insert(values, item[key])
        end
    end
    return values
end

---@param name string
---@return Item|nil
local function findItem(name)
    local lname = name:lower()

    --Remove leading and trailing spaces.
    lname = lname:gsub('^%s*(.-)%s*$', '%1')
    for _, item in pairs(itemsData) do
        if lname == item.name:lower() then
            return item
        end
    end
end

---@param desc1 string # Description generated by enchantment.getTooltip(n, n)
---@param desc2 string # Description generated by enchantment.getTooltip(n, n+a)
---@return string # Combined description with values in brackets
local function combineItemSetDescription(desc1, desc2)
    if not (desc1 and desc2) then
        return ""
    end
    desc1 = tostring(desc1)
    desc2 = tostring(desc2)
    local sentenceEnd = { ',', '.', '!', '?' }
    local split1 = mw.text.split(desc1, " ", true)
    local split2 = mw.text.split(desc2, " ", true)
    local newDesc = ""

    for i, word1 in ipairs(split1) do
        local word2 = split2[i]
        if word1 == word2 then
            newDesc = newDesc .. word1
        else
            if word1:sub(1, 1) == "[" then
                local insert1 = mw.text.split(word1, "]", true)
                newDesc = newDesc .. insert1[1] .. "|"
                if includes(sentenceEnd, word2:sub(-1)) then
                    newDesc = newDesc .. word2:sub(0, #word2 - 1)
                else
                    newDesc = newDesc .. word2
                end
                newDesc = newDesc .. "]" .. insert1[2]
            elseif includes(sentenceEnd, word1:sub(-1)) then
                newDesc = string.format("%s[%s|%s]%s", newDesc, word1:sub(1, -2), word2:sub(1, -2), word1:sub(-1))
            else
                newDesc = newDesc .. ("[%s|%s]"):format(word1, word2)
            end
        end
        newDesc = newDesc .. " "
    end

    newDesc = newDesc:sub(1, -2)
    return newDesc
end


---@param sets number[] # List of enchantment IDs (sets are just encantments with requirements)
---@return table<string, string> # Table of enchantment id, formatted description pairs
function p._formatItemSets(sets)
    local descriptions = {}

    if sets then
        for _, enchantmentId in ipairs(sets) do
            local enchantment = enchantmentData[tostring(enchantmentId)]
            if enchantment then
                local description
                for _, requirement in ipairs(enchantment.setRequirements or {}) do
                    if requirement.strength > 0 then
                        local tooltip = enchantment.getTooltip(requirement.strength, enchantment.strengthPerLevel):gsub("[\n\t]+", " ")
                        description = description or tooltip
                        description = combineItemSetDescription(description, tooltip)
                    end
                end
                if description then
                    descriptions[tostring(enchantmentId)] = description
                end
            end
        end
    end

    return descriptions
end

function p.itemSets(frame)
    local args = frame:getParent().args
    local name = args.name or args.title or args[1] or mw.title.getCurrentTitle().text

    return p._itemSets(name)
end

function p._itemSets(name)
    local item = findItem(name)
    if not item then return "" end

    local equipmentStats = item.equipmentStats
    if not equipmentStats then return "" end

    local text = ""
    if equipmentStats.itemSet then
        local descriptions = p._formatItemSets(equipmentStats.itemSet)
        for id, description in pairs(descriptions) do
            local enchantment = enchantmentData[id]
            local req = table.concat(getValuesByKey(enchantment.setRequirements), ", ")
            text = text .. string.format(
                "<p>[[%s]]%s<br>%s</p><br>",
                enchantment.name,
                req ~= "" and (" [" .. req .. "]") or "",
                description
            )
        end
    end

    text = text:gsub("<br>$", "")
    return text
end


return p