Module:Sandbox/LVL: Difference between revisions

LVL (talk | contribs)
No edit summary
LVL (talk | contribs)
No edit summary
Line 465: Line 465:
display_scaling_icons = true
display_scaling_icons = true
end
end
-- Initializations and declarations
local body_rows_str = ""
local in_development
local is_disabled
local template_title = ""
local template_args = {}
local hero_icon
local hero_td_style
local scalar_str
-- Add hero comp stats to  
-- Add hero comp stats to  
local stats_to_include = {
local stats_to_include = {
Weapon = {
Weapon = {
"DPS",
"DPS", "SustainedDPS", "BulletDamage", "RoundsPerSecond", "FireRate", "ClipSize", "ReloadTime", "ReloadDelay", "BulletsPerShot", "BulletsPerBurst", "BurstInterShotInterval", "LightMeleeDamage", "HeavyMeleeDamage", "ReloadSingle", "BulletSpeed", "BulletGravityScale", "FalloffStartRange", "FalloffEndRange", "BonusAttackRange", "RoundsPerSecondAtMaxSpin", "SpinAcceleration", "SpinDeceleration"
            "SustainedDPS",
            "BulletDamage",
            "RoundsPerSecond",
            "FireRate",
            "ClipSize",
            "ReloadTime",
            "ReloadDelay",
            "BulletsPerShot",
            "BulletsPerBurst",
            "BurstInterShotInterval",
            "LightMeleeDamage",
            "HeavyMeleeDamage",
            "ReloadSingle",
            "BulletSpeed",
            "BulletGravityScale",
            "FalloffStartRange",
            "FalloffEndRange",
            "BonusAttackRange",
            "RoundsPerSecondAtMaxSpin",
            "SpinAcceleration",
            "SpinDeceleration"
},
},
Vitality = {
Vitality = {
"MaxHealth",
"MaxHealth", "BaseHealthRegen", "BulletResist", "TechResist", "CritDamageReceivedScale", "MaxMoveSpeed", "SprintSpeed", "StaminaCooldown", "Stamina"
            "BaseHealthRegen",
            "BulletResist",
            "TechResist",
            "CritDamageReceivedScale",
            "MaxMoveSpeed",
            "SprintSpeed",
            "StaminaCooldown",
            "Stamina"
}
}
}
}
-- Use mw.html builder to construct the table safely
local table = mw.html.create('table')
:addClass('wikitable sortable')
:cssText('table-layout: auto; width: 100%;')
-- Iterate heroes
-- Build Header
local thead = table:tag('thead')
local header_row = thead:tag('tr')
-- Top-left corner cell
header_row:tag('th')
:cssText('position: sticky; top: 0; left: 0; z-index: 2; background-color: ' .. sticky_header_bg .. ';')
:wikitext('Hero')
local category_data = attribute_module.get_category_data()
local postfix_key_map = {
["ReloadDelay"] = "StatDesc_ReloadTime_postfix", ["BulletsPerShot"] = "", ["BulletsPerBurst"] = "", ["BurstInterShotInterval"] = "StatDesc_ReloadTime_postfix", ["ReloadSingle"] = "", ["BonusAttackRange"] = "StatDesc_WeaponRangeFalloffMax_postfix", ["SustainedDPS"] = "DPS_postfix", ["RoundsPerSecondAtMaxSpin"] = "", ["SpinAcceleration"] = "BonusFireRate_postfix", ["SpinDeceleration"] = "BonusFireRate_postfix"
}
for _, category in ipairs(attribute_orders["category_order"]) do
local category_attrs = attributes_data[category]
local category_rgb = category_data[category]["rgb"]
if (stats_to_include[category] ~= nil) then
for _, attr_key in ipairs(stats_to_include[category]) do
local attr_data = category_attrs[attr_key]
local attr_localized, postfix
if (attr_data ~= nil) then
attr_localized = lang_module.get_string(attr_data["label"])
if (attr_localized == nil or attr_localized == "") then attr_localized = util_module.add_space_before_cap(attr_key) end
postfix = lang_module.get_string(attr_data["postfix"])
if (postfix == nil or postfix == "") then postfix = "" else postfix = " (" .. postfix .. ")" end
else
attr_localized = dictionary_module.translate(attr_key)
postfix = lang_module.get_string(postfix_key_map[attr_key])
if postfix == nil then return "attr_key " .. attr_key .. " must be added to postfix_key_map" end
if postfix ~= "" then postfix = " (" .. postfix .. ")" end
end
header_row:tag('th')
:cssText('position: sticky; top: 0; z-index: 1; background-color: rgb(' .. category_rgb .. ');')
:wikitext(attr_localized .. postfix)
end
end
end
 
-- Build Body
local tbody = table:tag('tbody')
for hero_key, hero_data in pairs(heroes_data) do
for hero_key, hero_data in pairs(heroes_data) do
-- Ensure they are not in development and they are an active hero
local in_development = hero_data["InDevelopment"]
in_development = hero_data["InDevelopment"]
if (not in_development) then
if (not in_development) then
is_disabled = hero_data["IsDisabled"]
local is_disabled = hero_data["IsDisabled"]
if (not is_disabled) then  
if (not is_disabled) then  
local body_row = tbody:tag('tr')
local row_content = ""
-- Hero Icon cell
local hero_name = localize(hero_key, hero_key)
local hero_name_en = hero_data["Name"]
local hero_icon_args = { [1] = hero_name_en, [2] = hero_name }
local hero_icon = frame:expandTemplate{ title = "Template:HeroIcon", args = hero_icon_args }
-- Retrieve hero's localized name
body_row:tag('td')
hero_name = localize(hero_key, hero_key)
:cssText('position: sticky; left: 0; z-index: 1; background-color: ' .. sticky_cell_bg .. ';')
:wikitext(hero_icon)
-- Retrieve hero's english name, used for hero icon
hero_name_en = hero_data["Name"]
-- Stat cells
-- Expand hero icon
template_title = "Template:HeroIcon"
template_args[1] = hero_name_en
template_args[2] = hero_name
hero_icon = mw.getCurrentFrame():expandTemplate{ title = template_title, args = template_args }
-- First column in each row is hero name. Make it sticky. Add z-index to fix overlap.
row_content = row_content .. '<td style="position: sticky; left: 0; z-index: 1; background-color: ' .. sticky_cell_bg .. ';">' .. hero_icon .. "</td>"
-- Consecutive columns are then stats
-- Iterate categories
for _, category in ipairs(attribute_orders["category_order"]) do
for _, category in ipairs(attribute_orders["category_order"]) do
category_attrs = attributes_data[category]
-- Iterate attributes within the category
if (stats_to_include[category] ~= nil) then
if (stats_to_include[category] ~= nil) then
for _, attr_key in ipairs(stats_to_include[category]) do
for _, attr_key in ipairs(stats_to_include[category]) do
local stat_value = hero_data[attr_key]
--Retrieve the stats value from hero data
stat_value = hero_data[attr_key]
if (stat_value == nil) then stat_value = 0 end
if (stat_value == nil) then stat_value = 0 end
-- Retrieve scaling val and str if it scales
local scaling_data = p.get_hero_scaling_data(hero_data, attr_key)
local scaling_data = p.get_hero_scaling_data(hero_data, attr_key)
local scaling_strs = ""
local scaling_strs = ""
if (scaling_data ~= nil) then
if (scaling_data ~= nil) then
for scaling_value, scaling_type in pairs(scaling_data) do
for scaling_val, scaling_type in pairs(scaling_data) do
local scaling_str = p.write_scalar_str(scaling_value, scaling_type)
local scaling_str = p.write_scalar_str(scaling_val, scaling_type)
if (scaling_str ~= "") then scaling_str = " " .. scaling_str end
if (scaling_str ~= "") then scaling_str = " " .. scaling_str end
if (scaling_str ~= nil) then
if (scaling_str ~= nil) then scaling_strs = scaling_strs .. scaling_str end
scaling_strs = scaling_strs .. scaling_str  
end
-- Scale the stat value
if (scaling_type == "Spirit") then
if (scaling_type == "Spirit") then
stat_value = stat_value + (spirit_power * scaling_value)
stat_value = stat_value + (spirit_power * scaling_val)
elseif (scaling_type == "Level") then
elseif (scaling_type == "Level") then
if attr_key == 'TechResist' or attr_key == 'BulletResist' then
if attr_key == 'TechResist' or attr_key == 'BulletResist' then
-- each PI for resists is multiplicative
stat_value = (stat_value/100 + 1 - (1-scaling_val/100)^power_increases)*100
stat_value = (stat_value/100 + 1 - (1-scaling_value/100)^power_increases)*100
else
else
stat_value = stat_value + (power_increases * scaling_value)
stat_value = stat_value + (power_increases * scaling_val)
end
end
end
end
Line 579: Line 570:
if (not display_scaling_icons) then scaling_strs = "" end
if (not display_scaling_icons) then scaling_strs = "" end
-- Convert from boolean to string, or round it
if (type(stat_value)) == 'boolean' then
if (type(stat_value)) == 'boolean' then
stat_value = tostring(stat_value)
stat_value = tostring(stat_value)
Line 588: Line 576:
end
end
-- Add it to the row
body_row:tag('td'):wikitext(stat_value .. scaling_strs)
row_content = row_content .. "<td>" .. stat_value .. scaling_strs .. "</td>"
end
end
end
end
end
-- Add row to the body
body_rows_str = body_rows_str .. "<tr>" .. row_content .. "</tr>"
end
end
end
end
end
-- Wrap body rows in tbody for semantic HTML and correct sticky behavior
local body_str = "<tbody>" .. body_rows_str .. "</tbody>"
-- First header is Hero. The top-left corner cell needs to be sticky in both directions.
local header_cells_str = '<th style="position: sticky; top: 0; left: 0; z-index: 2; background-color: ' .. sticky_header_bg .. ';">' .. "Hero" .. "</th>"
local header_style
local category_data = attribute_module.get_category_data()
local postfix
-- Used for keys that are not localized by Valve
local postfix_key_map = {
["ReloadDelay"] = "StatDesc_ReloadTime_postfix",
["BulletsPerShot"] = "",
["BulletsPerBurst"] = "",
["BurstInterShotInterval"] = "StatDesc_ReloadTime_postfix",
["ReloadSingle"] = "",
["BonusAttackRange"] = "StatDesc_WeaponRangeFalloffMax_postfix",
["SustainedDPS"] = "DPS_postfix",
["RoundsPerSecondAtMaxSpin"] = "",
["SpinAcceleration"] = "BonusFireRate_postfix",
["SpinDeceleration"] = "BonusFireRate_postfix"
}
-- Base style for headers to avoid recreating the string in the loop
local header_base_style = ' style="position: sticky; top: 0; z-index: 1; background-color: rgb('
-- Iterate stats again for displaying headers with their respective color
for _, category in ipairs(attribute_orders["category_order"]) do
category_attrs = attributes_data[category]
category_rgb = category_data[category]["rgb"]
-- Iterate attributes within the category
if (stats_to_include[category] ~= nil) then
for _, attr_key in ipairs(stats_to_include[category]) do
attr_data = category_attrs[attr_key]
if (attr_data ~= nil) then
-- Localize, fallback to attr_key with proper spaces
attr_localized = lang_module.get_string(attr_data["label"])
if (attr_localized == nil or attr_localized == "") then attr_localized = util_module.add_space_before_cap(attr_key) end
-- Get postfix
postfix = lang_module.get_string(attr_data["postfix"])
if (postfix == nil or postfix == "") then
postfix = ""
else
postfix = " (" .. postfix .. ")"
end
else -- If not in attributes data, use dictionary translate and postfix
attr_localized = dictionary_module.translate(attr_key)
postfix = lang_module.get_string(postfix_key_map[attr_key])
if postfix == nil then
return "attr_key " .. attr_key .. " must be added to postfix_key_map"
end
if postfix ~= "" then
postfix = " (" .. postfix .. ")"
end
end
-- Make header cells sticky to the top (for vertical scrolling). z-index: 1 keeps them above the body but below the corner cell.
header_style = header_base_style .. category_rgb .. ');"'
header_cells_str = header_cells_str .. "<th" .. header_style .. ">" .. attr_localized .. postfix .. "</th>"
end
end
end
end
end
-- Wrap header cells in thead and tr for semantic HTML and correct sticky behavior
local headers_str = "<thead><tr>" .. header_cells_str .. "</tr></thead>"


local table_str = '<table class="wikitable sortable" style="table-layout: auto; width: 100%;">' .. headers_str .. body_str .. "</table>"
-- Final wrapper div
local output_str = '<div style="overflow-x: auto; width: 100%;">' .. table_str .. '</div>'
local div = mw.html.create('div')
return output_str
:cssText('overflow-x: auto; width: 100%;')
:node(table)
 
return tostring(div)
end
end