Yu-Gi-Oh! Wiki
Advertisement
Yu-Gi-Oh! Wiki

Lua error in Dev:Docbunto at line 609: attempt to concatenate local 'item_name' (a nil value).



local card = {}
----------------------------
-- Libraries of functions --
----------------------------
-- stands for High Frequency
local HF = require('Module:HF')
-- Parses invocation and template parameters, trims whitespace, and removes blanks.
local getArgs = require('Dev:Arguments').getArgs
-- Generates lists
local L = require('Dev:List')
-- Categories / SMW properties for site maintenance 
-- local M = require('Module:Card/Maintenance')
-- Indicates deprecated parameters 
-- local D = require('Module:Deprecated')
-- Card Set functions
-- local CS = require('Module:Card/Set')
-- Navigation functions
local N = require('Module:Card/Navigation')
-- The video game table
local vgT = require('Module:Card/vgTable')

-- Gives the name of the current page. It's expensive, so we only do it once.
-- The _G then makes it global, available to all page functions.
_G.page_title = mw.title.getCurrentTitle().text
_G.namespace = mw.title.getCurrentTitle().nsText

-- Parses template parameters from article, trims whitespace, and removes blanks.
_G.t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    
-- The occasions where we need the same "variables" to process multiple fields are global.
--- {{ #vardefine: $level-rank | {{ #if: {{ #pos: {{{type2}}}{{{type3}}}{{{type4}}} | Xyz }} | Rank | Level }} }}
_G.level_rank = ( string.match( 
    (t['type2'] or '')..
    (t['type3'] or '')..
    (t['type4'] or ''), 'Xyz') and 'Rank' ) or 'Level'

-- These two lines are equivalent
-- if t_args['kr_sets'] or t_args['ko_sets'] then _G.kr_release = 1 end
-- _G.kr_release = (t_args['kr_sets'] or t_args['ko_sets']) and 1
if t['kr_sets'] or t['ko_sets'] then _G.kr_release = 1 end
if t['ae_sets'] then _G.ae_release = 1 end
--_G.tc_release = t['tc_sets'] and 1
if t['tc_sets'] then _G.tc_release = 1 end
if t['na_sets'] then _G.na_release = 1 end
if t['eu_sets'] then _G.eu_release = 1 end
if t['de_sets'] then _G.de_release = 1 end
if t['it_sets'] then _G.it_release = 1 end
if t['pt_sets'] then _G.pt_release = 1 end
if t['sp_sets'] then _G.sp_release = 1 end
if t['jp_sets'] or t['ja_sets']  then _G.ocg_jp = 1 end
_G.ocg = (ocg_jp or '') .. (kr_release or '') .. (ae_release or '') .. (tc_release or '')
if t['en_sets'] or na_release or eu_release or t['au_sets'] then _G.tcg_en = 1 end
if t['fr_sets'] or t['fc_sets']  then _G.tcg_fr = 1 end
_G.tcg = (tcg_en or '') .. (tcg_fr or '') .. (de_release or '') .. (it_release or '') .. (pt_release or '') .. (sp_release or '')
_G.ocg_tcg = ocg .. tcg

----------------------------------------------------------
-- Public functions (called from a Template or article) --
----------------------------------------------------------
-- English name handler
function card.name(frame)
    local t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    local pagename = HF.NP()
    local name = t['name'] or t['cardgame'] or pagename
    local sortkey = _defaultsort(pagename) or ''
    mw.smw.set{ 
        ['English name (linked)'] = HF.Link(pagename, name),
        ['Page name'] = pagename
    } 
    return name..sortkey
end

-- Primary image handler
-- use {{#invoke:Card|image_front}} inside {{Card}}
function card.image_front(frame)
    local t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    local image = t['image']
    mw.smw.set{ ['Card image'] = image }
    return ( image ) .. ( t['image2'] and '{{!}}Front' or '' )
end

-- Primary image handler
-- use {{#invoke:Card|image_back}} inside {{Card}}
function card.image_back(frame)
    local t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    local type = t['type']
    local backs = {
        ['Strategy Card'] = 'StrategyCard-EN-Back.png',
        ['Tip Card'] = 'StrategyCard-EN-Back.png',
        ['FAQ Card'] = 'StrategyCard-EN-Back.png'
    }
    local image_back = backs[type] or ('Back-'..((tcg and 'EN') or ( ocg_jp or tc_release and 'JP' ) or ( kr_release and 'KR' ) or ( ae_release and 'AE' ) or ( vg and 'TF-EN-VG' ) or 'EN' )..'.png')
    return ( t['card_back'] or image_back )
end

-- Machine translation link
-- use {{#invoke:Card|translate|lang|parameter|label}} inside {{Card}}
-- "label" is optional, and defaults to 📃
function card.translate(frame)
    -- Parses invocation parameters, trims whitespace.
    local vars = getArgs(frame, { trim = true, frameOnly = true })
    assert(vars[1], 'No language code given for translation link.')
    assert(vars[2], 'No text given for translation link.')
    local language, parameter, label = vars[1], vars[2], vars[3] or '📃'
    local text = t[parameter] or ''
    local URI = mw.uri.new( { protocol = 'https', host = 'translate.google.com', path = '/#'..language..'/en/'..mw.uri.encode(text) } )
    local element = mw.html.create('span'):addClass('plainlinks'):addClass('sysop-show')
        :wikitext(HF.ExternalLink( tostring(URI), label )):allDone()
    return tostring(element)
end

-- Render ultimate type
-- use {{#invoke:Card|type}} inside {{Card}}
-- TODO: Migrate function to local
function card.type(frame)
    -- Parses template parameters, trims whitespace, and removes blanks.
    local t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    local out = {}
    local type1, type2, type3, type4 = t['type'] or '', t['type2'], t['type3'], t['type4']
    local type1U = mw.getContentLanguage():ucfirst(type1)
    local normal_types = { 'Normal', 'Pendulum' }
    local abnormal_types = { 'Effect', 'Fusion', 'Ritual', 'Synchro', 'Token', 'Xyz', 'Link' }
    local non_effect_monster_types = { 'Fusion', 'Ritual', 'Synchro', 'Xyz', 'Link' }
    local type3_types = { 'Tuner', 'Spirit', 'Flip' }
    local monster = (t['atk'] or t['def'] or t['level'] or t['rank'] or t['link_arrows'] or t['type2'] == 'Token') and true
    local effect_monster = ( 
        t['effect_types'] or 
        (t['type2'] and t['type2']:match('Effect')) or 
        (t['type3'] and t['type3']:match('Effect')) or 
        (t['type4'] and t['type4']:match('Effect'))
    ) and true
    local non_effect_monster = (
        (type2 and non_effect_monster_types[type2]) or
        (type3 and non_effect_monster_types[type3]) or
        (type4 and non_effect_monster_types[type4])
    ) and true
    local pendulum_monster = (
        t['pendulum_effect'] 
        or t['pendulum_effect_types'] 
        or  (t['type2'] and t['type2']:match('Pendulum')) or 
            (t['type3'] and t['type3']:match('Pendulum')) or 
            (t['type4'] and t['type4']:match('Pendulum'))) and true
    local switch = {
        [''] = "",
        ['Equip Card'] = HF.Link(type1U),
        ['Tip Card'] = HF.Link(type1U),
        ['Strategy Card'] = HF.Link(type1U),
        ['FAQ Card'] = HF.Link(type1U),
        ['Illustration Card'] = HF.Link(type1U),
        ['Counter'] = HF.Link(type1U),
    }
    local special_types = {
        ['Flip'] = "Flip monster",
        ['Spirit'] = "Spirit monster",
        ['Union'] = "Union monster",
        ['Toon'] = "Toon monster",
        ['Gemini'] = "Gemini monster",
        ['Tuner'] = "Tuner monster",
        ['Dark Tuner'] = "Dark Tuner monster",
    }
    if t['type'] or type2 or type3 or type4 then
        if switch[type1] and type1 ~= '' then 
            mw.smw.set{ ['Card type'] = type1 } 
        else
            mw.smw.set{ ['Type'] = type1 }
        end
        local type1_prefix = type1:match('(%a*)%(') or type1
        table.insert(out, 
            switch[type1] or
             HF.Link(type1U, type1_prefix) )
        if type2 then 
            table.insert(out, HF.Link( special_types[type2] or type2..' Monster' , type2))
            if abnormal_types[type2] or normal_types[type2] then 
                mw.smw.set{
                    ['Primary type'] = type2..' Monster',
                    ['Card type'] = type2..' Monster',
                }
            elseif special_types[type2] and (not abnormal_types[type2]) then 
                mw.smw.set{
                    ['Primary type'] = effect_monster and 'Effect Monster' or 'Normal Monster',
                    ['Card type'] = effect_monster and 'Effect Monster' or 'Normal Monster',
                    ['Secondary type'] = type2..' Monster',
                    ['Monster type'] = type2..' monster'
                }
            elseif special_types[type2] then 
                mw.smw.set{
                    ['Secondary type'] = type2..' Monster',
                    ['Monster type'] = type2..' monster'
                }
             end
        end
        if type3 then 
            table.insert(out, HF.Link( special_types[type3] or type3..' Monster', type3))
            mw.smw.set{['Type3'] = type3}
            if type3_types[type3] and
                (not abnormal_types[type2]) then 
                mw.smw.set{
                    ['Primary type'] = effect_monster and 'Effect Monster' or 'Normal Monster',
                    ['Secondary type'] = type3..' monster',
                    ['Monster type'] = type3..' monster',
                    ['Card type'] = effect_monster and 'Effect' or 'Normal',
                }
            elseif type3_types[type3] then 
                mw.smw.set{
                    ['Secondary type'] = type3..' monster',
                    ['Card type'] = effect_monster and 'Effect',
                    ['Monster type'] = type3..' monster',
                }
            end
        end
        if type4 then 
            table.insert(out, HF.Link( type4..' Monster', type4))
            mw.smw.set{['Type4'] = type4}
        end
    end
    if monster or t['type'] and 
        not(effect_monster or t['type2'] or t['attribute']:uc():match('DIVINE') or token_counter or non_game) then
        mw.smw.set{
            ['Primary type'] = 'Normal Monster',
            ['Card type'] = 'Normal Monster'
        }
    end
    if pendulum_monster then
        mw.smw.set{
            ['Primary type'] = 'Pendulum Monster'
        }
        if not(non_effect_monster) then
            mw.smw.set{
                    ['Primary type'] = effect_monster and 'Effect Monster' or 'Normal Monster',
                    ['Card type'] = effect_monster and 'Effect Monster' or 'Normal Monster'
            }
        end
    end

    if not(ocg_tcg) then
        if t['type2'] == 'Token' then mw.smw.set{['Class 1'] = 'NR Tokens'} end
        --if vg then mw.smw.set{['Class 1'] = 'VGEx'} end -- This should go in vgTable
    end
    
    return table.concat(out, ' / ')
end

-- use {{#invoke:Card|card_type}} inside {{Card}}
-- TODO: Migrate function to local
function card.card_type (frame)
    -- Parses template parameters, trims whitespace, and removes blanks.
    local t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    local monster = (t['atk'] or t['def'] or t['level'] or t['rank'] or t['link_arrows'] or t['type2'] == 'Token') and true
    local out = {}
    if monster or t['card_type'] then
      local m = (t['card_type'] or 'Monster')..' Card'
        table.insert(out, HF.Link( m, (t['card_type'] or 'Monster')))
      if t['card_type'] == 'Speed Spell' then
        table.insert(out, '[[File:SPELL.svg|28px|alt=]] [[File:Speed Spell.svg|x28px|alt=]]')
      elseif not monster then
        table.insert(out, '[[File:'..string.upper(t['card_type'])..'.svg|28px|alt=]]')
      end
        mw.smw.set{
            ['Card type'] = m,
            ['Card type (short)'] = HF.Link( m, (t['card_type'] or 'Monster') )
            }
      if monster then 
          mw.smw.set{['Card category'] = 'Monster Card'}
      end
    end
    return table.concat(out)
end

-- use {{#invoke:Card|level}} inside {{Card}}
-- TODO: Migrate function to local
function card.level (frame)
    -- Parses template parameters, trims whitespace, and removes blanks.
    local t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    local stars = t['level'] or t['rank'] or nil
    local out, SMW = {}
    if stars then
        table.insert(out, HF.Link(level_rank..' '..stars..' Monster Cards', stars))
        if ocg_tcg or vg then 
            table.insert(out, 
                string.rep( '[[File:'..((level_rank == 'Rank') and 'Rank' or 'CG')..' '..( tonumber(stars) and 'Star' or 'Star Unknown')..'.svg|18px|link=]]', ( tonumber(stars) or 1 ) )
        )
        end
        mw.smw.set{
            [( tonumber(stars) and '' or '?' )..' '..level_rank] = stars,
            [level_rank..' string'] = stars,
            [( tonumber(stars) and '' or '?' )..'Stars'] = stars,
            ['Stars string'] = stars
            }
        return table.concat(out)
    end
end

-- Formats card sets in rows
-- Detects if the content uses a wrapper template, or is data
-- use {{#invoke:Card|cardset_format|{{{parameter}}}|}} inside {{Card}}
function card.cardset_format (frame)
    local vars = getArgs(frame, { trim = true, frameOnly = true })
    local out = {}
    -- no logic yet
    table.insert(out, _cardset_envelope(vars))
    return table.concat(out)
end

-- Detects if the content uses a wrapper template, or is data
-- use {{#invoke:Card|cardset_categories|{{{parameter}}}|property}} inside {{Card}}
-- TODO: Migrate function to local
function card.search_categories (frame)
    -- Parses invocation parameters, trims whitespace.
    local vars = getArgs(frame, { trim = true, frameOnly = true })
    -- Parses template parameters, trims whitespace, and removes blanks.
    local t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    local parameter = assert(vars[1], 'No parameter is specified.')
    local value = t[parameter]
    local property = vars[2]
    local out = {} -- output

    local test = mw.text.split(value, '%*')
    local hash = {}
    local raw_result = {}
    local list_items = {}
    
    for _,v in ipairs(test) do
       if (not hash[v] and v ~= '') then
           table.insert( raw_result, v )
           hash[v] = true
       end
    end
    -- unique results are now in table 'raw_result'
    
    if #raw_result > 0 then
        for i, v in ipairs( raw_result ) do
            v_unlinked = ( v:match( '%[%[:?(.-)[|%]]' ) or HF.trim( v ) )
            table.insert( list_items, 
                HF.Link( v_unlinked, ( v_unlinked:match('(.+)%(') or v_unlinked ) )
            )
            mw.smw.set{ property..'='..v_unlinked }
        end
        local list = L.makeList( 'horizontal' , list_items )
        table.insert(out, tostring(list))
    end
    if parameter == 'summoning' and t['monster'] and (not t['token']) then
        if (not value:lower():match('nomi')) and 
            not (value:lower():match('cannot special summon') or value:lower():match('cannot be special summoned')) then
                mw.smw.set{['Summoning'] = 'Can be Special Summoned' }
            if not ( value:lower():match('semi[ -]?nomi') or
                value:lower():match('special summon-only monster') or
                t['monster_type']) then
                    mw.smw.set{['Summoning'] = 'Can always be Special Summoned' }
            end
        end
    end
    return table.concat(out)
end

function card.ctaama (frame)
    -- Parses template parameters, trims whitespace, and removes blanks.
    local args = getArgs(frame, { trim = true, frameOnly = true })
        --{{ctaama|{{{appears_in_5d|}}} | series = 5D's | type = Episode }}
    return _ctaama( args[1], args['series'], args['type'] )
end

function card.vg_table (frame)
    -- Parses template parameters, trims whitespace, and removes blanks.
    local t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    return vgT._table(t)
end

function card.related (frame)
    -- Parses template parameters, trims whitespace, and removes blanks.
    local t = getArgs(frame, { trim = true, removeBlanks = true, parentOnly = true })
    return N.related(t)
end

---------------------------------------------------------
-- Internal functions (used in this and other Modules) --
---------------------------------------------------------
-- Create an envelope for existing tables
function _cardset_envelope (inv_args)
    local envelope = mw.html.create('div')
    :addClass('mw-collapsible'):addClass('mw-collapsed')
    :attr('data-expandtext','Show'):attr('data-collapsetext','Hide')
    :wikitext(inv_args[1]):allDone()
    return tostring(envelope)
end

function _defaultsort (PN)
    local SORTKEY = ''
    if PN:match('^A ') then 
        return '{{'..'DEFAULTSORT:'..PN:match('^A (.*)')..'}}'
    elseif PN:match('^An ') then
        return '{{'..'DEFAULTSORT:'..PN:match('^An (.*)')..'}}'
    elseif PN:match('^The ') and not (PN:match('The Agent') or PN:match('The Fabled')) then
        return '{{'..'DEFAULTSORT:'..PN:match('^The (.*)')..'}}'
    elseif (PN:match('The Agent') or PN:match('The Fabled')) then
        return
    elseif PN:match('^Number %a+%d+') then
        local epoch, order, remainder = PN:match('^Number (%a+)(%d+)(.*)')
         if tonumber(order) < 10 then order = '000'..order
         elseif tonumber(order) < 100 then order = '00'..order
         elseif tonumber(order) < 1000 then order = '0'..order
         end
        return '{{'..'DEFAULTSORT:Number '..epoch..order..remainder..'}}'
    else
        return
    end
    
end

function _ctaama( parameter, series, appearance_type )
    local _t = ( appearance_type == 'Episode' ) and 'episode' or 'chapter'
    local _s = 'Yu-Gi-Oh! '..(series or '')
    local _e = HF.unique(mw.text.split(parameter, ','))
    local app_prop_link = ('%s %s appearances (linked)'):format(_s, _t)
    local app_prop = ('%s %s appearances'):format(_s, _t)
    local o = {}
    for _,_episode in ipairs(_e) do
        _target = ( #_episode < 4 ) and ('Yu-Gi-Oh! %s - %s  %s'):format(_s, _t, _episode) or _episode
        _link = HF.Link( _target, _episode )
        mw.smw.set{ 
            app_prop_link = _link,
            app_prop = _episode
        }
        table.insert( o, _link )
    end
    table.concat( o, ",&#32;")
--[==[
<!--
-->{{ #vardefine: $t | {{ #ifeq: {{{type}}} | Episode | episode | chapter }} }}<!--
-->{{ #vardefine: $s | Yu-Gi-Oh! {{{series|}}} }}<!--
-->{{ #arraydefine: $episodes | {{{1|}}} | , }}{{ #arrayunique: $episodes }}{{ #arrayprint: $episodes
| ,&#32;
| $episode
| {{IfSemantics
  | [[{{ #var: $s }} {{ #var: $t }} appearances (linked)::[[{{ #ifexpr: {{ #len: $episode }} < 4 | Yu-Gi-Oh! {{{series|}}} - {{{type}}} }} $episode|$episode]]]]
  | [[{{ #ifexpr: {{ #len: $episode }} < 4 | Yu-Gi-Oh! {{{series|}}} - {{{type}}} }} $episode|$episode]]
  }}[[{{ #var: $s }} {{ #var: $t }} appearances::$episode| ]]
}}
--]==]
end

function _CT2effect( )
    -- See {{CardTable2/effect}}
end

------------------------------------------------
-- Local functions (only used in this Module) --
------------------------------------------------

-------------------------------------------------
-- Output (send it back to whatever called it) --
-------------------------------------------------
return card
Advertisement