Module:HeroData/nav: Difference between revisions

From The Deadlock Wiki
Jump to navigation Jump to search
Sur (talk | contribs)
m parameterize text size and card size
3D model function
 
(42 intermediate revisions by 8 users not shown)
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 hero_release_module = require('Module:HeroData/release')
local lang_module = require('Module:Lang')
local lang_module = require('Module:Lang')
local utilities = require('Module:Utilities')


-- for [[Template:Hero Navbox]] on /Heroes, i.e. {{Hero Card Nav|Hero=Abrams}} {{Hero Card Nav|Hero=Bebop}}
-- Cache to store results of get_heroes if called multiple times in one page render
local heroes_cache = {}
 
-- Shared helper function
local function get_heroes(in_herolabs)
    -- Return cached result if it exists
    if heroes_cache[in_herolabs] then
        return heroes_cache[in_herolabs]
    end
 
    local heroes = {}
 
    for hero_key, hero_data in pairs(heroes_data) do
        -- hero_werewolf_transformed is consolidated in Silver's page
        if hero_data["Name"] ~= nil and hero_key ~= 'hero_werewolf_transformed' then
 
            local this_hero_status = hero_release_module.get_hero_release_status(hero_key)
 
            if ((in_herolabs == 'true' and this_hero_status == 'HeroLabs') or
                (in_herolabs == 'false' and this_hero_status == 'Released')) then
 
                local is_recommended = hero_data['IsRecommended'] or false
 
                --- Create a sort key for each hero to ensure correct alphabetical ordering.
                local hero_name = lang_module.get_string(hero_key, nil, 'en')
                local sort_key_to_find = hero_key .. '_sort'
                local potential_sort_key = lang_module.get_string(sort_key_to_find, nil, 'en')
 
                local sort_key
                -- Detect translation failure if the returned string contains the original search key
                if string.find(potential_sort_key, sort_key_to_find, 1, true) then
                    sort_key = hero_name
                else
                    sort_key = potential_sort_key
                end
 
                -- NOTE: Check if lang_module.get_string(hero_key, 'en') returns the same value as hero_name.
                -- If the second argument defaults to nil natively, you can optimize further by setting: link = hero_name
                local hero_link = lang_module.get_string(hero_key, 'en')
 
                -- Store reusable hero data
                local hero = {
                    key = hero_key,
                    name = hero_name,
                    sort_key = sort_key,
                    link = hero_link,
                    recommended = tostring(is_recommended)
                }
 
                table.insert(heroes, hero)
            end
        end
    end
 
    -- Sort heroes
    table.sort(heroes, function(a, b)
        return a.sort_key < b.sort_key
    end)
 
    heroes_cache[in_herolabs] = heroes
    return heroes
end
 
-- for [[Template:Deadlock_Wiki/Heroes]]
function p.get_hero_nav_cards(frame)
function p.get_hero_nav_cards(frame)
local current_or_upcoming = frame.args[1]
    local text_size = frame.args['text_size']
if current_or_upcoming ~= 'Current' and current_or_upcoming ~= 'Upcoming' then
    local card_size = frame.args['card_size']
return 'First parameter must be Current or Upcoming'
    local in_herolabs = frame.args['in_herolabs'] or 'false'
end
    local debug_mode = frame.args['debug_mode'] == 'true'
 
local heroes = {}
    local heroes = get_heroes(in_herolabs)
for hero_key, hero_data in pairs(heroes_data) do
    local parts = {}
if hero_data["Name"] ~= nil and hero_data["IsDisabled"] == false then
 
if (hero_data["InDevelopment"] == false and current_or_upcoming == 'Current' or hero_data["InDevelopment"] == true and current_or_upcoming == 'Upcoming') then
    for _, hero in ipairs(heroes) do
table.insert(heroes, lang_module.get_string(hero_key))
        table.insert(parts, string.format('{{Hero card2|heroName=%s|cardSize=%s|textSize=%s|isHeroLabs=%s}}',
end
            hero.link, card_size, text_size, in_herolabs))
end
    end
end
 
    local ret = table.concat(parts)
--Order list alphabetically
 
table.sort(heroes) --O(nlogn)
    if debug_mode then
        return ret
--Add each item to output
    else
local ret = ''
        return frame:preprocess(ret)
for index, hero_name in ipairs(heroes) do
    end
ret = ret .. '{{Hero Card Nav|Hero=' .. hero_name .. '}} '
end
--Remove the last space
ret = string.sub(ret, 1, -(string.len(' '))-1)
return frame:preprocess(ret)
end
end


-- for [[Template:Deadlock_Wiki/Heroes]] on home page, i.e. [[Template:Hero card2]]
-- for [[Template:Roster]]
function p.get_hero_nav_cards_homepage(frame)
function p.get_hero_roster(frame)
--true or false
    local in_herolabs = frame.args['in_herolabs'] or 'false'
local in_herolabs = frame.args[1]
    local debug_mode = frame.args['debug_mode'] == 'true'
local text_size = frame.args[2]
local card_size = frame.args[3]


if in_herolabs ~= 'true' and in_herolabs ~= 'false' then
    local heroes = get_heroes(in_herolabs)
return 'in_herolabs must be either true or false as the first unnamed parameter'
    local parts = {}
end
 
if text_size == nil then text_size = 20 end
    for _, hero in ipairs(heroes) do
if card_size == nil then card_size = 132 end
        table.insert(parts, string.format('{{HeroRosterCard|name=%s|key=%s}}', hero.name, hero.key))
    end
--Iterate heroes
 
local heroes = {}
    local ret = table.concat(parts)
for hero_key, hero_data in pairs(heroes_data) do
 
if hero_data["Name"] ~= nil then
    if debug_mode then
-- if herolabs is requested, only needs to have herolabs=true
        return ret
-- otherwise, needs to be not disabled, in development, nd herolabs is nil or false
    else
if ((in_herolabs == 'true' and hero_data['InHeroLabs']) or
        return frame:preprocess(ret)
(in_herolabs == 'false' and not hero_data['IsDisabled'] and not hero_data['InDevelopment'] and (hero_data['InHeroLabs'] == nil or not hero_data['InHeroLabs']))) then
    end
end
local is_recommended = hero_data['Recommended']
 
if is_recommended == nil then
-- for [[Template:Quotes Navbox]] etc.
is_recommended = false
p.get_hero_bulletpoints = function(frame)
end
    local subpage = frame.args['1']
    local in_herolabs = frame.args['in_herolabs'] or 'false'
local hero_str = lang_module.get_string(hero_key) .. '|recommended=' .. tostring(is_recommended)
    local debug_mode = frame.args['debug_mode'] == 'true'
    local no_redlinks = frame.args['no_redlinks'] == 'true'
table.insert(heroes, hero_str)
 
end
    local heroes = get_heroes(in_herolabs)
end
    local parts = {}
end
 
    for _, hero in ipairs(heroes) do
--Order list alphabetically
        -- Lua optimization: clean ternary fallback for page_title assignment
table.sort(heroes) --O(nlogn)
        local page_title = subpage and (hero.link .. '/' .. subpage) or hero.name
 
--Add each item to output
        -- Skip redlinks entirely when enabled
local ret = ''
        if not (no_redlinks and not utilities.page_exists(page_title)) then
for index, hero_name in ipairs(heroes) do
            local item
ret = ret .. '{{Hero_card2|name=' .. hero_name
            if subpage then
ret = ret .. '|text_size=' .. text_size
                item = string.format('{{PageRef|%s|alt_link=%s}}', hero.link, page_title)
ret = ret .. '|herolabs=' .. in_herolabs
            else
ret = ret .. '|card_size=' .. card_size
                item = string.format('{{HeroIcon|%s}}', hero.link)
ret = ret .. '}} '
            end
end
            table.insert(parts, item)
        end
--Remove the last space
    end
ret = string.sub(ret, 1, -(string.len(' '))-1)
 
    local ret = table.concat(parts, ' &bull; ')
return frame:preprocess(ret)
 
    if debug_mode then
        return ret
    else
        return frame:preprocess(ret)
    end
end
 
-- for image galleries
p.get_hero_gallery = function(frame)
    local file_name = frame.args['1'] or ''
    local description = frame.args['2'] or ''
    local in_herolabs = frame.args['in_herolabs'] or 'false'
    local debug_mode = frame.args['debug_mode'] == 'true'
 
    local heroes = get_heroes(in_herolabs)
    local parts = {}
 
    for _, hero in ipairs(heroes) do
        table.insert(parts, string.format('File:%s%s|%s%s\n', hero.link, file_name, hero.name, description))
    end
   
    local ret = '<gallery>\n' .. table.concat(parts) .. '</gallery>'
 
    if debug_mode then
        return ret
    else
        return frame:preprocess(ret)
    end
end
 
-- Generate 3D model gallery
function p.get_hero_models(frame)
    local in_herolabs = frame.args['in_herolabs'] or 'false'
    local debug_mode = frame.args['debug_mode'] == 'true'
 
    local heroes = get_heroes(in_herolabs)
    local parts = {}
 
    for _, hero in ipairs(heroes) do
        table.insert(parts, string.format('{{3D Model|%s}}', hero.name))
    end
 
    local ret = table.concat(parts)
 
    if debug_mode then
        return ret
    else
        return frame:preprocess(ret)
    end
end
end
return p
return p

Latest revision as of 13:54, 7 August 2026

Overview

[edit source]

Generates hero navigation cards

Functions

[edit source]

get_hero_nav_cards

[edit source]

For Template:Hero Navbox on Heroes, individual hero pages like Abrams, and the home page.

Examples

[edit source]

First with debug_mode on, to help visualize what the output's source looks like.

{{#invoke:HeroData/nav|get_hero_nav_cards
|text_size=13
|card_size=88
|in_herolabs=false
|debug_mode=true
}}

{{Hero card2|heroName=Abrams|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Apollo|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Bebop|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Billy|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Calico|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Celeste|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=The Doorman|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Drifter|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Dynamo|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Graves|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Grey Talon|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Haze|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Holliday|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Infernus|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Ivy|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Kelvin|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Lady Geist|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Lash|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=McGinnis|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Mina|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Mirage|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Mo & Krill|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Paige|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Paradox|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Pocket|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Rem|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Seven|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Shiv|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Silver|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Sinclair|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Venator|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Victor|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Vindicta|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Viscous|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Vyper|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Warden|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Wraith|cardSize=88|textSize=13|isHeroLabs=false}}{{Hero card2|heroName=Yamato|cardSize=88|textSize=13|isHeroLabs=false}}

Now with debug_mode defaulted to false (off) to see actual visual output.

{{#invoke:HeroData/nav|get_hero_nav_cards
|text_size=13
|card_size=88
|in_herolabs=false
}}

Hero Labs

Abrams

Hero Labs

Apollo

Hero Labs

Bebop

Hero Labs

Billy

Hero Labs

Calico

Hero Labs

Celeste

Hero Labs

The Doorman

Hero Labs

Drifter

Hero Labs

Dynamo

Hero Labs

Graves

Hero Labs

Grey Talon

Hero Labs

Haze

Hero Labs

Holliday

Hero Labs

Infernus

Hero Labs

Ivy

Hero Labs

Kelvin

Hero Labs

Lady Geist

Hero Labs

Lash

Hero Labs

McGinnis

Hero Labs

Mina

Hero Labs

Mirage

Hero Labs

Mo & Krill

Hero Labs

Paige

Hero Labs

Paradox

Hero Labs

Pocket

Hero Labs

Rem

Hero Labs

Seven

Hero Labs

Shiv

Hero Labs

Silver

Hero Labs

Sinclair

Hero Labs

Venator

Hero Labs

Victor

Hero Labs

Vindicta

Hero Labs

Viscous

Hero Labs

Vyper

Hero Labs

Warden

Hero Labs

Wraith

Hero Labs

Yamato

Parameters

[edit source]
  • text_size - Font size of the hero name
  • card_size - Size of the hero card
  • in_herolabs - Get hero labs heroes (there are none at the moment)
  • debug_mode - (OPTIONAL) Defaults to false. With true, the output is raw wikitext source that isn't processed, allowing to see more clearly what is ran.

debug_mode is the only optional parameter. All other parameters are required. Template:Hero card2 utilizes this with some default values, see there for suggested values.

get_hero_roster

[edit source]

For Template:Roster on Heroes, generate a list using Template:HeroRosterCard.

get_hero_bulletpoints

[edit source]

For navboxes such as Template:Quotes Navbox, generate a bulletpoint list of heroes.

Add the name of a subpage to link to specific subpages. It will still display only the hero name but link to the subpage instead.

Add variable "no_redlinks=true" to hide red links (non-existent pages).

Examples

[edit source]
{{#invoke:HeroData/nav|get_hero_bulletpoints}}

Abrams Apollo Bebop Billy Calico Celeste The Doorman Drifter Dynamo Graves Grey Talon Haze Holliday Infernus Ivy Kelvin Lady Geist Lash McGinnis Mina Mirage Mo & Krill Paige Paradox Pocket Rem Seven Shiv Silver Sinclair Venator Victor Vindicta Viscous Vyper Warden Wraith Yamato

To link to "/Movement" subpages:

{{#invoke:HeroData/nav|get_hero_bulletpoints|Movement}}

AbramsApolloBebopBillyCalicoCelesteThe DoormanDrifterDynamoGravesGrey TalonHazeHollidayInfernusIvyKelvinLady GeistLashMcGinnisMinaMirageMo & KrillPaigeParadoxPocketRemSevenShivSilverSinclairVenatorVictorVindictaViscousVyperWardenWraithYamato

Hide redlinks:

{{#invoke:HeroData/nav|get_hero_bulletpoints|Movement|no_redlinks=true}}

AbramsThe DoormanDrifterDynamoHazeHollidayInfernusIvyLashMo & KrillParadoxPocketSevenShivSinclairVindictaViscousWraithYamato


local p = {}
local heroes_data = mw.loadJsonData("Data:HeroData.json")
local hero_release_module = require('Module:HeroData/release')
local lang_module = require('Module:Lang')
local utilities = require('Module:Utilities')

-- Cache to store results of get_heroes if called multiple times in one page render
local heroes_cache = {}

-- Shared helper function
local function get_heroes(in_herolabs)
    -- Return cached result if it exists
    if heroes_cache[in_herolabs] then
        return heroes_cache[in_herolabs]
    end

    local heroes = {}

    for hero_key, hero_data in pairs(heroes_data) do
        -- hero_werewolf_transformed is consolidated in Silver's page
        if hero_data["Name"] ~= nil and hero_key ~= 'hero_werewolf_transformed' then

            local this_hero_status = hero_release_module.get_hero_release_status(hero_key)

            if ((in_herolabs == 'true' and this_hero_status == 'HeroLabs') or
                (in_herolabs == 'false' and this_hero_status == 'Released')) then

                local is_recommended = hero_data['IsRecommended'] or false

                --- Create a sort key for each hero to ensure correct alphabetical ordering.
                local hero_name = lang_module.get_string(hero_key, nil, 'en')
                local sort_key_to_find = hero_key .. '_sort'
                local potential_sort_key = lang_module.get_string(sort_key_to_find, nil, 'en')

                local sort_key
                -- Detect translation failure if the returned string contains the original search key
                if string.find(potential_sort_key, sort_key_to_find, 1, true) then
                    sort_key = hero_name
                else
                    sort_key = potential_sort_key
                end

                -- NOTE: Check if lang_module.get_string(hero_key, 'en') returns the same value as hero_name.
                -- If the second argument defaults to nil natively, you can optimize further by setting: link = hero_name
                local hero_link = lang_module.get_string(hero_key, 'en')

                -- Store reusable hero data
                local hero = {
                    key = hero_key,
                    name = hero_name,
                    sort_key = sort_key,
                    link = hero_link,
                    recommended = tostring(is_recommended)
                }

                table.insert(heroes, hero)
            end
        end
    end

    -- Sort heroes
    table.sort(heroes, function(a, b)
        return a.sort_key < b.sort_key
    end)

    heroes_cache[in_herolabs] = heroes
    return heroes
end

-- for [[Template:Deadlock_Wiki/Heroes]]
function p.get_hero_nav_cards(frame)
    local text_size = frame.args['text_size']
    local card_size = frame.args['card_size']
    local in_herolabs = frame.args['in_herolabs'] or 'false'
    local debug_mode = frame.args['debug_mode'] == 'true'

    local heroes = get_heroes(in_herolabs)
    local parts = {}

    for _, hero in ipairs(heroes) do
        table.insert(parts, string.format('{{Hero card2|heroName=%s|cardSize=%s|textSize=%s|isHeroLabs=%s}}',
            hero.link, card_size, text_size, in_herolabs))
    end

    local ret = table.concat(parts)

    if debug_mode then
        return ret
    else
        return frame:preprocess(ret)
    end
end

-- for [[Template:Roster]]
function p.get_hero_roster(frame)
    local in_herolabs = frame.args['in_herolabs'] or 'false'
    local debug_mode = frame.args['debug_mode'] == 'true'

    local heroes = get_heroes(in_herolabs)
    local parts = {}

    for _, hero in ipairs(heroes) do
        table.insert(parts, string.format('{{HeroRosterCard|name=%s|key=%s}}', hero.name, hero.key))
    end

    local ret = table.concat(parts)

    if debug_mode then
        return ret
    else
        return frame:preprocess(ret)
    end
end

-- for [[Template:Quotes Navbox]] etc.
p.get_hero_bulletpoints = function(frame)
    local subpage = frame.args['1']
    local in_herolabs = frame.args['in_herolabs'] or 'false'
    local debug_mode = frame.args['debug_mode'] == 'true'
    local no_redlinks = frame.args['no_redlinks'] == 'true'

    local heroes = get_heroes(in_herolabs)
    local parts = {}

    for _, hero in ipairs(heroes) do
        -- Lua optimization: clean ternary fallback for page_title assignment
        local page_title = subpage and (hero.link .. '/' .. subpage) or hero.name

        -- Skip redlinks entirely when enabled
        if not (no_redlinks and not utilities.page_exists(page_title)) then
            local item
            if subpage then
                item = string.format('{{PageRef|%s|alt_link=%s}}', hero.link, page_title)
            else
                item = string.format('{{HeroIcon|%s}}', hero.link)
            end
            table.insert(parts, item)
        end
    end

    local ret = table.concat(parts, ' &bull; ')

    if debug_mode then
        return ret
    else
        return frame:preprocess(ret)
    end
end

-- for image galleries
p.get_hero_gallery = function(frame)
    local file_name = frame.args['1'] or ''
    local description = frame.args['2'] or ''
    local in_herolabs = frame.args['in_herolabs'] or 'false'
    local debug_mode = frame.args['debug_mode'] == 'true'

    local heroes = get_heroes(in_herolabs)
    local parts = {}

    for _, hero in ipairs(heroes) do
        table.insert(parts, string.format('File:%s%s|%s%s\n', hero.link, file_name, hero.name, description))
    end
    
    local ret = '<gallery>\n' .. table.concat(parts) .. '</gallery>'

    if debug_mode then
        return ret
    else
        return frame:preprocess(ret)
    end
end

-- Generate 3D model gallery
function p.get_hero_models(frame)
    local in_herolabs = frame.args['in_herolabs'] or 'false'
    local debug_mode = frame.args['debug_mode'] == 'true'

    local heroes = get_heroes(in_herolabs)
    local parts = {}

    for _, hero in ipairs(heroes) do
        table.insert(parts, string.format('{{3D Model|%s}}', hero.name))
    end

    local ret = table.concat(parts)

    if debug_mode then
        return ret
    else
        return frame:preprocess(ret)
    end
end

return p