Editing Module:AbilityTableGive feedback
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
| Latest revision | Your text | ||
| Line 7: | Line 7: | ||
local p = {} | local p = {} | ||
-- ============================================================ | |||
-- Extra columns: maps stat names to their column headers and | |||
-- cell renderer functions from ComplexRenderers. | |||
-- Stats not listed here get a plain Hero + Ability + Notes table. | |||
-- ============================================================ | |||
local extra_columns = { | local extra_columns = { | ||
["charges"] = { | ["charges"] = { | ||
headers = { "Charges", "Time Between Charges", "Notes" }, | headers = { "Charges", "Time Between Charges", "Notes" }, | ||
| Line 18: | Line 20: | ||
}, | }, | ||
["melee"] = { | ["melee"] = { | ||
headers = { | headers = { "Light Melee Scaling", "Notes" }, | ||
get_cells = Renderers.RenderMelee, | get_cells = Renderers.RenderMelee, | ||
}, | }, | ||
["healreduce"] = { | ["healreduce"] = { | ||
headers = { "Heal Reduction", "Notes" }, | headers = { "Heal Reduction", "Notes" }, | ||
get_cells = Renderers.RenderHealReduce, | get_cells = Renderers.RenderHealReduce, | ||
}, | |||
["debuffresist"] = { | |||
headers = { "Notes" }, | |||
get_cells = function(ability) return Renderers.RenderDebuff(ability, "debuffresist") end, | |||
}, | |||
["dispelmagic"] = { | |||
headers = { "Notes" }, | |||
get_cells = function(ability) return Renderers.RenderDebuff(ability, "dispelmagic") end, | |||
}, | }, | ||
["moveslow"] = { | ["moveslow"] = { | ||
| Line 40: | Line 42: | ||
headers = { "Dash Slow", "Notes" }, | headers = { "Dash Slow", "Notes" }, | ||
get_cells = Renderers.RenderDashSlow, | get_cells = Renderers.RenderDashSlow, | ||
}, | }, | ||
} | } | ||
-- ============================================================ | -- ============================================================ | ||
-- | -- Human-note formatters | ||
-- ============================================================ | -- ============================================================ | ||
-- | -- Capitalises the first letter of a human note before merging (full-table mode). | ||
local function human_note_full(note) | |||
local function | if not note or note == "" then return note end | ||
if | return note:sub(1,1):upper() .. note:sub(2) | ||
end | |||
-- Ensures the final merged Notes string ends with "." (full-table mode). | |||
local function ensure_period(s) | |||
if not s or s == "" then return s end | |||
if s:sub(-1) ~= "." then s = s .. "." end | |||
return s | |||
end | |||
-- Compact mode: decapitalise first letter unless it looks like a tier prefix | |||
-- (e.g. "T1", "T2"). Also strips any trailing ".". | |||
local function human_note_compact(note) | |||
if not note or note == "" then return note end | |||
local first = note:sub(1,1) | |||
if first:match("%u") and not note:sub(2,2):match("%d") then | |||
note = first:lower() .. note:sub(2) | |||
end | end | ||
if | if note:sub(-1) == "." then note = note:sub(1, -2) end | ||
return note | |||
end | |||
-- ============================================================ | |||
-- Filtering | |||
-- ============================================================ | |||
local function filter_abilities(stat, abilities, key_lookup) | |||
local excluded = {} | |||
if Lists.exclude_abilities[stat] then | |||
for _, name in ipairs(Lists.exclude_abilities[stat]) do | |||
excluded[name] = true | |||
end | |||
end | end | ||
local result = {} | |||
for _, ability in ipairs(abilities) do | |||
local key = ability["Key"] | |||
local info = key and key_lookup[key] | |||
if info and not excluded[ability["Name"]] then | |||
local | local skip = false | ||
if | if stat == "dispelmagic" and info.abilityNum == 4 then | ||
skip = true | |||
end | |||
if not skip then | |||
table.insert(result, ability) | |||
end | |||
end | end | ||
end | end | ||
return result | |||
end | end | ||
-- ============================================================ | -- ============================================================ | ||
-- | -- Hero lookup | ||
-- ============================================================ | -- ============================================================ | ||
local | local _key_lookup = nil | ||
local | local _name_to_key = nil | ||
local function | local function build_lookup() | ||
if | if _key_lookup then return _key_lookup, _name_to_key end | ||
_key_lookup = {} | |||
_name_to_key = {} | |||
local hero_data = mw.loadJsonData("Data:HeroData.json") | local hero_data = mw.loadJsonData("Data:HeroData.json") | ||
| Line 105: | Line 127: | ||
end | end | ||
local cards = mw.loadJsonData("Data:AbilityCards.json") | |||
local cards | |||
for _, hero_entry in pairs(cards) do | for _, hero_entry in pairs(cards) do | ||
if type(hero_entry) == "table" then | if type(hero_entry) == "table" then | ||
| Line 115: | Line 134: | ||
for slot_str, ability in pairs(hero_entry) do | for slot_str, ability in pairs(hero_entry) do | ||
local slot_num = tonumber(slot_str) | local slot_num = tonumber(slot_str) | ||
if slot_num and type(ability) == "table" then | |||
local info = { heroName = hero_name, abilityNum = slot_num } | |||
if ability["Key"] then | |||
_key_lookup[ability["Key"]] = info | |||
end | |||
if ability["Name"] and ability["Key"] then | |||
_name_to_key[ability["Name"]] = ability["Key"] | |||
end | |||
end | end | ||
end | end | ||
| Line 124: | Line 148: | ||
end | end | ||
return _key_lookup, _name_to_key | |||
return | |||
end | end | ||
| Line 228: | Line 171: | ||
local compact = mw.text.trim(frame.args["compact"] or "") ~= "" | local compact = mw.text.trim(frame.args["compact"] or "") ~= "" | ||
local | local key_lookup, _ = build_lookup() | ||
local spec = extra_columns[stat] | local spec = extra_columns[stat] | ||
local headers = spec and spec.headers or {} | local headers = spec and spec.headers or {} | ||
| Line 236: | Line 177: | ||
local stat_notes = Notes[stat] | local stat_notes = Notes[stat] | ||
local | local abilities = GameData.get_entities(GameData.Dataset.ABILITIES, internal_keys) | ||
local filtered = filter_abilities(stat, abilities, key_lookup) | |||
if #filtered == 0 then | if #filtered == 0 then | ||
| Line 247: | Line 184: | ||
end | end | ||
local | table.sort(filtered, function(a, b) | ||
local | local ia = key_lookup[a["Key"]] | ||
local ib = key_lookup[b["Key"]] | |||
if not ia and not ib then return (a["Name"] or "") < (b["Name"] or "") end | |||
if not ia then return false end | |||
if not ib then return true end | |||
if ia.heroName ~= ib.heroName then return ia.heroName < ib.heroName end | |||
return ia.abilityNum < ib.abilityNum | |||
end) | |||
local edit_url = mw.uri.fullUrl("Module:AbilityTable", { action = "edit" }) | |||
local disclaimer = frame:preprocess( | local disclaimer = frame:preprocess( | ||
'<div class="ability-table-disclaimer">' | '<div class="ability-table-disclaimer">' | ||
.. | .. "This is an automatic list. " | ||
.. "[" .. tostring(edit_url) .. " Click here]" | |||
.. | .. " to add notes or correct the contents." | ||
.. | .. "</div>" | ||
.. | |||
) | ) | ||
| Line 262: | Line 206: | ||
local hero_order = {} | local hero_order = {} | ||
local hero_abilities = {} | local hero_abilities = {} | ||
for _, | for _, ability in ipairs(filtered) do | ||
local | local info = key_lookup[ability["Key"]] | ||
local hero = info and info.heroName or "—" | |||
if not hero_abilities[hero] then | if not hero_abilities[hero] then | ||
table.insert(hero_order, hero) | table.insert(hero_order, hero) | ||
hero_abilities[hero] = {} | hero_abilities[hero] = {} | ||
end | end | ||
table.insert(hero_abilities[hero], | table.insert(hero_abilities[hero], ability) | ||
end | end | ||
| Line 280: | Line 225: | ||
local extra = get_cells(ability) | local extra = get_cells(ability) | ||
if stat_notes and stat_notes[name] then | |||
local human = human_note_compact(stat_notes[name]) | |||
extra["Notes"] = extra["Notes"] and (extra["Notes"] .. "; " .. human) or human | |||
end | |||
local note = extra["Notes"] | local note = extra["Notes"] | ||
| Line 306: | Line 254: | ||
local needs_notes = (has_notes_header or stat_notes ~= nil) and not hide_set["Notes"] | 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 | if needs_notes then table.insert(final_headers, "Notes") end | ||
local out = {} | local out = {} | ||
table.insert(out, disclaimer) | table.insert(out, disclaimer) | ||
table.insert(out, '{| class=" | 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' | ||
| Line 327: | Line 267: | ||
table.insert(out, header_row) | table.insert(out, header_row) | ||
for _, ability in ipairs(filtered) do | |||
for _, | local info = key_lookup[ability["Key"]] | ||
local | |||
local hero_cell | |||
local | if info then | ||
hero_cell = frame:expandTemplate{ title = "HeroIcon", args = { info.heroName } } | |||
else | |||
hero_cell = "—" | |||
local ability_cell = frame:expandTemplate{ | end | ||
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 | |||
local human = human_note_full(stat_notes[ability["Name"]]) | |||
if | extra["Notes"] = extra["Notes"] and (extra["Notes"] .. ". " .. human) or human | ||
local | |||
end | end | ||
extra["Notes"] = ensure_period(extra["Notes"]) | |||
local row = '| class="ability-table-cell-hero" | ' .. hero_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] | ||