| Latest revision |
Your text |
| Line 1: |
Line 1: |
| local p = {}; | | local p = {}; |
| local heroes_data = mw.loadJsonData("Data:HeroData.json") | | local heroes_data = mw.loadJsonData("Data:HeroData.json") |
| | local attributes_data = mw.loadJsonData("Data:AttributeData.json") |
| | local attribute_orders = mw.loadJsonData("Data:StatBoxAttrs.json") |
| local util_module = require('Module:Utilities') | | local util_module = require('Module:Utilities') |
| local lang_module = require('Module:Lang') | | local lang_module = require('Module:Lang') |
| | | local attribute_module = require('Module:AttributeData') |
| --------------------------------------------------------------------------------
| |
| -- Internal helpers
| |
| --------------------------------------------------------------------------------
| |
| | |
| -- Localized string for a key, falling back to a readable version of `fallback`
| |
| -- plus a "missing translation" tooltip.
| |
| local 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
| |
| | |
| -- Raw scaling value of a stat under LevelScaling / SpiritScaling, or nil when
| |
| -- the hero has no scaling of that type for that stat.
| |
| local function raw_scaling(hero_data, scaling_type, stat)
| |
| local scaling = hero_data and hero_data[scaling_type .. "Scaling"]
| |
| if (scaling == nil or stat == nil) then return nil end
| |
| return scaling[stat]
| |
| 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",
| |
| ["Apollo"] = "Fencer",
| |
| ["Graves"] = "Necro",
| |
| ["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",
| |
| ["Celeste"] = "Unicorn",
| |
| ["Pocket"] = "Synth",
| |
| ["Rem"] = "Familiar",
| |
| ["Seven"] = "Gigawatt",
| |
| ["Shiv"] = "Shiv",
| |
| ["Silver"] = "Werewolf",
| |
| ["Silver (Transformed)"] = "Werewolf",
| |
| ["Sinclair"] = "Magician",
| |
| ["Venator"] = "Priest",
| |
| ["Victor"] = "Frank",
| |
| ["Vindicta"] = "Vindicta",
| |
| ["Viscous"] = "Viscous",
| |
| ["Vyper"] = "Viper",
| |
| ["Warden"] = "Warden",
| |
| ["Wraith"] = "Wraith",
| |
| ["Yamato"] = "Yamato",
| |
| }
| |
| | |
| --------------------------------------------------------------------------------
| |
| -- Data access, for use by other modules
| |
| --------------------------------------------------------------------------------
| |
|
| |
|
| -- returns the table of a specific item, used by external modules | | -- returns the table of a specific item, used by external modules |
| Line 83: |
Line 17: |
| end | | end |
|
| |
|
| -- Hero table for a hero_* key or an exact English name, or nil. | | -- returns the key of the specified hero's english name |
| local function hero_by_key_or_name(input)
| | function p.get_hero_key(name) |
| local hero = heroes_data[input] | | for i,v in pairs(heroes_data) do |
| if (hero == nil) then hero = p.get_json_item(input) end
| | if (v["Name"] == name) then |
| return hero | | return i |
| | end |
| | end |
| | return nil |
| end | | end |
|
| |
|
| -- Value of a stat, checking the hero's top level, then Weapon, then AltFire.
| |
| -- Returns nil when the hero has no such stat.
| |
| function p.get_stat(hero_data, stat)
| |
| if (hero_data == nil or stat == nil) then return nil end
| |
| local value = hero_data[stat]
| |
| if (value == nil and hero_data.Weapon) then
| |
| value = hero_data.Weapon[stat]
| |
| end
| |
| if (value == nil and hero_data.Weapon and hero_data.Weapon.AltFire) then
| |
| value = hero_data.Weapon.AltFire[stat]
| |
| end
| |
| return value
| |
| end
| |
|
| |
|
| -- Ordered list of a hero's scalings for a stat, Level first then Spirit: | | --{{#invoke:HeroData|get_hero_stat|HERO_NAME|STAT_NAME}}-- |
| -- { { type = "Level", value = 1.5 }, { type = "Spirit", value = 0.04 } }
| | p.get_hero_stat = function(frame) |
| -- Absent scalings are omitted, so an empty list means "no scaling". Zero | | local hero_name = frame.args[1] |
| -- scalings are omitted too unless include_zero is set, which only the
| | local hero_stat_key = frame.args[2] |
| -- deprecated get_hero_scaling_data below needs.
| | |
| function p.get_scalings(hero_data, stat, include_zero) | | local hero = p.get_json_item(hero_name) |
| local scalings = {} | | if(hero == nil) then return "Hero Not Found" end |
| for _, scaling_type in ipairs({"Level", "Spirit"}) do | | |
| local value = raw_scaling(hero_data, scaling_type, stat)
| | local var_value = hero[hero_stat_key] |
| if (value ~= nil and (include_zero or value ~= 0)) then
| | if(var_value == nil) then return 0 end |
| table.insert(scalings, { type = scaling_type, value = value })
| |
| end
| |
| end
| |
| return scalings
| |
| end | |
|
| |
|
| -- DEPRECATED, kept for [[Module:HeroComparisonTable]]. Use p.get_scalings.
| | return var_value |
| -- Keyed by scaling value, so it silently drops an entry when Level and Spirit
| |
| -- scale by the same amount, and it keeps zero scalings.
| |
| function p.get_hero_scaling_data(hero_data, hero_stat_key)
| |
| local scaling_data_returned = {}
| |
| -- Walked backwards so Level is written last and wins a value collision,
| |
| -- matching the original Spirit-then-Level assignment order.
| |
| local scalings = p.get_scalings(hero_data, hero_stat_key, true)
| |
| for i = #scalings, 1, -1 do
| |
| scaling_data_returned[scalings[i].value] = scalings[i].type
| |
| end
| |
| return scaling_data_returned | |
| end | | end |
|
| |
|
| -- Whether a hero has a stat at all: a non-zero base value, or any scaling.
| |
| function p.has_stat(hero_data, stat)
| |
| local base = p.get_stat(hero_data, stat)
| |
| if (base ~= nil and base ~= 0) then return true end
| |
| return #p.get_scalings(hero_data, stat) > 0
| |
| end
| |
|
| |
|
| -- Resolves a hero_* key or an English hero name to a hero_* key. | | --{{#invoke:HeroData|get_localized_var|HERO_NAME|HERO_VAR}}-- |
| -- Returns nil when the input matches no hero. Name matching is case-insensitive. | | --i.e. |Abrams|Role -> hero_atlas_role -> Charges into close combat |
| function p.find_hero_key(input)
| | p.get_localized_var = function(frame) |
| if (input == nil or input == '') then return nil end | | local hero_name = frame.args[1] |
| if (heroes_data[input] ~= nil) then return input end | | local unlocalized_var = frame.args[2] |
| local wanted = mw.ustring.lower(input)
| | lore_key = p.get_json_item(hero_name)[unlocalized_var] |
| for hero_key, hero_data in pairs(heroes_data) do | | if (lore_key ~= nil) then |
| if (hero_data["Name"] and mw.ustring.lower(hero_data["Name"]) == wanted) then | | return lang_module._get_string(lore_key) |
| return hero_key
| | else |
| end
| | return "Hero does not have " .. unlocalized_var .. " in their data" |
| end | | end |
| return nil
| |
| end | | end |
|
| |
|
| -- A hero's Nth roster tag (1-3) by English name, or '' when there is no such tag. | | |
| function p.hero_tag(hero_en, index)
| | --If the hero scales with the stat, it returns {{Ss|value}} or {{Ls|value}}, else blank string |
| local tagname = hero_en and TAG_NAME_MAP[hero_en] | | --{{#invoke:HeroData|get_hero_scalar_str_invoke|HERO_NAME|STAT_NAME}}-- |
| if (tagname == nil) then return '' end | | p.get_hero_scalar_str_invoke = function(frame) |
| if (index ~= 1 and index ~= 2 and index ~= 3) then return '' end | | local hero_name = frame.args[1] |
| return lang_module.get_string(string.format("Citadel_%s_HeroTag_%d", tagname, index)) or '' | | local hero_stat_key = frame.args[2] |
| | local hero_data = p.get_json_item(hero_name) |
| | if(hero_data == nil) then return "Hero Not Found" end |
| | return p.get_hero_scalar_str(hero_data, hero_stat_key) --surely theres a better way |
| end | | end |
|
| |
|
| -------------------------------------------------------------------------------- | | function p.get_hero_scalar_str(hero, hero_stat_key) |
| -- Wikitext entry points | | local scaling_type_full |
| --------------------------------------------------------------------------------
| | local scaling_data |
| | | local scaling_value |
| -- returns the key of the specified hero's english name | | local scaling_types = {"Spirit", "Level"} |
| function p.get_hero_key(frame)
| | local scaling_abbrevs = {"Ss", "Ls"} |
| local hero_name_input = frame.args[1]
| | |
| if not hero_name_input then
| | for index, scaling_type in ipairs(scaling_types) do |
| return "Error: Hero name not specified." | | scaling_type_full = scaling_type .. "Scaling" |
| | scaling_data = hero[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_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[index] --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 |
| | end |
| end | | end |
| return p.find_hero_key(hero_name_input) or "Hero not found." | | |
| | -- Otherwise return empty string |
| | return "" |
| end | | end |
|
| |
|
| --{{#invoke:HeroData|resolve_key|HERO_KEY_OR_NAME}}-- | | --HERO_NAME in english |
| -- The matching hero_* key, or '' when the input matches no hero.
| | --{{#invoke:HeroData|write_infobox|HERO_NAME}}-- |
| function p.resolve_key(frame)
| | p.write_infobox = function(frame) |
| return p.find_hero_key(frame.args[1]) or ''
| | -- Get hero data |
| end
| | hero_name = frame.args[1] |
| | | hero_data = p.get_json_item(hero_name) |
| --{{#invoke:HeroData|get_hero_var|HERO_NAME|STAT_NAME|sig_figs_or_localize}}-- | | if(hero_data == nil) then return "Hero Not Found" end |
| --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 = hero_by_key_or_name(hero_name) | | local infobox_attributes = { |
| if(hero == nil) then return "Hero Not Found" end
| | Weapon = {'DPS','ClipSize','RoundsPerSecond','ReloadTime'}, |
| | Vitality = {'MaxHealth','BulletArmorDamageReduction','TechArmorDamageReduction','MaxMoveSpeed'} |
| | } |
| | | |
| local var_value = p.get_stat(hero, hero_stat_key) | | -- Declarations and initializations |
| if(var_value == nil) then return 0 end | | 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 = ""} |
| | | |
| --round | | -- Add the main parameters |
| if (sig_figs_or_localize ~= nil and tonumber(sig_figs_or_localize) ~= nil) then | | template_args["name_english"] = hero_name |
| 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 | | template_args["name_localized"] = lang_module._get_string(p.get_hero_key(hero_name)) |
| if (sig_figs_or_localize == "true") then
| |
| return lang_module.get_string(var_value)
| |
| end
| |
| | |
| return var_value
| |
| end
| |
| | |
| --{{#invoke:HeroData|get_alt_fire_var|HERO_NAME|STAT_NAME|sig_figs_or_localize}}--
| |
| p.get_alt_fire_var = function(frame) | |
| local hero_name = frame.args[1]
| |
| local stat_key = frame.args[2]
| |
| local sig_figs_or_localize = frame.args[3]
| |
| | | |
| local hero = hero_by_key_or_name(hero_name) | | local wep_name = hero_data["WeaponName"] |
| if(hero == nil) then return "Hero Not Found" end | | if (wep_name ~= nil) then template_args["weapon_name"] = lang_module._get_string(wep_name) end |
| | | |
| if not (hero.Weapon and hero.Weapon.AltFire) then | | local wep_desc = hero_data["WeaponDescription"] |
| return "No Alt Fire"
| | if (wep_desc ~= nil) then template_args["weapon_description"] = lang_module._get_string(wep_desc) end |
| end
| |
| | | |
| local var_value = hero.Weapon.AltFire[stat_key] | | local role = hero_data["Role"] |
| if(var_value == nil) then return 0 end | | if (role ~= nil) then template_args["role"] = lang_module._get_string(role) end |
| | | |
| --round | | local playstyle = hero_data["Playstyle"] |
| if (sig_figs_or_localize ~= nil and tonumber(sig_figs_or_localize) ~= nil) then | | if (playstyle ~= nil) then template_args["playstyle"] = lang_module._get_string(playstyle) end |
| var_value = util_module.round_to_sig_fig(var_value, sig_figs_or_localize)
| |
| end
| |
| | | |
| --localize | | -- Iterate attribute categories |
| if (sig_figs_or_localize == "true") then | | for category, stats in pairs(infobox_attributes) do |
| return lang_module.get_string(var_value)
| | -- Iterate stats |
| end
| | for _, stat_name in ipairs(stats) do |
| | | -- Confirm its in attribute data and retrieve it |
| return var_value
| | attribute_data = attributes_data[category] |
| end | | if (attribute_data == nil) then return "Category " .. category .. " in infobox_attributes is not in Data:AttributeData" end |
| | | stat_data = attribute_data[stat_name] |
| --{{#invoke:HeroData|get_list_elem|HERO_NAME|VAR|NUMBER|LOCALIZE}} | | if (stat_data == nil) then return "Attribute " .. stat_name .. " in infobox_attributes is not in Data:AttributeData" end |
| p.get_list_elem = function(frame)
| | |
| local hero_name = frame.args[1]
| | -- gets the stat's value |
| local var = frame.args[2]
| | stat_value = hero_data[stat_name] |
| local number_int = tonumber(frame.args[3])
| | if (stat_value == nil) then |
| local localize_arg = frame.args[4]
| | stat_value = 0 --default to 0 if not present |
|
| | end |
| local hero = hero_by_key_or_name(hero_name)
| | |
| if(hero == nil) then return "Hero Not Found" end
| | --Round value to 3 significant figures |
|
| | stat_value = util_module.round_to_sig_fig(stat_value, 3) |
| local list = p.get_stat(hero, var)
| | |
| if (list == nil) then return "" end
| | -- get label and postfix |
| local element = list[number_int]
| | label = lang_module._get_string(stat_data["label"]) |
| if (element == nil) then return "" end
| | postfix = stat_data["postfix"] |
|
| | if (postfix == nil) then |
| if localize_arg=="true" then
| | postfix = "" |
| element = lang_module.get_string(element) | | else |
| | postfix = lang_module._get_string(postfix) |
| | 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 |
| | if (stat_name == "DPS") then |
| | icon_color = "Brown" |
| | else |
| | icon_color = "Grey" |
| | end |
| | 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 } |
| | |
| | -- First add localized stat name for left column |
| | stat_values[category] = stat_values[category] .. ',<span style="color: #999999; background-color: #2F2F2F; display: inline-flex; width: 100%; height: 100%; justify-content: center; align-items: center;">' .. label .. '</span>' |
| | |
| | -- 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 | | end |
|
| | |
| return element
| | -- 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 | | 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) | | --{{#invoke:HeroData|write_stat_boxes|HERO_NAME}} |
| local hero_key = frame.args[1] | | --Creates {{StatBox}}'s' for the 3 categories Weapon, Vitality, Spirit |
| local hero_data = heroes_data[hero_key]
| | p.write_stat_boxes = function(frame) |
| if (hero_data == nil) then return hero_key.." not found" end | | local hero_name = frame.args[1] |
| local role_key = hero_data["Role"]
| | if(hero_name == nil) then return "Hero parameter missing" end |
| 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 | | -- Use expandTemplate to evaluate the Infobox_hero template |
| local template_args = {}
| | local template_title = mw.title.new("Template:StatBox") --name of the template |
| template_args[1] = ""
| | local template_calls = "" --all template calls concatenated |
| template_args[2] = str | | local template_call --current template call |
| return frame:expandTemplate{title = 'Quotation', args = template_args}
| | local template_args = {} --current template arguments |
| end
| | local cell_values --current cell values |
| | | local cell_value --current cell value |
| p.write_default_items = function(frame)
| | local label --current stat's label |
| local hero_key = frame.args[1] --unlocalized | | local postfix --current stat's postfix |
| if (hero_key == nil) then return "No hero key provided" end | | local stat_value --current stat's numerical value in the hero data |
| local str = "" | | local hero_data = p.get_json_item(hero_name) |
| local hero = heroes_data[hero_key] | | local stats --stats of the current category |
| if (hero == nil) then return "Hero not found, must be unlocalized" end
| | local image_file_name --name of the image_file to check |
| local template_title = 'PageRef' | | local image_file --mw returned image file |
| for i, item_key in ipairs(hero["RecommendedItems"] or {}) do
| | local extra_blank_cell --add a blank cell after certain stats |
| local template_args = {}
| | local stats_to_add_blank_after = {BulletLifesteal = true, CritDamageReceivedScale = true} |
| template_args[1] = lang_module.get_string(item_key, 'en')
| | if (hero_data == nil) then return "Hero Not Found in AttrData" end |
| template_args['alt_name'] = localize(item_key, item_key)
| | local category_data = attribute_module.get_category_data() |
| local expanded_template = mw.getCurrentFrame():expandTemplate{ title = template_title, args = template_args }
| | local should_display |
| str = str .. "* " .. expanded_template .. "\n"
| |
| end | |
| return str
| |
| end
| |
| | |
| --If the hero scales with the stat, it returns {{Ss|value}} or {{PI|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 no_template = frame.args["no_template"] | |
| | | |
| local hero_data = hero_by_key_or_name(hero_key) | | for _, category in ipairs(attribute_orders["_category_order"]) do |
| if(hero_data == nil) then return "Hero not found." end
| | stats = attributes_data[category] |
|
| | local category_values = category_data[category] |
| local scaling_value = raw_scaling(hero_data, scaling_type, hero_stat_key)
| | template_args["box_name"] = category_values.unlocalized_name |
| if scaling_value == nil then return "" end
| | template_args["box_rgb"] = category_values.rgb |
| | | template_args["num_cols"] = 2 |
| --round
| | cell_values = "" |
| 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) | | -- Determine cell values |
| if (scaling_value == nil) then return "get_hero_scalar() error with rounding" end | | for _, stat_name in ipairs(attribute_orders[category]["_attribute_order"]) do |
| end
| | stat_data = stats[stat_name] |
|
| | |
| --localize
| | -- Confirm its meant to be displayed in hero statbox |
| if (sig_figs_or_localize == "true") then
| | should_display = stat_data['display_regions']['hero_statbox'] |
| return lang_module.get_string(scaling_value)
| | if (should_display ~= nil) then |
| end
| | |
|
| | -- gets the stat's value if it has that stat, default to 0 if not |
| if no_template == "true" then
| | stat_value = hero_data[stat_name] |
| return scaling_value
| | if (stat_value == nil) then |
| end
| | stat_value = 0 --default to 0 if not present |
|
| | end |
| return p.write_scalar_str(scaling_value, scaling_type)
| | |
| end
| | --Round value to 3 significant figures |
| | | stat_value = util_module.round_to_sig_fig(stat_value, 3) |
| -- Check if a hero has a stat (Base, Boons, or Spirit Scaling) | | |
| -- Returns "true" if found, nil if not (for #if templates)
| | -- get label and postfix |
| p.hero_has_stat = function(frame)
| | label = lang_module._get_string(stat_data["label"]) |
| local hero_key = frame.args[1]
| | postfix = stat_data["postfix"] |
| local stat_key = frame.args[2]
| | if (postfix == nil) then |
| if (hero_key == nil) then return nil end
| | postfix = "" |
|
| | else |
| local hero_data = hero_by_key_or_name(hero_key)
| | postfix = lang_module._get_string(postfix) |
| if (hero_data == nil) then return nil end
| | end |
|
| | -- if a language is missing the postfix, use no postfix |
| if p.has_stat(hero_data, stat_key) then return "true" end
| | if (postfix == nil) then |
| return nil
| | postfix = "" |
| end
| | end |
| | | |
| -- Function to call hero tags based on name | | -- Check if icon file exists, and if not, don't use any image |
| p.get_hero_tag = function (frame)
| | image_file_name = 'File:AttributeIcon' .. stat_name .. '.png' |
| local name = frame.args[1]
| | image_file = util_module.get_image_file(image_file_name) |
| local number = tonumber(frame.args[2])
| | |
| | | -- Add an empty cell following some stats to align them correctly as seen in game |
| -- Validate input
| | if (stats_to_add_blank_after[stat_name]) then |
| if not name then
| | extra_blank_cell = " ," --prefixed space is needed |
| return "Error: Missing name input."
| | else |
| end
| | extra_blank_cell = "" |
| | | 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]))
| | -- Add the scaling str if it scales |
| end
| | local scalar_str = p.get_hero_scalar_str(hero_data, stat_name) |
| | | |
| if TAG_NAME_MAP[name] == nil then
| | -- Set cell value as "Icon StatvaluePostfix Statname Scaling," |
| return string.format("Error: Unknown name '%s'.", name)
| | -- If icon file already exists, set it to #REDIRECT to the duplicate file page |
| end
| | cell_value = image_file .. " " .. stat_value .. postfix .. " " .. label .. " " .. scalar_str .. "," .. extra_blank_cell |
| | | |
| return p.hero_tag(name, number)
| | cell_values = cell_values .. cell_value --add value to values list |
| end
| | end |
| | | end |
| --{{#invoke:HeroData|has_tags|HERO_ENGLISH_NAME}}-- | | template_args["cell_values"] = cell_values |
| -- 'true' when the hero has roster tags, '' otherwise. | | |
| function p.has_tags(frame)
| | |
| if p.hero_tag(frame.args[1], 1) ~= '' then return 'true' end
| | -- Write current call |
| return ''
| | template_call = mw.getCurrentFrame():expandTemplate{ title = template_title, args = template_args } |
| 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 {{PI|scalar}}
| |
| function p.write_scalar_str(scaling_value, scaling_type, compact)
| |
| local scaling_abbrevs = {Spirit = "Ss", Level = "PI"}
| |
| | | |
| -- Return blank if it doesnt scale
| | -- Add call to the set of calls |
| if (scaling_value == 0) then return "" end
| | template_calls = template_calls .. "\n" .. template_call |
|
| |
| -- 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]
| |
| local template_args = {}
| |
| template_args["1"] = scaling_value
| |
| if compact then
| |
| template_args["compact"] = "yes"
| |
| template_args["show_value"] = "yes"
| |
| end | | end |
| | | |
| local template_call = mw.getCurrentFrame():expandTemplate{ title = template_title, args = template_args }
| | return template_calls |
| local result = template_call:gsub("\n", ""):gsub("\r", "")
| |
|
| |
| return result | |
| end
| |
| | |
| -- Outputs a wikitable of heroes grouped by GroundDashDuration using {{HeroIcon|hero_name}}
| |
| -- {{#invoke:HeroData|write_ground_dash_buckets}}
| |
| p.write_ground_dash_buckets = function(frame)
| |
| local buckets = {
| |
| [0.62] = {},
| |
| [0.68] = {},
| |
| [0.72] = {},
| |
| }
| |
| | |
| -- Collect heroes
| |
| for hero_key, hero_data in pairs(heroes_data) do
| |
| if not hero_data.InDevelopment and not hero_data.IsDisabled then
| |
| local dash = p.get_stat(hero_data, "GroundDashDuration")
| |
| if dash and buckets[dash] then
| |
| table.insert(buckets[dash], hero_data.Name or hero_key)
| |
| end
| |
| end
| |
| end
| |
| | |
| -- Sort alphabetically
| |
| for _, list in pairs(buckets) do
| |
| table.sort(list)
| |
| end
| |
| | |
| -- Determine max rows dynamically
| |
| local max_rows = 0
| |
| for _, list in pairs(buckets) do
| |
| if #list > max_rows then max_rows = #list end
| |
| end
| |
| | |
| local output = {"{| class='wikitable mw-collapsible'",
| |
| "|+Hero Dash Buckets", "! Bucket 1 !! Bucket 2 !! Bucket 3"}
| |
| local current_frame = frame or mw.getCurrentFrame()
| |
| | |
| for i = 1, max_rows do
| |
| local row = {}
| |
| for _, bucket in ipairs({0.62, 0.68, 0.72}) do
| |
| local hero_name = buckets[bucket][i]
| |
| table.insert(row, hero_name and current_frame:expandTemplate{title = "HeroIcon", args = {hero_name}} or "")
| |
| end
| |
| table.insert(output, "|-\n| " .. table.concat(row, " || "))
| |
| end
| |
| | |
| table.insert(output, "|}")
| |
| return table.concat(output, "\n")
| |
| end | | end |
|
| |
|
| return p | | return p |