Module:Sandbox/LVL: Difference between revisionsGive feedback
No edit summary |
No edit summary |
||
| (5 intermediate revisions by the same user not shown) | |||
| Line 107: | Line 107: | ||
end | end | ||
end | end | ||
local scaled_dps = calculate_dps(scaled_stats, dps_type) | local scaled_dps = calculate_dps(scaled_stats, dps_type) | ||
return scaled_dps - base_dps | return scaled_dps - base_dps | ||
| Line 143: | Line 128: | ||
Weapon = { | Weapon = { | ||
"DPS", "SustainedDPS", "BulletDamage", "RoundsPerSecond", "FireRate", | "DPS", "SustainedDPS", "BulletDamage", "RoundsPerSecond", "FireRate", | ||
"ClipSize", "ReloadTime", "ReloadDelay", "BulletsPerShot", "BulletsPerBurst", | "ClipSize", "ReloadTime", "ReloadDelay", "ReloadSingle", "BulletsPerShot", "BulletsPerBurst", | ||
"BurstInterShotInterval", "LightMeleeDamage", "HeavyMeleeDamage", | "BurstInterShotInterval", "LightMeleeDamage", "HeavyMeleeDamage", | ||
"BulletSpeed", "FalloffStartRange", "FalloffEndRange", | |||
"CritDamageBonusPercent", "RoundsPerSecondAtMaxSpin", "SpinAcceleration", "SpinDeceleration" | "CritDamageBonusPercent", "BulletRadius", "RoundsPerSecondAtMaxSpin", "SpinAcceleration", "SpinDeceleration" | ||
}, | }, | ||
Vitality = { | Vitality = { | ||
| Line 172: | Line 157: | ||
-- Build a single stat cell (<td>) with data attributes for JS recalculation | -- Build a single stat cell (<td>) with data attributes for JS recalculation | ||
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) | ||
-- Conversion factors for stats that need unit changes (e.g. metres → centimetres) | |||
local unit_conversion = { | |||
BulletRadius = 100 -- metres to centimetres | |||
} | |||
local conv_factor = unit_conversion[attr_key] or 1 | |||
local base_value | local base_value | ||
if is_alt_fire then | if is_alt_fire then | ||
| Line 184: | Line 175: | ||
else | else | ||
base_value = get_nested_stat_value(hero_data, attr_key) | base_value = get_nested_stat_value(hero_data, attr_key) | ||
end | |||
-- Apply unit conversion to the base value | |||
if type(base_value) == "number" then | |||
base_value = base_value * conv_factor | |||
end | end | ||
| Line 193: | Line 189: | ||
if attr_key == "ClipSize" or attr_key == "ReloadTime" then | if attr_key == "ClipSize" or attr_key == "ReloadTime" 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 (attr_key == "DPS" or attr_key == "SustainedDPS") | elseif (attr_key == "DPS" or attr_key == "SustainedDPS") | ||
and hero_data.Weapon and hero_data.Weapon.AltFire then | and hero_data.Weapon and hero_data.Weapon.AltFire then | ||
| Line 257: | Line 225: | ||
for scaling_val, scaling_type in pairs(scaling_data) do | for scaling_val, scaling_type in pairs(scaling_data) do | ||
if scaling_type == "Spirit" then | if scaling_type == "Spirit" then | ||
spirit_val = scaling_val | spirit_val = scaling_val * conv_factor -- apply unit conversion | ||
elseif scaling_type == "Level" then | elseif scaling_type == "Level" then | ||
level_val = scaling_val | level_val = scaling_val * conv_factor -- apply unit conversion | ||
end | end | ||
end | end | ||
| Line 299: | Line 267: | ||
stat_value = tostring(stat_value) | stat_value = tostring(stat_value) | ||
else | else | ||
stat_value = util_module.round_to_sig_fig(stat_value, | stat_value = util_module.round_to_sig_fig(stat_value, 5) | ||
end | end | ||
| Line 346: | Line 314: | ||
end | end | ||
local sort_name = (hero_data["Name"] or hero_key):gsub("^The ", "") | local sort_name = (hero_data["Name"] or hero_key):gsub("^The ", "") | ||
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: var(--background-color-base-2); isolation: isolate; overflow: hidden; min-width: 150px;" data-sort-value="' .. sort_name .. '">' .. 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 421: | Line 389: | ||
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 and next(alt_scaling) ~= nil then | ||
stats_with_any_scaling[attr_key] = true | |||
local has_spirit_alt, has_level_alt = false, false | |||
for _, stype in pairs(alt_scaling) do | |||
if stype == "Spirit" then has_spirit_alt = true | |||
elseif stype == "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 | |||
else | else | ||
if attr_key == "DPS" or attr_key == "SustainedDPS" then | |||
if | |||
local alt_stats = hero_data.Weapon.AltFire | local alt_stats = hero_data.Weapon.AltFire | ||
local dps_type = attr_key == "DPS" and 'burst' or 'sustained' | local dps_type = attr_key == "DPS" and 'burst' or 'sustained' | ||
| Line 469: | Line 420: | ||
-- Build table header row | -- Build table header row | ||
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: var(--background-color-base-5); isolation: isolate; min-width: 150px;">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 480: | Line 431: | ||
["SustainedDPS"] = "DPS_postfix", | ["SustainedDPS"] = "DPS_postfix", | ||
["RoundsPerSecondAtMaxSpin"] = "", | ["RoundsPerSecondAtMaxSpin"] = "", | ||
[" | ["CritDamageBonusPercent"] = "StatDesc_CritDamageBonusScale_postfix", | ||
["CritDamageReceivedPercent"] = "StatDesc_CritDamageReceivedScale_postfix", | |||
["BulletLifesteal"] = "BulletLifestealPercentHero_postfix", | ["BulletLifesteal"] = "BulletLifestealPercentHero_postfix", | ||
["GroundDashSpeed"] = "DashSpeed_postfix" | ["GroundDashSpeed"] = "DashSpeed_postfix" | ||
| Line 491: | Line 442: | ||
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] | ||
-- Fallback: if the stat is missing from this category, check all other categories | |||
if attr_data == nil then | |||
for _, fallback_cat_data in pairs(attributes_data) do | |||
if fallback_cat_data[attr_key] ~= nil then | |||
attr_data = fallback_cat_data[attr_key] | |||
break | |||
end | |||
end | |||
end | |||
local attr_localized, postfix | local attr_localized, postfix | ||
if attr_data ~= nil then | if attr_data ~= nil then | ||
| Line 500: | Line 462: | ||
if postfix == nil or postfix == "" then postfix = "" | if postfix == nil or postfix == "" then postfix = "" | ||
else postfix = " (" .. postfix .. ")" end | else postfix = " (" .. postfix .. ")" end | ||
if attr_key == "BulletRadius" then postfix = " (cm)" end | |||
else | else | ||
attr_localized = dictionary_module.translate(attr_key) | attr_localized = dictionary_module.translate(attr_key) | ||