Difference between revisions of "Module:Card type"

From Yugipedia
Jump to: navigation, search
(Trying to make this more efficient. Deal with colored Egyptian Gods. Set up for other cards.)
m (Remove trailing spaces.)
 
(15 intermediate revisions by 3 users not shown)
Line 2: Line 2:
 
--  Module for {{Card type}}.
 
--  Module for {{Card type}}.
 
--  Can also be used through other modules.
 
--  Can also be used through other modules.
--  @@@ for ideas.  
+
--  @@@ for ideas.
 
local CardType = {};
 
local CardType = {};
  
Line 8: Line 8:
 
--  External modules:
 
--  External modules:
 
---------------------
 
---------------------
local getArgs = require( 'Dev:Arguments' ).getArgs;
+
local getArgs = require( 'Module:Arguments' ).getArgs;
  
 
---------
 
---------
 
--  Data:
 
--  Data:
 
---------
 
---------
local data             = mw.loadData( 'Module:Card type/data' );
+
local data             = mw.loadData( 'Module:Card type/data' );
local abilities         = data.abilities;
+
local FAQtypes        = data.FAQtypes;
local monsterCardTypes = data.monsterCardTypes;
+
local abilities       = data.abilities;
 +
local monsterCardTypes = data.monsterCardTypes;
  
 
------------------
 
------------------
Line 27: Line 28:
 
--  If the input is only white space, returns nil.
 
--  If the input is only white space, returns nil.
 
function _trim( s )
 
function _trim( s )
    if s and not s:match( '^%s*$' ) then
+
if s and not s:match( '^%s*$' ) then
        return mw.text.trim( s ); -- If not nil nor empty.
+
return mw.text.trim( s ); -- If not nil nor empty.
    end
+
end
 
end
 
end
  
Line 38: Line 39:
 
--  uses a table of labels, respectively for each entry, when given.
 
--  uses a table of labels, respectively for each entry, when given.
 
function _link( v, ... )
 
function _link( v, ... )
    local labels = type( ... or nil ) == 'table' and ... or  { ... };  --  Make sure it's a table.
+
local labels = type( ... or nil ) == 'table' and ... or  { ... };  --  Make sure it's a table.
    local function __link( v, label )
+
local function __link( v, label )
        return ('[[%s|%s]]'):format( v, (_trim( label ) or split( v, ' %(' )[1]) );
+
return ('[[%s|%s]]'):format( v, (_trim( label ) or split( v, ' %(' )[1]) );
    end
+
end
    if type( v ) == 'string' then
+
if type( v ) == 'string' then
        return __link( v, labels[1] );
+
return __link( v, labels[1] );
    elseif type( v ) == 'table' then
+
elseif type( v ) == 'table' then
        local t = {};
+
local t = {};
        for key, value in ipairs( v ) do
+
for key, value in ipairs( v ) do
            table.insert( t, __link( value, labels[key] ));
+
table.insert( t, __link( value, labels[key] ) );
        end
+
end
        return t;
+
return t;
    else
+
else
        return v; -- @@@ error()
+
return v; -- @@@ error()
    end
+
end
 
end
 
end
  
 
--  Unlink function:
 
--  Unlink function:
 
--  If a string is passed, unlinks
 
--  If a string is passed, unlinks
--  and returns the page name (not the label).
+
--  and returns the page name (not the label, unless «getLabel»).
 
--  If a table is passed, unlinks every instance of it
 
--  If a table is passed, unlinks every instance of it
 
--  and returns the table with the page names for each respective entry.
 
--  and returns the table with the page names for each respective entry.
function _unlink( v )
+
function _unlink( v, getLabel )
    local function __unlink( v )
+
local function __unlink( v, getLabel )
        return _trim( v ) and (v:match( '%[%[:?(.-)[|%]]' ) or _trim( v ));
+
return _trim( v ) and (getLabel and v:match( '%[%[:?.-|(.-)]]' ) or v:match( '%[%[:?(.-)[|%]]' )) or _trim( v );
    end
+
end
    if type( v ) == 'string' then
+
if type( v ) == 'string' then
        return __unlink( v );
+
return __unlink( v, getLabel );
    elseif type( v ) == 'table' then
+
elseif type( v ) == 'table' then
        local t = {};
+
local t = {};
        for key, value in ipairs( v ) do
+
for key, value in ipairs( v ) do
            table.insert( t, __unlink( value ));
+
table.insert( t, __unlink( value, getLabel ) );
        end
+
end
        return t;
+
return t;
    else
+
else
        return v;
+
return v; -- @@@ error()
    end
+
end
 
end
 
end
  
Line 80: Line 81:
 
--  Given a table, counts how many valuee it has.
 
--  Given a table, counts how many valuee it has.
 
function _count( t ) -- @@@ error() for wrong type()
 
function _count( t ) -- @@@ error() for wrong type()
    local counter = 0;
+
local counter = 0;
    for key, value in pairs( t ) do
+
for key, value in pairs( t ) do
        counter = counter + 1;
+
counter = counter + 1;
    end
+
end
    return counter;
+
return counter;
 +
end
 +
 
 +
--  Categories function:
 +
--  Receives categories' names.
 +
--  Returns the linked categories.
 +
function _categories( ... )
 +
local categories = type( ... or nil ) == 'table' and ... or  { ... };  --  Make sure it's a table.
 +
local t = {};
 +
for _, category in pairs( categories ) do
 +
table.insert( t, ('[[Category:%s]]'):format( category ) );
 +
end
 +
return table.concat( t, '\n' );
 
end
 
end
  
 
--  Error function:
 
--  Error function:
 
--  Generates error messages and categories.
 
--  Generates error messages and categories.
function _error( message ) -- @@@ input list of categories.
+
function _error( message )
    local _error = mw.html.create( 'div' )
+
local _error = mw.html.create( 'div' )
                    :tag( 'strong' ):addClass( 'error' ):wikitext( ('Error: %s'):format( message ) ):done()
+
:tag( 'strong' ):addClass( 'error' )
                :allDone();
+
:wikitext( ('Error: %s'):format( message ) ):done()
    local cat = '[[Category:Pages with script errors]][[Category:((Card type)) transclusions to be checked]]';
+
:allDone();
    return ('%s\n%s'):format( tostring( _error ), cat ); -- @@@ or error()
+
local cat = _categories( 'Pages with script errors', '((Card type)) transclusions to be checked' );
 +
return ('%s\n%s'):format( tostring( _error ), cat ); -- @@@ or error()
 
end
 
end
  
 
function _redirect( card )
 
function _redirect( card )
    local pagename = _trim( _show( card, 'Page name' ) );
+
local pagename = _trim( _show( card, 'Page name' ) );
    return pagename ~= card and pagename;
+
return pagename ~= card and pagename;
 
end
 
end
  
 
--  Show function:
 
--  Show function:
 
--  Similar to #show parser function.
 
--  Similar to #show parser function.
--  Returns table with the results.
+
--  Returns string with the results.
 
function _show( page, property, link )
 
function _show( page, property, link )
    --  At this point, SMW is enabled and «page» is formatted properly (as pagename).
+
--  At this point, SMW is enabled and «page» is formatted properly (as pagename).
    local result =  mw.smw.ask{ _link( page ), ('?%s='):format( property ), mainlabel = '-' };
+
local result =  mw.smw.ask{
   
+
('[[%s]]'):format( page ),
    if not result or _count( result ) == 0 or _count( result[1] ) == 0 then
+
('?%s='):format( property ),
        return;
+
mainlabel = '-'
    end
+
};
   
+
 
    local show = type( result[1][1] ) == 'string' and result[1] or result[1][1];
+
if not result or _count( result ) == 0 or _count( result[1] ) == 0 then
 +
return;
 +
end
 +
 
 +
local show = type( result[1][1] ) == 'string' and result[1] or result[1][1];
  
    return table.concat( link and show or _unlink( show ), '\n' );
+
return table.concat( link and show or _unlink( show ), '\n' );
 
end
 
end
  
Line 125: Line 143:
 
--  «Pendulum» is not included here.
 
--  «Pendulum» is not included here.
 
function _monsterCardType( t )
 
function _monsterCardType( t )
    for key, value in ipairs( t ) do
+
for key, value in ipairs( t ) do
        if monsterCardTypes[_trim( value:lower():gsub( ' monster', '' ) )] then
+
if monsterCardTypes[_trim( value:lower():gsub( ' monster', '' ) )] then
            return value;
+
return value;
        end
+
end
    end
+
end
 
end
 
end
  
Line 135: Line 153:
 
--  Only one allowed per card.
 
--  Only one allowed per card.
 
function _ability( t )
 
function _ability( t )
    for key, value in ipairs( t ) do
+
for key, value in ipairs( t ) do
        if abilities[_trim( value:lower():gsub( ' monster', '' ) )] then
+
if abilities[_trim( value:lower():gsub( ' monster', '' ) )] then
            return value;
+
return value;
        end
+
end
    end
+
end
 
end
 
end
  
 
--  Effect function:
 
--  Effect function:
--  Misleading name; checks for Effect/Normal Monster.  
+
--  Misleading name; checks for Effect/Normal Monster.
 
function _effect( t )
 
function _effect( t )
    for key, value in ipairs( t ) do
+
for key, value in ipairs( t ) do
        if value:match('Effect') then
+
if value:match('Effect') then
            return 'Effect Monster';
+
return 'Effect Monster';
        elseif value:match('Normal') then
+
elseif value:match('Normal') then
            return 'Normal Monster';
+
return 'Normal Monster';
        end
+
end
    end
+
end
 
end
 
end
  
Line 158: Line 176:
 
--  Concatenates them and returns.
 
--  Concatenates them and returns.
 
function _full( pendulum, monsterCardType, tuner, ability, effect )
 
function _full( pendulum, monsterCardType, tuner, ability, effect )
    --  Effect <Ability> Tuner <Monster card type> Pendulum
+
--  Effect <Ability> Tuner <Monster card type> Pendulum
    --  Build backwards.
+
--  Build backwards.
    local cardType = {};
+
local cardType = {};
    local notLast  = false;
+
local notLast  = false;
    if pendulum then
+
if pendulum then
        table.insert( cardType, 1, _link( 'Pendulum Monster' ));
+
table.insert( cardType, 1, _link( 'Pendulum Monster' ) );
        notLast = true;
+
notLast = true;
    end
+
end
    if monsterCardType then
+
if monsterCardType then
        table.insert( cardType, 1, _link( monsterCardType, notLast and monsterCardType:gsub( ' [Mm]onster', '' ) ) );
+
table.insert( cardType, 1, _link( monsterCardType, notLast and monsterCardType:gsub( ' [Mm]onster', '' ) ) );
        notLast = true;
+
notLast = true;
    end
+
end
    if tuner then
+
if tuner then
        table.insert( cardType, 1, _link( 'Tuner monster' , notLast and 'Tuner' ) );
+
table.insert( cardType, 1, _link( 'Tuner monster' , notLast and 'Tuner' ) );
        notLast = true;
+
notLast = true;
    end
+
end
    if ability then
+
if ability then
        table.insert( cardType, 1, _link( ability, notLast and ability:gsub( ' [Mm]onster', '' ) ) );
+
table.insert( cardType, 1, _link( ability, notLast and ability:gsub( ' [Mm]onster', '' ) ) );
        notLast = true;
+
notLast = true;
    end
+
end
    if effect and not ability then
+
if effect and not ability then
        table.insert( cardType, 1, _link( effect, notLast and effect:gsub( ' [Mm]onster', '' ) ) );
+
table.insert( cardType, 1, _link( effect, notLast and effect:gsub( ' [Mm]onster', '' ) ) );
    end
+
end
  
    return table.concat( cardType, ' ' ) -- @@@ [[Tuner Synchro]], unlink.
+
return table.concat( cardType, ' ' ) -- @@@ [[Tuner Synchro]], unlink.
 
end
 
end
  
Line 189: Line 207:
 
--  Prints full card type.
 
--  Prints full card type.
 
function _monster( card )
 
function _monster( card )
    local primary = _show( card, 'Primary type' );
+
local primary = _show( card, 'Primary type' );
    if not _trim( primary ) then
+
if not _trim( primary ) then
        return card:match( '(original)' ) and _link( 'Monster Card' )   --  For Egyptian Gods.
+
return card:match( '(original)' ) and _link( 'Monster Card' ) --  For Egyptian Gods.
            or _error( 'On «_monster»; No primary type available!' );
+
or '';
    end
+
end
    if primary:match('Token') then
+
if primary:match( 'Token' ) then
        return _link( 'Token Monster', 'Token' );
+
return _link( 'Monster Token', 'Token' );
    end
+
end
   
+
 
    --  Primary type:
+
--  Primary type:
    local primaryTable    = split( primary, '\n' );
+
local primaryTable    = split( primary, '\n' );
    local monsterCardType = _monsterCardType( primaryTable );
+
local monsterCardType = _monsterCardType( primaryTable );
    local pendulum        = primary:match('Pendulum');
+
local pendulum        = primary:match( 'Pendulum' );
    local effect          = _effect( primaryTable );
+
local effect          = _effect( primaryTable );
   
+
 
    --  Secondary type:
+
--  Secondary type:
    local secondary       = _trim( _show( card, 'Secondary type' ) );
+
local secondary     = _trim( _show( card, 'Secondary type' ) );
    local secondaryTable = secondary and split( secondary, '\n' );
+
local secondaryTable = secondary and split( secondary, '\n' );
    local ability         = secondary and _ability( secondaryTable );
+
local ability       = secondary and _ability( secondaryTable );
    local tuner           = secondary and secondary:match('Tuner');
+
local tuner         = secondary and secondary:match( 'Tuner' );
   
+
 
    --  Full monster card type:
+
--  Full monster card type:
    local full = _full( pendulum, monsterCardType, tuner, ability, effect );
+
return _full( pendulum, monsterCardType, tuner, ability, effect );
    return full;
 
 
end
 
end
  
--  Spell card function:
+
--  Spell/Trap card function:
 
--  Fetches property,
 
--  Fetches property,
 
--  Prints full card type.
 
--  Prints full card type.
function _spell( card )
+
function _spellTrap( card, ST )
    local _property = _show( card, 'Property' );
+
local _property = _show( card, 'Property' );
    if not _trim( _property ) then
+
if not _trim( _property ) then
        return _error( 'On «_spell»; No property available!' )
+
return _error( 'On «_spellTrap»; No property available!' )
    end
+
end
   
+
 
    return ('%s %s'):format( _show( card, 'Property (short)', true ), _link( 'Spell Card' ) );
+
--return ('%s %s'):format( _link( table.concat( { _property, ST }, ' ' ), _property ), _link( ST ) );
end
+
return ('%s %s'):format( _link( _property, _property:gsub(ST..' Card', '') ), _link( ST ) );
--@@@ may be merged, depending on what I want to do later.
 
--  Trap card function:
 
--  Fetches property,
 
--  Prints full card type.
 
function _trap( card )
 
    local _property = _show( card, 'Property' );
 
    if not _trim( _property ) then
 
        return _error( 'On «_trap»; No property available!' )
 
    end
 
   
 
    return ('%s %s'):format( _show( card, 'Property (short)', true ), _link( 'Spell Card' ) );
 
 
end
 
end
  
function _counter()
+
function _nonGame( t )
    return _link( 'Counter' );
+
if _count( t ) > 1 then
 +
return _error( 'On «_nonGame»; Too many card types!' )
 +
elseif ( t[ 1 ] or '' ):match( '?' ) then
 +
return '???'
 +
else
 +
return _link( FAQtypes[t[1]:lower():gsub( ' card', '' )] ) or _error( 'On «_nonGame»; Non-standard card type!' );
 +
end
 
end
 
end
  
Line 246: Line 258:
 
--  Processes the card, to figure out the actual card type:
 
--  Processes the card, to figure out the actual card type:
 
--  Monster, Spell, Trap, other.
 
--  Monster, Spell, Trap, other.
--  (where «other» can be Tip, Strategy, etc..)  
+
--  (where «other» can be Tip, Strategy, etc..)
 
function _type( card )
 
function _type( card )
    local _cardType = _show( card, 'Card type' );
+
local cardType = _show( card, 'Card type' );
    if not _trim( _cardType ) then
+
if not _trim( cardType ) then
        return _error( 'On «_type»; No card type available!' );
+
return _error( 'On «_type»; No card type available!' );
    end
+
end
   
 
    _cardType = _cardType:lower();
 
    if _cardType:match('monster') then
 
        return _monster( card );
 
    elseif _cardType:match('spell') then
 
        return _spell( card );
 
    elseif _cardType:match('trap') then
 
        return _trap( card );
 
    elseif _cardType:match('counter') then -- @@@ tip/strategy/nongame??NoSMW/FAQ??
 
        return _counter();
 
    else
 
        return _error( 'On «_type»; Non-standard card type!' );
 
    end
 
end
 
  
function _class( card )
+
cardType = cardType:lower();
 
+
if cardType:match( 'monster' ) then
  return  
+
return _monster( card );
 +
elseif cardType:match( 'spell' ) then
 +
return _spellTrap( card, 'Spell' );
 +
elseif cardType:match( 'trap' ) then
 +
return _spellTrap( card, 'Trap' );
 +
else
 +
return _nonGame( split( cardType, '\n' ) );
 +
end
 
end
 
end
  
--  _main function, to be exported:
+
--  _main function:
 
--  Processes a string, the card name.
 
--  Processes a string, the card name.
 
--  Looks for errors (if empty).
 
--  Looks for errors (if empty).
 
--  Else, figures the card type.
 
--  Else, figures the card type.
 
function _main( s )
 
function _main( s )
    local _card = _unlink( s );
+
local _card = _unlink( s );
    if not _card then
+
if not _card then
        return _error( 'Empty value!' );
+
return _error( 'Empty value!' );
    end
+
end
    local _page = _card:gsub( '#', '' );
+
local _page = _card:gsub( '#', '' );
    -- @@@ check if it's from the actual game( Class 1: Official )
+
local redirect = _redirect( _page ); -- @@@cat + text
    local redirect = _redirect( _page ); -- @@@cat + text
+
 
   
+
if not _trim( _show( _page, 'Page name' ) ) then
    return _type( _page )
+
-- If the page doesn't exist, basically. @@@ Fails for cases where SMW is down.
 +
return _categories( '((Card type)) transclusions to be checked' );
 +
end
 +
return _type( _page );--@@@ function _class( _page )
 
end
 
end
  
Line 295: Line 303:
 
--  Send it to _main directly.
 
--  Send it to _main directly.
 
function CardType.main( frame )
 
function CardType.main( frame )
    if not mw.smw then
+
if not mw.smw then
        return _error( 'mw.smw module not found' );
+
return _error( 'mw.smw module not found' );
    end
+
end
    if type( frame ) == 'string' then
+
if type( frame ) == 'string' then
        --  If used through other modules.
+
--  If used through other modules.
        return _main( frame );
+
return _main( frame );
    end
+
end
    --  «args» for the args table;
+
--  «args» for the args table;
    --  «argsN» for the number or arguments;
+
--  «argsN» for the number or arguments;
    local args = getArgs( frame, { trim = true, parentOnly = true } ); -- Args table.
+
local args = getArgs( frame, { trim = true, parentOnly = true } ); -- Args table.
   
+
 
    local argsN = _count( args );
+
local argsN = _count( args );
    if argsN > 1 then
+
if argsN > 1 then
        return _error( 'Too many arguments! Use only one!' );
+
return _error( 'Too many arguments! Use only one!' );
    elseif argsN < 1 then
+
elseif argsN < 1 then
        return _error( 'No arguments! Use one!' );
+
return _error( 'No arguments! Use one!' );
    end
+
end
   
+
 
    return _main( args[1] );
+
return _main( args[1] );
 
end
 
end
  
 
return CardType;
 
return CardType;
 
--  </pre>
 
--  </pre>

Latest revision as of 11:30, 3 June 2023

--  <pre>
--  Module for {{Card type}}.
--  Can also be used through other modules.
--  @@@ for ideas.
local CardType = {};

---------------------
--  External modules:
---------------------
local getArgs = require( 'Module:Arguments' ).getArgs;

---------
--  Data:
---------
local data             = mw.loadData( 'Module:Card type/data' );
local FAQtypes         = data.FAQtypes;
local abilities        = data.abilities;
local monsterCardTypes = data.monsterCardTypes;

------------------
--  Aux functions:
------------------
--  mw functions:
local split = mw.text.split;

--  Trim function:
--  Trims white space from front and tail of string.
--  If the input is only white space, returns nil.
function _trim( s )
	if s and not s:match( '^%s*$' ) then
		return mw.text.trim( s ); -- If not nil nor empty.
	end
end

--  Link function:
--  If a string is passed, links it;
--  uses a label, when given.
--  If a table is passed, links every instance of it;
--  uses a table of labels, respectively for each entry, when given.
function _link( v, ... )
	local labels = type( ... or nil ) == 'table' and ... or  { ... };  --  Make sure it's a table.
	local function __link( v, label )
		return ('[[%s|%s]]'):format( v, (_trim( label ) or split( v, ' %(' )[1]) );
	end
	if type( v ) == 'string' then
		return __link( v, labels[1] );
	elseif type( v ) == 'table' then
		local t = {};
		for key, value in ipairs( v ) do
			table.insert( t, __link( value, labels[key] ) );
		end
		return t;
	else
		return v; -- @@@ error()
	end
end

--  Unlink function:
--  If a string is passed, unlinks
--  and returns the page name (not the label, unless «getLabel»).
--  If a table is passed, unlinks every instance of it
--  and returns the table with the page names for each respective entry.
function _unlink( v, getLabel )
	local function __unlink( v, getLabel )
		return _trim( v ) and (getLabel and v:match( '%[%[:?.-|(.-)]]' ) or v:match( '%[%[:?(.-)[|%]]' )) or _trim( v );
	end
	if type( v ) == 'string' then
		return __unlink( v, getLabel );
	elseif type( v ) == 'table' then
		local t = {};
		for key, value in ipairs( v ) do
			table.insert( t, __unlink( value, getLabel ) );
		end
		return t;
	else
		return v; -- @@@ error()
	end
end

--  Table count function:
--  Given a table, counts how many valuee it has.
function _count( t ) -- @@@ error() for wrong type()
	local counter = 0;
	for key, value in pairs( t ) do
		counter = counter + 1;
	end
	return counter;
end

--  Categories function:
--  Receives categories' names.
--  Returns the linked categories.
function _categories( ... )
	local categories = type( ... or nil ) == 'table' and ... or  { ... };  --  Make sure it's a table.
	local t = {};
	for _, category in pairs( categories ) do
		table.insert( t, ('[[Category:%s]]'):format( category ) );
	end
	return table.concat( t, '\n' );
end

--  Error function:
--  Generates error messages and categories.
function _error( message )
	local _error = mw.html.create( 'div' )
		:tag( 'strong' ):addClass( 'error' )
			:wikitext( ('Error: %s'):format( message ) ):done()
	:allDone();
	local cat = _categories( 'Pages with script errors', '((Card type)) transclusions to be checked' );
	return ('%s\n%s'):format( tostring( _error ), cat ); -- @@@ or error()
end

function _redirect( card )
	local pagename = _trim( _show( card, 'Page name' ) );
	return pagename ~= card and pagename;
end

--  Show function:
--  Similar to #show parser function.
--  Returns string with the results.
function _show( page, property, link )
	--  At this point, SMW is enabled and «page» is formatted properly (as pagename).
	local result =  mw.smw.ask{
		('[[%s]]'):format( page ),
		('?%s='):format( property ),
		mainlabel = '-'
	};

	if not result or _count( result ) == 0 or _count( result[1] ) == 0 then
		return;
	end

	local show = type( result[1][1] ) == 'string' and result[1] or result[1][1];

	return table.concat( link and show or _unlink( show ), '\n' );
end

-------------------
--  Main functions:
-------------------
--  Monster card type function:
--  Only one allowed per card.
--  «Pendulum» is not included here.
function _monsterCardType( t )
	for key, value in ipairs( t ) do
		if monsterCardTypes[_trim( value:lower():gsub( ' monster', '' ) )] then
			return value;
		end
	end
end

--  Ability function:
--  Only one allowed per card.
function _ability( t )
	for key, value in ipairs( t ) do
		if abilities[_trim( value:lower():gsub( ' monster', '' ) )] then
			return value;
		end
	end
end

--  Effect function:
--  Misleading name; checks for Effect/Normal Monster.
function _effect( t )
	for key, value in ipairs( t ) do
		if value:match('Effect') then
			return 'Effect Monster';
		elseif value:match('Normal') then
			return 'Normal Monster';
		end
	end
end

--  Full card type function (for monsters only):
--  Given every value a monster can have,
--  Concatenates them and returns.
function _full( pendulum, monsterCardType, tuner, ability, effect )
	--  Effect <Ability> Tuner <Monster card type> Pendulum
	--  Build backwards.
	local cardType = {};
	local notLast  = false;
	if pendulum then
		table.insert( cardType, 1, _link( 'Pendulum Monster' ) );
		notLast = true;
	end
	if monsterCardType then
		table.insert( cardType, 1, _link( monsterCardType, notLast and monsterCardType:gsub( ' [Mm]onster', '' ) ) );
		notLast = true;
	end
	if tuner then
		table.insert( cardType, 1, _link( 'Tuner monster' , notLast and 'Tuner' ) );
		notLast = true;
	end
	if ability then
		table.insert( cardType, 1, _link( ability, notLast and ability:gsub( ' [Mm]onster', '' ) ) );
		notLast = true;
	end
	if effect and not ability then
		table.insert( cardType, 1, _link( effect, notLast and effect:gsub( ' [Mm]onster', '' ) ) );
	end

	return table.concat( cardType, ' ' ) -- @@@ [[Tuner Synchro]], unlink.
end

--  Monster card function:
--  Fetches monster card type, ability, Pendulum, Tuner, Token.
--  Prints full card type.
function _monster( card )
	local primary = _show( card, 'Primary type' );
	if not _trim( primary ) then
		return card:match( '(original)' ) and _link( 'Monster Card' ) --  For Egyptian Gods.
			or '';
	end
	if primary:match( 'Token' ) then
		return _link( 'Monster Token', 'Token' );
	end

	--  Primary type:
	local primaryTable    = split( primary, '\n' );
	local monsterCardType = _monsterCardType( primaryTable );
	local pendulum        = primary:match( 'Pendulum' );
	local effect          = _effect( primaryTable );

	--  Secondary type:
	local secondary      = _trim( _show( card, 'Secondary type' ) );
	local secondaryTable = secondary and split( secondary, '\n' );
	local ability        = secondary and _ability( secondaryTable );
	local tuner          = secondary and secondary:match( 'Tuner' );

	--  Full monster card type:
	return _full( pendulum, monsterCardType, tuner, ability, effect );
end

--  Spell/Trap card function:
--  Fetches property,
--  Prints full card type.
function _spellTrap( card, ST )
	local _property = _show( card, 'Property' );
	if not _trim( _property ) then
		return _error( 'On «_spellTrap»; No property available!' )
	end

	--return ('%s %s'):format( _link( table.concat( { _property, ST }, ' ' ), _property ), _link( ST ) );
	return ('%s %s'):format( _link( _property, _property:gsub(ST..' Card', '') ), _link( ST ) );
end

function _nonGame( t )
	if _count( t ) > 1 then
		return _error( 'On «_nonGame»; Too many card types!' )
	elseif ( t[ 1 ] or '' ):match( '?' ) then
		return '???'
	else
		return _link( FAQtypes[t[1]:lower():gsub( ' card', '' )] ) or _error( 'On «_nonGame»; Non-standard card type!' );
	end
end

--  Type function:
--  Processes the card, to figure out the actual card type:
--  Monster, Spell, Trap, other.
--  (where «other» can be Tip, Strategy, etc..)
function _type( card )
	local cardType = _show( card, 'Card type' );
	if not _trim( cardType ) then
		return _error( 'On «_type»; No card type available!' );
	end

	cardType = cardType:lower();
	if cardType:match( 'monster' ) then
		return _monster( card );
	elseif cardType:match( 'spell' ) then
		return _spellTrap( card, 'Spell' );
	elseif cardType:match( 'trap' ) then
		return _spellTrap( card, 'Trap' );
	else
		return _nonGame( split( cardType, '\n' ) );
	end
end

--  _main function:
--  Processes a string, the card name.
--  Looks for errors (if empty).
--  Else, figures the card type.
function _main( s )
	local _card = _unlink( s );
	if not _card then
		return _error( 'Empty value!' );
	end
	local _page = _card:gsub( '#', '' );
	local redirect = _redirect( _page ); -- @@@cat + text

	if not _trim( _show( _page, 'Page name' ) ) then
		-- If the page doesn't exist, basically. @@@ Fails for cases where SMW is down.
		return _categories( '((Card type)) transclusions to be checked' );
	end
	return _type( _page );--@@@ function _class( _page )
end

--  Main function:
--  Processes input;
--  if it's a frame (used externally, through {{Card type}},
--  fetch value, throws errors regarding the number of arguments; Then sends it to _main.
--  Else, (if it's a string (should be, if used through other modules!))
--  Send it to _main directly.
function CardType.main( frame )
	if not mw.smw then
		return _error( 'mw.smw module not found' );
	end
	if type( frame ) == 'string' then
		--  If used through other modules.
		return _main( frame );
	end
	--  «args» for the args table;
	--  «argsN» for the number or arguments;
	local args = getArgs( frame, { trim = true, parentOnly = true } ); -- Args table.

	local argsN = _count( args );
	if argsN > 1 then
		return _error( 'Too many arguments! Use only one!' );
	elseif argsN < 1 then
		return _error( 'No arguments! Use one!' );
	end

	return _main( args[1] );
end

return CardType;
--  </pre>