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, ", ")
--[==[
<!--
-->{{ #vardefine: $t | {{ #ifeq: {{{type}}} | Episode | episode | chapter }} }}<!--
-->{{ #vardefine: $s | Yu-Gi-Oh! {{{series|}}} }}<!--
-->{{ #arraydefine: $episodes | {{{1|}}} | , }}{{ #arrayunique: $episodes }}{{ #arrayprint: $episodes
| , 
| $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