Module:AbilityTable: Difference between revisions

Vergir (talk | contribs)
Use ability Name for AbilityIcon; add Notes column to charges with full analyze/note logic ported from Interaction/Charges (with help from vergir-bot LLM)
Vergir (talk | contribs)
Rename friendly_to_internal to stat_to_props; combine upgrade helpers; add column unit suffix map; keep analyze_charges separate from get_cells (with help from vergir-bot LLM)
Line 8: Line 8:
-- ADDING A NEW STAT
-- ADDING A NEW STAT
-- ============================================================
-- ============================================================
-- 1. Add an entry to friendly_to_internal mapping the friendly
-- 1. Add an entry to stat_to_props mapping the friendly name
--    name (lowercase) to the internal AbilityData property keys
--    (lowercase) to the internal AbilityData property keys that
--    that determine whether an ability appears in the table.
--    determine whether an ability appears in the table.
--
--
-- 2. Optionally add a matching entry to extra_columns to show
-- 2. Optionally add a matching entry to extra_columns to show
Line 16: Line 16:
--    Copy the "charges" block as a template:
--    Copy the "charges" block as a template:
--      - headers:    ordered list of column header strings
--      - headers:    ordered list of column header strings
--      - get_cells:  function(ability) that returns a table of
--      - get_cells:  function(ability) -> { ["Column Name"] = value }
--                    { ["Column Name"] = value } for one ability row.
--                    Return nil or omit a key to show "—" in that cell.
--                    Return nil or omit a key to show "—" in that cell.
--    If no extra_columns entry is added, only Hero and Ability
--    If no extra_columns entry is added, only Hero and Ability
--    columns are shown.
--    columns are shown.
--
-- 3. Optionally add entries to column_suffix to append a unit
--    string (e.g. "s", "%") after values in specific columns.
-- ============================================================
-- ============================================================


Line 28: Line 30:
-- Maps lowercase friendly stat names to internal AbilityData property keys.
-- Maps lowercase friendly stat names to internal AbilityData property keys.
-- Used to filter which abilities appear in the table.
-- Used to filter which abilities appear in the table.
local friendly_to_internal = {
local stat_to_props = {
     ["charges"] = { "AbilityCharges" },
     ["charges"] = { "AbilityCharges" },
}
-- Maps column header names to their display unit suffix.
-- Applied automatically to all non-nil, non-"—" cell values in that column.
local column_suffix = {
    ["Time Between Charges"] = "s",
}
}


Line 43: Line 51:


-- ============================================================
-- ============================================================
-- Charges: analysis helpers
-- Shared analysis helpers
-- Ported from Module:Interaction/Charges and Module:Interactions.
-- ============================================================
-- ============================================================


Line 54: Line 61:
end
end


-- Returns the 1-based index of the first Upgrades tier that contains a field,
-- Searches Upgrades[] for a field and returns { tier = N, value = V } at its
-- or nil if the field never appears in any upgrade tier.
-- first appearance, or nil if the field is absent from all upgrade tiers.
local function upgrade_grants_tier(ability, field)
local function find_in_upgrades(ability, field)
     local upgrades = ability["Upgrades"]
     local upgrades = ability["Upgrades"]
     if type(upgrades) ~= "table" then return nil end
     if type(upgrades) ~= "table" then return nil end
     for i, tier in ipairs(upgrades) do
     for i, tier in ipairs(upgrades) do
         if type(tier) == "table" and tier[field] ~= nil then
         if type(tier) == "table" and tier[field] ~= nil then
             return i
             return { tier = i, value = num_val(tier[field]) }
         end
         end
     end
     end
Line 67: Line 74:
end
end


-- Returns the numeric value of a field at its first appearance in Upgrades[].
-- ============================================================
local function upgrade_field_value(ability, field)
-- Charges: analysis
    local upgrades = ability["Upgrades"]
-- ============================================================
    if type(upgrades) ~= "table" then return nil end
    for _, tier in ipairs(upgrades) do
        if type(tier) == "table" and tier[field] ~= nil then
            return num_val(tier[field])
        end
    end
    return nil
end


-- Analyses a raw ability record for charge-related properties.
-- Analyses a raw ability record for charge-related properties.
-- Returns a record table, or nil if the ability has no charge mechanic.
-- Returns a structured record, or nil if the ability has no charge mechanic.
local function analyze_charges(ability)
local function analyze_charges(ability)
     local base_charges  = num_val(ability["AbilityCharges"])
     local base_charges  = num_val(ability["AbilityCharges"])
Line 87: Line 86:
     local has_base      = base_charges ~= nil and base_charges > 0
     local has_base      = base_charges ~= nil and base_charges > 0


     local upgrade_tier    = upgrade_grants_tier(ability, "AbilityCharges")
     local upgrade_info = find_in_upgrades(ability, "AbilityCharges")
    local upgrade_charges = upgrade_tier and upgrade_field_value(ability, "AbilityCharges") or nil


     if not has_base and not upgrade_tier then return nil end
     if not has_base and not upgrade_info then return nil end


     local cooldown, upgrade_cooldown
     local cooldown, upgrade_cooldown
Line 97: Line 95:
             cooldown = base_cooldown
             cooldown = base_cooldown
         else
         else
             local v = upgrade_field_value(ability, "AbilityCooldownBetweenCharge")
             local cd = find_in_upgrades(ability, "AbilityCooldownBetweenCharge")
             if v and v > 0 then cooldown = v end
             if cd and cd.value and cd.value > 0 then cooldown = cd.value end
         end
         end
     elseif upgrade_tier then
     else
         local v = upgrade_field_value(ability, "AbilityCooldownBetweenCharge")
         local cd = find_in_upgrades(ability, "AbilityCooldownBetweenCharge")
         if v and v > 0 then upgrade_cooldown = v end
         if cd and cd.value and cd.value > 0 then upgrade_cooldown = cd.value end
     end
     end


     return {
     return {
         base_charges   = has_base and base_charges or nil,
         base_charges     = has_base and base_charges or nil,
         upgrade_tier   = upgrade_tier,
         upgrade_tier     = upgrade_info and upgrade_info.tier or nil,
         upgrade_charges = upgrade_charges,
         upgrade_charges = upgrade_info and upgrade_info.value or nil,
         upgrade_cooldown = upgrade_cooldown,
         upgrade_cooldown = upgrade_cooldown,
         cooldown       = cooldown,
         cooldown         = cooldown,
         is_conditional = is_conditional,
         is_conditional   = is_conditional,
     }
     }
end
end


-- ============================================================
-- ============================================================
-- Extra columns definition
-- Extra columns per stat
-- ============================================================
-- ============================================================


Line 131: Line 129:
                 cells["Charges"] = tostring(rec.base_charges)
                 cells["Charges"] = tostring(rec.base_charges)
                 if rec.cooldown then
                 if rec.cooldown then
                     cells["Time Between Charges"] = rec.cooldown .. "s"
                     cells["Time Between Charges"] = tostring(rec.cooldown)
                 end
                 end
             end
             end
Line 152: Line 150:
             end
             end
             local human = charges_human_notes[ability["Name"]]
             local human = charges_human_notes[ability["Name"]]
             if human then
             if human then table.insert(note_parts, human) end
                table.insert(note_parts, human)
            end
             if #note_parts > 0 then
             if #note_parts > 0 then
                 cells["Notes"] = table.concat(note_parts, " ")
                 cells["Notes"] = table.concat(note_parts, " ")
Line 214: Line 210:
     local stat = mw.text.trim(frame.args[1] or ""):lower()
     local stat = mw.text.trim(frame.args[1] or ""):lower()


     local internal_keys = friendly_to_internal[stat]
     local internal_keys = stat_to_props[stat]
     if not internal_keys then
     if not internal_keys then
         return '<span class="error">AbilityTable: unknown stat "' .. stat .. '".</span>'
         return '<span class="error">AbilityTable: unknown stat "' .. stat .. '".</span>'
Line 274: Line 270:
         local extra = get_cells(ability)
         local extra = get_cells(ability)
         for _, header in ipairs(headers) do
         for _, header in ipairs(headers) do
             table.insert(cells, extra[header] or "—")
             local value = extra[header]
            if value ~= nil then
                local suffix = column_suffix[header] or ""
                table.insert(cells, value .. suffix)
            else
                table.insert(cells, "—")
            end
         end
         end