MagicArena Wiki
(Fix tap symbol in rules)
m (added jumstart)
 
(48 intermediate revisions by 2 users not shown)
Line 1: Line 1:
  +
--<nowiki>
 
local cardService = require("Module:CardService")
 
local cardService = require("Module:CardService")
 
local utils = require("Module:TemplateUtils")
 
local utils = require("Module:TemplateUtils")
Line 4: Line 5:
 
local p = {}
 
local p = {}
   
  +
local tinsert, sub, gsub = table.insert, string.sub, string.gsub
local cardRowTemplate= [[|-valign="top"
 
  +
 
local cardRowTemplate= [[|-
 
|%s
 
|%s
 
|%s
 
|%s
Line 10: Line 13:
 
]]
 
]]
   
local anyCardRowTemplate= [[|-valign="top"
+
local anyCardRowTemplate= [[|-
 
|%s
 
|%s
 
|%s
 
|%s
Line 28: Line 31:
 
%s
 
%s
 
|}
 
|}
 
[[File:%s.png|265px|link=]]]=]
<br/>
 
[[File:%s.png|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["ANA"]="Arena Only"
+
["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)
 
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 55: 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 61: 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
table.insert(target,v)
+
tinsert(target,v)
 
end
 
end
 
end
 
end
Line 79: 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 86: 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)
+
local function GetRulings(card, isOtherCard)
if card.Rulings == nil then return "" end
+
if card.Rulings == nil then
  +
return ""
local rulings = mw.loadData("Module:Data/Rulings")
 
  +
end
 
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 112: 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 123: Line 196:
 
local s = "\n\n----\n{|class=\"mdw-reprint-table\"\n|+ '''Other Sets'''\n"
 
local s = "\n\n----\n{|class=\"mdw-reprint-table\"\n|+ '''Other Sets'''\n"
 
for _, set in pairs(card.Sets) do
 
for _, set in pairs(card.Sets) do
local setTemplate = "{{" .. set.Set .. string.sub(set.Rarity,1,1) .. "}}"
+
local setTemplate = "{{" .. set.Set .. sub(set.Rarity,1,1) .. "}}"
 
local imageName = card.Name .. " " .. set.Set .. " " .. set.CardNumber
 
local imageName = card.Name .. " " .. set.Set .. " " .. set.CardNumber
 
local setlink = SetLinkName(set.Set)
 
local setlink = SetLinkName(set.Set)
Line 138: 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 153: Line 226:
 
bantext = bantext .. bannedFormat .. '; '
 
bantext = bantext .. bannedFormat .. '; '
 
end
 
end
return string.sub(bantext, 1, -3) .. "{{MoreBannedDetails}}"
+
return sub(bantext, 1, -3) .. "{{MoreBannedDetails}}"
 
end
 
end
   
local function GenerateCardPage(card)
+
local function GenerateCardInfo(card)
 
local contents = {}
 
local contents = {}
table.insert(contents,{"Name",card.Name})
+
tinsert(contents,{"Name",card.Name})
   
if card.Manacost then table.insert(contents, {"Mana Cost", card.Manacost}) end
+
if card.Manacost then tinsert(contents, {"Mana Cost", card.Manacost}) end
table.insert(contents, {"Converted Mana Cost", card.cmc or 0})
+
tinsert(contents, {"Converted Mana Cost", card.cmc or 0})
if card.Type then table.insert(contents, {"Types", card.Type}) end
+
if card.Type then tinsert(contents, {"Types", card.Type}) end
if card.Text then table.insert(contents, {"Text", card.Text}) end
+
if card.Text then tinsert(contents, {"Text", card.Text}) end
if card.Flavor then table.insert(contents, {"Flavor", card.Flavor}) end
+
if card.Flavor then tinsert(contents, {"Flavor", gsub(card.Flavor, "&lt;/?i&gt;", "''")}) end
if card.Loyalty then table.insert(contents, {"Loyalty", card.Loyalty}) end
+
if card.Loyalty then tinsert(contents, {"Loyalty", card.Loyalty}) end
if card.Power then table.insert(contents, {"P/T", PT(card)}) end
+
if card.Power then tinsert(contents, {"P/T", PT(card)}) end
table.insert(contents, {"Expansion", ExpansionSymbol(card) .. " " .. SetLink(card.SetCode)})
+
tinsert(contents, {"Expansion", ExpansionSymbol(card) .. " " .. SetLink(card.Allsets[1])})
table.insert(contents, {"Rarity", card.Rarity})
+
tinsert(contents, {"Rarity", card.Rarities[1]})
if card.Banned then table.insert(contents, {"Banned In", BanText(card.Banned)}) end
+
if card.Banned then tinsert(contents, {"Banned In", BanText(card.Banned)}) end
   
local cardContents = ""
+
local info = ""
 
for i = 1, #contents do
 
for i = 1, #contents do
cardContents = cardContents .. string.format(cardPageRowTemplate, contents[i][1], contents[i][2])
+
info = info .. string.format(cardPageRowTemplate, contents[i][1], contents[i][2])
 
end
 
end
  +
return info
   
  +
end
local reprints = GetReprints(card)
 
   
 
local function GenerateCardPage(card)
  +
local cardInfo = GenerateCardInfo(card)
 
local reprints = GetReprints(card)
 
return string.format(cardPageTemplate,
 
return string.format(cardPageTemplate,
cardContents,
+
cardInfo,
 
card.Name) .. GetRulings(card) .. reprints .. p.GetCardCategories(card)
 
card.Name) .. GetRulings(card) .. reprints .. p.GetCardCategories(card)
 
end
 
end
   
 
local function GenerateOtherCardPage(card)
 
local function GenerateOtherCardPage(card)
local contents = {}
+
local cardInfo = GenerateCardInfo(card)
 
return string.format(cardPageTemplate,
table.insert(contents,{"Card name",card.Name})
 
 
cardInfo,
if card.Manacost then table.insert(contents,{"Mana Cost",card.Manacost}) end
 
 
card.Name) .. GetRulings(card, true) .. p.GetCardCategories(card)
table.insert(contents,{"Converted Mana Cost",card.cmc or 0})
 
  +
end
if card.Type then table.insert(contents,{"Types",card.Type}) end
 
if card.Text then table.insert(contents,{"Card Text",card.Text}) end
 
if card.Flavor then table.insert(contents,{"Flavor Text",card.Flavor}) end
 
if card.Loyalty then table.insert(contents,{"Loyalty",card.Loyalty}) end
 
if card.Power then table.insert(contents,{"P/T",PT(card)}) end
 
table.insert(contents,{"Rarity",card.Rarity})
 
   
 
local function GetCardsTable(cards)
local cardContents = ""
 
for i = 1,#contents do
+
local output = {""}
 
local numresults = 0
cardContents = cardContents .. string.format(cardPageRowTemplate,contents[i][1],contents[i][2])
 
  +
for card in cards do
 
tinsert(output, GenerateCardRow(card))
 
numresults = numresults + 1
 
end
 
end
 
output[1] = [=[! colspan="3" align="right"|]=] .. numresults .. " result" .. (numresults ~= 1 and "s\n" or "\n")
 
 
return table.concat(output)
return "{{CardUnavailable}}\n{{clear}}\n"..string.format(cardPageTemplate,
 
cardContents,
 
card.Name)..GetRulings(card)..p.GetCardCategories(card)
 
 
end
 
end
   
local function GetCardsTable(criteria)
+
local function GetCardNames(cards)
local s = ""
+
local output = {}
  +
for card in cards do
local numresults = 0
 
  +
tinsert(output, card.Name)
for card in cardService.GetByCriteria(criteria) do
 
s = s .. GenerateCardRow(card)
 
numresults = numresults + 1
 
 
end
 
end
  +
return table.concat(output, "\n")
s = [=[! colspan="3" align="right"|]=]..numresults.." result"..(numresults~=1 and "s\n" or "\n")..s
 
  +
end
return s
 
  +
  +
function p.GetCardNames(frame)
  +
local criteria = utils.RecreateTable(frame:getParent().args)
 
local result = GetCardNames(cardService.GetByCriteria(criteria))
  +
return result
 
end
 
end
   
 
function p.GetCardsTable(frame)
 
function p.GetCardsTable(frame)
 
local criteria = utils.RecreateTable(frame:getParent().args)
 
local criteria = utils.RecreateTable(frame:getParent().args)
local result = GetCardsTable(criteria)
+
local result = GetCardsTable(cardService.GetByCriteria(criteria))
return frame:preprocess(result)
+
return frame:preprocess(result)
 
end
 
end
   
function p.TestGetCardsTable(criteria)
+
function p.GetOtherCardsTable(frame)
  +
local criteria = utils.RecreateTable(frame:getParent().args)
return GetCardsTable(criteria)
 
  +
local result = GetCardsTable(cardService.GetOtherByCriteria(criteria))
 
return frame:preprocess(result)
 
end
 
end
   
 
local function cardResultPageNavigation(startCard,endCard,numresults,page,linkBase)
 
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"
+
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
 
end
   
Line 246: Line 324:
   
 
for card in cardService.GetByCriteria(criteria) do
 
for card in cardService.GetByCriteria(criteria) do
table.insert(validCards, card)
+
tinsert(validCards, card)
 
numresults = numresults + 1
 
numresults = numresults + 1
 
end
 
end
Line 259: 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 271: Line 345:
 
local title = frame:getParent():getTitle()
 
local title = frame:getParent():getTitle()
 
local s = GetPagedCardsTable(criteria, title)
 
local s = GetPagedCardsTable(criteria, title)
return frame:preprocess(s)
+
return frame:preprocess(s)
 
end
 
end
   
-- TODO: (Aspallar) removal candidate, does not appear to be used in wiki
 
 
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
   
local function GetCardPage(name)
+
local function GetOtherCard(name)
  +
local s
local card = cardService.GetByName(name)
 
  +
local card = cardService.GetOtherByName(name)
if not card then
 
card = cardService.GetOtherByName(name)
+
if card then
  +
s = "{{NoticeCardUnavailable}}\n{{clear}}\n" .. GenerateOtherCardPage(card)
if not card then
 
 
if card.CardNumber and (string.find(card.CardNumber, "a")) then
return "There was an error generating this page. We're aware of it and will fix it soon.{{PagesWithScriptErrors}}"
 
 
local card2 = cardService.GetOtherByNumber(gsub(card.CardNumber, "a", "b"))
else
 
return GenerateOtherCardPage(card)
+
s = s .. "\n{{clear}}\n<big><big><big>" .. card2.Name .. "</big></big></big>\n" .. GenerateOtherCardPage(card2)
 
end
 
end
 
else
 
s = "There was an error generating this page. We're aware of it and will fix it soon.{{PagesWithScriptErrors}}"
 
end
 
end
  +
return s
if card.CardNumber and (string.find(card.CardNumber,"a")) then
 
  +
end
local card2 = cardService.GetByNumber(string.gsub(card.CardNumber,"a","b"))
 
  +
return GenerateCardPage(card) ..
 
  +
local function GetCard(card)
"\n{{clear}}\n<big><big><big>" .. card2.Name .. "</big></big></big>\n" ..
 
  +
local s = cardService.IsStandard(card) and "" or "{{NoticeHistoricCard}}\n"
GenerateCardPage(card2)
 
 
s = s .. GenerateCardPage(card)
else
 
  +
if card.CardNumber and (string.find(card.CardNumber, "a")) then
return GenerateCardPage(card)
 
  +
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
 
end
  +
return s
  +
end
  +
  +
local function GetCardPage(name)
 
local card = cardService.GetByName(name)
  +
return card and GetCard(card) or GetOtherCard(name)
 
end
 
end
   
 
function p.GetCardPage(frame)
 
function p.GetCardPage(frame)
local name = string.gsub( mw.uri.decode(frame:preprocess("{{PAGENAMEE}}")), "_", " ")
+
local name = gsub( mw.uri.decode(frame:preprocess("{{PAGENAMEE}}")), "_", " ")
 
return frame:preprocess(GetCardPage(name))
 
return frame:preprocess(GetCardPage(name))
end
 
 
function p.TestGetCardPage(name)
 
return GetCardPage(name)
 
 
end
 
end
   
 
function p.GetCardCategories(card)
 
function p.GetCardCategories(card)
 
local categories = {}
 
local categories = {}
table.insert(categories,"Cards")
+
tinsert(categories,"Cards")
for _,setcode in pairs(card.Allsets) do
+
for _,setcode in pairs(card.Allsets) do
table.insert(categories,setNames[setcode])
+
tinsert(categories,setNames[setcode])
end
+
end
 
ConcatTables(categories,card.Colors)
 
ConcatTables(categories,card.Colors)
table.insert(categories,card.Rarity)
+
tinsert(categories,card.Rarities[1])
 
ConcatTables(categories,card.SuperTypes)
 
ConcatTables(categories,card.SuperTypes)
 
ConcatTables(categories,card.Types)
 
ConcatTables(categories,card.Types)
 
ConcatTables(categories,card.SubTypes)
 
ConcatTables(categories,card.SubTypes)
if card.Watermark then table.insert(categories,card.Watermark) end
+
if card.Watermark then tinsert(categories,card.Watermark) end
if card.Sets then table.insert(categories,"Reprint") end
+
if card.Sets then tinsert(categories,"Reprint") end
if card.Banned then table.insert(categories,"Banned Card") end
+
if card.Banned then tinsert(categories,"Banned Card") end
   
 
local s = ""
 
local s = ""
Line 334: Line 414:
   
 
return p
 
return p
  +
--</nowiki>

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>