Difference between revisions of "Module:Infobox enchantment"

From Idlescape Wiki
Jump to navigation Jump to search
m (Fix ingredientSource to food-source to match old template param)
m (Fix remove brackets from food-source)
Line 262: Line 262:
 
             local sources = {}
 
             local sources = {}
 
             for s in ingredientSources:gmatch("[^,]+") do
 
             for s in ingredientSources:gmatch("[^,]+") do
                 table.insert(sources, (s:gsub("^%s*(.-)%s*$", "%1")))
+
                 table.insert(sources, (s:gsub("^%s*%[*(.-)%]*%s*$", "%1")))
 
             end
 
             end
 
             args[l()] = "Source"
 
             args[l()] = "Source"

Revision as of 19:13, 11 June 2025

Documentation for this module may be created at Module:Infobox enchantment/doc

--#region Variables and Imports
local p = {}

---@type table<string, Item>
local itemsData = mw.loadData("Module:Items/data")
---@type table<string, Enchantment>
local enchantmentData = require("Module:Enchantment/data")
---@type table<string, CookingItem>
local cookingListData = mw.loadData("Module:CookingList/data")
local craftingAugmentingData = mw.loadData("Module:CraftingAugmenting/data")
local infobox = require("Module:Infobox")

local headerCount = 1
local labelCount = 1
local dataCount = 1

local MAX_SLOTS = {
    ["arrows"] = 5,
    ["body"] = 8,
    ["boots"] = 7,
    ["cape"] = 2,
    ["chisel"] = 8,
    ["christmas elf gear"] = 0,
    ["combat-talisman"] = 4,
    ["cookingset"] = 3,
    ["fishingset"] = 3,
    ["foragingset"] = 3,
    ["gloves"] = 7,
    ["hatchet"] = 8,
    ["helm"] = 8,
    ["hoe"] = 8,
    ["ladle"] = 8,
    ["legs"] = 8,
    ["miningset"] = 3,
    ["necklace"] = 6,
    ["pickaxe"] = 8,
    ["ring"] = 6,
    ["runecraftingset"] = 3,
    ["shield"] = 8,
    ["smithingset"] = 3,
    ["tacklebox"] = 8,
    ["tome"] = 0,
    ["tongs"] = 8,
    ["weapon"] = 8,
}
--#endregion

--#region Utility Functions

---Finds the first table entry in the given table with key and value matching given values.
---@param tables table<any, table> # The tables to search.
---@param keys any # The key or an array of keys to search for.
---@param values any # The value or an array of values to search for.
---@return table|nil # The first table entry with first matching key and value, or nil if none was found.
---@return any|nil # The key of the found table entry, or nil if none was found.
local function findByKeyVal(tables, keys, values)
    if type(tables) ~= "table" then return nil end
    keys = type(keys) == "table" and keys or {keys}
    values = type(values) == "table" and values or {values}
    for tblk, tbl in pairs(tables) do
        for k, v in pairs(tbl) do
            for _, key in ipairs(keys) do
                for _, value in ipairs(values) do
                    if k == key and v == value then
                        return tbl, tblk
                    end
                end
            end
        end
    end
end
--#endregion

--#region Elements
local function clearInfoboxInstance()
    infobox.clear()
    headerCount = 1
    labelCount = 1
    dataCount = 1
end

local function h()
    local s = "header" .. headerCount
    headerCount = headerCount + 1
    labelCount = headerCount
    dataCount = headerCount
    return s
end

local function sbreak()
    local s = "sbreak" .. headerCount
    headerCount = headerCount + 1
    labelCount = headerCount
    dataCount = headerCount
    return s
end

local function l()
    local s = "label" .. labelCount
    dataCount = labelCount
    labelCount = labelCount + 1
    headerCount = labelCount
    return s
end

local function d()
    local s = "data" .. dataCount
    dataCount = dataCount + 1
    headerCount = dataCount
    labelCount = dataCount
    return s
end

local function sl()
    local s = "s" .. l()
    return s
end

local function sd()
    local s = "s" .. d()
    return s
end
--#endregion

--#region Generic Module Functions

---Formats the given URL to full play.idlescape.com URL.
local function fullUrl(url)
    local newUrl = url
    if url:sub(1, 4) == "http" or url:sub(1,2) == "[[" then
        return newUrl
    end

    if url:sub(1, 1) ~= "/" then
        newUrl = "/" .. newUrl
    end

    return "https://www.play.idlescape.com" .. newUrl
end

---Creates an image link for the given name and URL.
---@param name string # The name of the link and image.
---@param url string # The URL of the image.
---@param word boolean # Whether to include the name in the link, if falsy it will be an image only.
---@param size number|string # The size of the image.
---@return string
local function image(name, url, word, size)
    size = size or 20
    url = fullUrl(url)
    return string.format(
        '[[%s|<img src="%s" alt="%s" width="%d" height="%d"><span style="position:relative;top:1px;">%s</span>]]',
        name, url, name, size, size, word and name or ""
    )
end

local function dottedTooltip(name, tooltip)
    return string.format(
        '<span class="rt-commentedText tooltip tooltip-dotted" title="%s">%s</span>',
        tooltip,
        name
    )
end
--#endregion

--#region Infobox Elements

---Creates an infobox for the given enchantment/buff.
---@param enchant Enchantment
---@return string
local function createInfobox(enchant, ingredientSources)
    local args = {}
    args.autoheaders = "y"
    args.subbox = "no"
    args.bodystyle = " "
    args.title = enchant.name
    args.image = image(enchant.name, enchant.buffIcon, false, 150)

    --Upper limit of the buff 'level'
    args[l()] = "Max Level"
    args[d()] = enchant.strengthCap and tostring(enchant.strengthCap / enchant.strengthPerLevel) or ""

    args[l()] = "Debuff"
    args[d()] = enchant.isDebuff and "Yes" or "No"

    args[l()] = dottedTooltip(
        "Prolonging",
        "Is influenced by Prolonging? Prolonging has a chance to prevent an action from consuming a buff stack."
    )
    args[d()] = enchant.ignoreProlonging and "No" or "Yes"

    args[l()] = dottedTooltip("Stack Multiplier", "Food cooked gets its buff stacks multiplied by this value")
    args[d()] = enchant.stackMult and enchant.stackMult .. "x" or ""

    if enchant.relatedSkills then
        local relatedSkills = {}
        for _, skill in ipairs(enchant.relatedSkills) do
            table.insert(relatedSkills, (skill:gsub("^%l", string.upper)))
        end
        args[l()] = "Related Skills"
        args[d()] = "[[" .. table.concat(relatedSkills, "]]<br>[[") .. "]]"
    end

    if enchant.scrollID then
        local lang = mw.language.getContentLanguage()
        local scroll = itemsData[tostring(enchant.scrollID)]
        args[h()] = "Scroll"

        args[l()] = image(scroll.name, scroll.itemImage, false, 40)
        args[d()] = "[[" .. scroll.name .. "]]"

        if scroll.categories then
            local categories = {}
            for _, category in ipairs(scroll.categories) do
                local slots = MAX_SLOTS[category] or 0
                local cat = category:gsub("set$"," Set"):gsub('-',' '):gsub("^%l", string.upper):gsub(" %l", string.upper)
                cat = string.format("[[:Category:%s|%s]] (%s)", cat, cat, slots)
                table.insert(categories, cat)
            end
            args[l()] = "Slot (Max)"
            args[d()] = table.concat(categories, "<br>")
        end

        args[l()] = "Experience"
        args[d()] = lang:formatNum(scroll.experience)

        args[l()] = "Level"
        args[d()] = scroll.level and tostring(scroll.level) or ""

        local ca = craftingAugmentingData[tostring(enchant.scrollID)]
        if ca and ca.scrollcrafting then
            local items = {}
            for itemId, amount in pairs(ca.scrollcrafting) do
                table.insert(items, {id = itemId, amount = amount})
            end
            table.sort(items, function(a, b) return tonumber(a.id) < tonumber(b.id) end)

            for i, t in ipairs(items) do
                local item = itemsData[t.id]
                items[i] = string.format(
                    "%d %s",
                    lang:formatNum(t.amount),
                    image(item.name, item.itemImage, true, 20)
                )
            end

            args[l()] = "Cost"
            args[d()] = table.concat(items, "<br>")
        end
    end

    local _, ingredientId = findByKeyVal(
        cookingListData,
        {"alchemyEnchantment", "cookingEnchantment"},
        enchant.id
    )
    local ingredient = itemsData[tostring(ingredientId)]
    if ingredient then
        args[h()] = "Cooking Ingredient"
        args[d()] = image(ingredient.name, ingredient.itemImage, true, 40)

        if ingredientSources then
            local sources = {}
            for s in ingredientSources:gmatch("[^,]+") do
                table.insert(sources, (s:gsub("^%s*%[*(.-)%]*%s*$", "%1")))
            end
            args[l()] = "Source"
            args[d()] = "[[" .. table.concat(sources, "]]<br>[[") .. "]]"
        end
    end

    local description = enchant.getTooltip and enchant.getTooltip(1, enchant.strengthPerLevel) or enchant.desc
    args[h()] = "Description"
    args[d()] = '<p style="margin:auto;font-style:italic;font-size:1.2em">' .. description .. "</p>"

    return infobox.infobox(args)
end
--#endregion

--#region Module Functions
function p.enchantment(frame)
    local args = frame:getParent().args
    return p._enchantment(args)
end

---Creates an infobox for the given ability or abilities found in a item.
---@param args {[1]: string|nil, name: string|nil, title: string|nil, ["food-source"]: string|nil}
function p._enchantment(args)
    local name = args[1] or args.name or args.title or mw.title.getCurrentTitle().text
    local enchant = findByKeyVal(enchantmentData, "name", name)
    local ingredientSources = args["food-source"]

    if enchant then
        return createInfobox(enchant, ingredientSources)
    else
        return string.format(
            '<span class="error">Enchantment "%s" not found.</span>',
            name
        )
    end
end
--#endregion

return p