|
Tags: Blanking Manual revert |
| Line 1: |
Line 1: |
| local p = {};
| |
| local heroes_data = mw.loadJsonData("Data:HeroData.json")
| |
| local attributes_data = mw.loadJsonData("Data:AttributeData.json")
| |
| local attribute_orders = mw.loadJsonData("Data:StatInfoboxOrder.json")
| |
| local util_module = require('Module:Utilities')
| |
| local lang_module = require('Module:Lang')
| |
| local dictionary_module = require('Module:Dictionary')
| |
| local attribute_module = require('Module:AttributeData')
| |
|
| |
|
| -- returns the table of a specific item, used by external modules
| |
| function p.get_json_item(name)
| |
| for i,v in pairs(heroes_data) do
| |
| if (v["Name"] == name) then
| |
| return v
| |
| end
| |
| end
| |
| return nil
| |
| end
| |
|
| |
| -- Returns an array of item tables that have the same properties
| |
| -- @function get_similar_items
| |
| -- @param {string}
| |
| -- @return {array of tables}
| |
| local function get_similar_items(property)
| |
| local similarItems = {}
| |
| for _, v in pairs(heroes_data) do
| |
| if (v[property] ~= nil) then
| |
| table.insert(similarItems, v)
| |
| end
| |
| end
| |
| return similarItems
| |
| end
| |
|
| |
| -- returns the key of the specified hero's english name
| |
| function p.get_hero_key(name)
| |
| for i,v in pairs(heroes_data) do
| |
| if (v["Name"] == name) then
| |
| return i
| |
| end
| |
| end
| |
| return nil
| |
| end
| |
|
| |
|
| |
| --{{#invoke:HeroData|get_hero_var|HERO_NAME|STAT_NAME|sig_figs_or_localize}}--
| |
| --sig_figs optional for rounding floats
| |
| p.get_hero_var = function(frame)
| |
| local hero_name = frame.args[1]
| |
| local hero_stat_key = frame.args[2]
| |
| local sig_figs_or_localize = frame.args[3]
| |
|
| |
| local hero = heroes_data[hero_name] --check if hero key is passed instead
| |
| if(hero == nil) then hero = p.get_json_item(hero_name) end --check if hero name is passed
| |
| if(hero == nil) then return "Hero Not Found" end --both invalid, error
| |
|
| |
| local var_value = hero[hero_stat_key]
| |
| if(var_value == nil) then return 0 end
| |
|
| |
| --round
| |
| if (sig_figs_or_localize ~= nil and tonumber(sig_figs_or_localize) ~= nil) then
| |
| var_value = util_module.round_to_sig_fig(var_value, sig_figs_or_localize)
| |
| if (var_value == nil) then return "get_hero_var() error with rounding" end
| |
| end
| |
|
| |
| --localize
| |
| if (sig_figs_or_localize == "true") then
| |
| return lang_module.get_string(var_value)
| |
| end
| |
|
| |
| return var_value
| |
| end
| |
|
| |
| --{{#invoke:HeroData|get_list_elem|HERO_NAME|VAR|NUMBER|LOCALIZE}}
| |
| p.get_list_elem = function(frame)
| |
| local hero_name = frame.args[1]
| |
| local var = frame.args[2]
| |
| local number_str = frame.args[3]
| |
| local number_int = tonumber(number_str)
| |
| local localize = frame.args[4]
| |
| local hero = heroes_data[hero_name] --check if hero key is passed instead
| |
| if(hero == nil) then hero = p.get_json_item(hero_name) end --check if hero name is passed
| |
| if(hero == nil) then return "Hero Not Found" end --both invalid, error
| |
| if (hero == nil) then return "Hero " .. hero_name .. " not found" end
| |
| local list = hero[var]
| |
| if (list == nil) then return "" end
| |
| local element = list[number_int]
| |
| if (element == nil) then return "" end
| |
|
| |
| if localize=="true" then
| |
| element = lang_module.get_string(element)
| |
| end
| |
|
| |
| return element
| |
| end
| |
|
| |
| p.get_ability_key = function(frame)
| |
| local hero_key = frame.args[1]
| |
| local bound_slot_number = frame.args[2]
| |
| local hero_data = heroes_data[hero_key]
| |
| if (hero_data == nil) then return "Hero key "..hero_key.. " not found" end
| |
| local bound_abilities_data = hero_data["BoundAbilities"]
| |
| if (bound_abilities_data == nil) then return "Hero key " .. hero_key.. " has no BoundAbilities" end
| |
| return bound_abilities_data[tonumber(bound_slot_number)]["Key"]
| |
| end
| |
|
| |
| p.write_role_playstyle_quote = function(frame)
| |
| local hero_key = frame.args[1]
| |
| local hero_data = heroes_data[hero_key]
| |
| if (hero_data == nil) then return hero_key.." not found" end
| |
| local role_key = hero_data["Role"]
| |
| local role_localized = lang_module.get_string(role_key, nil, 'en')
| |
| local playstyle_key = hero_data["Playstyle"]
| |
| local playstyle_localized = lang_module.get_string(playstyle_key, nil, 'en')
| |
|
| |
| local str = "<b>" .. role_localized .. '</b><br>' .. playstyle_localized
| |
| local template_args = {}
| |
| template_args[1] = ""
| |
| template_args[2] = str
| |
| return frame:expandTemplate{title = 'Quotation', args = template_args}
| |
| end
| |
|
| |
| p.write_default_items = function(frame)
| |
| local hero_key = frame.args[1] --unlocalized
| |
| if (hero_key == nil) then return "No hero key provided" end
| |
| local str = ""
| |
| local hero = heroes_data[hero_key]
| |
| if (hero == nil) then return "Hero not found, must be unlocalized" end
| |
| local template_title = 'PageRef'
| |
| for i, item_key in ipairs(hero["RecommendedItems"]) do
| |
| template_args = {}
| |
| template_args[1] = lang_module.get_string(item_key, 'en')
| |
| template_args['alt_name'] = localize(item_key, item_key)
| |
| local expanded_template = mw.getCurrentFrame():expandTemplate{ title = template_title, args = template_args }
| |
| str = str .. "* " .. expanded_template .. "\n"
| |
| end
| |
| return str
| |
| end
| |
|
| |
|
| |
| --If the hero scales with the stat, it returns {{Ss|value}} or {{Ls|value}}, else blank string
| |
| --{{#invoke:HeroData|get_hero_scalar|HERO_NAME|SCALING_TYPE|STAT_NAME|sig_figs_or_localize}}--
| |
| p.get_hero_scalar = function(frame)
| |
| local hero_key = frame.args[1]
| |
| local scaling_type = frame.args[2]
| |
| local hero_stat_key = frame.args[3]
| |
| local sig_figs_or_localize = frame.args[4]
| |
|
| |
| local hero_data = heroes_data[hero_key]
| |
| if(hero_data == nil) then hero_data = p.get_json_item(hero_key) end
| |
| if(hero_data == nil) then return "Hero not found." end
| |
|
| |
| local scaling_data = hero_data[scaling_type .. "Scaling"]
| |
| if scaling_data == nil then return scaling_type .. "Scaling data not found for hero" .. hero_key end
| |
|
| |
| local scaling_value = scaling_data[hero_stat_key]
| |
| if scaling_value == nil then return scaling_type .. "Scaling data does not have key " .. hero_stat_key .. " for hero " .. hero_key end
| |
|
| |
| --round
| |
| if (sig_figs_or_localize ~= nil and tonumber(sig_figs_or_localize) ~= nil) then
| |
| scaling_value = util_module.round_to_sig_fig(scaling_value, sig_figs_or_localize)
| |
| if (scaling_value == nil) then return "get_hero_scalar() error with rounding" end
| |
| end
| |
|
| |
| --localize
| |
| if (sig_figs_or_localize == "true") then
| |
| return lang_module.get_string(scaling_value)
| |
| end
| |
|
| |
| local scaling_str = p.write_scalar_str(scaling_value, scaling_type)
| |
| if (scaling_str ~= "") then scaling_str = " " .. scaling_str end
| |
|
| |
| return scaling_str
| |
| end
| |
|
| |
| -- Retrieve scaling string of a hero's given stat, if it has scaling, else return blank
| |
| -- Scaling string meaning the expanded template {{Ss|scalar}} or {{Ls|scalar}}
| |
| function p.write_scalar_str(scaling_value, scaling_type)
| |
| local scaling_abbrevs = {Spirit = "Ss", Level = "PI"}
| |
|
| |
| -- Return blank if it doesnt scale
| |
| if (scaling_value == 0) then return "" end
| |
|
| |
| -- Round it
| |
| scaling_value = util_module.round_to_sig_fig(scaling_value, 3)
| |
|
| |
| --The hero has a scaling value with this stat
| |
| local template_title = "Template:" .. scaling_abbrevs[scaling_type] --scaling type's abbreviation
| |
|
| |
| local template_args = {}
| |
| template_args["1"] = scaling_value --store in 1st arg for {{{1}}} to grab it from {{SS}} or {{LS}} template
| |
|
| |
| local template_call = mw.getCurrentFrame():expandTemplate{ title = template_title, args = template_args }
| |
| return template_call
| |
| end
| |
|
| |
| -- Retrieve scaling value and type of a hero's given stat, if it has scaling, else return 0
| |
| function p.get_hero_scaling_data(hero_data, hero_stat_key)
| |
| local scaling_type_full
| |
| local scaling_data
| |
| local scaling_value
| |
| local scaling_types = {"Spirit", "Level"}
| |
| local scaling_data_returned = {}
| |
|
| |
| for index, scaling_type in ipairs(scaling_types) do
| |
| scaling_type_full = scaling_type .. "Scaling"
| |
| scaling_data = hero_data[scaling_type_full]
| |
|
| |
| --If the scaling data exists
| |
| if (scaling_data ~= nil) then
| |
| scaling_value = scaling_data[hero_stat_key]
| |
|
| |
| --If the stat scales
| |
| if (scaling_value ~= nil) then
| |
| scaling_data_returned[scaling_value] = scaling_type
| |
| end
| |
| end
| |
| end
| |
|
| |
| return scaling_data_returned
| |
| end
| |
|
| |
| --HERO_NAME in english
| |
| --{{#invoke:HeroData|write_infobox|HERO_NAME}}--
| |
| p.write_infobox = function(frame)
| |
| -- Get hero data
| |
| hero_key = frame.args[1]
| |
| hero_data = heroes_data[hero_key]
| |
| if(hero_data == nil) then return "Hero " .. hero_key .. " Not Found" end
| |
|
| |
| local infobox_attributes = {
| |
| Weapon = {'DPS','ClipSize','RoundsPerSecond','ReloadTime'},
| |
| Vitality = {'MaxHealth','BulletResist','TechResist','MaxMoveSpeed'}
| |
| }
| |
|
| |
| -- Declarations and initializations
| |
| local category_data = attribute_module.get_category_data()
| |
| local stats
| |
| local stat_data
| |
| local stat_value
| |
| local stat_text
| |
| local label
| |
| local postfix
| |
| local should_display
| |
| local image_file_name
| |
| local image_file
| |
| local icon_and_value_str
| |
| local template_args = {}
| |
| local stat_values = {Weapon = "", Vitality = ""}
| |
|
| |
| -- Add the main parameters
| |
| template_args["name_english"] = lang_module.get_string(hero_key, 'en')
| |
| template_args["name_localized"] = localize(hero_key, hero_key)
| |
|
| |
| -- Iterate attribute categories
| |
| for category, stats in pairs(infobox_attributes) do
| |
| -- Iterate stats
| |
| for _, stat_name in ipairs(stats) do
| |
| -- Confirm its in attribute data and retrieve it
| |
| attribute_data = attributes_data[category]
| |
| if (attribute_data == nil) then return "Category " .. category .. " in infobox_attributes is not in Data:AttributeData" end
| |
| stat_data = attribute_data[stat_name]
| |
| if (stat_data == nil) then return "Attribute " .. stat_name .. " in infobox_attributes is not in Data:AttributeData" end
| |
|
| |
| -- gets the stat's value
| |
| stat_value = hero_data[stat_name]
| |
| if (stat_value == nil) then
| |
| stat_value = 0 --default to 0 if not present
| |
| end
| |
|
| |
| --Round value to 3 significant figures
| |
| stat_value = util_module.round_to_sig_fig(stat_value, 3)
| |
|
| |
| -- get label and postfix
| |
| label = localize(stat_data["label"], stat_name)
| |
| postfix = stat_data["postfix"]
| |
| if (postfix == nil) then
| |
| postfix = ""
| |
| else
| |
| -- light grey for postfixes
| |
| postfix = lang_module.get_string(postfix)
| |
| if (postfix == nil) then
| |
| postfix = ""
| |
| end
| |
| postfix = '<span style="color: #666666;">' .. postfix .. "</span>"
| |
| end
| |
| -- if a language is missing the postfix, use no postfix
| |
|
| |
|
| |
| -- Check if icon file exists, and if not, don't use any image
| |
| image_file_name = 'File:AttributeIcon' .. stat_name .. '.png'
| |
| image_file = util_module.get_image_file(image_file_name, 15, stat_name)
| |
|
| |
| -- Create the template'd icon
| |
| local icon_color = attribute_module.get_attr_icon_color(stat_name)
| |
| icon_template_title = mw.title.new("Template:Icon/" .. icon_color)
| |
| icon_template_args = {}
| |
| icon_template_args[1] = image_file
| |
| icon_template_args[2] = stat_value .. postfix
| |
| icon_and_value_str = mw.getCurrentFrame():expandTemplate{ title = icon_template_title, args = icon_template_args }
| |
|
| |
| label = ',<span style="color: #999999; background-color: #2F2F2F; display: inline-flex; width: 100%; height: 100%; justify-content: center; align-items: center;">' .. label .. '</span>'
| |
|
| |
| -- First add localized stat name for left column
| |
| stat_values[category] = stat_values[category] .. label
| |
|
| |
| -- Then add icon and stat value for right column
| |
| stat_values[category] = stat_values[category] .. ',' .. icon_and_value_str
| |
| end
| |
|
| |
| -- Add the stat values in the category to i.e weapon_values and vitality_values parameters
| |
| template_args[string.lower(category) .. "_values"] = stat_values[category]
| |
| end
| |
|
| |
| -- Use expandTemplate to evaluate the Infobox_hero template
| |
| local template_title = mw.title.new("User:Sur")
| |
| local expanded_template = mw.getCurrentFrame():expandTemplate{ title = template_title, args = template_args }
| |
|
| |
| return expanded_template
| |
| end
| |
|
| |
|
| |
| --{{#invoke:HeroData|write_stat_infoboxes|HERO_KEY}}
| |
| --Creates {{Infobox_stat}}'s' for the 3 categories Weapon, Vitality, Spirit
| |
| p.write_stat_infoboxes = function(frame)
| |
| local hero_key = frame.args[1]
| |
| if(hero_key == nil) then return "Hero parameter missing" end
| |
|
| |
| -- Use expandTemplate to evaluate the Infobox_hero template
| |
| local template_title = mw.title.new("Template:Infobox_stat") --name of the template
| |
| local template_calls = '<div style="display: flex; flex-direction: column;">' --all template calls concatenated
| |
| local template_call --current template call
| |
| local template_args = {} --current template arguments
| |
| local cell_values --current cell values
| |
| local cell_value --current cell value
| |
| local label --current stat's label
| |
| local postfix --current stat's postfix
| |
| local stat_value --current stat's numerical value in the hero data
| |
| local hero_data = heroes_data[hero_key]
| |
| local stats --stats of the current category
| |
| local image_file_name --name of the image_file to check
| |
| local image_file --mw returned image file
| |
| local extra_blank_cell --add a blank cell after certain stats
| |
| local stats_to_add_blank_after = {CritDamageReceivedScale = true}
| |
| if (hero_data == nil) then return "Hero Not Found" end
| |
| local category_data = attribute_module.get_category_data()
| |
| local should_display
| |
|
| |
| for _, category in ipairs(attribute_orders["category_order"]) do
| |
| if (category ~= "Spirit") then --hide Spirit section for now
| |
| stats = attributes_data[category]
| |
| local category_values = category_data[category]
| |
| template_args["box_name"] = category_values.unlocalized_name
| |
| template_args["box_rgb"] = category_values.rgb
| |
| template_args["num_cols"] = 2
| |
| cell_values = ""
| |
|
| |
| -- Determine cell values
| |
| for _, stat_name in ipairs(attribute_orders[category]["attribute_order"]) do
| |
| local stat_data = stats[stat_name]
| |
| if stat_data == nil then return "Stat " .. stat_name .. " from StatInfoboxOrder has no data in AttributeData" end
| |
|
| |
| -- gets the stat's value if it has that stat, default to 0 if not
| |
| stat_value = hero_data[stat_name]
| |
| if (stat_value == nil) then
| |
| stat_value = 0 --default to 0 if not present
| |
| end
| |
|
| |
| --Round value to 3 significant figures
| |
| stat_value = util_module.round_to_sig_fig(stat_value, 3)
| |
|
| |
| -- get label and postfix
| |
| label = localize(stat_data["label"], stat_name)
| |
| postfix = stat_data["postfix"]
| |
| if (postfix == nil) then
| |
| postfix = ""
| |
| else
| |
| -- light grey for postfixes
| |
| postfix = '<span style="color: #666666;">' .. lang_module.get_string(postfix) .. "</span>"
| |
| end
| |
| -- if a language is missing the postfix, use no postfix
| |
| if (postfix == nil) then
| |
| postfix = ""
| |
| end
| |
|
| |
| -- Check if icon file exists, and if not, don't use any image
| |
| image_file_name = 'File:AttributeIcon' .. stat_name .. '.png'
| |
| -- 15px and link to stat name (page name might not match perfectly yet)
| |
| image_file = util_module.get_image_file(image_file_name, 15, stat_name)
| |
|
| |
| -- Create the template'd icon
| |
| local icon_color = attribute_module.get_attr_icon_color(stat_name)
| |
| if (icon_color == "Brown") then
| |
| image_file = '<span style="position: relative; bottom: 2px; filter: invert(42%) sepia(10%) saturate(2912%) hue-rotate(351deg) brightness(90%) contrast(87%);">' .. image_file .. '</span>'
| |
| end
| |
| -- use white instead of grey if grey is returned
| |
|
| |
| -- Add an empty cell following some stats to align them correctly as seen in game
| |
| if (stats_to_add_blank_after[stat_name]) then
| |
| extra_blank_cell = " ," --prefixed space is needed
| |
| else
| |
| extra_blank_cell = ""
| |
| end
| |
|
| |
| -- slightly lighter color for stat name
| |
| label = '<span style="color: #3d3d3d;">' .. label .. '</span>'
| |
|
| |
| -- Add the scaling str if it scales
| |
| local scaling_data = p.get_hero_scaling_data(hero_data, stat_name)
| |
| local scaling_strs = ""
| |
| if (scaling_data ~= nil) then
| |
| for scaling_value, scaling_type in pairs(scaling_data) do
| |
| local scaling_str = p.write_scalar_str(scaling_value, scaling_type)
| |
| if (scaling_str ~= "") then scaling_str = " " .. scaling_str end
| |
| scaling_strs = scaling_strs .. scaling_str
| |
| end
| |
| end
| |
|
| |
| -- Set cell value as "Icon StatvaluePostfix Statname Scaling,"
| |
| -- If icon file already exists, set it to #REDIRECT to the duplicate file page
| |
| cell_value = image_file .. " " .. stat_value .. postfix .. " " .. label .. scaling_strs .. "," .. extra_blank_cell
| |
|
| |
| cell_values = cell_values .. cell_value --add value to values list
| |
| end
| |
| template_args["cell_values"] = cell_values
| |
|
| |
|
| |
| -- Write current call
| |
| template_call = mw.getCurrentFrame():expandTemplate{ title = template_title, args = template_args }
| |
|
| |
| -- Add call to the set of calls
| |
| template_calls = template_calls .. "\n" .. template_call
| |
| end
| |
| end
| |
|
| |
| return template_calls .. "</div>"
| |
| end
| |
|
| |
| --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
| |
| --{{#invoke:HeroData|write_hero_comparison_table|POWER_INCREASES|SPIRIT_POWER|sticky-header-bg=#333|sticky-cell-bg=#202020}}
| |
| p.write_hero_comparison_table = function(frame)
| |
| local args = frame:getParent().args
| |
| -- process inputs
| |
| local power_increases = args[1]
| |
| if (power_increases == nil or power_increases == '') then power_increases = 0 end
| |
| local spirit_power = args[2]
| |
| if (spirit_power == nil or spirit_power == '') then spirit_power = 0 end
| |
|
| |
| -- Allow overriding sticky background colors, trim whitespace for robustness
| |
| local sticky_header_bg_arg = args['sticky-header-bg']
| |
| if sticky_header_bg_arg then
| |
| sticky_header_bg_arg = mw.text.trim(sticky_header_bg_arg)
| |
| end
| |
| local sticky_cell_bg_arg = args['sticky-cell-bg']
| |
| if sticky_cell_bg_arg then
| |
| sticky_cell_bg_arg = mw.text.trim(sticky_cell_bg_arg)
| |
| end
| |
|
| |
| local sticky_header_bg = (sticky_header_bg_arg and sticky_header_bg_arg ~= '') and sticky_header_bg_arg or '#333333'
| |
| local sticky_cell_bg = (sticky_cell_bg_arg and sticky_cell_bg_arg ~= '') and sticky_cell_bg_arg or '#202122'
| |
|
| |
| -- 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
| |
|
| |
| -- Add hero comp stats to
| |
| local stats_to_include = {
| |
| Weapon = {
| |
| "DPS", "SustainedDPS", "BulletDamage", "RoundsPerSecond", "FireRate", "ClipSize", "ReloadTime", "ReloadDelay", "BulletsPerShot", "BulletsPerBurst", "BurstInterShotInterval", "LightMeleeDamage", "HeavyMeleeDamage", "ReloadSingle", "BulletSpeed", "BulletGravityScale", "FalloffStartRange", "FalloffEndRange", "BonusAttackRange", "RoundsPerSecondAtMaxSpin", "SpinAcceleration", "SpinDeceleration"
| |
| },
| |
| Vitality = {
| |
| "MaxHealth", "BaseHealthRegen", "BulletResist", "TechResist", "CritDamageReceivedScale", "MaxMoveSpeed", "SprintSpeed", "StaminaCooldown", "Stamina"
| |
| }
| |
| }
| |
|
| |
| -- Build the entire HTML structure as a list of strings, then concat once at the end.
| |
| local html_parts = {}
| |
|
| |
| table.insert(html_parts, '<div style="overflow-x: auto; width: 100%;">')
| |
| table.insert(html_parts, '<table class="wikitable sortable" style="table-layout: auto; width: 100%;">')
| |
|
| |
| -- Build Header
| |
| table.insert(html_parts, '<thead><tr>')
| |
| table.insert(html_parts, '<th style="position: sticky; top: 0; left: 0; z-index: 2; background-color: ' .. sticky_header_bg .. ';">Hero</th>')
| |
|
| |
| 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
| |
|
| |
| local header_style = 'style="position: sticky; top: 0; z-index: 1; background-color: rgb(' .. category_rgb .. ');"'
| |
| table.insert(html_parts, '<th ' .. header_style .. '>' .. attr_localized .. postfix .. '</th>')
| |
| end
| |
| end
| |
| end
| |
| table.insert(html_parts, '</tr></thead>')
| |
|
| |
| -- Build Body
| |
| table.insert(html_parts, '<tbody>')
| |
| for hero_key, hero_data in pairs(heroes_data) do
| |
| local in_development = hero_data["InDevelopment"]
| |
| if (not in_development) then
| |
| local is_disabled = hero_data["IsDisabled"]
| |
| if (not is_disabled) then
| |
| table.insert(html_parts, '<tr>')
| |
|
| |
| -- 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 }
| |
|
| |
| table.insert(html_parts, '<td style="position: sticky; left: 0; z-index: 1; background-color: ' .. sticky_cell_bg .. ';">' .. hero_icon .. '</td>')
| |
|
| |
| -- Stat cells
| |
| for _, category in ipairs(attribute_orders["category_order"]) do
| |
| if (stats_to_include[category] ~= nil) then
| |
| for _, attr_key in ipairs(stats_to_include[category]) do
| |
| local stat_value = hero_data[attr_key]
| |
| if (stat_value == nil) then stat_value = 0 end
| |
|
| |
| local scaling_data = p.get_hero_scaling_data(hero_data, attr_key)
| |
| local scaling_strs = ""
| |
| 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
| |
|
| |
| if (scaling_type == "Spirit") then
| |
| stat_value = stat_value + (spirit_power * scaling_val)
| |
| elseif (scaling_type == "Level") then
| |
| if attr_key == 'TechResist' or attr_key == 'BulletResist' then
| |
| 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
| |
| if (not display_scaling_icons) then scaling_strs = "" end
| |
|
| |
| if (type(stat_value)) == 'boolean' then
| |
| stat_value = tostring(stat_value)
| |
| else
| |
| stat_value = util_module.round_to_sig_fig(stat_value, 3)
| |
| end
| |
|
| |
| table.insert(html_parts, '<td>' .. stat_value .. scaling_strs .. '</td>')
| |
| end
| |
| end
| |
| end
| |
| table.insert(html_parts, '</tr>')
| |
| end
| |
| end
| |
| end
| |
| table.insert(html_parts, '</tbody>')
| |
|
| |
| table.insert(html_parts, '</table>')
| |
| table.insert(html_parts, '</div>')
| |
|
| |
| return table.concat(html_parts)
| |
| end
| |
|
| |
| function localize(key, fallback)
| |
| local result = lang_module.get_string(key)
| |
| if (result == "") or (result == nil) then
| |
| result = util_module.add_space_before_cap(fallback) .. mw.getCurrentFrame():expandTemplate{title="MissingValveTranslationTooltip"}
| |
| end
| |
| return result
| |
| end
| |
|
| |
| -- Mapping from hero name to internal tag name
| |
| local TAG_NAME_MAP = {
| |
| ["Abrams"] = "Abrams",
| |
| ["Bebop"] = "Bebop",
| |
| ["Billy"] = "Punkgoat",
| |
| ["Calico"] = "Nano",
| |
| ["The Doorman"] = "Doorman",
| |
| ["Drifter"] = "Drifter",
| |
| ["Dynamo"] = "Dynamo",
| |
| ["Grey Talon"] = "Orion",
| |
| ["Haze"] = "Haze",
| |
| ["Holliday"] = "Astro",
| |
| ["Infernus"] = "Inferno",
| |
| ["Ivy"] = "Tengu",
| |
| ["Kelvin"] = "Kelvin",
| |
| ["Lady Geist"] = "Geist",
| |
| ["Lash"] = "Lash",
| |
| ["McGinnis"] = "Engineer",
| |
| ["Mina"] = "VampireBat",
| |
| ["Mirage"] = "Mirage",
| |
| ["Mo & Krill"] = "Digger",
| |
| ["Paige"] = "Bookworm",
| |
| ["Paradox"] = "Chrono",
| |
| ["Pocket"] = "Synth",
| |
| ["Seven"] = "Gigawatt",
| |
| ["Shiv"] = "Shiv",
| |
| ["Sinclair"] = "Magician",
| |
| ["Victor"] = "Frank",
| |
| ["Vindicta"] = "Vindicta",
| |
| ["Viscous"] = "Viscous",
| |
| ["Vyper"] = "Viper",
| |
| ["Warden"] = "Warden",
| |
| ["Wraith"] = "Wraith",
| |
| ["Yamato"] = "Yamato",
| |
| }
| |
|
| |
| -- Function to call hero tags based on name
| |
| p.get_hero_tag = function (frame)
| |
| local name = frame.args[1]
| |
| local number = tonumber(frame.args[2])
| |
|
| |
| -- Validate input
| |
| if not name then
| |
| return "Error: Missing name input."
| |
| end
| |
|
| |
| if number ~= 1 and number ~= 2 and number ~= 3 then
| |
| return string.format("Error: Invalid number '%s'. Must be 1, 2, or 3.", tostring(frame.args[2]))
| |
| end
| |
|
| |
| local tagname = TAG_NAME_MAP[name]
| |
| if not tagname then
| |
| return string.format("Error: Unknown name '%s'.", name)
| |
| end
| |
|
| |
| -- Build localization key
| |
| local key = string.format("Citadel_%s_HeroTag_%d", tagname, number)
| |
|
| |
| -- Call Lang.get_string
| |
| local result = lang_module.get_string(key)
| |
|
| |
| return result or ("[Missing string for key: " .. key .. "]")
| |
| end
| |
|
| |
| return p
| |