Module:Sandbox/Vergir: Difference between revisions

Vergir (talk | contribs)
Test draft: generic StatScaling builder, base + scaling cells (with help from vergir-bot LLM)
Vergir (talk | contribs)
Final test draft of StatScaling before publishing (with help from vergir-bot LLM)
Line 4: Line 4:
-- Each public function below renders one table. The shared work lives in
-- Each public function below renders one table. The shared work lives in
-- build_scaling_table(), so adding a table for another scaling type (Boons,
-- build_scaling_table(), so adding a table for another scaling type (Boons,
-- for instance) only takes a new wrapper naming its data key and caption.
-- for instance) only takes a new wrapper naming its scaling type.
--
--
-- {{#invoke:Sandbox/Vergir|write_spirit_scaling_table}}
-- {{#invoke:Sandbox/Vergir|write_spirit_scaling_table}}
Line 15: Line 15:
local dictionary_module = require('Module:Dictionary')
local dictionary_module = require('Module:Dictionary')
local hero_data_module  = require('Module:HeroData')
local hero_data_module  = require('Module:HeroData')
-- Never listed: both are derived from the weapon stats that are already
-- listed in their own right, so they only ever duplicate a row.
local EXCLUDED_STATS = {
DPS = true,
SustainedDPS = true,
}
-- Per stat handling of the base value shown before the scaling.
--  text:    printed verbatim, for stats the data holds no base value for
--  sig_figs: rounds an over-precise base value
local BASE_DISPLAY = {
BulletResist    = {text = "0%"},
TechResist      = {text = "0%"},
RoundsPerSecond = {sig_figs = 3},
}


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Line 28: Line 44:
table.sort(keys)
table.sort(keys)
return 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
end


Line 70: Line 78:
end
end


-- "6.3 + x0.0084", or just the scaling for stats that have no base value
-- Base value as displayed, or nil when the stat has none to show.
-- (percentage stats such as Fire Rate and the resistances).
local function base_value(hero_data, stat)
local display = BASE_DISPLAY[stat]
if (display ~= nil and display.text ~= nil) then return display.text end
 
local base = hero_data_module.get_stat(hero_data, stat)
if (type(base) ~= "number") then return nil end
if (display ~= nil and display.sig_figs ~= nil) then
base = util_module.round_to_sig_fig(base, display.sig_figs)
end
return tostring(base)
end
 
-- "6.3 + x0.0084", or the scaling alone when there is no base value to show.
local function scaling_cell(hero_data, stat, value, scaling_type)
local function scaling_cell(hero_data, stat, value, scaling_type)
local scaling_str = hero_data_module.write_scalar_str(value, scaling_type)
local scaling_str = hero_data_module.write_scalar_str(value, scaling_type)
local base = hero_data_module.get_stat(hero_data, stat)
local base = base_value(hero_data, stat)
if (type(base) ~= "number") then return scaling_str end
if (base == nil) then return scaling_str end
return base .. ' + ' .. scaling_str
return base .. ' + ' .. scaling_str
end
end
Line 82: Line 102:
-- zeroes, ordered by localized stat name:
-- zeroes, ordered by localized stat name:
--  { { stat = , label = , value = }, ... }
--  { { stat = , label = , value = }, ... }
local function hero_scalings(hero_data, scaling_key, excluded_stats)
local function hero_scalings(hero_data, scaling_key)
local scalings = {}
local scalings = {}
local hero_scaling_data = hero_data[scaling_key]
local hero_scaling_data = hero_data[scaling_key]
for _, stat in ipairs(sorted_keys(hero_scaling_data)) do
for _, stat in ipairs(sorted_keys(hero_scaling_data)) do
local value = hero_scaling_data[stat]
local value = hero_scaling_data[stat]
if (not excluded_stats[stat] and type(value) == "number" and value ~= 0) then
if (not EXCLUDED_STATS[stat] and type(value) == "number" and value ~= 0) then
table.insert(scalings, {stat = stat, label = stat_label(stat), value = value})
table.insert(scalings, {stat = stat, label = stat_label(stat), value = value})
end
end
Line 102: Line 122:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------


-- options:
-- scaling_type: "Spirit" or "Level", picking both the <type>Scaling data key
--  scaling_type: "Spirit" or "Level", picks both the <type>Scaling data key
-- and the scaling template ({{Ss}} or {{PI}}).
--                 and the scaling template ({{Ss}} or {{PI}})
local function build_scaling_table(scaling_type)
--  caption_key:  [[Data:Dictionary]] key for the table caption
local scaling_key = scaling_type .. "Scaling"
--  excluded_stats: set of stat keys to leave out
local function build_scaling_table(options)
local scaling_key = options.scaling_type .. "Scaling"


-- Collect the heroes that have anything left to show
-- Collect the heroes that have anything to show
local rows = {}
local rows = {}
for _, hero_key in ipairs(sorted_keys(heroes_data)) do
for _, hero_key in ipairs(sorted_keys(heroes_data)) do
local hero_data = heroes_data[hero_key]
local hero_data = heroes_data[hero_key]
if (not hero_data["InDevelopment"] and not hero_data["IsDisabled"]) then
if (not hero_data["InDevelopment"] and not hero_data["IsDisabled"]) then
local scalings = hero_scalings(hero_data, scaling_key, options.excluded_stats)
local scalings = hero_scalings(hero_data, scaling_key)
if (#scalings > 0) then
if (#scalings > 0) then
table.insert(rows, {
table.insert(rows, {
Line 131: Line 148:
-- Build the table
-- Build the table
local output = {
local output = {
'{| class="wikitable"',
'{| class="wikitable sortable"',
'|+ ' .. dictionary_module.translate(options.caption_key),
'! ' .. dictionary_module.translate("Hero"),
'! ' .. dictionary_module.translate("Hero"),
'! ' .. dictionary_module.translate("Stats"),
'! ' .. dictionary_module.translate("Stats"),
Line 141: Line 157:
table.insert(output, '|-')
table.insert(output, '|-')
if (index == 1) then
if (index == 1) then
local rowspan = ''
local attributes = 'data-sort-value="' .. row.sort_name .. '"'
if (#row.scalings > 1) then rowspan = ' rowspan="' .. #row.scalings .. '" |' end
if (#row.scalings > 1) then
table.insert(output, '|' .. rowspan .. ' ' .. hero_icon(row.key, row.data))
attributes = attributes .. ' rowspan="' .. #row.scalings .. '"'
end
table.insert(output, '| ' .. attributes .. ' | ' .. hero_icon(row.key, row.data))
end
end
table.insert(output, '| ' .. scaling.label)
table.insert(output, '| ' .. scaling.label)
table.insert(output, '| ' ..
table.insert(output, '| ' .. scaling_cell(row.data, scaling.stat, scaling.value, scaling_type))
scaling_cell(row.data, scaling.stat, scaling.value, options.scaling_type))
end
end
end
end
Line 160: Line 177:


-- Hero base stats that scale with Spirit Power.
-- Hero base stats that scale with Spirit Power.
--{{#invoke:Sandbox/Vergir|write_spirit_scaling_table|exclude=}}
--{{#invoke:Sandbox/Vergir|write_spirit_scaling_table}}
-- exclude: comma separated stat keys to leave out. Defaults to DPS and
--          SustainedDPS, which are both derived from stats already listed.
--          Pass an empty value to list every stat.
function p.write_spirit_scaling_table(frame)
function p.write_spirit_scaling_table(frame)
local args = frame.args or {}
return build_scaling_table("Spirit")
return build_scaling_table{
scaling_type = "Spirit",
caption_key = "HeroSpiritScalingCaption",
excluded_stats = to_set(args["exclude"] or "DPS,SustainedDPS"),
}
end
end


return p
return p