Module:Sandbox/LVL

From The Deadlock Wiki
Revision as of 15:21, 9 February 2026 by LVL (talk | contribs)
Jump to navigation Jump to search

Documentation for this module may be created at Module:Sandbox/LVL/doc

local p = {}

-- Load language codes
local lang_codes = mw.loadJsonData("Data:LangCodes.json")

-- Cache for compiled icon data (persists during page render)
local iconDataCache = nil
local cachedLangCode, cachedLangData

-- Build unified lookup table from bot-uploaded JSONs
local function buildIconData()
    if iconDataCache then
        return iconDataCache
    end
    
    local lookup = {}
    
    -- Load bot data
    local heroData = mw.loadJsonData("Data:HeroData.json")
    local abilityData = mw.loadJsonData("Data:AbilityData.json")
    local itemData = mw.loadJsonData("Data:ItemData.json")
    
    -- Track which hero owns which ability (for linking)
    local abilityToHero = {}
    
    -- Process Heroes
    for heroKey, hero in pairs(heroData) do
        if type(hero) == "table" and hero.Name then
            local name = hero.Name
            local lowerName = name:lower()
            
            lookup[lowerName] = {
                name = name,
                key = heroKey,
                link = name,
                image = name .. ".png",
                type = "hero"
            }
            
            -- Map abilities to parent hero
            if hero.BoundAbilities then
                for slot, ability in pairs(hero.BoundAbilities) do
                    if ability.Key then
                        abilityToHero[ability.Key] = {
                            heroName = name,
                            abilityName = ability.Name -- Use name from hero data if available
                        }
                    end
                end
            end
        end
    end
    
    -- Process Abilities
    for abilityKey, ability in pairs(abilityData) do
        if type(ability) == "table" and ability.Name then
            local name = ability.Name
            local lowerName = name:lower()
            local parentInfo = abilityToHero[abilityKey]
            
            -- Determine link (fallback to ability name if no parent found)
            local link = parentInfo and parentInfo.heroName or name
            
            lookup[lowerName] = {
                name = name,
                key = abilityKey,
                link = link,
                image = name .. ".png",
                type = "ability",
                class = "theme"  -- Abilities get theme class by default
            }
        end
    end
    
    -- Process Items
    for itemKey, item in pairs(itemData) do
        if type(item) == "table" and item.Name then
            local name = item.Name
            local lowerName = name:lower()
            
            lookup[lowerName] = {
                name = name,
                key = itemKey,
                link = name,
                image = name .. ".png",
                type = "item"
            }
        end
    end
    
    iconDataCache = lookup
    return lookup
end

-- Get icon data by name (with alias support)
local function getIconData(iconName)
    local data = buildIconData()
    local lowerName = iconName:lower()
    
    -- Check main lookup
    if data[lowerName] then
        return data[lowerName], nil
    end
    
    -- Check aliases (for edge cases like "doorman" -> "the doorman")
    local aliases = {
        ["doorman"] = "the doorman",
        ["mo and krill"] = "mo & krill",
        ["mo"] = "mo & krill",
        ["krill"] = "mo & krill",
        ["curse"] = "cursed relic",
        ["debuff remover"] = "dispel magic"
    }
    
    if aliases[lowerName] then
        return data[aliases[lowerName]], nil
    end
    
    return nil, string.format("[[:Category:Module:Icon ERROR|Icon not found]] ('%s'). [[Category:Module:Icon ERROR]]", iconName)
end

-- Language handling (unchanged from your original)
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 (updated to handle missing keys gracefully)
function p.render(frame)
    local args = frame:getParent().args
    local name = args[1] or ""
    local customText = args.l1 or ""
    
    -- Set Defaults
    local size = args.size or "20px"
    local noLink = args["no-link"] == "true"
    local iconOnly = args["icon-only"] == "true"

    -- Scan unnamed parameters
    for k, v in pairs(args) do
        if type(k) == "number" and k > 1 then
            local val = mw.text.trim(v)
            
            if val == "icon-only" then
                iconOnly = true
            elseif val == "no-link" then
                noLink = true
            elseif val:match("^%d+px$") then 
                size = val
            end
        end
    end

    -- Get icon data automatically from JSON
    local iconData, err = getIconData(name)
    if not iconData then
        return "Error: " .. err
    end

    local langCode, langData = getLangData()
    
    -- Determine display name
    local displayName = ""
    if customText ~= "" then
        displayName = customText
    elseif iconData.key and langData[iconData.key] then
        displayName = langData[iconData.key]
    else
        displayName = iconData.name
    end

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

    -- Style logic (only abilities get theme class by default)
    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

    -- Generate icon HTML
    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