Module:IconGive feedback
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:
{{HeroIcon}}{{AbilityIcon}}{{ItemIcon}}{{EntityIcon}}
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 language codes
local lang_codes = mw.loadJsonData("Data:LangCodes.json")
-- Cache for compiled icon data, split by type (persists during page render)
local heroCacheBuilt = false
local abilityCacheBuilt = false
local itemCacheBuilt = false
local iconDataCache = {}
local cachedLangCode, cachedLangData
-- Cache for expensive existence checks (persists during page render)
local existenceCache = {}
-- Heroes/Items that don't have images uploaded yet
local missingImageOverrides = {
-- Unreleased Heroes
["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",
-- Add any others that show red links
}
-- Build lookup table from bot-uploaded JSONs, only loading the relevant JSON per type
-- to reduce CPU cost on pages with many icon calls
local function buildIconData(iconType)
-- Only load hero data if not already built
if iconType == "hero" and not heroCacheBuilt then
local heroData = mw.loadJsonData("Data:HeroData.json")
-- 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()
-- Check for missing image override
local imageName = missingImageOverrides[lowerName] or (name .. ".png")
iconDataCache[lowerName] = {
name = name,
key = heroKey,
link = name,
image = imageName,
type = "hero"
}
end
end
heroCacheBuilt = true
-- Only load ability data (and hero data for parent linking) if not already built
elseif iconType == "ability" and not abilityCacheBuilt then
local heroData = mw.loadJsonData("Data:HeroData.json")
local abilityData = mw.loadJsonData("Data:AbilityData.json")
-- Track which hero owns which ability (for linking)
local abilityToHero = {}
for heroKey, hero in pairs(heroData) do
if type(hero) == "table" and hero.BoundAbilities then
for slot, ability in pairs(hero.BoundAbilities) do
if ability.Key then
abilityToHero[ability.Key] = {
heroName = hero.Name,
abilityName = ability.Name
}
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]
-- If we already have this ability name, prefer the one linked to a hero
if iconDataCache[lowerName] and iconDataCache[lowerName].type == "ability" then
local existingHasParent = iconDataCache[lowerName].link ~= iconDataCache[lowerName].name
local newHasParent = parentInfo ~= nil
-- Skip if existing is linked to hero but this one isn't (prevents orphans from overwriting real ones)
if existingHasParent and not newHasParent then
-- Skip this orphan ability
else
-- Overwrite: new has parent and existing doesn't, or both/neither have parents
local link = parentInfo and parentInfo.heroName or name
iconDataCache[lowerName] = {
name = name,
key = abilityKey,
link = link,
image = name .. ".png",
type = "ability",
class = "theme"
}
end
else
-- No existing entry, add normally
local link = parentInfo and parentInfo.heroName or name
iconDataCache[lowerName] = {
name = name,
key = abilityKey,
link = link,
image = name .. ".png",
type = "ability",
class = "theme"
}
end
end
end
abilityCacheBuilt = true
-- Only load item data if not already built
elseif iconType == "item" and not itemCacheBuilt then
local itemData = mw.loadJsonData("Data:ItemData.json")
-- 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()
iconDataCache[lowerName] = {
name = name,
key = itemKey,
link = name,
image = name .. ".png",
type = "item"
}
end
end
itemCacheBuilt = true
end
end
-- Get icon data by name and type (with alias support)
local function getIconData(iconName, iconType)
buildIconData(iconType)
local lowerName = iconName:lower()
-- Check main lookup
if iconDataCache[lowerName] then
return iconDataCache[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
local entry = iconDataCache[aliases[lowerName]]
if entry then
return entry, nil
end
end
return nil, string.format("[[:Category:Module:Icon ERROR|Icon not found]] ('%s'). [[Category:Module:Icon ERROR]]", iconName)
end
-- Language handling
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 ""
-- type is passed via #invoke so must be read from frame.args, not parent args
local iconType = frame.args.type or "item"
-- 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, using type to limit which JSON is loaded
local iconData, err = getIconData(name, iconType)
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 = baseLink
if langCode ~= "en" and baseLink ~= "" then
link = baseLink .. "/" .. langCode
end
-- Style logic (only abilities get theme class by default)
local class = iconData.class or ""
local style
if class:find("theme", 1, true) then
style = 'class="module-icon-ability" style="position:relative; bottom:2px;"'
else
style = 'style="position:relative; bottom:2px;"'
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