Module:Crafting Uses

From Idlescape Wiki
Jump to navigation Jump to search

local p = {}
local findId = require("Module:FindId")
local img = require("Module:Img")
local craftingAugmentingData = mw.loadData("Module:CraftingAugmenting/data")
local itemsData = mw.loadData("Module:Items/data")

local pageName = mw.title.getCurrentTitle().fullText

---@alias mw.html table
-- Convert from CSV string to table (converts a single line of a CSV file)
local function fromCSV(s)
    s = s .. ',' -- ending comma
    local t = {} -- table to collect fields
    local fieldstart = 1
    repeat
        local nexti = string.find(s, ',', fieldstart)
        table.insert(t, string.sub(s, fieldstart, nexti - 1))
        fieldstart = nexti + 1
    until fieldstart > string.len(s)
    return t
end

local function tablelength(T)
    local count = 0
    for _ in pairs(T) do count = count + 1 end
    return count
end

local function pairsByKeys(t, f)
    local a = {}
    local orgi_key_type
    local orgi_key_numbered
    for n in pairs(t) do
        if tonumber(n) == nil then
            table.insert(a, n)
            orgi_key_type = "word"
        elseif type(n) == "number" then
            table.insert(a, n)
            orgi_key_type = "int"
        elseif type(n) == "string" and type(tonumber(n) == "number") then
            orgi_key_type = "number"
            table.insert(a, tonumber(n))
        end
    end
    table.sort(a, f)
    local key
    local value
    local i = 0             -- iterator variable
    local iter = function() -- iterator function
        i = i + 1
        if a[i] == nil then
            return nil
        elseif orgi_key_type == "word" or orgi_key_type == "int" then
            key = a[i]
            value = t[a[i]]
        elseif orgi_key_type == "number" then
            key = tostring(a[i])
            value = t[tostring(a[i])]
        end
        return key, value
    end
    return iter
end

---fetches an item object
---@param itemId integer|string or string
---@return table|string
local function getItem(itemId)
    local item = itemsData[tostring(itemId)]
    if item then
        return item
    else
        return "Module:Items/data out of date"
    end
end

---generates an mw.html table object
---@param names table
---@param collapse integer
---@return mw.html
local function genTable(names, collapse)
    local collapseS = ""
    if collapse == 1 then
        collapseS = " mw-made-collapsible mw-collapsible"
    elseif collapse == 2 then
        collapseS = " mw-made-collapsible mw-collapsible mw-collapsed"
    end
    local t = mw.html.create("table")
    t:addClass("wikitable sortable jquery-tablesorter" .. collapseS)
    t:tag("tr")
        :tag("th")
        :attr("colspan", "2")
        :wikitext("Item Created")
        :done()
        :tag("th")
        :wikitext("Category")
        :done()
        :tag("th")
        :wikitext("Lvl.</br>Req.")
        :done()
        :tag("th")
        :wikitext("XP")
        :done()
        :tag("th")
        :wikitext("Materials")
        :done()
        :done()
    local matchedRecipes = {}
    local earlyreturn = false
    for _, itemName in ipairs(names) do
        local itemId = findId._findId({ itemName, "item" })
        for iId, iData in pairsByKeys(craftingAugmentingData) do
            if iData.crafting then
                for _, fullRecipe in ipairs(iData.crafting) do
                    for mId, mQuantity in pairsByKeys(fullRecipe.recipe) do
                        if tonumber(mId) == itemId then
                            matchedRecipes[iId] = {}
                            local i = 0
                            local _dupe = false
                            for _, v in pairs(matchedRecipes) do
                                if v.recipe then
                                    for key, value in pairs(v.recipe) do
                                        if key == mId and value == mQuantity then
                                            i = i + 1
                                        end
                                        if i == tablelength(fullRecipe.recipe) then
                                            _dupe = true
                                            earlyreturn = true
                                            break
                                        end
                                    end
                                    if earlyreturn then
                                        break
                                    end
                                end
                            end
                            if not _dupe then
                                table.insert(matchedRecipes[iId], fullRecipe)
                            end
                        end
                    end
                end
            end
        end
    end

    for itemId, fullRecipes in pairsByKeys(matchedRecipes) do
        local item = getItem(itemId)
        local recipeCount = tablelength(matchedRecipes[itemId])
        local matCellAddedCount = recipeCount
        local matCells = {}

        local imgCell = mw.html.create('td')
        if recipeCount > 1 then
            imgCell:attr("rowspan", tostring(recipeCount))
        end
        imgCell:wikitext(img._img({ item.name, "40" }))

        local nameCell = mw.html.create('td')

        local categoryCell = mw.html.create('td')
        if recipeCount > 1 then
            categoryCell:attr("rowspan", tostring(recipeCount))
        end
        categoryCell:wikitext(item.craftingStats.category)

        local lvlCell = mw.html.create('td')
        if recipeCount > 1 then
            lvlCell:attr("rowspan", tostring(recipeCount))
        end
        lvlCell:wikitext(tostring(item.craftingStats.level))

        local xpCell = mw.html.create('td')
        if recipeCount > 1 then
            xpCell:attr("rowspan", tostring(recipeCount))
        end
        xpCell:wikitext(tostring(item.craftingStats.experience))
        for _, fullRecipe in ipairs(fullRecipes) do
            local matS = ""
            for matId, matQuantity in pairs(fullRecipe.recipe) do
                local mat = getItem(matId)
                matS = matS .. tostring(matQuantity) .. img._img({ mat.name, '20', word = 1 }) .. "<br>"
            end
            local matCell = mw.html.create('td')
            matCell:wikitext(matS)
            table.insert(matCells, matCell)

            local multS = ""
            if item.craftingStats.multiplier then
                if fullRecipe.multiplier then
                    if fullRecipe.multiplier > 1 then
                        multS = tostring(fullRecipe.multiplier) .. "x "
                    end
                else
                    if item.craftingStats.multiplier > 1 then
                        multS = tostring(item.craftingStats.multiplier) .. "x "
                    end
                end
            end
            if recipeCount > 1 then
                nameCell:attr("rowspan", tostring(recipeCount))
            end
            nameCell:wikitext(multS .. "[[" .. item.name .. "]]")
        end
        local dTr = t:tag("tr")
            :node(imgCell)
            :node(nameCell)
            :node(categoryCell)
            :node(lvlCell)
            :node(xpCell)
        for _, matCell in ipairs(matCells) do
            dTr:node(matCell)
                :allDone()
            matCellAddedCount = matCellAddedCount - 1
            if matCellAddedCount > 0 then
                t:tag('tr')
            end
        end
    end
    return t
end

function p.craftingUses(frame)
    return p._craftingUses(frame:getParent().args)
end

function p._craftingUses(_args)
    local collapse = 0
    local names = {}
    if tablelength(_args) == 0 then
        table.insert(names, pageName)
    elseif _args["collapse"] and not _args[1] then
        table.insert(names, pageName)
    elseif _args["collapse"] and _args[1] then
        names = fromCSV(_args[1])
    else
        names = fromCSV(_args[1])
    end
    if _args["collapse"] == "collapsible" then
        collapse = 1
    elseif _args["collapse"] == "collapsed" then
        collapse =2
    end
    local t = genTable(names, collapse)
    return t
end

return p