Module:Icon: Difference between revisions

LVL (talk | contribs)
Fixed "Icon not found" errors for unused items by adding legacyItems fallback logic and image overrides for Bullet/Spirit Armor.
LVL (talk | contribs)
mNo edit summary
 
(21 intermediate revisions by 6 users not shown)
Line 1: Line 1:
local p = {}
local p = {}


local iconData = mw.loadJsonData("Data:ResourceLookup.json")
local iconDataRaw = mw.loadJsonData("Data:ResourceLookup.json")
local lang_codes = mw.loadJsonData("Data:LangCodes.json")
local iconData2 = mw.loadJsonData("Data:ResourceLookup2.json")
local dictionary = mw.loadJsonData("Data:Dictionary")
 
local iconData = {}


local cachedLangCode, cachedLangData
for k, v in pairs(iconDataRaw) do
    iconData[k] = v
end


local linkOverrides = {
for k, v in pairs(iconData2) do
    ["Bullet Lifesteal"] = "Bullet Lifesteal (item)",
     iconData[k] = v
     ["Spirit Lifesteal"] = "Spirit Lifesteal (item)"
end
}


local legacyItems = {
local lang_codes = mw.loadJsonData("Data:LangCodes.json")
    ["ammo scavenger"] = { name = "Ammo Scavenger", type = "item" },
local lang_module = require("Module:Lang")
    ["enduring spirit"] = { name = "Enduring Spirit", type = "item" },
local table_data = require("Module:Icon/data")
    ["bullet armor"]    = { name = "Bullet Armor", type = "item" },
    ["spirit armor"]    = { name = "Spirit Armor", type = "item" },
    ["soul explosion"]  = { name = "Soul Explosion", type = "item" },
    ["soul rebirth"]    = { name = "Soul Rebirth", type = "item" },
}


local missingImageOverrides = {
local cachedLangCode
    ["boho"] = "Module-Icon missing.png",
    ["druid"] = "Module-Icon missing.png",
    ["fortuna"] = "Module-Icon missing.png",
    ["graf"] = "Module-Icon missing.png",
    ["gunslinger"] = "Module-Icon missing.png",
    ["skyrunner"] = "Module-Icon missing.png",
    ["swan"] = "Module-Icon missing.png",
    ["thumper"] = "Module-Icon missing.png",
    ["bullet armor"] = "Bullet Armor (item).png",
    ["spirit armor"] = "Spirit Armor (item).png",
}


local aliases = {
local linkOverrides = table_data.linkOverrides
    ["doorman"] = "the doorman",
local legacyItems = table_data.legacyItems
    ["mo and krill"] = "mo & krill",
local missingImageOverrides = table_data.missingImageOverrides
    ["mo"] = "mo & krill",
local aliases = table_data.aliases
    ["krill"] = "mo & krill",
local renames = table_data.renames
    ["curse"] = "cursed relic",
    ["debuff remover"] = "dispel magic",
    ["defend and fight!"] = "plot armor",
    ["conjure dragon"] = "bookwyrm",
    ["backstabber"] = "stalker",
    ["flying strike"] = "flying slash",
    ["tornado"] = "dust devil",
    ["kudzu bomb"] = "entangling thorns",
}


local function getLangData()
local function getLangCode()
     if cachedLangData then
     if cachedLangCode then
         return cachedLangCode, cachedLangData
         return cachedLangCode
     end
     end


Line 56: Line 35:
     local subpageLang = title:match("/([^/]+)$")
     local subpageLang = title:match("/([^/]+)$")
     local langCode = (subpageLang and lang_codes[subpageLang]) and subpageLang or "en"
     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
     cachedLangCode = langCode
    cachedLangData = langData
     return langCode
     return langCode, langData
end
end


-- Infer image path from name, with override support for missing images
-- Infer image path from name, with override support for missing images
local function getImage(iconInfo)
local function getImage(iconInfo, args)
     local lowerName = iconInfo.name:lower()
     local lowerName = iconInfo.name:lower()
    if args.image then
        return args.image
    end
     return missingImageOverrides[lowerName] or (iconInfo.name .. ".png")
     return missingImageOverrides[lowerName] or (iconInfo.name .. ".png")
end
-- Get the translated name
local function getTranslatedName(iconInfo, langCode)
    if langCode == "en" then
        return iconInfo.name
    end
    -- 1. Direct key
    if iconInfo.key and iconInfo.key ~= "" then
        local translated = lang_module.get_string(iconInfo.key, langCode, iconInfo.name
        )
        if type(translated) == "string" then
            return (translated:gsub("<[^>]+>", ""))
        end
        return iconInfo.name
    end
    -- 2. Dictionary lookup
    if iconInfo.key_dictionary and iconInfo.key_dictionary ~= "" then
        local entry = dictionary[iconInfo.key_dictionary]
        if type(entry) == "table" then
            return entry[langCode]
                or entry.en
                or iconInfo.name
        end
    end
    -- No valid key > fallback
    return iconInfo.name
end
end


-- Infer link from type and available fields
-- Infer link from type and available fields
local function getLink(iconInfo)
local function getLink(iconInfo, langCode)
     if iconInfo.type == "ability" then
     if iconInfo.type == "ability" then
         return iconInfo.hero_name or iconInfo.name
         local hero = iconInfo.hero_name or iconInfo.name
       
        -- Get the translated name for the specific ability
        local abilityName = getTranslatedName(iconInfo, langCode)
       
        -- Format for URL: replace spaces with underscores
        local anchor = abilityName:gsub(" ", "_")
       
        return hero .. "#" .. anchor
     end
     end
     return linkOverrides[iconInfo.name] or iconInfo.name
     return linkOverrides[iconInfo.name] or iconInfo.name
end
end


function p.render(frame)
-- Returns the canonical display name for a given user input
     local args = frame:getParent().args
-- Used by templates to store the correct casing in data attributes
    local name = args[1] or ""
-- Normalizes casing so exact string matches work reliably in Lua modules
function p.getCanonicalName(frame)
     local name = frame.args[1] or ""
     local lowerName = name:lower()
     local lowerName = name:lower()


     if aliases[lowerName] then
     if renames[lowerName] then
        lowerName = renames[lowerName]
    elseif aliases[lowerName] then
         lowerName = aliases[lowerName]
         lowerName = aliases[lowerName]
     end
     end


    -- 1. Check live game data
     local iconInfo = iconData[lowerName] or legacyItems[lowerName]
     local iconInfo = iconData[lowerName]
 
   
     -- If unknown, return original input
     -- 2. If not found, check legacy/unused items
     if not iconInfo then
     if not iconInfo then
         iconInfo = legacyItems[lowerName]
         return name
     end
     end


     -- 3. If still not found, throw error
-- Quick hack: ability names are used by MediaWiki:Gadget-infobox-tooltip.js and expected to be localized
    local langCode = getLangCode()
 
    if iconInfo.type == "ability" then
        return getTranslatedName(iconInfo, langCode)
    end
 
    return iconInfo.name
end
 
local function render(name, args)
    local originalName = name
    local lowerName = name:lower()
    args = args or {}
 
    if renames[lowerName] then
        lowerName = renames[lowerName]
    elseif aliases[lowerName] then
        lowerName = aliases[lowerName]
    end
 
     -- Lookup live data > legacy fallback
    local iconInfo = iconData[lowerName] or legacyItems[lowerName]
 
    -- Throw error if not found
     if not iconInfo then
     if not iconInfo then
         return string.format("[[:Category:Module:Icon ERROR|Icon not found]] ('%s'). [[Category:Module:Icon ERROR]]", name)
         return string.format("[[:Category:Module:Icon ERROR|Icon not found]] ('%s'). [[Category:Module:Icon ERROR]]", name)
     end
     end


     local customText = args.l1 or ""
     local customText = args.l1 ~= "" and args.l1 or nil
    local customLink = args.link ~= "" and args.link or nil
     local size = args.size or "20px"
     local size = args.size or "20px"
     local noLink = args["no-link"] == "true"
     local noLink = args["no-link"] == "true"
    local noFile = args["no-file"] == "true"
     local iconOnly = args["icon-only"] == "true"
     local iconOnly = args["icon-only"] == "true"


Line 116: Line 160:
         if type(k) == "number" and k > 1 then
         if type(k) == "number" and k > 1 then
             local val = mw.text.trim(v)
             local val = mw.text.trim(v)
             if val == "icon-only" then iconOnly = true
             if val == "icon-only" then
             elseif val == "no-link" then noLink = true
                iconOnly = true
             elseif val:match("^%d+px$") then size = val end
             elseif val == "no-link" then
                noLink = true
             elseif val:match("^%d+px$") then
                size = val
            end
         end
         end
     end
     end


     local langCode, langData = getLangData()
     local langCode = getLangCode()


     local displayName = customText
     local displayName
     if displayName == "" then
    if customText then
         if iconInfo.key and langData[iconInfo.key] then
        displayName = customText
            displayName = langData[iconInfo.key]
     elseif renames[name:lower()] then
         else
        -- Preserve original if renamed
            displayName = iconInfo.name
        displayName = originalName
        end
    else
        displayName = getTranslatedName(iconInfo, langCode)
    end
 
    local baseLink = customLink or getLink(iconInfo, langCode)
    local fragment = ""
 
    -- Split the fragment (#Abilities) from the base link
    if baseLink:find("#") then
         local parts = mw.text.split(baseLink, "#", true)
        baseLink = parts[1]
         fragment = "#" .. (parts[2] or "")
     end
     end


    local baseLink = getLink(iconInfo)
     local link = baseLink
     local link = baseLink
     if langCode ~= "en" and baseLink ~= "" then
 
     if not customLink and langCode ~= "en" and baseLink ~= "" then
         link = baseLink .. "/" .. langCode
         link = baseLink .. "/" .. langCode
     end
     end


     -- Abilities get the module-icon-ability class for light/dark theme filter support
     -- Reattach fragment at the end
    link = link .. fragment
 
    -- Add CSS class for abilities
     local style
     local style
     if iconInfo.type == "ability" then
     if iconInfo.type == "ability" then
         style = 'class="module-icon-ability" style="position:relative; bottom:2px;"'
         style = 'class="module-icon-ability" style="position:relative; bottom:2px;"'
     else
     else
         style = 'style="position:relative; bottom:2px;"'
         style = 'class="c-icon" style="position:relative; bottom:2px;"'
     end
     end


    local image = getImage(iconInfo)
     local imageLink = noLink and "" or link
     local imageLink = noLink and "" or link
     local iconHtml = string.format('<span %s>[[File:%s|%s|link=%s]]</span>', style, image, size, imageLink)
     local iconHtml = ""
 
    if not noFile then
        local image = getImage(iconInfo, args)
        iconHtml = string.format('<span %s>[[File:%s|%s|link=%s]]</span>', style, image, size, imageLink)
    end


     if iconOnly or displayName == "" then
     if iconOnly or displayName == "" then
Line 156: Line 222:


     local textHtml = (noLink or link == "") and displayName or string.format('[[%s|%s]]', link, displayName)
     local textHtml = (noLink or link == "") and displayName or string.format('[[%s|%s]]', link, displayName)
     return '<span style="white-space:nowrap;">' .. iconHtml .. " " .. textHtml .. '</span>'
 
     if iconHtml ~= "" then
        return '<span style="white-space:nowrap;">' .. iconHtml .. " " .. textHtml .. '</span>'
    else
        return textHtml
    end
end
 
-- Template entrypoint
function p.render(frame)
    local args = frame:getParent().args
    local name = args[1] or ""
 
    return render(name, args)
end
 
-- Module entrypoint
function p._render(name, args)
    return render(name, args)
end
end


return p
return p