Module:AbilityTable: Difference between revisions

Vergir (talk | contribs)
Add compact parameter: one row per hero, abilities comma-separated, no extra columns (with help from vergir-bot LLM)
Vergir (talk | contribs)
Refactor compact mode: ul/li output, hero name as text, notes inline after each ability in parentheses (with help from vergir-bot LLM)
Line 22: Line 22:
}
}


-- Editor-authored notes appended to the Notes column.
-- Editor-authored notes appended to the Notes column (normal mode) or
-- inline after the ability name in parentheses (compact mode).
local human_notes = {
local human_notes = {
     ["charges"] = {
     ["charges"] = {
Line 31: Line 32:
     },
     },
     ["debuffresist"] = {
     ["debuffresist"] = {
         ["Aura of Suffering"] = "T1 slow, T3 extra damage. The effect is negligible.",
         ["Aura of Suffering"]   = "T1 slow, T3 extra damage. The effect is negligible.",
         ["Lightning Ball"]     = "T2 Slow. The effect is negligible.",
         ["Lightning Ball"]     = "T2 Slow. The effect is negligible.",
         ["Static Charge"]     = "Stun duration. Delay before stun is not affected.",
         ["Static Charge"]       = "Stun duration. Delay before stun is not affected.",
         ["Enchanter's Satchel"] = "T3 Slow.",
         ["Enchanter's Satchel"] = "T3 Slow.",
         ["Itani Lo Sahn"] = "Despite being described as \"debuff\", it can not be reduced with debuff resist.",
         ["Itani Lo Sahn"]       = "Despite being described as \"debuff\", it can not be reduced with debuff resist.",
         ["Scorn"]             = "T3 extra damage from Mo & Krill.",
         ["Scorn"]               = "T3 extra damage from Mo & Krill.",
         ["Hotel Guest"]       = "Only T2 late check-out stun can be reduced.",
         ["Hotel Guest"]         = "Only T2 late check-out stun can be reduced.",
         ["Jar of Dead"]       = "T2 slow.",
         ["Jar of Dead"]         = "T2 slow.",
         ["Grapple Arm"]       = "T1 extra damage from Bebop.",
         ["Grapple Arm"]         = "T1 extra damage from Bebop.",
         ["Binding Word"]       = "Immobilize Duration. Escape time is not affected.",
         ["Binding Word"]       = "Immobilize Duration. Escape time is not affected.",
         ["Power Slash"]       = "T1 slow.",
         ["Power Slash"]         = "T1 slow.",
         ["Kinetic Pulse"]     = "T2 bullet resist reduction and slow.",
         ["Kinetic Pulse"]       = "T2 bullet resist reduction and slow.",
         ["Pain Battery"]       = "T1 slow.",
         ["Pain Battery"]       = "T1 slow.",
         ["Power Surge"]       = "T3 Spirit Resist reduction.",
         ["Power Surge"]         = "T3 Spirit Resist reduction.",
         ["Rain of Arrows"]     = "T2 slow.",
         ["Rain of Arrows"]     = "T2 slow.",
         ["Soul Exchange"]     = "T2 silence.",
         ["Soul Exchange"]       = "T2 silence.",
         ["Ground Strike"]     = "T2 slow.",
         ["Ground Strike"]       = "T2 slow.",
         ["Flog"]               = "T2 Fire rate slow.",
         ["Flog"]               = "T2 Fire rate slow.",
     },
     },
}
}
Line 55: Line 56:
local exclude_list = {
local exclude_list = {
     ["debuffresist"] = {
     ["debuffresist"] = {
         "Bookwyrm", -- has debuffdurattion for some reason
         "Bookwyrm", -- has debuffduration for some reason
         "Slam Fire", -- has debuffduration for some reason
         "Slam Fire", -- has debuffduration for some reason
         "Splatter", -- has SlowPercent but no duration to shave off.
         "Splatter", -- has SlowPercent but no duration to shave off.
Line 427: Line 428:
         .. "</div>"
         .. "</div>"
     )
     )
    local out = {}
    table.insert(out, disclaimer)
    table.insert(out, '{| class="wikitable sortable ability-table"')


     if compact then
     if compact then
         -- Compact mode: one row per hero, abilities comma-separated in a single column.
         -- Compact mode: <ul> with one <li> per hero.
         table.insert(out, '! class="ability-table-col-hero" | Hero'
         -- Each item: "{HeroIcon}: {AbilityIcon} (note), {AbilityIcon}, ..."
                      .. ' !! class="ability-table-col-abilities" | Abilities')


         -- Group abilities by hero, preserving sort order.
         -- Group abilities by hero, preserving sort order.
         local hero_order = {} -- ordered list of hero names
         local hero_order     = {}
         local hero_abilities = {}  -- heroName -> list of ability names
         local hero_abilities = {}  -- heroName -> list of ability names
         for _, ability in ipairs(filtered) do
         for _, ability in ipairs(filtered) do
Line 450: Line 446:
         end
         end


        local items = {}
         for _, hero in ipairs(hero_order) do
         for _, hero in ipairs(hero_order) do
             local hero_cell = frame:expandTemplate{ title = "HeroIcon", args = { hero } }
             local hero_cell = frame:expandTemplate{ title = "HeroIcon", args = { hero } }
             local ability_parts = {}
             local ability_parts = {}
             for _, name in ipairs(hero_abilities[hero]) do
             for _, name in ipairs(hero_abilities[hero]) do
                 table.insert(ability_parts,
                 local ability_cell = frame:expandTemplate{ title = "AbilityIcon", args = { name } }
                    frame:expandTemplate{ title = "AbilityIcon", args = { name } })
                local note = stat_notes and stat_notes[name]
                if note then
                    table.insert(ability_parts, ability_cell .. " (" .. note .. ")")
                else
                    table.insert(ability_parts, ability_cell)
                end
             end
             end
             table.insert(out, "|-")
             table.insert(items, "<li>" .. hero_cell .. ": " .. table.concat(ability_parts, ", ") .. "</li>")
            table.insert(out,
                '| class="ability-table-cell-hero" | '      .. hero_cell
            .. ' || class="ability-table-cell-abilities" | ' .. table.concat(ability_parts, ", "))
         end
         end
     else
 
        -- Normal mode: one row per ability with stat-specific columns.
        return disclaimer .. "<ul>" .. table.concat(items) .. "</ul>"
        local has_notes_header = false
     end
        local final_headers = {}
 
        for _, h in ipairs(headers) do
    -- Normal mode: wikitable with one row per ability and stat-specific columns.
            if h == "Notes" then
    local has_notes_header = false
                has_notes_header = true
    local final_headers = {}
            elseif not hide_set[h] then
    for _, h in ipairs(headers) do
                table.insert(final_headers, h)
        if h == "Notes" then
            end
            has_notes_header = true
        elseif not hide_set[h] then
            table.insert(final_headers, h)
         end
         end
        local needs_notes = (has_notes_header or stat_notes ~= nil) and not hide_set["Notes"]
    end
        if needs_notes then table.insert(final_headers, "Notes") end
    local needs_notes = (has_notes_header or stat_notes ~= nil) and not hide_set["Notes"]
    if needs_notes then table.insert(final_headers, "Notes") end
 
    local out = {}
    table.insert(out, disclaimer)
    table.insert(out, '{| class="wikitable sortable ability-table"')


        local header_row = '! class="ability-table-col-hero" | Hero'
    local header_row = '! class="ability-table-col-hero" | Hero'
                        .. ' !! class="ability-table-col-ability" | Ability'
                    .. ' !! class="ability-table-col-ability" | Ability'
        for _, h in ipairs(final_headers) do
    for _, h in ipairs(final_headers) do
            header_row = header_row .. ' !! class="ability-table-col-'
        header_row = header_row .. ' !! class="ability-table-col-'
                .. h:lower():gsub("%s+", "-") .. '" | ' .. h
            .. h:lower():gsub("%s+", "-") .. '" | ' .. h
        end
    end
        table.insert(out, header_row)
    table.insert(out, header_row)


        for _, ability in ipairs(filtered) do
    for _, ability in ipairs(filtered) do
            local info = key_lookup[ability["Key"]]
        local info = key_lookup[ability["Key"]]


            local hero_cell
        local hero_cell
            if info then
        if info then
                hero_cell = frame:expandTemplate{ title = "HeroIcon", args = { info.heroName } }
            hero_cell = frame:expandTemplate{ title = "HeroIcon", args = { info.heroName } }
            else
        else
                hero_cell = "—"
            hero_cell = "—"
            end
        end
            local ability_cell = frame:expandTemplate{ title = "AbilityIcon", args = { ability["Name"] } }
        local ability_cell = frame:expandTemplate{ title = "AbilityIcon", args = { ability["Name"] } }


            local extra = get_cells(ability)
        local extra = get_cells(ability)


            if stat_notes and stat_notes[ability["Name"]] then
        if stat_notes and stat_notes[ability["Name"]] then
                local human = stat_notes[ability["Name"]]
            local human = stat_notes[ability["Name"]]
                extra["Notes"] = extra["Notes"] and (extra["Notes"] .. " " .. human) or human
            extra["Notes"] = extra["Notes"] and (extra["Notes"] .. " " .. human) or human
            end
        end


            local row = '| class="ability-table-cell-hero" | '    .. hero_cell
        local row = '| class="ability-table-cell-hero" | '    .. hero_cell
                    .. ' || class="ability-table-cell-ability" | ' .. ability_cell
                .. ' || class="ability-table-cell-ability" | ' .. ability_cell
            for _, header in ipairs(final_headers) do
        for _, header in ipairs(final_headers) do
                local value = extra[header]
            local value = extra[header]
                local cls  = "ability-table-cell-" .. header:lower():gsub("%s+", "-")
            local cls  = "ability-table-cell-" .. header:lower():gsub("%s+", "-")
                local content
            local content
                if value ~= nil then
            if value ~= nil then
                    local suffix = column_suffix[header] or ""
                local suffix = column_suffix[header] or ""
                    content = (type(value) == "string" and value:sub(1,1) == "(")
                content = (type(value) == "string" and value:sub(1,1) == "(")
                        and value or (value .. suffix)
                    and value or (value .. suffix)
                else
            else
                    content = "—"
                content = "—"
                end
                row = row .. ' || class="' .. cls .. '" | ' .. content
             end
             end
            row = row .. ' || class="' .. cls .. '" | ' .. content
        end


            table.insert(out, "|-")
        table.insert(out, "|-")
            table.insert(out, row)
        table.insert(out, row)
        end
     end
     end