Module:HeroData/nav: Difference between revisions

From The Deadlock Wiki
Jump to navigation Jump to search
Auto-detect language from subpage
3D model function
 
(31 intermediate revisions by 6 users not shown)
Line 3: Line 3:
local hero_release_module = require('Module:HeroData/release')
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:Deadlock_Wiki/Heroes]] on home page, i.e. [[Template:Hero card2]]
-- 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 in_herolabs = frame.args['in_herolabs'] -- true or false
     local text_size = frame.args['text_size']
     local text_size = frame.args['text_size']
     local card_size = frame.args['card_size']
     local card_size = frame.args['card_size']
     local sticker_size = frame.args['sticker_size']
     local in_herolabs = frame.args['in_herolabs'] or 'false'
    local herolabs_text_size = frame.args['herolabs_text_size']
     local debug_mode = frame.args['debug_mode'] == 'true'
     local debug_mode = frame.args['debug_mode']
 
   
     local heroes = get_heroes(in_herolabs)
    -- Get current page title and extract language code
     local parts = {}
     local current_title = mw.title.getCurrentTitle()
 
     local subpage = current_title.subpageText
     for _, hero in ipairs(heroes) do
    local lang_code = 'en' -- default to English
        table.insert(parts, string.format('{{Hero card2|heroName=%s|cardSize=%s|textSize=%s|isHeroLabs=%s}}',
      
            hero.link, card_size, text_size, in_herolabs))
    -- If there's a subpage and it's not empty and not "Sandbox", use it as language code
    if subpage and subpage ~= '' and subpage ~= 'Sandbox' then
        lang_code = subpage
     end
     end
      
 
    -- Turn debug_mode from string to bool, default to false
     local ret = table.concat(parts)
     if debug_mode == nil then
 
         debug_mode = false
     if debug_mode then
     elseif debug_mode == 'true' then
         return ret
        debug_mode = true
     else
    elseif debug_mode == 'false' then
         return frame:preprocess(ret)
         debug_mode = false
     end
     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'


     if in_herolabs ~= 'true' and in_herolabs ~= 'false' then
     local heroes = get_heroes(in_herolabs)
         return 'in_herolabs must be either true or false'
    local parts = {}
 
    for _, hero in ipairs(heroes) do
         table.insert(parts, string.format('{{HeroRosterCard|name=%s|key=%s}}', hero.name, hero.key))
     end
     end
   
 
    -- Only add subpage if not English
     local ret = table.concat(parts)
     local subpage_str = ''
 
     if lang_code ~= 'en' then  
     if debug_mode then
         subpage_str = '/' .. lang_code
         return ret
    else
        return frame:preprocess(ret)
     end
     end
   
end
    -- Iterate heroes
 
    local heroes = {}
-- for [[Template:Quotes Navbox]] etc.
    for hero_key, hero_data in pairs(heroes_data) do
p.get_hero_bulletpoints = function(frame)
        if hero_data["Name"] ~= nil then
    local subpage = frame.args['1']
            -- if herolabs is requested, only needs to have herolabs=true
    local in_herolabs = frame.args['in_herolabs'] or 'false'
            -- otherwise, needs to be not disabled, in development, nd herolabs is nil or false
    local debug_mode = frame.args['debug_mode'] == 'true'
            local this_hero_status = hero_release_module.get_hero_release_status(hero_key)
    local no_redlinks = frame.args['no_redlinks'] == 'true'
           
 
            if this_in_herolabs == nil then this_in_herolabs = false end
    local heroes = get_heroes(in_herolabs)
           
    local parts = {}
            if ((in_herolabs == 'true' and this_hero_status == 'HeroLabs') or
 
                (in_herolabs == 'false' and this_hero_status == 'Released')) then
    for _, hero in ipairs(heroes) do
               
        -- Lua optimization: clean ternary fallback for page_title assignment
                local is_recommended = hero_data['IsRecommended']
        local page_title = subpage and (hero.link .. '/' .. subpage) or hero.name
                if is_recommended == nil then
 
                    is_recommended = false
        -- Skip redlinks entirely when enabled
                end
        if not (no_redlinks and not utilities.page_exists(page_title)) then
               
            local item
                local hero_str = '|name=' .. lang_module.get_string(hero_key, nil, 'en') ..
            if subpage then
                              '|link=' .. lang_module.get_string(hero_key, 'en') ..
                item = string.format('{{PageRef|%s|alt_link=%s}}', hero.link, page_title)
                              '|subpage=' .. subpage_str ..
            else
                              '|recommended=' .. tostring(is_recommended)
                 item = string.format('{{HeroIcon|%s}}', hero.link)
               
                 table.insert(heroes, hero_str)
             end
             end
            table.insert(parts, item)
         end
         end
     end
     end
          
 
     -- Order list alphabetically
    local ret = table.concat(parts, ' &bull; ')
     table.sort(heroes) -- O(nlogn)
 
    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
      
      
    -- Add each item to output
     local ret = '<gallery>\n' .. table.concat(parts) .. '</gallery>'
     local ret = ''
 
    for index, hero_name in ipairs(heroes) do
    if debug_mode then
        ret = ret .. '{{Hero card2' .. hero_name
         return ret
         ret = ret .. '|text_size=' .. text_size
    else
        ret = ret .. '|herolabs=' .. in_herolabs
        return frame:preprocess(ret)
        ret = ret .. '|card_size=' .. card_size
    end
        ret = ret .. '|sticker_size=' .. sticker_size
end
        ret = ret .. '|herolabs_text_size=' .. herolabs_text_size
 
         ret = ret .. '}} '
-- 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
     end
   
 
    -- Remove the last space
     local ret = table.concat(parts)
     ret = string.sub(ret, 1, -(string.len(' '))-1)
 
   
     if debug_mode then
     if debug_mode then
         return ret
         return ret
     else -- evaluate wikitext if not in debug mode
     else
         return frame:preprocess(ret)
         return frame:preprocess(ret)
     end
     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