Module:Sandbox/LVL: Difference between revisionsGive feedback
No edit summary |
No edit summary |
||
| Line 552: | Line 552: | ||
--writes the massive hero comparison table for a specific PI and SP | --writes the massive hero comparison table for a specific PI and SP | ||
-- scaling icons are shown only if PI and SP are both 0 or both not provided | -- scaling icons are shown only if PI and SP are both 0 or both not provided | ||
--{{#invoke:HeroData|write_hero_comparison_table|POWER_INCREASES|SPIRIT_POWER| | --{{#invoke:HeroData|write_hero_comparison_table|POWER_INCREASES|SPIRIT_POWER|MAX_POWER|MAX_SPIRIT}} | ||
p.write_hero_comparison_table = function(frame) | p.write_hero_comparison_table = function(frame) | ||
-- process inputs | |||
local power_increases = frame.args[1] | |||
if (power_increases == nil) then power_increases = 0 end | |||
local spirit_power = frame.args[2] | |||
if (spirit_power == nil) then spirit_power = 0 end | |||
local max_power = frame.args[3] or 25 | |||
local max_spirit = frame.args[4] or 500 | |||
-- Show scaling icons if power/increases/spirit power are 0/not specified | |||
local display_scaling_icons = false | |||
if (power_increases == 0 and spirit_power == 0) then | |||
display_scaling_icons = true | |||
end | |||
-- Initializations and declarations | |||
local row_str = "" | |||
local body_str = "" | |||
local template_title = "" | |||
local template_args = {} | |||
local hero_icon | |||
-- Add hero comp stats to | |||
local stats_to_include = { | |||
Weapon = { | |||
"DPS", | |||
"SustainedDPS", | "SustainedDPS", | ||
"BulletDamage", | "BulletDamage", | ||
| Line 602: | Line 601: | ||
"SpinAcceleration", | "SpinAcceleration", | ||
"SpinDeceleration" | "SpinDeceleration" | ||
}, | |||
Vitality = { | |||
"MaxHealth", | |||
"BaseHealthRegen", | "BaseHealthRegen", | ||
"BulletResist", | "BulletResist", | ||
| Line 616: | Line 615: | ||
"Stamina", | "Stamina", | ||
"GroundDashSpeed" | "GroundDashSpeed" | ||
}, | |||
Spirit = { | |||
"TechPower" | |||
} | |||
} | |||
-- Collect and sort heroes alphabetically by name | |||
local sorted_heroes = {} | |||
for hero_key, hero_data in pairs(heroes_data) do | |||
if not hero_data["InDevelopment"] and not hero_data["IsDisabled"] then | |||
table.insert(sorted_heroes, {key = hero_key, data = hero_data}) | |||
end | |||
end | |||
table.sort(sorted_heroes, function(a, b) | |||
return (a.data["Name"] or a.key) < (b.data["Name"] or b.key) | |||
end) | |||
-- Iterate heroes | |||
for _, hero_entry in ipairs(sorted_heroes) do | |||
local hero_key = hero_entry.key | |||
local hero_data = hero_entry.data | |||
row_str = "" | |||
-- Retrieve hero's localized name | |||
hero_name = localize(hero_key, hero_key) | |||
-- Retrieve hero's english name, used for hero icon | |||
hero_name_en = hero_data["Name"] | |||
-- 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 (sticky) | |||
row_str = row_str .. '<td style="position: sticky; left: 0; z-index: 10; background-color: #202122; isolation: isolate;">' .. hero_icon .. "</td>" | |||
-- Consecutive columns are then stats | |||
-- Iterate categories | |||
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 | |||
for _, attr_key in ipairs(stats_to_include[category]) do | |||
--Retrieve the stats value from hero data | |||
local base_value = get_nested_stat_value(hero_data, attr_key) | |||
local stat_value = base_value | |||
-- Retrieve scaling val and str if it scales | |||
local scaling_data = p.get_hero_scaling_data(hero_data, attr_key) | |||
local scaling_strs = "" | |||
local spirit_scale = 0 | |||
local level_scale = 0 | |||
local is_resist = (attr_key == 'TechResist' or attr_key == 'BulletResist') | |||
if (scaling_data ~= nil) then | |||
for scaling_val, scaling_type in pairs(scaling_data) do | |||
local scaling_str = p.write_scalar_str(scaling_val, scaling_type) | |||
if (scaling_str ~= "") then scaling_str = " " .. scaling_str end | |||
if (scaling_str ~= nil) then | |||
scaling_strs = scaling_strs .. scaling_str | |||
end | |||
-- Track scaling values for data attributes | |||
if (scaling_type == "Spirit") then | |||
spirit_scale = scaling_val | |||
stat_value = stat_value + (spirit_power * scaling_val) | |||
elseif (scaling_type == "Level") then | |||
level_scale = scaling_val | |||
if is_resist then | |||
-- each PI for resists is multiplicative | |||
stat_value = (stat_value/100 + 1 - (1-scaling_val/100)^power_increases)*100 | |||
else | |||
stat_value = stat_value + (power_increases * scaling_val) | |||
end | |||
end | |||
end | |||
end | |||
-- Hide scaling icons if not at base values | |||
if (not display_scaling_icons) then scaling_strs = "" end | |||
-- Convert from boolean to string, or round it | |||
if (type(stat_value)) == 'boolean' then | |||
stat_value = tostring(stat_value) | |||
else | |||
stat_value = util_module.round_to_sig_fig(stat_value, 3) | |||
end | |||
-- Build data attributes for JavaScript manipulation | |||
local data_attrs = string.format( | |||
'data-base="%s" data-spirit-scale="%s" data-level-scale="%s"%s', | |||
base_value, | |||
spirit_scale, | |||
level_scale, | |||
is_resist and ' data-is-resist="true"' or '' | |||
) | |||
-- Add it to the row with data attributes and span wrapper | |||
row_str = row_str .. string.format( | |||
'<td %s><span class="stat-num">%s</span>%s</td>', | |||
data_attrs, | |||
stat_value, | |||
scaling_strs | |||
) | |||
end | |||
end | |||
end | |||
-- Add row to the body | |||
row_str = "<tr>" .. row_str .. "</tr>" | |||
body_str = body_str .. row_str | |||
end | |||
-- First header is Hero (sticky) | |||
local headers_str = '<th style="position: sticky; left: 0; top: 0; z-index: 12; background-color: #27292d; isolation: isolate;">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"] = "", | |||
["CritDamageBonusScale"] = "StatDesc_CritDamageBonusScale_postfix", | |||
["BonusCritDamagePercent"] = "BonusCritDamagePercent_postfix", | |||
["BulletLifesteal"] = "BulletLifestealPercentHero_postfix", | |||
["GroundDashSpeed"] = "DashSpeed_postfix" | |||
} | |||
-- 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 | |||
header_style = ' style="position: sticky; top: 0; z-index: 3; background-color: rgb(' .. category_rgb .. ');"' | |||
headers_str = headers_str .. "<th" .. header_style .. ">" .. attr_localized .. postfix .. "</th>" | |||
end | |||
end | |||
end | |||
headers_str = "<tr>" .. headers_str .. "</tr>" | |||
-- Wrap table in container with data attributes for JS | |||
local table_str = string.format( | |||
'<div id="hero-comparison-container" data-max-power="%s" data-max-spirit="%s">' .. | |||
'<div style="overflow: auto; max-height: 70vh; width: 100%%;">' .. | |||
'<table class="wikitable sortable" style="table-layout: auto; width: 100%%;" id="hero-comparison-table">%s%s</table>' .. | |||
'</div></div>', | |||
max_power, | |||
max_spirit, | |||
headers_str, | |||
body_str | |||
) | |||
return table_str | |||
end | end | ||