Editing Module:Sandbox/LVLGive 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 107: | Line 107: | ||
end | end | ||
end | end | ||
local scaled_dps = calculate_dps(scaled_stats, dps_type) | |||
return scaled_dps - base_dps | |||
end | |||
-- Compute DPS scaling delta from explicit component scalings. | |||
-- Used for Shiv, whose alt-fire BulletDamage uses primary scaling. | |||
local function compute_dps_scaling_from_components(base_stats, dps_type, component_scalings) | |||
local scaled_stats = {} | |||
for k, v in pairs(base_stats) do scaled_stats[k] = v end | |||
for comp_key, scale_val in pairs(component_scalings) do | |||
if scaled_stats[comp_key] ~= nil then | |||
scaled_stats[comp_key] = scaled_stats[comp_key] + scale_val | |||
end | |||
end | |||
local base_dps = calculate_dps(base_stats, dps_type) | |||
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 128: | Line 143: | ||
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 157: | Line 172: | ||
-- 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) | ||
local base_value | local base_value | ||
if is_alt_fire then | if is_alt_fire then | ||
| Line 175: | Line 184: | ||
else | else | ||
base_value = get_nested_stat_value(hero_data, attr_key) | base_value = get_nested_stat_value(hero_data, attr_key) | ||
end | end | ||
| Line 189: | Line 193: | ||
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 hero_key == "hero_shiv" and attr_key == "BulletDamage" then | |||
-- Shiv's alt-fire BulletDamage uses the primary fire's scaling | |||
scaling_data = hero_data_module.get_hero_scaling_data(hero_data, attr_key) | |||
elseif hero_key == "hero_shiv" and (attr_key == "DPS" or attr_key == "SustainedDPS") | |||
and hero_data.Weapon and hero_data.Weapon.AltFire then | |||
-- Shiv's alt-fire DPS scales from primary BulletDamage scaling | |||
local alt_stats = hero_data.Weapon.AltFire | |||
local dps_type = attr_key == "DPS" and 'burst' or 'sustained' | |||
local bd_scaling = hero_data_module.get_hero_scaling_data(hero_data, "BulletDamage") | |||
local level_scale = 0 | |||
local spirit_scale = 0 | |||
if bd_scaling and next(bd_scaling) ~= nil then | |||
for val, stype in pairs(bd_scaling) do | |||
local component = { ["BulletDamage"] = val } | |||
local delta = compute_dps_scaling_from_components(alt_stats, dps_type, component) | |||
if stype == "Level" then | |||
level_scale = delta | |||
elseif stype == "Spirit" then | |||
spirit_scale = delta | |||
end | |||
end | |||
end | |||
level_scale = util_module.round_to_sig_fig(level_scale, 5) | |||
spirit_scale = util_module.round_to_sig_fig(spirit_scale, 5) | |||
scaling_data = {} | |||
if level_scale ~= 0 then scaling_data[level_scale] = "Level" end | |||
if spirit_scale ~= 0 then scaling_data[spirit_scale] = "Spirit" end | |||
if next(scaling_data) == nil then scaling_data = nil end | |||
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 225: | Line 257: | ||
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 | ||
elseif scaling_type == "Level" then | elseif scaling_type == "Level" then | ||
level_val = scaling_val | level_val = scaling_val | ||
end | end | ||
end | end | ||
| Line 267: | Line 299: | ||
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, 3) | ||
end | end | ||
| Line 314: | Line 346: | ||
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: #202122; 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 389: | Line 421: | ||
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 | 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 _, stype in pairs(alt_scaling) do | |||
if stype == "Spirit" then has_spirit_alt = true | |||
elseif stype == "Level" then has_level_alt = true end | |||
end | |||
if has_spirit_alt and has_level_alt then stats_with_both_scaling[attr_key] = true end | |||
end | end | ||
else | else | ||
if attr_key == "DPS" or attr_key == "SustainedDPS" then | -- Shiv's alt-fire DPS/SustainedDPS uses primary BulletDamage scaling | ||
if hero_entry.key == "hero_shiv" and (attr_key == "DPS" or attr_key == "SustainedDPS") then | |||
local bd_scaling = hero_data_module.get_hero_scaling_data(hero_data, "BulletDamage") | |||
if bd_scaling and next(bd_scaling) ~= nil then | |||
local alt_stats = hero_data.Weapon.AltFire | |||
local dps_type = attr_key == "DPS" and 'burst' or 'sustained' | |||
for val, stype in pairs(bd_scaling) do | |||
local component = { BulletDamage = val } | |||
local delta = compute_dps_scaling_from_components(alt_stats, dps_type, component) | |||
if delta ~= 0 then | |||
stats_with_any_scaling[attr_key] = true | |||
end | |||
end | |||
end | |||
-- Alt-fire DPS/SustainedDPS for other heroes: compute from component scalings | |||
elseif attr_key == "DPS" or attr_key == "SustainedDPS" then | |||
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 420: | Line 469: | ||
-- 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: #444; 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 431: | Line 480: | ||
["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 491: | ||
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 500: | ||
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) | ||