Editing Module:Sandbox/LVLGive 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 29: | Line 29: | ||
return result | return result | ||
end | end | ||
p.write_hero_comparison_table = function(frame) | p.write_hero_comparison_table = function(frame) | ||
| Line 123: | Line 38: | ||
local display_scaling_icons = (power_increases == 0 and spirit_power == 0) | local display_scaling_icons = (power_increases == 0 and spirit_power == 0) | ||
local body_str = "" | local body_str = "" | ||
local stats_to_include = { | local stats_to_include = { | ||
Weapon = { | Weapon = { | ||
"DPS", "SustainedDPS", "BulletDamage", "RoundsPerSecond", "FireRate", | "DPS", "SustainedDPS", "BulletDamage", "RoundsPerSecond", "FireRate", | ||
"ClipSize", "ReloadTime", "ReloadDelay | "ClipSize", "ReloadTime", "ReloadDelay", "BulletsPerShot", "BulletsPerBurst", | ||
"BurstInterShotInterval", "LightMeleeDamage", "HeavyMeleeDamage", | "BurstInterShotInterval", "LightMeleeDamage", "HeavyMeleeDamage", | ||
"BulletSpeed", "FalloffStartRange", "FalloffEndRange", | "ReloadSingle", "BulletSpeed", "FalloffStartRange", "FalloffEndRange", | ||
"CritDamageBonusPercent | "CritDamageBonusPercent", "RoundsPerSecondAtMaxSpin", "SpinAcceleration", "SpinDeceleration" | ||
}, | }, | ||
Vitality = { | Vitality = { | ||
| Line 141: | Line 56: | ||
} | } | ||
-- Collect and sort heroes | -- Collect and sort heroes | ||
local sorted_heroes = {} | local sorted_heroes = {} | ||
for hero_key, hero_data in pairs(heroes_data) do | for hero_key, hero_data in pairs(heroes_data) do | ||
| Line 155: | Line 70: | ||
end) | end) | ||
-- | -- Shared stat cell builder | ||
local function buildStatCell(hero_data, hero_key, attr_key, is_alt_fire, category) | local function buildStatCell(hero_data, hero_key, attr_key, is_alt_fire, category) | ||
local base_value | local base_value | ||
if is_alt_fire then | if is_alt_fire then | ||
if attr_key == "ClipSize | if attr_key == "ClipSize" then | ||
base_value = get_nested_stat_value(hero_data, attr_key) | base_value = get_nested_stat_value(hero_data, attr_key) | ||
elseif hero_data.Weapon and hero_data.Weapon.AltFire | elseif hero_data.Weapon and hero_data.Weapon.AltFire | ||
| Line 175: | Line 84: | ||
else | else | ||
base_value = get_nested_stat_value(hero_data, attr_key) | base_value = get_nested_stat_value(hero_data, attr_key) | ||
end | end | ||
local stat_value = base_value | local stat_value = base_value | ||
local scaling_data | local scaling_data | ||
if is_alt_fire then | if is_alt_fire then | ||
if attr_key == "ClipSize" | if attr_key == "ClipSize" then | ||
scaling_data = hero_data_module.get_hero_scaling_data(hero_data, attr_key) | |||
elseif hero_key == "hero_shiv" and attr_key == "BulletDamage" then | |||
scaling_data = hero_data_module.get_hero_scaling_data(hero_data, attr_key) | scaling_data = hero_data_module.get_hero_scaling_data(hero_data, attr_key) | ||
elseif hero_data.Weapon and hero_data.Weapon.AltFire | elseif hero_data.Weapon and hero_data.Weapon.AltFire | ||
and hero_data.Weapon.AltFire[attr_key] ~= nil then | and hero_data.Weapon.AltFire[attr_key] ~= nil then | ||
| Line 220: | Line 106: | ||
local spirit_scale = 0 | local spirit_scale = 0 | ||
local level_scale = 0 | local level_scale = 0 | ||
if scaling_data ~= nil then | if scaling_data ~= nil then | ||
for scaling_val, scaling_type in pairs(scaling_data) do | for scaling_val, scaling_type in pairs(scaling_data) do | ||
local scaling_str = hero_data_module.write_scalar_str(scaling_val, scaling_type, true) | |||
if scaling_str ~= "" then scaling_str = " " .. scaling_str end | |||
if scaling_str ~= nil then | |||
scaling_strs = scaling_strs .. scaling_str | |||
end | |||
if scaling_type == "Spirit" then | if scaling_type == "Spirit" then | ||
spirit_scale = scaling_val | |||
stat_value = stat_value + (spirit_power * scaling_val) | |||
elseif scaling_type == "Level" then | elseif scaling_type == "Level" then | ||
level_scale = scaling_val | |||
stat_value = stat_value + (power_increases * scaling_val) | |||
end | end | ||
end | end | ||
end | end | ||
if attr_key == "TechPower" and spirit_scale == 0 then | if attr_key == "TechPower" and spirit_scale == 0 then | ||
spirit_scale = 1.0 | spirit_scale = 1.0 | ||
stat_value = stat_value + (spirit_power * spirit_scale) | |||
end | end | ||
local innate_spirit_scale = | local innate_spirit_scale = (hero_data["LevelScaling"] and hero_data["LevelScaling"]["TechPower"]) or 0 | ||
if not display_scaling_icons then scaling_strs = "" end | if not display_scaling_icons then scaling_strs = "" end | ||
if type(stat_value) == "boolean" then | if type(stat_value) == "boolean" then stat_value = tostring(stat_value) | ||
else stat_value = util_module.round_to_sig_fig(stat_value, 3) end | |||
else | |||
local cell_inner = string.format( | local cell_inner = string.format( | ||
'<span class="stat-num">%s</span><span class="stat-scaling">%s</span>', | '<span class="stat-num">%s</span><span class="stat-scaling">%s</span>', | ||
stat_value, | stat_value, scaling_strs | ||
) | ) | ||
| Line 281: | Line 144: | ||
end | end | ||
local hit_once = "false" | local hit_once = "false" | ||
if (attr_key == "DPS" or attr_key == "SustainedDPS") | if (attr_key == "DPS" or attr_key == "SustainedDPS") and weapon_table and weapon_table.HitOnceAcrossAllBullets then | ||
hit_once = "true" | hit_once = "true" | ||
end | end | ||
| Line 298: | Line 158: | ||
hit_once | hit_once | ||
) | ) | ||
return string.format('<td style="white-space: nowrap;" %s>%s</td>', data_attrs, cell_inner) | return string.format('<td style="white-space: nowrap;" %s>%s</td>', data_attrs, cell_inner) | ||
end | end | ||
-- | -- Primary row generator | ||
local function generatePrimaryRow(hero_data, hero_key, has_alt) | local function generatePrimaryRow(hero_data, hero_key, has_alt) | ||
local row_str = "" | local row_str = "" | ||
| Line 309: | Line 168: | ||
local template_args = {[1] = hero_name_en, l1 = hero_name_local} | local template_args = {[1] = hero_name_en, l1 = hero_name_local} | ||
local hero_icon = mw.getCurrentFrame():expandTemplate{ title = "Template:HeroIcon", args = template_args } | local hero_icon = mw.getCurrentFrame():expandTemplate{ title = "Template:HeroIcon", args = template_args } | ||
local hero_cell_content = hero_icon | local hero_cell_content = hero_icon | ||
if has_alt then | if has_alt then | ||
-- Wikilink toggle (JS will prevent default and handle click) | |||
hero_cell_content = '[[#alt-fire-' .. hero_key .. '|+]] ' .. hero_cell_content | hero_cell_content = '[[#alt-fire-' .. hero_key .. '|+]] ' .. hero_cell_content | ||
end | end | ||
local | local rowspan_attr = has_alt and ' rowspan="2"' or '' | ||
row_str = row_str .. '<td style="position: sticky; left: 0; z-index: 10; background-color: | row_str = row_str .. '<td style="position: sticky; left: 0; z-index: 10; background-color: #202122; isolation: isolate;"' .. rowspan_attr .. '>' .. hero_cell_content .. '</td>' | ||
for _, category in ipairs(attribute_orders["category_order"]) do | for _, category in ipairs(attribute_orders["category_order"]) do | ||
if stats_to_include[category] ~= nil then | if stats_to_include[category] ~= nil then | ||
| Line 325: | Line 187: | ||
end | end | ||
-- | -- Alt-fire sub-row generator | ||
local function generateAltFireSubRow(hero_data, hero_key) | local function generateAltFireSubRow(hero_data, hero_key) | ||
local row_str = "" | local row_str = "" | ||
for _, category in ipairs(attribute_orders["category_order"]) do | for _, category in ipairs(attribute_orders["category_order"]) do | ||
if stats_to_include[category] ~= nil then | if stats_to_include[category] ~= nil then | ||
| Line 349: | Line 204: | ||
end | end | ||
-- Build | -- Build body | ||
for _, hero_entry in ipairs(sorted_heroes) do | for _, hero_entry in ipairs(sorted_heroes) do | ||
local hero_key = hero_entry.key | local hero_key = hero_entry.key | ||
| Line 360: | Line 215: | ||
end | end | ||
-- Pre-pass | -- Pre-pass (unchanged) | ||
local stats_with_any_scaling = {} | local stats_with_any_scaling = {} | ||
local stats_with_both_scaling = {} | local stats_with_both_scaling = {} | ||
| Line 369: | Line 223: | ||
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 scaling_data = hero_data_module.get_hero_scaling_data(hero_data, attr_key) | local scaling_data = hero_data_module.get_hero_scaling_data(hero_data, attr_key) | ||
if scaling_data ~= nil and next(scaling_data) ~= nil then | if scaling_data ~= nil and next(scaling_data) ~= nil then | ||
| Line 380: | Line 233: | ||
if has_spirit and has_level then stats_with_both_scaling[attr_key] = true end | if has_spirit and has_level then stats_with_both_scaling[attr_key] = true end | ||
end | end | ||
if hero_data.Weapon and hero_data.Weapon.AltFire and hero_data.Weapon.AltFire[attr_key] ~= nil then | |||
if hero_data.Weapon | |||
if attr_key ~= "ClipSize" then | if attr_key ~= "ClipSize" then | ||
local alt_scaling = hero_data_module.get_hero_scaling_data(hero_data, attr_key .. "AltFire") | local alt_scaling = hero_data_module.get_hero_scaling_data(hero_data, attr_key .. "AltFire") | ||
if alt_scaling and next(alt_scaling) ~= nil then | if alt_scaling ~= nil and next(alt_scaling) ~= nil then | ||
stats_with_any_scaling[attr_key] = true | if not (hero_entry.key == "hero_shiv" and attr_key == "BulletDamage") then | ||
stats_with_any_scaling[attr_key] = true | |||
local has_spirit_alt, has_level_alt = false, false | |||
for _, scaling_type in pairs(alt_scaling) do | |||
if scaling_type == "Spirit" then has_spirit_alt = true | |||
elseif scaling_type == "Level" then has_level_alt = true end | |||
end | end | ||
if has_spirit_alt and has_level_alt then stats_with_both_scaling[attr_key] = true end | |||
end | end | ||
end | end | ||
| Line 419: | Line 254: | ||
end | end | ||
-- | -- Header (unchanged) | ||
local headers_str = '<th style="position: sticky; left: 0; top: -1px; z-index: 12; background-color: | local headers_str = '<th style="position: sticky; left: 0; top: -1px; z-index: 12; background-color: #27292d; isolation: isolate;">Hero</th>' | ||
local category_data = attribute_module.get_category_data() | local category_data = attribute_module.get_category_data() | ||
local postfix_key_map = { | local postfix_key_map = { | ||
| Line 431: | Line 266: | ||
["SustainedDPS"] = "DPS_postfix", | ["SustainedDPS"] = "DPS_postfix", | ||
["RoundsPerSecondAtMaxSpin"] = "", | ["RoundsPerSecondAtMaxSpin"] = "", | ||
[" | ["CritDamageBonusScale"] = "StatDesc_CritDamageBonusScale_postfix", | ||
["BonusCritDamagePercent"] = "BonusCritDamagePercent_postfix", | |||
["BulletLifesteal"] = "BulletLifestealPercentHero_postfix", | ["BulletLifesteal"] = "BulletLifestealPercentHero_postfix", | ||
["GroundDashSpeed"] = "DashSpeed_postfix" | ["GroundDashSpeed"] = "DashSpeed_postfix" | ||
| Line 442: | Line 277: | ||
for _, attr_key in ipairs(stats_to_include[category]) do | for _, attr_key in ipairs(stats_to_include[category]) do | ||
local attr_data = category_attrs[attr_key] | local attr_data = category_attrs[attr_key] | ||
local attr_localized, postfix | local attr_localized, postfix | ||
if attr_data ~= nil then | if attr_data ~= nil then | ||
| Line 462: | Line 286: | ||
if postfix == nil or postfix == "" then postfix = "" | if postfix == nil or postfix == "" then postfix = "" | ||
else postfix = " (" .. postfix .. ")" end | else postfix = " (" .. postfix .. ")" end | ||
else | else | ||
attr_localized = dictionary_module.translate(attr_key) | attr_localized = dictionary_module.translate(attr_key) | ||