Editing Module:Sandbox/VergirGive feedback
Jump to navigation
Jump to search
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 1: | Line 1: | ||
-- Renders a table of hero base stats that scale with Spirit Power, built from | |||
-- the SpiritScaling entries in [[Data:HeroData.json]]. | |||
-- {{#invoke:Sandbox/Vergir|write_spirit_scaling_table}} | |||
local p = {} | local p = {} | ||
local heroes_data = mw.loadJsonData("Data:HeroData.json") | |||
local attributes_data = mw.loadJsonData("Data:AttributeData.json") | |||
local util_module = require('Module:Utilities') | |||
local lang_module = require('Module:Lang') | |||
local dictionary_module = require('Module:Dictionary') | |||
local hero_data_module = require('Module:HeroData') | |||
-- Stats left out by default. Both are derived from stats that are already | |||
-- listed in their own right, so including them would duplicate every row. | |||
local DEFAULT_EXCLUDED_STATS = "DPS,SustainedDPS" | |||
-------------------------------------------------------------------------------- | |||
-- Helpers | |||
-------------------------------------------------------------------------------- | |||
-- next() ignores metamethods and mw.loadJsonData hands back proxy tables, so | |||
-- keys always have to be collected through pairs() rather than tested with next(). | |||
local function sorted_keys(tbl) | |||
local keys = {} | |||
if (tbl == nil) then return keys end | |||
for key in pairs(tbl) do table.insert(keys, key) end | |||
table.sort(keys) | |||
return keys | |||
end | |||
-- Comma or whitespace separated list to a set. | |||
local function to_set(list) | |||
local set = {} | |||
if (list == nil) then return set end | |||
for entry in string.gmatch(list, "[^,%s]+") do set[entry] = true end | |||
return set | |||
end | |||
local function missing_translation_tooltip() | |||
return mw.getCurrentFrame():expandTemplate{title = "MissingValveTranslationTooltip"} | |||
end | |||
-- Localized name of a stat, resolved in three steps: | |||
-- 1. [[Data:AttributeData.json]] label -> Valve's own translation | |||
-- 2. [[Data:Dictionary]] entry, for stats Valve has no label for | |||
-- 3. the raw key, spaced out, with a missing-translation tooltip | |||
local function stat_label(stat) | |||
for _, category in pairs(attributes_data) do | |||
local attribute = category[stat] | |||
if (attribute ~= nil and attribute["label"] ~= nil) then | |||
local localized = lang_module.get_string(attribute["label"]) | |||
if (localized ~= nil and localized ~= '') then return localized end | |||
end | |||
end | |||
local translated = dictionary_module.translate(stat) | |||
if (translated ~= nil and translated:sub(1, 5) ~= "Key '") then return translated end | |||
return util_module.add_space_before_cap(stat) .. missing_translation_tooltip() | |||
end | |||
-- Heroes are listed as they are read, so "The Doorman" sorts under D. | |||
local function sort_name(hero_data, hero_key) | |||
return (hero_data["Name"] or hero_key):gsub("^The ", "") | |||
end | |||
local function hero_icon(hero_key, hero_data) | |||
local template_args = { | |||
[1] = hero_data["Name"] or hero_key, | |||
l1 = lang_module.get_string(hero_key), | |||
} | |||
return mw.getCurrentFrame():expandTemplate{title = "HeroIcon", args = template_args} | |||
end | |||
-- Every Spirit scaling a hero has, minus the excluded stats and any zeroes, | |||
-- ordered by localized stat name: { { stat = , label = , value = }, ... } | |||
local function hero_scalings(hero_data, excluded_stats) | |||
local scalings = {} | |||
for _, stat in ipairs(sorted_keys(hero_data["SpiritScaling"])) do | |||
local value = hero_data["SpiritScaling"][stat] | |||
if (not excluded_stats[stat] and type(value) == "number" and value ~= 0) then | |||
table.insert(scalings, {stat = stat, label = stat_label(stat), value = value}) | |||
end | |||
end | |||
table.sort(scalings, function(a, b) | |||
if (a.label == b.label) then return a.stat < b.stat end | |||
return a.label < b.label | |||
end) | |||
return scalings | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Wikitext entry point | |||
-------------------------------------------------------------------------------- | |||
--{{#invoke:Sandbox/Vergir|write_spirit_scaling_table|exclude=|include_unreleased=}} | |||
-- exclude: comma separated stat keys to leave out, defaults to | |||
-- "DPS,SustainedDPS". Pass an empty value to list every stat. | |||
-- include_unreleased: "yes" to also list heroes flagged InDevelopment or IsDisabled. | |||
function p.write_spirit_scaling_table(frame) | |||
local args = frame.args or {} | |||
local excluded_stats = to_set(args["exclude"] or DEFAULT_EXCLUDED_STATS) | |||
local include_unreleased = (args["include_unreleased"] == "yes" or args["include_unreleased"] == "true") | |||
-- Collect the heroes that have anything left to show | |||
local rows = {} | |||
for _, hero_key in ipairs(sorted_keys(heroes_data)) do | |||
local hero_data = heroes_data[hero_key] | |||
local released = not hero_data["InDevelopment"] and not hero_data["IsDisabled"] | |||
if (released or include_unreleased) then | |||
local scalings = hero_scalings(hero_data, excluded_stats) | |||
if (#scalings > 0) then | |||
table.insert(rows, { | |||
key = hero_key, | |||
data = hero_data, | |||
sort_name = sort_name(hero_data, hero_key), | |||
scalings = scalings, | |||
}) | |||
end | |||
end | |||
end | |||
if (#rows == 0) then return '' end | |||
table.sort(rows, function(a, b) return a.sort_name < b.sort_name end) | |||
-- Build the table | |||
local output = { | |||
'{| class="wikitable"', | |||
'|+ ' .. dictionary_module.translate("SpiritScalingTableCaption"), | |||
'! ' .. dictionary_module.translate("Hero"), | |||
'! ' .. dictionary_module.translate("Stats"), | |||
'! ' .. dictionary_module.translate("Scaling"), | |||
} | |||
for _, row in ipairs(rows) do | |||
for index, scaling in ipairs(row.scalings) do | |||
table.insert(output, '|-') | |||
if (index == 1) then | |||
local rowspan = '' | |||
if (#row.scalings > 1) then rowspan = ' rowspan="' .. #row.scalings .. '" |' end | |||
table.insert(output, '|' .. rowspan .. ' ' .. hero_icon(row.key, row.data)) | |||
end | |||
table.insert(output, '| ' .. scaling.label) | |||
table.insert(output, '| ' .. hero_data_module.write_scalar_str(scaling.value, "Spirit")) | |||
end | |||
end | |||
table.insert(output, '|}') | |||
return table.concat(output, '\n') | |||
end | |||
return p | return p | ||