Editing Module:Sandbox/Vergir

Warning: You are not logged in. Once you make an edit, a temporary account will be created for you. Learn more. Log in or create an account to continue receiving notifications after this account expires, and to access other features.
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 1: Line 1:
--------------------------------------------------------------------------------
-- Module:InfoboxHero
--
-- Renders the hero infobox. Called from [[Template:Infobox hero]], which passes
-- the editor's parameters through as the parent frame:
--
--    {{#invoke:InfoboxHero|render}}
--
-- May also be invoked directly for testing, in which case parameters are read
-- from the invoke itself:
--
--    {{#invoke:InfoboxHero|render|key=hero_atlas}}
--
-- Stat data comes from [[Data:HeroData.json]]; per-hero colors, backgrounds and
-- logo sizes from [[Data:Infobox hero.json]]; labels from [[Module:Lang]] and
-- [[Module:Dictionary]]. Styling lives in [[Template:Infobox hero/styles.css]]
-- and [[Template:Infobox hero/themes.css]].
--
--------------------------------------------------------------------------------
local p = {}
local p = {}
local hero_data_all = mw.loadJsonData('Data:HeroData.json')
local theme_data    = mw.loadJsonData('Data:Infobox_hero.json')
local util        = require('Module:Utilities')
local lang_module = require('Module:Lang')
local dict_module = require('Module:Dictionary')
local hero_module = require('Module:HeroData')
local sb_module  = require('Module:StreetBrawlAbilities')
-- Shared hero-data lookups, see [[Module:HeroData]].
local get_stat    = hero_module.get_stat
local get_scalings = hero_module.get_scalings
local has_stat    = hero_module.has_stat
local has_override_or_stat, stat_number
--------------------------------------------------------------------------------
-- CONFIG
--------------------------------------------------------------------------------
local DEFAULT_HERO_KEY = 'hero_targetdummy'  -- used when |key= is missing/unknown
local DEFAULT_SIG_FIGS = 3
local FALLBACK_CARD    = 'Dummy card.png'
-- Row fields (all optional except a label):
--  stat        Key in Data:HeroData.json. Resolved top-level, then .Weapon,
--              then .Weapon.AltFire. Omit for manual-input-only rows.
--  param      |param= that overrides the value.
--  label      Key in Data:Lang_<code>.json.
--  label_dict  Key in Data:Dictionary. Used instead of `label`.
--  label_text  Literal, untranslated label. Used instead of `label`.
--  link        Target for the label, as 'Page' or 'Page#Anchor'. The language
--              suffix is inserted for us, so write the plain English title.
--  icon_link  Target for the icon. Defaults to `link`.
--  icon        File: name of the value icon. Omit for no icon.
--  sig_figs    Significant figures. Defaults to 3.
--  suffix      Appended directly after the value, e.g. '%', 's', 'm/s'.
--  scaling    Set false to suppress the Boon/Spirit scaling span. Scaling is
--              shown by default wherever the data provides it.
--  optional    Hide the row unless the hero has a non-zero value or scaling.
--  cell_class  Extra class on the value cell.
--  show        function(ctx) -> boolean. Row omitted when false.
local SECTIONS = {
{
class  = 'infobox-h-dropdown-weapon',
header = 'CitadelHeroStats_Weapon',
link  = 'Stats#Weapon',
color  = 'Brown',
rows = {
{
stat    = 'DPS',
param  = 'dps',
label  = 'DPS_label',
link    = 'Damage per second',
icon    = 'Damage.png',
-- DPS is derived from bullet damage and fire rate, both of which
-- show their own scaling; repeating it here would double-count.
scaling = false,
},
{
stat      = 'BulletDamage',
param      = 'bullet_damage',
label      = 'StatDesc_BulletDamage',
link      = 'Bullet Damage',
icon      = 'Bullet damage.png',
cell_class = 'infobox-h-stat-value-padded',
},
{
stat      = 'BulletsPerShot',
param    = 'pellets_per_shot',
label    = 'BonusPelletsPerShot_label',
link      = 'Damage per second',
icon      = 'Bullets per sec icon.png',
icon_link = 'Fire Rate',
show      = function(ctx) return ctx.pellets > 1 end,
},
{
stat      = 'BulletsPerBurst',
param      = 'bullets_per_burst',
label_dict = 'BulletsPerBurst',
link      = 'Damage per second',
icon      = 'Bullets per sec icon.png',
icon_link  = 'Fire Rate',
show      = function(ctx) return ctx.burst > 1 end,
},
{
stat  = 'ClipSize',
param = 'ammo',
label = 'StatDesc_ClipSizeBonus',
link  = 'Ammo',
icon  = 'Clip size icon.png',
},
{
stat  = 'RoundsPerSecond',
param = 'bullets_per_sec',
label = 'StatDesc_RoundsPerSecond',
link  = 'Fire Rate',
icon  = 'Bullets per sec icon.png',
},
{
stat  = 'ReloadTime',
param  = 'reload_time',
label  = 'StatDesc_ReloadTime',
link  = 'Reload Time',
icon  = 'AttributeIconReloadTime.png',
suffix = 's',
},
{
stat  = 'BulletSpeed',
param  = 'bullet_velocity',
label  = 'StatDesc_BulletSpeed',
link  = 'Bullet Velocity',
icon  = 'AttributeIconBulletSpeed.png',
suffix = 'm/s',
},
{
stat      = 'LightMeleeDamage',
param      = 'light_melee',
label      = 'StatDesc_LightMeleeDamage',
link      = 'Melee Damage',
icon      = 'Melee damage.png',
cell_class = 'infobox-h-stat-value-padded',
},
{
stat      = 'HeavyMeleeDamage',
param      = 'heavy_melee',
label      = 'StatDesc_HeavyMeleeDamage',
link      = 'Melee Damage',
icon      = 'Melee damage.png',
cell_class = 'infobox-h-stat-value-padded',
},
{
param      = 'max_range',
label_text = 'Max Range',
link      = 'Falloff Range',
show      = function(ctx) return ctx.args.max_range ~= '' end,
},
{
stat  = 'CritDamageBonusPercent',
label  = 'StatDesc_CritDamageBonusScale',
link  = 'Weapon Damage#Crit_Multiplier',
icon  = 'Crit reduction.png',
suffix = '%',
show  = function(ctx)
return stat_number(ctx, 'CritDamageBonusPercent') ~= 0
end,
},
},
},
{
class  = 'infobox-h-dropdown-vitality',
header = 'CitadelHeroStats_Vitality',
link  = 'Stats#Vitality',
color  = 'Green',
rows = {
{
stat  = 'MaxHealth',
param = 'max_health',
label = 'StatDesc_HealthAttribute',
link  = 'Health',
icon  = 'Health.png',
},
{
stat    = 'BaseHealthRegen',
param    = 'health_regen',
label    = 'StatDesc_HealthRegen',
link    = 'Health Regen',
icon    = 'Health regen.png',
sig_figs = 2,
},
{
stat    = 'CritDamageReceivedPercent',
param    = 'crit_reduction',
label    = 'StatDesc_CritDamageReceivedScale',
link    = 'Damage Resistance#Crit_Reduction',
icon    = 'Crit reduction.png',
suffix  = '%',
optional = true,
},
{
stat      = 'BulletResist',
param    = 'bullet_resist',
label    = 'StatDesc_BulletArmorDamageReduction',
link      = 'Damage Resistance',
icon      = 'Bullet Armor.png',
icon_link = 'Bullet Resist',
suffix    = '%',
optional  = true,
},
{
stat    = 'TechResist',
param    = 'spirit_resist',
label    = 'StatDesc_TechArmorDamageReduction',
link    = 'Damage Resistance#Spirit_Resist',
icon    = 'Spirit Armor.png',
suffix  = '%',
optional = true,
},
{
stat    = 'MeleeResist',
param    = 'melee_resist',
label    = 'StatDesc_MeleeResist',
link    = 'Damage Resistance#Melee Resist',
icon    = 'Melee damage.png',
suffix  = '%',
optional = true,
},
{
stat    = 'DebuffResist',
param    = 'debuff_resist',
label    = 'StatDesc_DebuffResist',
link    = 'Debuff Resist',
icon    = 'Spirit Armor.png',
suffix  = '%',
optional = true,
},
{
stat    = 'BulletLifesteal',
param    = 'bullet_lifesteal',
label    = 'StatDesc_BulletLifesteal',
link    = 'Lifesteal#Bullet Lifesteal',
icon    = 'AttributeIconBulletLifesteal.png',
suffix  = '%',
optional = true,
},
{
stat    = 'SpiritLifesteal',
param    = 'spirit_lifesteal',
label    = 'StatDesc_SpiritLifesteal',
link    = 'Lifesteal#Spirit Lifesteal',
icon    = 'AttributeIconBulletLifesteal.png',
suffix  = '%',
optional = true,
},
{
stat    = 'MaxMoveSpeed',
param    = 'move_speed',
label    = 'StatDesc_RunSpeed',
link    = 'Move Speed',
icon    = 'Move speed.png',
sig_figs = 2,
suffix  = 'm/s',
},
{
stat    = 'SprintSpeed',
param    = 'sprint_speed',
label    = 'StatDesc_SprintSpeed',
link    = 'Move Speed#Sprint',
icon    = 'Move speed sprint.png',
sig_figs = 2,
suffix  = 'm/s',
},
{
stat  = 'GroundDashSpeed',
label  = 'DashSpeed_label',
link  = 'Stamina#Dash_Speed',
icon  = 'Springy boots icon.png',
suffix = 'm/s',
},
{
stat    = 'Stamina',
param    = 'stamina',
label    = 'StatDesc_Stamina',
link    = 'Stamina',
icon    = 'Springy boots icon.png',
sig_figs = 2,
},
{
stat    = 'StaminaCooldown',
param    = 'stamina_cooldown',
label    = 'StatDesc_StaminaCooldown',
link    = 'Stamina#Cooldown',
icon    = 'AttributeIconTechDuration.png',
sig_figs = 2,
suffix  = 's',
},
},
},
{
class  = 'infobox-h-dropdown-spirit',
header = 'CitadelHeroStats_Spirit',
link  = 'Stats#Spirit',
color  = 'Purple',
rows = {
{
stat    = 'TechPower',
param    = 'spirit_power',
label    = 'SpiritPower_label',
link    = 'Spirit Power',
icon    = 'Spirit icon noborder.png',
sig_figs = 2,
},
},
},
}
-- The "Information" block. Manual input only; hidden entirely when all are empty.
local INFO_ROWS = {
{ param = 'pronouns',    label_dict = 'Pronouns' },
{ param = 'voice_actor',  label_dict = 'VoiceActor', link = 'Voice actors' },
{ param = 'release_date', label_dict = 'ReleaseDate', link = 'Heroes by release' },
{ param = 'codenames',    label_dict = 'Codenames', tooltip = 'Codenames used for this hero in the game files' },
}
-- name: literal, or function(ctx) -> string.  when: function(ctx) -> boolean.
local CATEGORIES = {
{ name = 'Heroes' },
{
name = function(ctx) return ctx.hero_en end,
-- Silver (Transformed) is documented on Silver's page and shares her category.
when = function(ctx) return ctx.hero_en ~= 'Silver (Transformed)' end,
},
{
name = 'Heroes with spreadshot weapons',
when = function(ctx) return ctx.pellets > 1 end,
},
{
name = 'Heroes with single damage spreadshot weapons',
when = function(ctx)
return ctx.pellets > 1 and get_stat(ctx.hero, 'HitOnceAcrossAllBullets') == true
end,
},
{
name = 'Heroes with burst weapons',
when = function(ctx) return ctx.burst > 1 end,
},
{
name = 'Heroes with automatic weapons',
when = function(ctx) return ctx.pellets <= 1 and ctx.burst <= 1 end,
},
{
name = 'Heroes with alternate fire weapons',
when = function(ctx)
return ctx.hero.Weapon ~= nil and ctx.hero.Weapon.AltFire ~= nil
end,
},
{
name = 'Heroes with single reload weapons',
when = function(ctx) return get_stat(ctx.hero, 'ReloadSingle') == true end,
},
{
name = 'Heroes with spin up weapons',
when = function(ctx) return has_stat(ctx.hero, 'SpinAcceleration') end,
},
{
name = 'Heroes with no weapon damage falloff',
when = function(ctx)
return (get_stat(ctx.hero, 'FalloffStartRange') or 0)
    == (get_stat(ctx.hero, 'FalloffEndRange') or 0)
end,
},
{
name = "Heroes that don't deal critical damage",
when = function(ctx) return get_stat(ctx.hero, 'CanCrit') == false end,
},
{
name = 'Heroes with modified crit scale',
when = function(ctx) return stat_number(ctx, 'CritDamageBonusPercent') ~= 0 end,
},
{
name = 'Heroes with modified crit resistance',
when = function(ctx)
return has_override_or_stat(ctx, 'crit_reduction', 'CritDamageReceivedPercent')
end,
},
{
name = 'Heroes with modified bullet resist',
when = function(ctx)
return has_override_or_stat(ctx, 'bullet_resist', 'BulletResist')
end,
},
{
name = 'Heroes with modified spirit resist',
when = function(ctx)
return has_override_or_stat(ctx, 'spirit_resist', 'TechResist')
end,
},
{
name = 'Heroes with modified melee resist',
when = function(ctx)
return has_override_or_stat(ctx, 'melee_resist', 'MeleeResist')
end,
},
{
name = 'Heroes with modified debuff resist',
when = function(ctx)
return has_override_or_stat(ctx, 'debuff_resist', 'DebuffResist')
end,
},
{
name = 'Heroes with modified bullet lifesteal',
when = function(ctx)
return has_override_or_stat(ctx, 'bullet_lifesteal', 'BulletLifesteal')
end,
},
{
name = 'Heroes with modified spirit lifesteal',
when = function(ctx)
return has_override_or_stat(ctx, 'spirit_lifesteal', 'SpiritLifesteal')
end,
},
{
name = 'Heroes with modified gravity scale',
when = function(ctx) return has_stat(ctx.hero, 'GravityChange') end,
},
{
name = function(ctx) return 'Heroes with ' .. ctx.stamina .. ' stamina' end,
when = function(ctx) return ctx.stamina ~= '' end,
},
{
name = function(ctx)
if ctx.dash < 14.7 then return 'Heroes with slow dash speed' end
if ctx.dash > 14.7 then return 'Heroes with fast dash speed' end
return 'Heroes with medium dash speed'
end,
},
{
name = 'Heroes with Street Brawl changes',
when = function(ctx) return sb_module.hero_has_changes(ctx.hero_key) end,
},
}
--------------------------------------------------------------------------------
-- Data access
--------------------------------------------------------------------------------
has_override_or_stat = function(ctx, param, stat)
if param and ctx.args[param] ~= '' then return true end
return has_stat(ctx.hero, stat)
end
-- Rounded numeric value of a stat, honouring a |param= override.
stat_number = function(ctx, stat, param)
if param and ctx.args[param] ~= '' then return tonumber(ctx.args[param]) or 0 end
return tonumber(util.round_to_sig_fig(get_stat(ctx.hero, stat) or 0, DEFAULT_SIG_FIGS)) or 0
end
local function format_value(raw, sig_figs)
if raw == nil then return '0' end
local rounded = util.round_to_sig_fig(raw, sig_figs or DEFAULT_SIG_FIGS)
return tostring(rounded ~= nil and rounded or raw)
end
--------------------------------------------------------------------------------
-- Rendering helpers
--------------------------------------------------------------------------------
local function theme_var(hero_key, name)
local hero_theme = theme_data[hero_key]
if hero_theme and hero_theme[name] ~= nil then return hero_theme[name] end
return theme_data['hero_default'][name]
end
local function label_of(row)
if row.label_text then return row.label_text end
if row.label_dict then return dict_module.translate(row.label_dict) end
return lang_module.get_string(row.label)
end
-- 'Damage Resistance#Spirit_Resist' -> 'Damage Resistance/ru#Spirit_Resist'
local function page_link(ctx, target)
if not target then return '' end
local page, anchor = target:match('^([^#]*)(#?.*)$')
return page .. ctx.if_lang .. anchor
end
local function icon_cell(ctx, row, color, value_html)
local icon = ''
if row.icon then
icon = string.format('[[File:%s|20px|link=%s]]', row.icon,
page_link(ctx, row.icon_link or row.link))
end
return ctx.frame:expandTemplate{ title = 'Icon/' .. color, args = { icon, value_html } }
end
-- Ammo and reload time are meaningless for heroes whose weapon never reloads.
local NO_AMMO_STATS = { ClipSize = true, ReloadTime = true }
-- Returns true when the row rendered.
local function render_stat_row(ctx, tbl, row, color, is_first)
if row.show and not row.show(ctx) then return false end
if row.optional and not has_override_or_stat(ctx, row.param, row.stat) then return false end
local value, scaling_inner
if NO_AMMO_STATS[row.stat] and ctx.args.no_ammo == 'true' then
value, scaling_inner = 'N/A', ''
else
local override = row.param and ctx.args[row.param] or ''
if override ~= '' then
value = override
else
value = format_value(get_stat(ctx.hero, row.stat), row.sig_figs)
end
value = value .. (row.suffix or '')
if row.stat and row.scaling ~= false then
local parts = {}
for _, scaling in ipairs(get_scalings(ctx.hero, row.stat)) do
parts[#parts + 1] = hero_module.write_scalar_str(scaling.value, scaling.type)
end
scaling_inner = table.concat(parts)
value = value .. '<span class="infobox-h-spiritboon">' .. scaling_inner .. '</span>'
else
scaling_inner = ''
end
end
local tr = tbl:tag('tr')
local label_cell = tr:tag('td')
-- The section's first row needs extra headroom when it carries a scaling icon.
if is_first and scaling_inner ~= '' then
label_cell:addClass('infobox-h-stat-label-scaled')
end
if row.link then
label_cell:wikitext(string.format('[[%s|<span class="infobox-h-stat-label">%s</span>]]:',
page_link(ctx, row.link), label_of(row)))
else
label_cell:wikitext(label_of(row) .. ':')
end
local value_cell = tr:tag('td')
if row.cell_class then value_cell:addClass(row.cell_class) end
value_cell:wikitext(icon_cell(ctx, row, color, value))
return true
end
local function render_section(ctx, parent, section)
local tbl = parent:tag('tr'):tag('th')
:attr('colspan', '2')
:addClass('infobox-h-subsection infobox-h-dropdown ' .. section.class)
:tag('table'):addClass('mw-collapsible infobox-h-subsection-child')
local caption = tbl:tag('caption'):addClass('infobox-h-dropdown-header')
if ctx.if_lang == '/ru' then
caption:addClass('infobox-h-dropdown-header-overflow')
end
caption:wikitext(string.format(
'[[%s|<span class="infotext-h-bold infobox-h-dropdown-title">%s</span>]]',
page_link(ctx, section.link), lang_module.get_string(section.header)))
local is_first = true
for _, row in ipairs(section.rows) do
if render_stat_row(ctx, tbl, row, section.color, is_first) then
is_first = false
end
end
end
local function render_information(ctx, parent)
local present = {}
for _, row in ipairs(INFO_ROWS) do
if ctx.args[row.param] ~= '' then present[#present + 1] = row end
end
if #present == 0 then return end
parent:tag('tr'):tag('th')
:attr('colspan', '2')
:addClass('infobox-h-text-stat-subtitle')
:wikitext('<span class="infotext-h-bold infotext-h-title infotext-h-big">'
.. dict_module.translate('Information') .. '</span>')
local tbl = parent:tag('tr'):tag('th')
:attr('colspan', '2')
:addClass('infobox-h-subsection')
:tag('table'):addClass('infobox-h-subsection-child')
for _, row in ipairs(present) do
local tr = tbl:tag('tr')
local label = dict_module.translate(row.label_dict)
if row.tooltip then
label = ctx.frame:expandTemplate{ title = 'Tooltip', args = { label, row.tooltip } }
end
if row.link then
tr:tag('td'):wikitext(string.format('[[%s|<span class="infobox-h-stat-label">%s</span>]]:',
page_link(ctx, row.link), label))
else
tr:tag('td'):wikitext(label .. ':')
end
tr:tag('td'):wikitext(ctx.args[row.param])
end
end
local function render_title(ctx, parent)
local th = parent:tag('tr'):tag('th'):attr('colspan', '2'):addClass('infobox-h-title')
if ctx.args.name_font_size ~= '' then
th:cssText('font-size: ' .. ctx.args.name_font_size .. ';')
end
local wrap = th:tag('div'):addClass('infobox-h-title-hero')
wrap:tag('div'):addClass('infobox-h-title-hero-left')
-- Name logo: <Name>_name.svg, or <Name>_name_<lang>.svg on translated pages.
-- Heroes without a logo fall back to their name as plain text.
local svg = ((ctx.args.name ~= '' and ctx.args.name) or ctx.hero_en) .. '_name'
if ctx.if_lang ~= '' then svg = svg .. '_' .. ctx.lang_code end
local middle = wrap:tag('div'):addClass('infobox-h-title-hero-middle')
if util.page_exists('File:' .. svg .. '.svg') then
middle:wikitext(ctx.frame:expandTemplate{ title = 'Icon/White', args = {
string.format('[[File:%s.svg|%s|class=notpageimage]]',
svg, theme_var(ctx.hero_key, 'logo-height')) } })
else
middle:wikitext(ctx.display_name)
end
local right = wrap:tag('div'):addClass('infobox-h-title-hero-right'):tag('div')
if ctx.show_icon then
local icon = ((ctx.args.icon ~= '' and ctx.args.icon) or ctx.hero_en) .. '.png'
if util.page_exists('File:' .. icon) then
right:tag('div'):addClass('infobox-h-title-hero-tornbox')
right:tag('div'):addClass('infobox-h-title-hero-icon')
:wikitext(string.format('[[File:%s|center|35px|class=notpageimage]]', icon))
end
end
end
local function render_card(ctx, parent)
local card = (ctx.args.card ~= '' and ctx.args.card) or (ctx.hero_en .. ' card.png')
if not util.page_exists('File:' .. card) then card = FALLBACK_CARD end
parent:tag('tr'):tag('th')
:attr('colspan', '2')
:addClass('infobox-h-image')
:tag('div')
:wikitext(string.format('[[File:%s|150px|alt=%s]]',
card, mw.title.getCurrentTitle().baseText))
end
local function render_tags(ctx, parent)
if not ctx.show_hero_tags then return end
local tags = {}
for i = 1, 3 do
local tag = hero_module.hero_tag(ctx.hero_en, i)
if tag ~= '' then
tags[#tags + 1] = tag
end
end
if #tags == 0 then return end
local inner = parent:tag('tr'):tag('td')
:attr('colspan', '2')
:addClass('infobox-h-herotags-row')
:tag('div'):addClass('infobox-h-herotags-inner ' .. ctx.hero_key)
for _, tag in ipairs(tags) do
inner:tag('div'):addClass('infobox-h-herotag-pill'):wikitext(tag)
end
end
local function render_categories(ctx)
if mw.ustring.lower(ctx.args.nocat ~= '' and ctx.args.nocat or 'false') ~= 'false' then
return ''
end
if get_stat(ctx.hero, 'IsDisabled') ~= false then return '' end
local out = {}
for _, category in ipairs(CATEGORIES) do
if category.when == nil or category.when(ctx) then
local name = category.name
if type(name) == 'function' then name = name(ctx) end
out[#out + 1] = ctx.frame:expandTemplate{ title = 'lang cat', args = { name } }
end
end
return table.concat(out)
end
--------------------------------------------------------------------------------
-- Entry point
--------------------------------------------------------------------------------
function p.render(frame)
local parent = frame:getParent()
local invoke_args = frame.args
local template_args = parent and parent.args or {}
-- Missing parameters read as '' so callers never have to nil-check.
local args = setmetatable({}, { __index = function(_, k)
local value = invoke_args[k]
if value == nil then value = template_args[k] end
return value or ''
end })
-- |key= accepts a hero_* key or the hero's English name; unknown values fall
-- back to the target dummy, the default character in Sandbox mode.
local hero_key = hero_module.find_hero_key(args.key) or DEFAULT_HERO_KEY
local hero = hero_data_all[hero_key]
local ctx = {
frame    = frame,
args      = args,
hero      = hero,
hero_key  = hero_key,
hero_en  = hero.Name,
lang_code = lang_module.get_lang_code(),
if_lang  = frame:expandTemplate{ title = 'If lang' },
}
ctx.display_name = (args.name ~= '' and args.name) or lang_module.get_string(hero_key)
ctx.show_hero_tags = args.show_hero_tags ~= 'false'
ctx.show_icon      = args.show_icon ~= 'false'
-- Needed by both row visibility and the category rules.
ctx.pellets = stat_number(ctx, 'BulletsPerShot', 'pellets_per_shot')
ctx.burst  = stat_number(ctx, 'BulletsPerBurst', 'bullets_per_burst')
ctx.dash    = stat_number(ctx, 'GroundDashSpeed')
ctx.stamina = (args.stamina ~= '' and args.stamina)
or format_value(get_stat(hero, 'Stamina'), 2)
local root = mw.html.create('div'):addClass('infobox-h ' .. hero_key)
root:tag('div'):addClass('infobox-h-background')
:wikitext(string.format('[[File:%s|%s|right|link=|class=notpageimage]]',
theme_var(hero_key, 'bg-image'), theme_var(hero_key, 'bg-height')))
local tbl = root:tag('table'):addClass('infobox-h-content')
render_title(ctx, tbl)
render_card(ctx, tbl)
render_tags(ctx, tbl)
for _, section in ipairs(SECTIONS) do
render_section(ctx, tbl, section)
end
render_information(ctx, tbl)
if mw.title.getCurrentTitle().nsText ~= 'Template' then
frame:callParserFunction('DISPLAYTITLE', ctx.display_name)
end
return tostring(root) .. render_categories(ctx)
end
--------------------------------------------------------------------------------
-- TEMPORARY render-diff harness - NOT part of the live module.
-- {{#invoke:Sandbox/Vergir|diff}} or |diff|hero_atlas,hero_viscous
--------------------------------------------------------------------------------
-- Kept small: each render makes several expensive page_exists calls, and the
-- parser allows only 100 per page.
local SAMPLE_HEROES = {
'hero_atlas',      -- burst-ish baseline, has scaling on many stats
'hero_viscous',    -- has an AltFire block
'hero_haze',      -- spreadshot
'hero_werewolf',  -- Silver, has a transformed variant
'hero_targetdummy',-- the fallback hero
}
function p.diff(frame)
local other = require('Module:InfoboxHero')
local keys = {}
if frame.args[1] and frame.args[1] ~= '' then
for key in string.gmatch(frame.args[1], '[^,%s]+') do
table.insert(keys, key)
end
else
keys = SAMPLE_HEROES
end
local checked, mismatches = 0, {}
for _, hero_key in ipairs(keys) do
local child = frame:newChild{ args = { key = hero_key } }
local ok_a, a = pcall(other.render, child)
local ok_b, b = pcall(p.render, child)
if not ok_a then a = 'ERR:' .. tostring(a) end
if not ok_b then b = 'ERR:' .. tostring(b) end
checked = checked + 1
if a ~= b then
table.insert(mismatches, hero_key .. ' (len ' .. #tostring(a) .. ' vs ' .. #tostring(b) .. ')')
end
end
return 'Heroes rendered through both modules: ' .. checked ..
'\n\nMismatches: ' .. #mismatches ..
(#mismatches > 0 and ('\n* ' .. table.concat(mismatches, '\n* ')) or '\n\nIdentical output.')
end
return p
return p
Please note that all contributions to The Deadlock Wiki are considered to be released under the Creative Commons Attribution-NonCommercial-ShareAlike (see Deadlock:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)
Preview page with this template

Page included on this page: