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 24: | Line 26: | ||
headers = { "Base Damage", "Heavy Melee Scaling", "Notes" }, | headers = { "Base Damage", "Heavy Melee Scaling", "Notes" }, | ||
get_cells = Renderers.RenderHeavyMelee, | get_cells = Renderers.RenderHeavyMelee, | ||
}, | }, | ||
["healreduce"] = { | ["healreduce"] = { | ||
| Line 40: | Line 38: | ||
headers = { "Dash Slow", "Notes" }, | headers = { "Dash Slow", "Notes" }, | ||
get_cells = Renderers.RenderDashSlow, | get_cells = Renderers.RenderDashSlow, | ||
}, | }, | ||
} | } | ||
| Line 75: | Line 69: | ||
extra["Notes"] = extra["Notes"] and (extra["Notes"] .. "; " .. human_note) or human_note | extra["Notes"] = extra["Notes"] and (extra["Notes"] .. "; " .. human_note) or human_note | ||
end | end | ||
end | end | ||
-- ============================================================ | -- ============================================================ | ||
-- Membership | -- Membership | ||
-- | -- Shared source of truth for "is ability X a member of list Y". | ||
-- | -- Also consumed by Module:AbilityInteractions to decide which | ||
-- interaction icons to show on ability cards. | |||
-- ============================================================ | -- ============================================================ | ||
| Line 185: | Line 97: | ||
end | end | ||
-- Public: does ability | -- Public: does an ability record belong to list `stat`? | ||
function p.is_member(stat, | -- record an entry from Data:AbilityData.json | ||
-- ability_num the ability's slot (1-4), used by special rules | |||
function p.is_member(stat, record, ability_num) | |||
local props = Lists.lists[stat] | local props = Lists.lists[stat] | ||
if not props then return false end | if not props then return false end | ||
local name = record["Name"] | |||
if name and excluded_set(stat)[name] then return false end | |||
if not special_ok(stat, record, ability_num) then return false end | |||
return GameData.entity_matches(record, props) | |||
end | |||
-- ============================================================ | |||
-- Filtering | |||
-- ============================================================ | |||
local function filter_abilities(stat, abilities, key_lookup) | |||
local result = {} | |||
for _, ability in ipairs(abilities) do | |||
local info = ability["Key"] and key_lookup[ability["Key"]] | |||
if info and p.is_member(stat, ability, info.abilityNum) then | |||
table.insert(result, ability) | |||
end | |||
end | end | ||
return result | |||
end | |||
local | -- ============================================================ | ||
-- Hero lookup | |||
-- ============================================================ | |||
local _key_lookup = nil | |||
local _name_to_key = nil | |||
local function build_lookup() | |||
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 active_heroes = {} | |||
for _, hero in pairs(hero_data) do | |||
if type(hero) == "table" | |||
and hero["IsDisabled"] == false | |||
and type(hero["Name"]) == "string" | |||
and (hero["IsSelectable"] == nil or hero["IsSelectable"] ~= false) | |||
then | |||
active_heroes[hero["Name"]] = true | |||
end | |||
end | |||
local cards = mw.loadJsonData("Data:AbilityCards.json") | |||
if | for _, hero_entry in pairs(cards) do | ||
if type(hero_entry) == "table" then | |||
local hero_name = hero_entry["Name"] | |||
if hero_name and active_heroes[hero_name] then | |||
for slot_str, ability in pairs(hero_entry) do | |||
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 | |||
end | |||
return | return _key_lookup, _name_to_key | ||
end | end | ||
| Line 227: | Line 191: | ||
local compact = mw.text.trim(frame.args["compact"] or "") ~= "" | local compact = mw.text.trim(frame.args["compact"] or "") ~= "" | ||
local collapsed = mw.text.trim(frame.args["collapsed"] or ""):lower() | local collapsed = mw.text.trim(frame.args["collapsed"] or ""):lower() | ||
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 200: | ||
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 | ||
return "No abilities found for list: " .. stat | return "No abilities found for list: " .. stat | ||
end | end | ||
table.sort(filtered, function(a, b) | |||
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 lists_url = mw.uri.fullUrl("Module:AbilityTable/Lists") | local lists_url = mw.uri.fullUrl("Module:AbilityTable/Lists") | ||
| Line 262: | Line 232: | ||
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 327: | Line 298: | ||
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 | |||
if info then | |||
hero_cell = frame:expandTemplate{ title = "HeroIcon", args = { info.heroName } } | |||
else | |||
hero_cell = "—" | |||
end | |||
local ability_cell = frame:expandTemplate{ title = "AbilityIcon", args = { ability["Name"] } } | |||
local ability_cell = frame:expandTemplate{ | |||
local extra = get_cells(ability) | local extra = get_cells(ability) | ||
enrich_notes_full(extra, stat_notes and stat_notes[ability["Name"]]) | enrich_notes_full(extra, stat_notes and stat_notes[ability["Name"]]) | ||
local | 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] | ||