Module:Icon

Revision as of 17:46, 27 November 2025 by LVL (talk | contribs) (Made icons have a link.)

Main module for rendering game icons.

Note: This module is not intended for direct use. Use the templates below.

Data sources

The module reads from Data:ResourceLookup.json, a pre-indexed lookup table generated by Deadbot at deploy time. When the bot uploads new game files, hero, ability, and item icons update automatically.

An additional resource for other icons can be found at Data:ResourceLookup2.json, a manually maintained table; some entries may rely on a dictionary key.

See Module:Icon/data for manual overrides, legacy items, aliases, and renames used by this module.

Usage

Any of the following templates can be used. The module automatically detects the icon type:

Note: While all four templates work identically, it is recommended to use the appropriate one for clarity (e.g., use {{AbilityIcon|Siphon Life}} even though {{HeroIcon|Siphon Life}} will also work).

Error tracking

Icons that fail to render are added to Category:Module:Icon ERROR.


local p = {}

-- Load icon data and language codes
local iconData = require("Module:Icon/data")
local lang_codes = mw.loadJsonData("Data:LangCodes.json")

-- Per-page cache
local cachedLangCode, cachedLangData

-- Get icon data by name
local function getIconData(iconName)
    local entry = iconData[iconName:lower()]
    if entry then
        return entry, nil
    end
    return nil, string.format("[[:Category:Module:Icon ERROR|Icon not found]] ('%s'). [[Category:Module:Icon ERROR]]", iconName)
end

-- Get cached or loaded language code and JSON data
local function getLangData()
    if cachedLangData then
        return cachedLangCode, cachedLangData
    end

    local title = mw.title.getCurrentTitle().fullText
    local subpageLang = title:match("/([^/]+)$")
    local langCode = (subpageLang and lang_codes[subpageLang]) and subpageLang or "en"

    local langData = {}
    if langCode ~= "en" then
        local success, data = pcall(function()
            return mw.loadJsonData("Data:Lang " .. langCode .. ".json")
        end)
        if success and type(data) == "table" then
            langData = data
        end
    end

    cachedLangCode = langCode
    cachedLangData = langData

    return langCode, langData
end

-- Main render function
function p.render(frame)
    local args = frame:getParent().args
    local name = args[1] or ""
    local customText = args.l1 or ""
    
    -- 1. Set Defaults from named arguments
    local size = args.size or "20px"
    local noLink = args["no-link"] == "true"
    local iconOnly = args["icon-only"] == "true"

    -- 2. Scan unnamed parameters (2, 3, 4...) for flags and size
    -- This allows: {{HeroIcon|Name|icon-only|no-link}} or {{HeroIcon|Name|40px|icon-only}}
    for k, v in pairs(args) do
        if type(k) == "number" and k > 1 then
            local val = mw.text.trim(v) -- Clean up whitespace
            
            if val == "icon-only" then
                iconOnly = true
            elseif val == "no-link" then
                noLink = true
            elseif val:match("^%d+px$") then 
                -- If it looks like "20px" or "40px", set the size
                size = val
            end
        end
    end

    -- 3. Proceed with standard logic...
    local iconData, err = getIconData(name)
    if not iconData then
        return "Error: " .. err
    end

    local langCode, langData = getLangData()
    
    -- Determine display name with clear priority
    local displayName = ""
    if customText ~= "" then
        displayName = customText
    elseif iconData.key and langData[iconData.key] then
        displayName = langData[iconData.key]
    elseif iconData.name then
        displayName = iconData.name
    elseif iconOnly then
        displayName = ""
    else
        displayName = name  -- fallback to input name
    end

    -- Localize link if on a translated subpage
    local baseLink = iconData.link or ""
    local link = (langCode ~= "en" and baseLink ~= "") and (baseLink .. "/" .. langCode) or baseLink

    -- Style logic
    local class = iconData.class or ""
    local extra = (class:find("invert", 1, true) and " filter:invert(1);" or "")
    local style
    if class:find("theme", 1, true) then
        style = 'class="module-icon-ability" style="position:relative; bottom:2px;' .. extra .. '"'
    else
        style = 'style="position:relative; bottom:2px;' .. extra .. '"'
    end

    -- 4. Generate icon HTML (with link if not disabled)
    local imageLink = noLink and "" or link
    local iconHtml = string.format('<span %s>[[File:%s|%s|link=%s]]</span>', style, iconData.image, size, imageLink)

    if iconOnly or displayName == "" then
        return iconHtml
    end

    local textHtml = (noLink or link == "") and displayName or string.format('[[%s|%s]]', link, displayName)
    return '<span style="white-space:nowrap;">' .. iconHtml .. " " .. textHtml .. '</span>'
end

return p