Module:Item Recipes

From Idlescape Wiki
Revision as of 05:14, 25 April 2025 by Broono (talk | contribs) (Add support for named argument 'ids'. Through 'ids' a table with ids can be passed. See 'Module:Item Recipes/doc' for more info.)
Jump to navigation Jump to search

For basic use of Template:Item Recipes, see Template:Item Recipes/doc


List of names

Module:Item Recipes accepts a string as its first (unnamed) argument. This string should be the name of an item or a semicolon separated list of item names, such as:

local itemRecipes = require('Module:Item Recipes')
local name = 'Snowball'
local html = itemRecipes._itemRecipes({name})

or:

local itemRecipes = require('Module:Item Recipes')
local names = ''
    names = names .. 'Worm Composting Bin;'
    names = names .. 'Earth Rune;'
    names = names .. 'Scroll of Embers;'
    names = names .. 'Stygian Bar;'
local html = itemRecipes._itemRecipes({names})

The variable html holds a mw.html table and can be returned as template output.

Named argument: ids

Module:Item Recipes supports the use of named argument ids. Using this argument, a table with item ids can be passed:

local itemRecipes = require('Module:Item Recipes')
local tbl = {
    { ['id'] = 4510 },
    { ['id'] = 511 },
    { ['id'] = 1601 },
    { ['id'] = 207 },
}
local html = itemRecipes._itemRecipes({['ids'] = tbl})

The variable html holds a mw.html table and can be returned as template output.

Sorting and collapsing

Currently, a table with at least 8 items becomes sortable and collapsible, a table with at least 16 items auto-collapses.

WIP

Features planned to be added:

  • Options for forcing setting whether a table is sortable, collapsible, or auto-collapses.
  • Support for augmenting/researching recipes.

local p = {}

local addSeparator = require('Module:AddSeparator')
local findId = require('Module:FindId')
local img = require('Module:Img')

local data = {}
data.craftingAugmenting = mw.loadData('Module:CraftingAugmenting/data')
data.items = mw.loadData('Module:Items/data')


local COLLAPSIBLE = 7
local COLLAPSED = 15
local SORTABLE = 7


local function strip(s)
    return s:match('^%s*(.-)%s*$')
end

local function split(s, sep)
   local t = {}
   if sep == nil or sep == '' then
      sep = '%s'
   end
   for m in s:gmatch('([^' .. sep .. ']+)') do
      table.insert(t, m)
   end
   return t
end

function table.length(t)
    local count = 0
    for _ in pairs(t) do count = count + 1 end
    return count
end

local function addItemIds(t, names)
    local _names = split(names, ';')
    for _, name in pairs(_names) do
        name = strip(name)
        if name ~= '' then
            local id = findId._findId({name, 'item'})
            if type(id) == 'number' then
                table.insert(t, {['id'] = id})
            else
                table.insert(t, {['error'] = {'name', name}})
            end
        end
    end
end

local function addOtherItemFields(t)
    for i in pairs(t) do
        if t[i].id then
            local id = tostring(t[i].id)
            local craftingStats
            if data.items[id] and data.items[id].craftingStats then
                craftingStats = data.items[id].craftingStats
            elseif data.items[id] then
                craftingStats = data.items[id]
            else
                t[i].error = { 'id', t[i].id }
            end
            if not t[i].error then
                t[i].name = data.items[id].name
                t[i].level = craftingStats.level
                t[i].experience = craftingStats.experience
                t[i].category = craftingStats.category
            end
        else
            t[i].error = {'id', 'nil'}
        end
    end
end

local function addRecipes(t)
    for i in pairs(t) do
    local id = tostring(t[i].id)
        if data.craftingAugmenting[id] and not t[i].error then
            t[i].recipes = {}
            if data.craftingAugmenting[id].crafting then
                for _, recipe in pairs(data.craftingAugmenting[id].crafting) do
                    table.insert(t[i].recipes, recipe.recipe)
                    t[i].skill = 'Crafting'
                end
            elseif data.craftingAugmenting[id].scrollcrafting then
                table.insert(t[i].recipes, data.craftingAugmenting[id].scrollcrafting)
                t[i].skill = 'Scrollcrafting'
            elseif data.craftingAugmenting[id].runecrafting then
                table.insert(t[i].recipes, data.craftingAugmenting[id].runecrafting)
                t[i].skill = 'Runecrafting'
            elseif data.craftingAugmenting[id].smithing then
                table.insert(t[i].recipes, data.craftingAugmenting[id].smithing)
                t[i].skill = 'Smithing'
            end
        elseif not t[i].error then
            t[i].error = {'recipe', id .. ' (' .. t[i].name .. ')'}
        end
    end
end

local function generateTableRecipe(t)
    local ingredients = {}
    for id, amt in pairs(t) do
        local name = data.items[id].name
        local image = img._img({name, 30})
        table.insert(ingredients, image .. ' x'.. addSeparator._addSeparator({amt}))
    end
    return table.concat(ingredients, ', ')
end

local function generateTableBody(t)

    local tbody = mw.html.create(nil)

    for i = 1, table.length(t) do

        local row = mw.html.create('tr')
        local rowspan = 0

        if t[i].error then
            local e
            if t[i].error[1] == 'recipe' then
                e = 'Could not find a recipe for item with id: ' .. t[i].error[2]
            else            
                e = '\'\'Could not find item with ' .. t[i].error[1] .. ': '
                e = e ..'\'\'\'' .. t[i].error[2] .. '\'\'\'.'
                if t[i].error[1] == 'name' then
                    e = e .. ' Please check spelling or update data modules.'
                end
            end

            row:tag('td')
                :css('text-align', 'center')
                :attr('colspan', 5)
                :wikitext(e)
        else
            rowspan = table.length(t[i].recipes)
            -- Icon
            row:node(mw.html.create('td')
                :attr('rowspan', rowspan)
                :css('text-align', 'center')
                :wikitext(img._img({t[i].name, 30, alt=''})))

            -- Name
            local name
            if t[i].name == mw.title.getCurrentTitle().fullText then
                name = '\'\'\'' .. t[i].name .. '\'\'\''
            else
                name = '\'\'\'[[' .. t[i].name .. ']]\'\'\''
            end
            row:node(mw.html.create('td')
                :attr('rowspan', rowspan)
                :attr('scope', 'row')
                :wikitext(name))

            -- Skill: Level
            local skill
            if t[i].category then
                skill = img._img({t[i].skill, 30, word='1', alt=''}) .. ' (' .. t[i].category .. '): ' .. t[i].level
            else
                skill = img._img({t[i].skill, 30, word='1', alt=''}) .. ': ' .. t[i].level
            end
            row:node(mw.html.create('td')
                :attr('rowspan', rowspan)
                :wikitext(skill))

            -- Experience
            row:node(mw.html.create('td')
                :attr('rowspan', rowspan)
                :css('text-align', 'center')
                :wikitext(addSeparator._addSeparator({t[i].experience})))

            -- Recipe
            row:node(mw.html.create('td')
                :wikitext(generateTableRecipe(t[i].recipes[1])))
        end
        tbody:node(row)

        -- More recipes if item has more than one
        if rowspan > 1 then
            for j = 2, rowspan do
            tbody
            :tag('tr')
                :tag('td')
                    :wikitext(generateTableRecipe(t[i].recipes[j]))
            end
        end
    end

    return tbody
end

local function generateTableHead()

    local thead = mw.html.create(nil)
    local row = mw.html.create('tr')

    row
    :tag('th')
        :attr('scope', 'col')
        :wikitext('Icon')
    :done()
    :tag('th')
        :attr('scope', 'col')
        :wikitext('Name')
    :done()
    :tag('th')
        :attr('scope', 'col')
        :wikitext('Skill: Level')
    :done()
    :tag('th')
        :attr('scope', 'col')
        :wikitext('Experience')
    :done()
    :tag('th')
        :attr('scope', 'col')
        :wikitext('Recipe')
    :done()

    thead:node(row)

    return thead
end

local function generateTable(t)
    local tbl = mw.html.create('table')

    tbl
    :addClass('wikitable')
    if table.length(t) > SORTABLE then tbl:addClass('sortable') end
    if table.length(t) > COLLAPSIBLE then tbl:addClass('mw-collapsible') end
    if table.length(t) > COLLAPSED then tbl:addClass('mw-collapsed') end

    tbl:node(generateTableHead())
    tbl:node(generateTableBody(t))

    return tbl
end

function p.itemRecipes(frame)
    return p._itemRecipes(frame:getParent().args)
end

--[[
    If item ids are supplied through the named argument 'ids', the table must
    be in the following form:

    {
        { ['id'] = value_1 },
        { ['id'] = value_2 },
        .
        .
        .
        { ['id'] = value_n }
    }

    The actual id values can be either numbers or strings.
]]
function p._itemRecipes(args)

    local items = {}

    if not args[1] or args[1] == '' then
        args[1] = mw.title.getCurrentTitle().fullText
    end

    if args['ids'] and type(args['ids']) == 'table' then
        items = args['ids']
    else
        addItemIds(items, args[1])
    end

    addOtherItemFields(items)
    addRecipes(items)

    return generateTable(items)
end

return p