MagicArena Wiki
(Support italics in card flavor text)
m (added jumstart)
 
(33 intermediate revisions by 2 users not shown)
Line 7: Line 7:
 
local tinsert, sub, gsub = table.insert, string.sub, string.gsub
 
local tinsert, sub, gsub = table.insert, string.sub, string.gsub
   
local cardRowTemplate= [[|-valign="top"
+
local cardRowTemplate= [[|-
 
|%s
 
|%s
 
|%s
 
|%s
Line 13: Line 13:
 
]]
 
]]
   
local anyCardRowTemplate= [[|-valign="top"
+
local anyCardRowTemplate= [[|-
 
|%s
 
|%s
 
|%s
 
|%s
Line 31: Line 31:
 
%s
 
%s
 
|}
 
|}
<br/>
 
 
[[File:%s.png|265px|link=]]]=]
 
[[File:%s.png|265px|link=]]]=]
   
 
local numCardsPerPage = 100
 
local numCardsPerPage = 100
   
local setNames = {}
+
local setNames = {
setNames["KLD"]="Kaladesh"
+
["KLD"]="Kaladesh";
setNames["AER"]="Aether Revolt"
+
["AER"]="Aether Revolt";
setNames["W17"]="Welcome Deck 2017"
+
["W17"]="Welcome Deck 2017";
setNames["AKH"]="Amonkhet"
+
["AKH"]="Amonkhet";
setNames["HOU"]="Hour of Devastation"
+
["HOU"]="Hour of Devastation";
setNames["XLN"]="Ixalan"
+
["XLN"]="Ixalan";
setNames["RIX"]="Rivals of Ixalan"
+
["RIX"]="Rivals of Ixalan";
setNames["DOM"]="Dominaria"
+
["DOM"]="Dominaria";
setNames["M19"]="Core Set 2019"
+
["M19"]="Core Set 2019";
setNames["G18"]="Gift Pack"
+
["G18"]="Gift Pack";
setNames["ANA"]="Arena Only"
+
["ANA"]="Arena Only";
setNames["GRN"]="Guilds of Ravnica"
+
["GRN"]="Guilds of Ravnica";
setNames["RNA"]="Ravnica Allegiance"
+
["RNA"]="Ravnica Allegiance";
setNames["WAR"]="War of the Spark"
+
["WAR"]="War of the Spark";
setNames["M20"]="Core Set 2020"
+
["M20"]="Core Set 2020";
  +
["ELD"]="Throne of Eldraine";
  +
["HA1"]="Historic Anthology 1";
  +
["GTC"]="Gatecrash";
  +
["INV"]="Invasion";
  +
["EMN"]="Eldritch Moon";
  +
["DST"]="Darksteel";
  +
["ORI"]="Magic Origins";
  +
["SOK"]="Saviors of Kamigawa";
  +
["M10"]="Magic 2010";
  +
["LRW"]="Lorwyn";
  +
["ROE"]="Rise of the Eldrazi";
  +
["MOR"]="Morningtide";
  +
["WTH"]="Weatherlight";
  +
["8ED"]="Eighth Edition";
  +
["M11"]="Magic 2011";
  +
["WWK"]="Worldwake";
  +
["MH1"]="Modern Horizons";
  +
["SHM"]="Shadowmoor";
  +
["THB"]="Theros Beyond Death";
  +
["M15"]="Magic 2015 Core Set";
  +
["ARB"]="Alara Reborn";
  +
["CON"]="Conflux";
  +
["DKA"]="Dark Ascension";
  +
["DTK"]="Dragons of Tarkir";
  +
["ISD"]="Innistrad";
  +
["JOU"]="Journey into Nyx";
  +
["M13"]="Magic 2013";
  +
["MMQ"]="Mercadian Masques";
  +
["ODY"]="Odyssey";
  +
["ONS"]="Onslaught";
  +
["RTR"]="Return to Ravnica";
  +
["SOM"]="Scars of Mirrodin";
  +
["SCG"]="Scourge";
  +
["ALA"]="Shards of Alara";
  +
["ZEN"]="Zendikar";
  +
["SOI"]="Shadows over Innistrad";
  +
["IKO"]="Ikoria Lair of Behemoths";
  +
["PLC"]="Planar Chaos";
  +
["TOR"]="Torment";
  +
["LGN"]="Legions";
  +
["CHK"]="Champions of Kamigawa";
  +
["DGM"]="Dragon's Maze";
  +
["JUD"]="Judgment";
  +
["TSP"]="Time Spiral";
  +
["NPH"]="New Phyrexia";
  +
["THS"]="Theros";
  +
["M12"]="Magic 2012";
  +
["BFZ"]="Battle for Zendikar";
  +
["M21"]="Core Set 2021";
  +
["JMP"]="Jumpstart";
  +
}
   
 
local function SetLinkName(setCode)
 
local function SetLinkName(setCode)
 
if setCode == "HOU" then
 
if setCode == "HOU" then
 
return "Hour of Devastation (set)"
 
return "Hour of Devastation (set)"
 
end
  +
if setCode == "WTH" then
  +
return "Weatherlight (set)"
 
end
 
end
 
return setNames[setCode]
 
return setNames[setCode]
Line 63: Line 116:
 
if setCode == "HOU" then
 
if setCode == "HOU" then
 
return "[[Hour of Devastation (set)|Hour of Devastation]]"
 
return "[[Hour of Devastation (set)|Hour of Devastation]]"
 
end
  +
if setCode == "WTH" then
  +
return "[[Weatherlight (set)|Weatherlight]]"
 
end
 
end
 
return "[[" .. setNames[setCode] .. "]]"
 
return "[[" .. setNames[setCode] .. "]]"
Line 69: Line 125:
   
 
local function ConcatTables(target,source)
 
local function ConcatTables(target,source)
if not source then return end
+
if not source then
  +
return
  +
end
 
for _,v in pairs(source) do
 
for _,v in pairs(source) do
 
tinsert(target,v)
 
tinsert(target,v)
Line 87: Line 145:
 
end
 
end
   
local function DescriptionBox(card)
+
local function DescriptionBox(card, amount)
  +
amount = (amount and amount ~= "") and '<span class="mdw-card-amount">' .. amount .. '</span> x ' or ""
return "[["..card.Name.."]] "..(card.Manacost or "").." ("..(card.cmc or 0)..")<br/>"..
+
return amount .. "[["..card.Name.."]] "..(card.Manacost or "").." ("..(card.cmc or 0)..")<br/>"..
 
card.Type.." "..PT(card).."<br/>"..
 
card.Type.." "..PT(card).."<br/>"..
 
(card.Text or "")
 
(card.Text or "")
Line 94: Line 153:
   
 
local function ExpansionSymbol(card)
 
local function ExpansionSymbol(card)
  +
local rarity = card.Rarities[1]
return "{{"..card.SetCode..card.Rarity:sub(1,1).."}}"
 
  +
local setCode = card.Allsets[1]
  +
local title = setNames[setCode] .. " " .. rarity
  +
return "<span title=\"" .. title .. "\">{{" .. setCode .. rarity:sub(1,1).."}}</span>"
 
end
 
end
   
 
local function GetRulings(card, isOtherCard)
 
local function GetRulings(card, isOtherCard)
if card.Rulings == nil then return "" end
+
if card.Rulings == nil then
  +
return ""
  +
end
 
local rulings = isOtherCard and mw.loadData("Module:Data/OtherRulings") or mw.loadData("Module:Data/Rulings")
 
local rulings = isOtherCard and mw.loadData("Module:Data/OtherRulings") or mw.loadData("Module:Data/Rulings")
 
local rules = rulings[card.CardNumber]
 
local rules = rulings[card.CardNumber]
if rules == nil then return "" end
+
if rules == nil then
  +
return ""
  +
end
 
local s = [=[{{clear}}
 
local s = [=[{{clear}}
 
{| class="article-table mdw-cardrulings-table"
 
{| class="article-table mdw-cardrulings-table"
Line 120: Line 186:
 
end
 
end
   
local function GenerateAnyCardRow(card)
+
local function GenerateAnyCardRow(card, amount)
 
return string.format(anyCardRowTemplate,
 
return string.format(anyCardRowTemplate,
"[[File:"..card.Name..".png|95px|link="..card.Name.."]]",
+
'<span class="card-image-tooltip" data-parameter="' .. card.Name .. '">[[File:' .. card.Name .. '.png|95px|link=' .. card.Name .. ']]</span>',
DescriptionBox(card))
+
DescriptionBox(card, amount))
 
end
 
end
 
   
 
local function GetReprintsTable(card)
 
local function GetReprintsTable(card)
Line 146: Line 211:
 
if card.Sets then
 
if card.Sets then
 
reprints = "{{Clear}}\n"
 
reprints = "{{Clear}}\n"
if card.Rarity == "Basic Land" then
+
if card.Rarities[1] == "Basic Land" then
 
reprints = reprints .. "{{LandReprint}}"
 
reprints = reprints .. "{{LandReprint}}"
 
else
 
else
Line 175: Line 240:
 
if card.Loyalty then tinsert(contents, {"Loyalty", card.Loyalty}) end
 
if card.Loyalty then tinsert(contents, {"Loyalty", card.Loyalty}) end
 
if card.Power then tinsert(contents, {"P/T", PT(card)}) end
 
if card.Power then tinsert(contents, {"P/T", PT(card)}) end
tinsert(contents, {"Expansion", ExpansionSymbol(card) .. " " .. SetLink(card.SetCode)})
+
tinsert(contents, {"Expansion", ExpansionSymbol(card) .. " " .. SetLink(card.Allsets[1])})
tinsert(contents, {"Rarity", card.Rarity})
+
tinsert(contents, {"Rarity", card.Rarities[1]})
 
if card.Banned then tinsert(contents, {"Banned In", BanText(card.Banned)}) end
 
if card.Banned then tinsert(contents, {"Banned In", BanText(card.Banned)}) end
   
Line 211: Line 276:
 
output[1] = [=[! colspan="3" align="right"|]=] .. numresults .. " result" .. (numresults ~= 1 and "s\n" or "\n")
 
output[1] = [=[! colspan="3" align="right"|]=] .. numresults .. " result" .. (numresults ~= 1 and "s\n" or "\n")
 
return table.concat(output)
 
return table.concat(output)
  +
end
  +
  +
local function GetCardNames(cards)
  +
local output = {}
  +
for card in cards do
  +
tinsert(output, card.Name)
  +
end
  +
return table.concat(output, "\n")
  +
end
  +
  +
function p.GetCardNames(frame)
  +
local criteria = utils.RecreateTable(frame:getParent().args)
  +
local result = GetCardNames(cardService.GetByCriteria(criteria))
  +
return result
 
end
 
end
   
Line 223: Line 302:
 
local result = GetCardsTable(cardService.GetOtherByCriteria(criteria))
 
local result = GetCardsTable(cardService.GetOtherByCriteria(criteria))
 
return frame:preprocess(result)
 
return frame:preprocess(result)
end
 
 
function p.TestGetCardsTable(criteria)
 
return GetCardsTable(criteria)
 
 
end
 
end
   
Line 262: Line 337:
 
s = cardResultPageNavigation(startCard, endCard, numresults, page, linkBase) ..
 
s = cardResultPageNavigation(startCard, endCard, numresults, page, linkBase) ..
 
s .. "\n|-\n" ..
 
s .. "\n|-\n" ..
cardResultPageNavigation(startCard,endCard,numresults,page,linkBase)
+
cardResultPageNavigation(startCard, endCard, numresults, page, linkBase)
 
return s
 
return s
end
 
 
function p.TestGetPagedCardsTable(criteria, title)
 
return GetPagedCardsTable(criteria, title)
 
 
end
 
end
   
Line 279: Line 350:
 
function p.GetAnyCardRow(frame)
 
function p.GetAnyCardRow(frame)
 
local name = frame.args[1]
 
local name = frame.args[1]
  +
local amount = frame.args[2]
 
local card = cardService.GetByNameIgnoreCase(name)
 
local card = cardService.GetByNameIgnoreCase(name)
return frame:preprocess(GenerateAnyCardRow(card))
+
return frame:preprocess(GenerateAnyCardRow(card, amount))
 
end
 
end
   
Line 287: Line 359:
 
local card = cardService.GetOtherByName(name)
 
local card = cardService.GetOtherByName(name)
 
if card then
 
if card then
s = "{{CardUnavailable}}\n{{clear}}\n" .. GenerateOtherCardPage(card)
+
s = "{{NoticeCardUnavailable}}\n{{clear}}\n" .. GenerateOtherCardPage(card)
 
if card.CardNumber and (string.find(card.CardNumber, "a")) then
 
if card.CardNumber and (string.find(card.CardNumber, "a")) then
 
local card2 = cardService.GetOtherByNumber(gsub(card.CardNumber, "a", "b"))
 
local card2 = cardService.GetOtherByNumber(gsub(card.CardNumber, "a", "b"))
Line 299: Line 371:
   
 
local function GetCard(card)
 
local function GetCard(card)
local s = GenerateCardPage(card)
+
local s = cardService.IsStandard(card) and "" or "{{NoticeHistoricCard}}\n"
  +
s = s .. GenerateCardPage(card)
 
if card.CardNumber and (string.find(card.CardNumber, "a")) then
 
if card.CardNumber and (string.find(card.CardNumber, "a")) then
 
local card2 = cardService.GetByNumber(gsub(card.CardNumber, "a", "b"))
 
local card2 = cardService.GetByNumber(gsub(card.CardNumber, "a", "b"))
Line 324: Line 397:
 
end
 
end
 
ConcatTables(categories,card.Colors)
 
ConcatTables(categories,card.Colors)
tinsert(categories,card.Rarity)
+
tinsert(categories,card.Rarities[1])
 
ConcatTables(categories,card.SuperTypes)
 
ConcatTables(categories,card.SuperTypes)
 
ConcatTables(categories,card.Types)
 
ConcatTables(categories,card.Types)

Latest revision as of 00:17, 28 July 2020

Documentation for this module may be created at Module:Cards/doc

--<nowiki>
local cardService = require("Module:CardService")
local utils = require("Module:TemplateUtils")

local p = {}

local tinsert, sub, gsub = table.insert, string.sub, string.gsub

local cardRowTemplate= [[|-
|%s
|%s
|%s
]]

local anyCardRowTemplate= [[|-
|%s
|%s
]]

local cardPageRowTemplate = [[|-
!%s
| %s
]]

local rulingTemplate = [[|-
|%s
|%s
]]

local cardPageTemplate = [=[{| class="article-table mdw-cardinfo-table"
%s
|}
[[File:%s.png|265px|link=]]]=]

local numCardsPerPage = 100

local setNames = {
    ["KLD"]="Kaladesh";
    ["AER"]="Aether Revolt";
    ["W17"]="Welcome Deck 2017";
    ["AKH"]="Amonkhet";
    ["HOU"]="Hour of Devastation";
    ["XLN"]="Ixalan";
    ["RIX"]="Rivals of Ixalan";
    ["DOM"]="Dominaria";
    ["M19"]="Core Set 2019";
    ["G18"]="Gift Pack";
    ["ANA"]="Arena Only";
    ["GRN"]="Guilds of Ravnica";
    ["RNA"]="Ravnica Allegiance";
    ["WAR"]="War of the Spark";
    ["M20"]="Core Set 2020";
    ["ELD"]="Throne of Eldraine";
    ["HA1"]="Historic Anthology 1";
    ["GTC"]="Gatecrash";
    ["INV"]="Invasion";
    ["EMN"]="Eldritch Moon";
    ["DST"]="Darksteel";
    ["ORI"]="Magic Origins";
    ["SOK"]="Saviors of Kamigawa";
    ["M10"]="Magic 2010";
    ["LRW"]="Lorwyn";
    ["ROE"]="Rise of the Eldrazi";
    ["MOR"]="Morningtide";
    ["WTH"]="Weatherlight";
    ["8ED"]="Eighth Edition";
    ["M11"]="Magic 2011";
    ["WWK"]="Worldwake";
    ["MH1"]="Modern Horizons";
    ["SHM"]="Shadowmoor";
    ["THB"]="Theros Beyond Death";
    ["M15"]="Magic 2015 Core Set";
    ["ARB"]="Alara Reborn";
    ["CON"]="Conflux";
    ["DKA"]="Dark Ascension";
    ["DTK"]="Dragons of Tarkir";
    ["ISD"]="Innistrad";
    ["JOU"]="Journey into Nyx";
    ["M13"]="Magic 2013";
    ["MMQ"]="Mercadian Masques";
    ["ODY"]="Odyssey";
    ["ONS"]="Onslaught";
    ["RTR"]="Return to Ravnica";
    ["SOM"]="Scars of Mirrodin";
    ["SCG"]="Scourge";
    ["ALA"]="Shards of Alara";
    ["ZEN"]="Zendikar";
    ["SOI"]="Shadows over Innistrad";
    ["IKO"]="Ikoria Lair of Behemoths";
    ["PLC"]="Planar Chaos";
    ["TOR"]="Torment";
    ["LGN"]="Legions";
    ["CHK"]="Champions of Kamigawa";
    ["DGM"]="Dragon's Maze";
    ["JUD"]="Judgment";
    ["TSP"]="Time Spiral";
    ["NPH"]="New Phyrexia";
    ["THS"]="Theros";
    ["M12"]="Magic 2012";
    ["BFZ"]="Battle for Zendikar";
    ["M21"]="Core Set 2021";
    ["JMP"]="Jumpstart";
}

local function SetLinkName(setCode)
    if setCode == "HOU" then
        return "Hour of Devastation (set)"
    end
    if setCode == "WTH" then
        return "Weatherlight (set)"
    end
    return setNames[setCode]
end

local function SetLink(setCode)
    if setCode == "HOU" then
        return "[[Hour of Devastation (set)|Hour of Devastation]]"
    end
    if setCode == "WTH" then
        return "[[Weatherlight (set)|Weatherlight]]"
    end
    return "[[" .. setNames[setCode] .. "]]"
end


local function ConcatTables(target,source)
    if not source then
        return
    end
    for _,v in pairs(source) do
        tinsert(target,v)
    end
end

local function PT(card)
    if ((card.Power == nil) or (card.Toughness == nil)) then
        if card.Loyalty ~= nil then
            return "("..card.Loyalty..")"
        else
            return ""
        end
    else
        return "("..card.Power.."/"..card.Toughness..")"
    end
end

local function DescriptionBox(card, amount)
    amount = (amount and amount ~= "") and '<span class="mdw-card-amount">' .. amount .. '</span> x ' or ""
    return amount .. "[["..card.Name.."]] "..(card.Manacost or "").." ("..(card.cmc or 0)..")<br/>"..
    card.Type.." "..PT(card).."<br/>"..
    (card.Text or "")
end

local function ExpansionSymbol(card)
    local rarity = card.Rarities[1]
    local setCode = card.Allsets[1]
    local title = setNames[setCode] .. " " .. rarity
    return "<span title=\"" .. title .. "\">{{" .. setCode .. rarity:sub(1,1).."}}</span>"
end

local function GetRulings(card, isOtherCard)
    if card.Rulings == nil then
         return ""
    end
    local rulings = isOtherCard and mw.loadData("Module:Data/OtherRulings") or mw.loadData("Module:Data/Rulings")
    local rules = rulings[card.CardNumber]
    if rules == nil then
        return ""
    end
    local s = [=[{{clear}}
{| class="article-table mdw-cardrulings-table"
|+ Card rulings ([[Card rulings|?]])
]=]
    for _, rule in pairs(rules) do
        s = s .. string.format(rulingTemplate, rule.Date, utils.ExpandSymbols(rule.Text))
    end
    s = s .. "|}"
    return s
end

local function GenerateCardRow(card)
    return string.format(cardRowTemplate,
        "[[File:"..card.Name..".png|95px|link="..card.Name.."]]",
        DescriptionBox(card),
        ExpansionSymbol(card))
end

local function GenerateAnyCardRow(card, amount)
    return string.format(anyCardRowTemplate,
        '<span class="card-image-tooltip" data-parameter="' .. card.Name .. '">[[File:' .. card.Name .. '.png|95px|link=' .. card.Name .. ']]</span>',
        DescriptionBox(card, amount))
end

local function GetReprintsTable(card)
    local row = "{{ReprintRow|%s|%s|%s|<br />%s}}\n"
    local s = "\n\n----\n{|class=\"mdw-reprint-table\"\n|+ '''Other Sets'''\n"
    for _, set in pairs(card.Sets) do
        local setTemplate = "{{" .. set.Set .. sub(set.Rarity,1,1) .. "}}"
        local imageName = card.Name .. " " .. set.Set .. " " .. set.CardNumber
        local setlink = SetLinkName(set.Set)
        local setname = setNames[set.Set]
        local flavor = set.Flavor or ""
        local text = setTemplate ..  " " .. set.Rarity .. "<br />" .. flavor
        s = s .. string.format(row, imageName, setlink, setname, text)
    end
    return s .. "|}"
end

local function GetReprints(card)
    local reprints = ""
    if card.Sets then
        reprints = "{{Clear}}\n"
        if card.Rarities[1] == "Basic Land" then
            reprints = reprints .. "{{LandReprint}}"
        else
            reprints = reprints .. GetReprintsTable(card)
        end
    end
    return reprints
end

local function BanText(banned)
    -- table.concat didn't work here, don't know why, so manualy concat
    local bantext = ""
    for _, bannedFormat in pairs(banned) do
        bantext = bantext .. bannedFormat .. '; '
    end
    return sub(bantext, 1, -3) .. "{{MoreBannedDetails}}"
end

local function GenerateCardInfo(card)
    local contents = {}
    tinsert(contents,{"Name",card.Name})

    if card.Manacost then tinsert(contents, {"Mana Cost", card.Manacost}) end
    tinsert(contents, {"Converted Mana Cost", card.cmc or 0})
    if card.Type then tinsert(contents, {"Types", card.Type}) end
    if card.Text then tinsert(contents, {"Text", card.Text}) end
    if card.Flavor then tinsert(contents, {"Flavor", gsub(card.Flavor, "&lt;/?i&gt;", "''")}) end
    if card.Loyalty then tinsert(contents, {"Loyalty", card.Loyalty}) end
    if card.Power then tinsert(contents, {"P/T", PT(card)}) end
    tinsert(contents, {"Expansion", ExpansionSymbol(card) .. " " .. SetLink(card.Allsets[1])})
    tinsert(contents, {"Rarity", card.Rarities[1]})
    if card.Banned then tinsert(contents, {"Banned In", BanText(card.Banned)}) end

    local info = ""
    for i = 1, #contents do
         info = info .. string.format(cardPageRowTemplate, contents[i][1], contents[i][2])
    end
    return info

end

local function GenerateCardPage(card)
    local cardInfo = GenerateCardInfo(card)
    local reprints = GetReprints(card)
    return string.format(cardPageTemplate,
        cardInfo,
        card.Name) .. GetRulings(card) .. reprints .. p.GetCardCategories(card)
end

local function GenerateOtherCardPage(card)
    local cardInfo = GenerateCardInfo(card)
    return string.format(cardPageTemplate,
        cardInfo,
        card.Name) ..  GetRulings(card, true) .. p.GetCardCategories(card)
end

local function GetCardsTable(cards)
    local output = {""}
    local numresults = 0
    for card in cards do
        tinsert(output, GenerateCardRow(card))
        numresults = numresults + 1
    end
    output[1] = [=[! colspan="3" align="right"|]=] .. numresults .. " result" .. (numresults ~= 1 and "s\n" or "\n")
    return table.concat(output)
end

local function GetCardNames(cards)
    local output = {}
    for card in cards do
        tinsert(output, card.Name)
    end
    return table.concat(output, "\n")
end

function p.GetCardNames(frame)
    local criteria = utils.RecreateTable(frame:getParent().args)
    local result = GetCardNames(cardService.GetByCriteria(criteria))
    return result
end

function p.GetCardsTable(frame)
    local criteria = utils.RecreateTable(frame:getParent().args)
    local result = GetCardsTable(cardService.GetByCriteria(criteria))
    return frame:preprocess(result)
end

function p.GetOtherCardsTable(frame)
    local criteria = utils.RecreateTable(frame:getParent().args)
    local result = GetCardsTable(cardService.GetOtherByCriteria(criteria))
    return frame:preprocess(result)
end

local function cardResultPageNavigation(startCard,endCard,numresults,page,linkBase)
    return [[! colspan="3" align="right"|Showing results ]]..startCard.." to "..endCard.." out of "..numresults.." "..((page == 1 ) and "" or([=[[[]=]..linkBase.. page - 1 ..[=[|Previous page]]]=])).." "..((startCard+numCardsPerPage>numresults) and "" or ([=[[[]=]..linkBase.. page + 1 ..[=[|Next page]]]=])).."\n"
end

local function GetPagedCardsTable(criteria, title)
    local titleparts = mw.text.split(title, '/', true)
    local page
    if (#titleparts == 0) or (tonumber(titleparts[#titleparts]) == nil) then
        page = 1
    else
        page = tonumber(titleparts[#titleparts])
        table.remove(titleparts, #titleparts)
    end
    local linkBase = table.concat(titleparts, '/') .. '/'

    local s = ""
    local numresults = 0
    local validCards = {}

    for card in cardService.GetByCriteria(criteria) do
        tinsert(validCards, card)
        numresults = numresults + 1
    end

    local startCard = (page - 1) * numCardsPerPage + 1
    local endCard = math.min((page - 1) * numCardsPerPage + numCardsPerPage, numresults)

    for i = startCard, endCard do
        s = s .. GenerateCardRow(validCards[i])
    end

    s = cardResultPageNavigation(startCard, endCard, numresults, page, linkBase) ..
        s .. "\n|-\n" ..
        cardResultPageNavigation(startCard, endCard, numresults, page, linkBase)
    return s
end

function p.GetPagedCardsTable(frame)
    local criteria = utils.RecreateTable(frame.args)
    local title = frame:getParent():getTitle()
    local s = GetPagedCardsTable(criteria, title)
    return frame:preprocess(s)
end

function p.GetAnyCardRow(frame)
    local name = frame.args[1]
    local amount = frame.args[2]
    local card = cardService.GetByNameIgnoreCase(name)
    return frame:preprocess(GenerateAnyCardRow(card, amount))
end

local function GetOtherCard(name)
    local s
    local card = cardService.GetOtherByName(name)
    if card then
        s = "{{NoticeCardUnavailable}}\n{{clear}}\n" .. GenerateOtherCardPage(card)
        if card.CardNumber and (string.find(card.CardNumber, "a")) then
            local card2 = cardService.GetOtherByNumber(gsub(card.CardNumber, "a", "b"))
            s = s .. "\n{{clear}}\n<big><big><big>" .. card2.Name .. "</big></big></big>\n" .. GenerateOtherCardPage(card2)
        end
    else
        s = "There was an error generating this page. We're aware of it and will fix it soon.{{PagesWithScriptErrors}}"
    end
    return s
end

local function GetCard(card)
    local s = cardService.IsStandard(card) and "" or "{{NoticeHistoricCard}}\n"
    s = s .. GenerateCardPage(card)
    if card.CardNumber and (string.find(card.CardNumber, "a")) then
        local card2 = cardService.GetByNumber(gsub(card.CardNumber, "a", "b"))
        s = s .. "\n{{clear}}\n<big><big><big>" .. card2.Name .. "</big></big></big>\n" .. GenerateCardPage(card2)
    end
    return s
end

local function GetCardPage(name)
    local card = cardService.GetByName(name)
    return card and GetCard(card) or GetOtherCard(name)
end

function p.GetCardPage(frame)
    local name = gsub( mw.uri.decode(frame:preprocess("{{PAGENAMEE}}")), "_", " ")
    return frame:preprocess(GetCardPage(name))
end

function p.GetCardCategories(card)
    local categories = {}
    tinsert(categories,"Cards")
    for _,setcode in pairs(card.Allsets) do
        tinsert(categories,setNames[setcode])
    end
    ConcatTables(categories,card.Colors)
    tinsert(categories,card.Rarities[1])
    ConcatTables(categories,card.SuperTypes)
    ConcatTables(categories,card.Types)
    ConcatTables(categories,card.SubTypes)
    if card.Watermark then tinsert(categories,card.Watermark) end
    if card.Sets then tinsert(categories,"Reprint") end
    if card.Banned then tinsert(categories,"Banned Card") end

    local s = ""
    for _,v in pairs(categories) do
         s = s .. "[[Category:"..v.."]]"
    end

    return s
end

return p
--</nowiki>