Module:HeroData/nav: Difference between revisions

From The Deadlock Wiki
Jump to navigation Jump to search
Auto-detect language from subpage
3D model function
 
(29 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)
local function get_language_from_subpage()
    -- Get the full page path (including subpages)
     local full_page_name = mw.title.getCurrentTitle().fullText
   
    -- Split path by slashes
     local parts = {}
     local parts = {}
     for part in full_page_name:gmatch("[^/]+") do
 
         table.insert(parts, part)
     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
     end
   
 
    -- Last part - potential language code
     local ret = table.concat(parts)
     local last_part = parts[#parts] or ""
 
   
     if debug_mode then
    -- Check for language codes matching:
         return ret
    -- 1. Exactly 2 letters (like 'ru'), OR
    else
    -- 2. 2 letters + hyphen + any characters (like 'zh-hans')
         return frame:preprocess(ret)
     if last_part:match("^[a-z][a-z]$") or last_part:match("^[a-z][a-z]%-[%w]+$") then
         -- Convert to lowercase and replace _ with -
         return last_part:lower():gsub("_", "-")
     end
     end
   
    return "en" -- Default to English
end
end
 
local lang_code = get_language_from_subpage() -- Get the language code
-- for [[Template:Roster]]
   
function p.get_hero_roster(frame)
     -- Turn debug_mode from string to bool, default to false
     local in_herolabs = frame.args['in_herolabs'] or 'false'
     if debug_mode == nil then
     local debug_mode = frame.args['debug_mode'] == 'true'
        debug_mode = false
 
    elseif debug_mode == 'true' then
    local heroes = get_heroes(in_herolabs)
        debug_mode = true
     local parts = {}
     elseif debug_mode == 'false' then
 
         debug_mode = false
    for _, hero in ipairs(heroes) do
         table.insert(parts, string.format('{{HeroRosterCard|name=%s|key=%s}}', hero.name, hero.key))
     end
     end


     if in_herolabs ~= 'true' and in_herolabs ~= 'false' then
    local ret = table.concat(parts)
         return 'in_herolabs must be either true or false'
 
     if debug_mode then
         return ret
    else
        return frame:preprocess(ret)
     end
     end
   
end
    -- Only add subpage if not English
 
     local subpage_str = ''
-- for [[Template:Quotes Navbox]] etc.
     if lang_code ~= 'en' then
p.get_hero_bulletpoints = function(frame)
        subpage_str = '/' .. lang_code
    local subpage = frame.args['1']
     end
     local in_herolabs = frame.args['in_herolabs'] or 'false'
   
     local debug_mode = frame.args['debug_mode'] == 'true'
     -- Iterate heroes
     local no_redlinks = frame.args['no_redlinks'] == 'true'
     local heroes = {}
 
     for hero_key, hero_data in pairs(heroes_data) do
     local heroes = get_heroes(in_herolabs)
         if hero_data["Name"] ~= nil then
     local parts = {}
            -- if herolabs is requested, only needs to have herolabs=true
 
            -- otherwise, needs to be not disabled, in development, nd herolabs is nil or false
     for _, hero in ipairs(heroes) do
            local this_hero_status = hero_release_module.get_hero_release_status(hero_key)
         -- Lua optimization: clean ternary fallback for page_title assignment
           
        local page_title = subpage and (hero.link .. '/' .. subpage) or hero.name
            if this_in_herolabs == nil then this_in_herolabs = false end
 
           
        -- Skip redlinks entirely when enabled
            if ((in_herolabs == 'true' and this_hero_status == 'HeroLabs') or
        if not (no_redlinks and not utilities.page_exists(page_title)) then
                (in_herolabs == 'false' and this_hero_status == 'Released')) then
            local item
               
            if subpage then
                local is_recommended = hero_data['IsRecommended']
                 item = string.format('{{PageRef|%s|alt_link=%s}}', hero.link, page_title)
                if is_recommended == nil then
            else
                    is_recommended = false
                item = string.format('{{HeroIcon|%s}}', hero.link)
                end
                  
                local hero_str = '|name=' .. lang_module.get_string(hero_key, nil, 'en') ..  
                              '|link=' .. lang_module.get_string(hero_key, 'en') ..
                              '|subpage=' .. subpage_str ..
                              '|recommended=' .. tostring(is_recommended)
               
                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