Module:AbilityTable: Difference between revisions

Vergir (talk | contribs)
mNo edit summary
Vergir (talk | contribs)
Add moveslow and dashslow stats with Move Slow % and Dash Slow % columns and upgrade notes (with help from vergir-bot LLM)
Line 19: Line 19:
         -- can also just list abilities if they don't have a reusable property
         -- can also just list abilities if they don't have a reusable property
         "Hotel Guest", "Life Drain", "Combo", "Light Eater", "Spirit Lasso", "Card Trick"
         "Hotel Guest", "Life Drain", "Combo", "Light Eater", "Spirit Lasso", "Card Trick"
    },
    ["moveslow"] = { "SlowPercent", "EnemySlowPct", "MoveSlowPercent" },
    ["dashslow"]  = {
        "GroundDashReductionPercent", "MaxGroundDashReductionPercent",
        "MoveSpeedAndDashSlowPct", "EnemyDashSlowPercent",
     },
     },
}
}
Line 55: Line 60:
     ["debuffresist"] = {
     ["debuffresist"] = {
         "Bookwyrm", -- has debuffduration for some reason
         "Bookwyrm", -- has debuffduration for some reason
         "Itani Lo Sahn", -- has debufffduration but does not get reduced
         "Itani Lo Sahn", -- has debuffduration but does not get reduced
         "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 93: Line 98:
     end
     end
     return nil
     return nil
end
-- Finds the first non-zero value for any of the given fields, checking base
-- then upgrades in order. Returns field, tier (nil=base, N=upgrade), abs value.
local function find_first_value(ability, fields)
    for _, field in ipairs(fields) do
        local v = num_val(ability[field])
        if v and v ~= 0 then return field, nil, math.abs(v) end
    end
    local upgrades = ability["Upgrades"]
    if type(upgrades) == "table" then
        for i, tier in ipairs(upgrades) do
            if type(tier) == "table" then
                for _, field in ipairs(fields) do
                    local v = num_val(tier[field])
                    if v and v ~= 0 then return field, i, math.abs(v) end
                end
            end
        end
    end
    return nil, nil, nil
end
end


Line 290: Line 316:
     if #notes > 0 then cells["Notes"] = table.concat(notes, " ") end
     if #notes > 0 then cells["Notes"] = table.concat(notes, " ") end
     return cells
     return cells
end
-- Generic renderer for a single percentage stat (move slow, dash slow).
-- col_name: the column header string (e.g. "Move Slow")
-- fields: ordered list of property names to check (first non-zero wins for display)
-- Upgrade deltas are additive; notes track totals.
local function pct_stat_cells(ability, col_name, fields)
    local cells  = {}
    local notes  = {}
    local first_field, first_tier, first_val = find_first_value(ability, fields)
    if not first_field then return cells end
    local cell_str = tostring(first_val) .. "%"
    if first_tier then cell_str = cell_str .. " (T" .. first_tier .. ")" end
    cells[col_name] = cell_str
    -- Scan upgrades for changes after the first value.
    local upgrades = ability["Upgrades"]
    if type(upgrades) == "table" then
        local running  = first_val
        local seen_first = (first_tier == nil)
        for i, tier in ipairs(upgrades) do
            if type(tier) == "table" then
                if first_tier == i then
                    seen_first = true
                else
                    -- Check if any of our fields has a delta in this tier
                    local delta = nil
                    for _, field in ipairs(fields) do
                        local v = num_val(tier[field])
                        if v and v ~= 0 then delta = math.abs(v); break end
                    end
                    if seen_first and delta then
                        local total = running + delta
                        table.insert(notes, "T" .. i .. " upgrade increases "
                            .. col_name:lower() .. " by " .. delta
                            .. "% (total " .. total .. "%).")
                        running = total
                    end
                end
            end
        end
    end
    if #notes > 0 then cells["Notes"] = table.concat(notes, " ") end
    return cells
end
local function moveslow_cells(ability)
    return pct_stat_cells(ability, "Move Slow", { "SlowPercent", "EnemySlowPct", "MoveSlowPercent" })
end
local function dashslow_cells(ability)
    return pct_stat_cells(ability, "Dash Slow", {
        "GroundDashReductionPercent", "MaxGroundDashReductionPercent",
        "MoveSpeedAndDashSlowPct", "EnemyDashSlowPercent",
    })
end
end


Line 304: Line 389:
         headers  = { "Heal Reduction", "Duration", "Notes" },
         headers  = { "Heal Reduction", "Duration", "Notes" },
         get_cells = healreduce_cells,
         get_cells = healreduce_cells,
    },
    ["moveslow"] = {
        headers  = { "Move Slow", "Notes" },
        get_cells = moveslow_cells,
    },
    ["dashslow"] = {
        headers  = { "Dash Slow", "Notes" },
        get_cells = dashslow_cells,
     },
     },
}
}
Line 431: Line 524:
         -- Compact mode: <ul> with one <li> per hero.
         -- Compact mode: <ul> with one <li> per hero.
         -- Each item: "{HeroIcon}: {AbilityIcon} (note), {AbilityIcon}, ..."
         -- Each item: "{HeroIcon}: {AbilityIcon} (note), {AbilityIcon}, ..."
        -- Group abilities by hero, preserving sort order.
         local hero_order    = {}
         local hero_order    = {}
         local hero_abilities = {} -- heroName -> list of ability names
         local hero_abilities = {}
         for _, ability in ipairs(filtered) do
         for _, ability in ipairs(filtered) do
             local info = key_lookup[ability["Key"]]
             local info = key_lookup[ability["Key"]]