Module:AbilityHints: Difference between revisions

From The Deadlock Wiki
Jump to navigation Jump to search
Vergir (talk | contribs)
Update stale class name in comment after the iconbox- rename (with help from vergir-bot LLM)
Vergir (talk | contribs)
m add sorting for ability hints
Line 4: Line 4:
local AbilityTable = require("Module:AbilityTable")
local AbilityTable = require("Module:AbilityTable")
local ability_data = mw.loadJsonData("Data:AbilityData.json")
local ability_data = mw.loadJsonData("Data:AbilityData.json")
local resource_lookup = mw.loadJsonData("Data:ResourceLookup.json")
local item_data = mw.loadJsonData("Data:ItemData.json")


local p = {}
local p = {}


-- Display order. Each entry: { list, file, tip }
-- Automatic hints that get shown without corresponding {{AbilityInteraction}}. Powered by Module:AbilityTable
local CONFIG = {
local CONFIG = {
     { list = "melee",          file = "Melee Charge.png",    tip = "Benefits from melee items ([[Melee Charge]])" },
     { list = "melee",          file = "Melee Charge.png",    tip = "Benefits from melee items ([[Melee Charge]])" },
Line 20: Line 22:
     { list = "summons",        file = "Monster Rounds.png",  tip = "Summons affected by [[Monster Rounds]] and [[Heroic Aura]]" },
     { list = "summons",        file = "Monster Rounds.png",  tip = "Summons affected by [[Monster Rounds]] and [[Heroic Aura]]" },
}
}
-- Display order: item slot (Weapon, then Vitality, then Spirit), then cost, then name.
local function sort_key(file)
    local base = mw.ustring.lower((file:gsub('%.%w+$', '')))
    local entry = resource_lookup[base]
    local item = (entry ~= nil and entry.type == 'item') and item_data[entry.key] or nil
    if item == nil then
        return { 99, math.huge, base }
    end
    local slot = item["Slot"]
    local slot_rank = (slot == "Weapon" and 1) or (slot == "Armor" and 2) or (slot == "Tech" and 3) or 98
    return {
        slot_rank,
        tonumber(item["Cost"]) or math.huge,
        mw.ustring.lower(item["Name"] or base),
    }
end
local function compare(a, b)
    for i = 1, 3 do
        if a.sort[i] ~= b.sort[i] then return a.sort[i] < b.sort[i] end
    end
    return false
end


-- partial: split the icon so the top-left half is grayscale (mirrors the iconbox-partial box icon).
-- partial: split the icon so the top-left half is grayscale (mirrors the iconbox-partial box icon).
Line 57: Line 83:
     manual = manual or {}
     manual = manual or {}


    -- Manual icons indexed by file so an override can take its automatic hint's slot.
     local manual_by_file = {}
     local manual_by_file = {}
     for _, m in ipairs(manual) do
     for _, m in ipairs(manual) do
Line 63: Line 88:
     end
     end


     local icons = {}
     local entries = {}
     local placed = {}
     local placed = {}


    -- Automatic hints in CONFIG order; an overriding manual icon takes the slot.
     local record = ability_data[ability_key]
     local record = ability_data[ability_key]
     if record ~= nil then
     if record ~= nil then
Line 75: Line 99:
                 local m = manual_by_file[key]
                 local m = manual_by_file[key]
                 if m ~= nil then
                 if m ~= nil then
                     table.insert(icons, manual_icon(m))
                     table.insert(entries, { file = m.file, html = manual_icon(m) })
                     placed[key] = true
                     placed[key] = true
                 else
                 else
                     table.insert(icons, hint_icon(def))
                     table.insert(entries, { file = def.file, html = hint_icon(def) })
                 end
                 end
             end
             end
Line 84: Line 108:
     end
     end


    -- Remaining manual icons (no automatic slot) in their original order.
     for _, m in ipairs(manual) do
     for _, m in ipairs(manual) do
         if not placed[mw.ustring.lower(m.file)] then
         if not placed[mw.ustring.lower(m.file)] then
             table.insert(icons, manual_icon(m))
             table.insert(entries, { file = m.file, html = manual_icon(m) })
         end
         end
     end
     end


     if #icons == 0 then return '' end
     if #entries == 0 then return '' end
 
    for _, e in ipairs(entries) do e.sort = sort_key(e.file) end
    table.sort(entries, compare)
 
    local icons = {}
    for _, e in ipairs(entries) do table.insert(icons, e.html) end
 
     return '<div class="ability-section-hints">' .. table.concat(icons) .. '</div>'
     return '<div class="ability-section-hints">' .. table.concat(icons) .. '</div>'
end
end


return p
return p

Revision as of 22:47, 15 July 2026

Overview

Renders a small strip of item icons showing how an ability interacts with items and used by Module:AbilitySection. Each icon displays a configured image and has a hover tooltip.

Hints can be "automatic" and "manual".

  • Automatic come from Module:AbilityTable/Lists. If an ability is part of 'debuffresist' list, then it will show automatic debuff resist hint. List of enabled automatic hints is configured through CONFIG in this module. Clicking on an icon does nothing, however tooltip often will have a link to relevant item/mechanic.
  • Manual hints come from {{AbilityInteraction}} blocks used on AbilitySection. Whenetever an editor describes an interaction using that block a hint will be displayed. Clicking on a hint reveals that hand-written block.

Entry point

p.get_icons(ability_key, ability_num)

Returns the rail HTML for one ability, or an empty string when the ability matches no lists.

Configuration

CONFIG

List of the icons the rail can show. Order within CONFIG does not affect the rendered output — see Display order. Each entry:

Field Description
list List name in Module:AbilityTable/Lists whose membership triggers the icon.
file Image file to display, e.g. Reactive Barrier.png. Also determines the icon's position in the rail.
tip Hover tooltip text. May contain wikilinks and simple HTML (<br>, <b>).

To add an icon, add a CONFIG row: pick the triggering list, the display file, and the tip. To re-scope which abilities an icon covers, edit the list in Module:AbilityTable/Lists.


-- Small item icons on ability cards showing how an ability interacts with items (dispellable, reduced, blocked, etc.).
-- Used by Template:AbilitySection. Styles are there too.

local AbilityTable = require("Module:AbilityTable")
local ability_data = mw.loadJsonData("Data:AbilityData.json")
local resource_lookup = mw.loadJsonData("Data:ResourceLookup.json")
local item_data = mw.loadJsonData("Data:ItemData.json")

local p = {}

-- Automatic hints that get shown without corresponding {{AbilityInteraction}}. Powered by Module:AbilityTable
local CONFIG = {
    { list = "melee",           file = "Melee Charge.png",     tip = "Benefits from melee items ([[Melee Charge]])" },
    { list = "movementbased",   file = "Slowing Hex.png",      tip = "Disabled by [[Slowing Hex]]" },
    { list = "debuffresist",    file = "Debuff Reducer.png",   tip = "Debuff duration reduced by [[Debuff Resist]]" },
    { list = "heal",            file = "Healing Booster.png",  tip = "[[Healing]] amplified by [[Healing Booster]] and affected by healing reduction" },
    { list = "reactivebarrier", file = "Reactive Barrier.png", tip = "Triggers [[Reactive Barrier]]" },
    { list = "dispelmagic",     file = "Dispel Magic.png",     tip = "Effect can be [[Dispel Magic|dispelled]]" },
    { list = "indomitable",     file = "Indomitable.png",      tip = "Disable prevented by [[Indomitable]]" },
    { list = "unstoppable",     file = "Unstoppable.png",      tip = "Disable prevented by [[Unstoppable]]" },
    { list = "platedarmor",     file = "Plated Armor.png",     tip = "On-shot effect prevented by [[Plated Armor]]" },
    { list = "summons",         file = "Monster Rounds.png",   tip = "Summons affected by [[Monster Rounds]] and [[Heroic Aura]]" },
}

-- Display order: item slot (Weapon, then Vitality, then Spirit), then cost, then name.
local function sort_key(file)
    local base = mw.ustring.lower((file:gsub('%.%w+$', '')))
    local entry = resource_lookup[base]
    local item = (entry ~= nil and entry.type == 'item') and item_data[entry.key] or nil
    if item == nil then
        return { 99, math.huge, base }
    end
    local slot = item["Slot"]
    local slot_rank = (slot == "Weapon" and 1) or (slot == "Armor" and 2) or (slot == "Tech" and 3) or 98
    return {
        slot_rank,
        tonumber(item["Cost"]) or math.huge,
        mw.ustring.lower(item["Name"] or base),
    }
end

local function compare(a, b)
    for i = 1, 3 do
        if a.sort[i] ~= b.sort[i] then return a.sort[i] < b.sort[i] end
    end
    return false
end

-- partial: split the icon so the top-left half is grayscale (mirrors the iconbox-partial box icon).
-- An empty link makes the icon non-clickable; automatic hints link from their tooltip text instead.
local function icon_img(file, link, partial)
    link = link or ''
    if partial then
        return '<span class="ability-hint-icon"><span class="ability-hint-split">'
            .. '[[File:' .. file .. '|24px|link=' .. link .. ']]'
            .. '<span class="ability-hint-split-gray">[[File:' .. file .. '|24px|link=]]</span>'
            .. '</span></span>'
    end
    return '<span class="ability-hint-icon">[[File:' .. file .. '|24px|link=' .. link .. ']]</span>'
end

local function hint_icon(def)
    return '<span class="ability-hint">' .. icon_img(def.file)
        .. '<span class="ability-hint-tip">' .. def.tip .. '</span></span>'
end

local function manual_icon(m)
    local cls = 'ability-hint'
    local verb = 'Interacts with'
    local partial = false
    if m.state == 'disabled' then
        cls = cls .. ' ability-hint--disabled'
        verb = 'Does not interact with'
    elseif m.state == 'partial' then
        verb = 'Interacts partially with'
        partial = true
    end
    return '<span class="' .. cls .. '">' .. icon_img(m.file, '#' .. m.anchor, partial)
        .. '<span class="ability-hint-tip">' .. verb .. ' ' .. m.title .. '.<br>Click to reveal more info.</span></span>'
end

function p.get_icons(ability_key, ability_num, manual)
    manual = manual or {}

    local manual_by_file = {}
    for _, m in ipairs(manual) do
        manual_by_file[mw.ustring.lower(m.file)] = m
    end

    local entries = {}
    local placed = {}

    local record = ability_data[ability_key]
    if record ~= nil then
        local num = tonumber(ability_num)
        for _, def in ipairs(CONFIG) do
            if AbilityTable.is_member(def.list, record, num) then
                local key = mw.ustring.lower(def.file)
                local m = manual_by_file[key]
                if m ~= nil then
                    table.insert(entries, { file = m.file, html = manual_icon(m) })
                    placed[key] = true
                else
                    table.insert(entries, { file = def.file, html = hint_icon(def) })
                end
            end
        end
    end

    for _, m in ipairs(manual) do
        if not placed[mw.ustring.lower(m.file)] then
            table.insert(entries, { file = m.file, html = manual_icon(m) })
        end
    end

    if #entries == 0 then return '' end

    for _, e in ipairs(entries) do e.sort = sort_key(e.file) end
    table.sort(entries, compare)

    local icons = {}
    for _, e in ipairs(entries) do table.insert(icons, e.html) end

    return '<div class="ability-section-hints">' .. table.concat(icons) .. '</div>'
end

return p