Description
This Module handles everything around Legends of Runeterra Collectibles and Cosmetics. Currently we're testing skins, but we want to include other forms of cosmetics as well, such as card backs, emotes, boards and icons.
Submodules:
Public Functions
-- Creates a tabber with all skins of a single card, to be used on a subpage or under a heading on that page. {{#invoke: LoRCosmetics | skinpage | cardcode OR 1 = String (The cardcode of the card for which to generate skins) }} -- Generates a tooltip for a skin. Called by {{t|Tooltip/Skin/LoR}}, should not be used manually. Note that the argument names are determined by the Tooltip template! This applies to any card, not just champion cards! {{#invoke: LoRCosmetics | skintooltip | champion = String (The name of the card) | skin = String (The name of the skin, defaults to "Original") | variant = String (The cardcode of the card, defaults to the ''first'' cardcode of the card, i.e. Level 1) }} -- Generates categories to appear on the file pages. Called by LoRData.fileCategories {{#invoke: LoRCosmetics | fileCategories | cardcode = String (The cardcode of the card) | skin = String (The name of the skin) | modifiers = Table | HD = Boolean (Is this an HD file?) | alternate = Boolean (Is this a censored file?) | display = Boolean (Is this a League Displays File?) | artwork = Boolean (Is this a full artwork? If not, it's just a card.) }} -- Generates links to all skins that an artist worked on. Either cardcode or cardname and either skin or skinindex must be given to identify the skin! {{#invoke: LoRCosmetics | splashartistPage | artist or 1 = String (The name of the artist or studio to search for, defaults to the page title) }} -- Prints a display of the skin. To be used on patchnotes, but currently no template uses this. {{#invoke: LoRCosmetics | displaySkin | cardcode = String (The cardcode of the card) | cardname or 1 = String (The name of the card) | skin or 2 = String (The name of the skin) | skinindex = Number (The number of the skin to show) | limit = Number (How many skins to display, defaults to unlimited) }} -- Links to a skin and creates a tooltip when hovered. Used by {{t|LoR Card Skin Link}}. Either cardcode or cardname and either skin or skinindex must be given to identify the skin! {{#invoke: LoRCosmetics | linkSkin | cardcode = String (The cardcode of the card) | cardname or 1 = String (The name of the card) | skin or 2 = String (The name of the skin) | skinindex = Number (The number of the skin to show) | text = String (The text of the link, defaults to "cardname skin") | card = Number or "all" (If "all", lists all cards with a tooltip. If a number is given, only links to that card of the skin, i.e. Level 1, Level 2 or other associated cards like Living Shadow.) }} -- Returns a String with the Voiceactor of a skin. Either cardcode or cardname must be given to identify the skin! {{#invoke: LoRCosmetics | getVoiceactor | cardcode = String (The cardcode of the card) | cardname or 1 = String (The name of the card) | skin or 2 = String (The name of the skin, defaults to "Original") }} -- Returns a String with the Splashartist of a skin. Either cardcode or cardname must be given to identify the skin! {{#invoke: LoRCosmetics | getSplashartist | cardcode = String (The cardcode of the card) | cardname or 1 = String (The name of the card) | skin or 2 = String (The name of the skin, defaults to "Original") }} -- Returns a String with the Sets / Themes of a skin. Either cardcode or cardname must be given to identify the skin! {{#invoke: LoRCosmetics | getSet | cardcode = String (The cardcode of the card) | cardname or 1 = String (The name of the card) | skin or 2 = String (The name of the skin, defaults to "Original") }} -- Returns a String with the lore / flavortext of a skin. Either returns the text for a single card, or concatenates all cards with <br /> Either cardcode or cardname must be given to identify the skin! {{#invoke: LoRCosmetics | getLore | cardcode = String (The cardcode of the card) | cardname or 1 = String (The name of the card) | skin or 2 = String (The name of the skin, defaults to "Original") | card = Number or "all" (If "all", lists the flavor text of all cards. If a number is given, only lists the flavor text of that card of the skin, i.e. Level 1, Level 2 or other associated cards like Living Shadow.) }}
-- <pre>
local p = {}
local lorSkindata = mw.loadData('Module:LoRCosmetics/skins')
local lorData = require('Module:LoRData')
local get = require('Module:LoRData/getter')
local color = require('Module:Color')
local lib = require('Module:Feature')
local userError = require('Dev:User error')
--------------------------
-- GENERATING FUNCTIONS --
--------------------------
-- generates the skins cosmetics section for a card.
function p.skinPage(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
args['cardcode'] = args['cardcode'] or args[1]
local cardname = get.name(args['cardcode'])
local t = lorSkindata[args['cardcode']]
if t == nil then
return userError("Card ''" .. args['cardcode'] .. "'' does not exist in Module:LoRCosmetics/skins", "LuaError")
end
local temp_t = {}
for skinname, skin in pairs(t) do
table.insert(temp_t, {skinname, skin})
end
table.sort(temp_t, function (a,b) return idxcomp(a[2], b[2]) end)
-- generates all categories of all sets of all skins of said champion
local k = "[[" .. "Category:LoR Card cosmetics]] [[Category:"..cardname.."]]"
for skinname, skin in pairs(t) do
local theme = p.getSet{cardcode = args['cardcode'], skin = skinname}
if theme ~= nil then
k = k .. require('Module:SkinThemes').handleThemes{theme = theme, date = skin.release}
end
end
--Generated string begins here
local s = '<div style="clear:both"></div>\n== Skins ==\n<div style="font-size:small"><tabber>'
for i, value in ipairs(temp_t) do
local skinname = value[1]
local skin = value[2]
if (skin.idx > 0) then
s = s .. "|-|\n"
end
s = s .. skinname .. "=\n"
s = s .. skinDisplay(args['cardcode'], skinname, skin, nil)
end
s = s .. '</tabber></div><div style="clear:both"></div>' .. k -- append categories and stuff
return frame:preprocess(s)
end
-- Generates mouseover overview for skins
function p.skinTooltip(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
-- Leftover from the templates that generate tooltips, we only have access to variables "champion", "skin" and "variant"
local cardname = args['champion'] or "Zed"
local skin = args['skin'] or "Original" -- Original Zed as default
local t, cardcode
t, skin, cardcode = findSkin{cardname, skin} -- Also returns skinname (known) and cardcode.
local associatedCard = args['variant'] or cardcode
local IL = require('Module:ImageLink')
local FN = require('Module:Filename')
local c = nil -- array of things associated with a specific card of the skin
for _, v in pairs(t.associatedCards) do
if v.cardcode == associatedCard then
c = v
break
end
end
if c == nil then
return userError("Can not find associated card ''".. associatedCard .. "'' for skin ''" .. formatname .. "''", "LuaError")
end
local cost = t['cost']
local rarity = t['rarity'] or "Base"
local voiceactor = p.getVoiceactor{cardcode = cardcode, skin=skin}
local splashartist = p.getSplashartist{cardcode = cardcode, skin=skin}
local set = p.getSet{cardcode = cardcode, skin=skin}
local changedcardname = c['name'] or get.name(associatedCard)
local formatname = t['formatname'] or skin .. ' ' .. cardname
local lore = c['flavor']
local filename = FN.lorskin{cardcode=c.cardcode, skin=skin}
local filter = t['voice'] == "filter" -- voice can be original, original but filtered, new quotes and completely new VO
local newquotes = t['voice'] == "added"
local newvoice = t['voice'] == "new"
local neweffects = t['newEffects'] -- currently unused but possible in the future
local newlevelanimation = t['newLevelAnimation'] -- Level up only, other things count as EFFECTS.
local extras = t['extras'] -- unknown if that will be used
local s = ''
s = s .. '<div style="position:relative;">[[File:' .. filename .. '|700px]]'
s = s .. '<div class="skin-features" style="padding:15px 45px 15px 15px; position:absolute; bottom:16px; left:16px; background-color:RGBA(10, 24, 39, 0.75); max-width:576px;">'
s = s .. '<div style="font-family:BeaufortLoL;">'
s = s .. '<span style="font-size:16px; color:#f1e6d0; width:100%; text-transform:uppercase;">'
s = s .. formatname .. ' <small>(' .. changedcardname .. ')</small>'
s = s .. '</span> <span style="font-size:14px; color:#c9aa71; width:100%;">'
if cost == 0 and rarity == "Base" then
s = s .. '‑ ' .. tostring(IL.basic{["link"] = "Wildcard (Legends of Runeterra)", ["text"] = 1, ["alttext"] = "1 Wildcards", ["image"] = "LoR " .. get.rarity(cardcode) .. " Wildcard icon.png", ["border"] = "false", ["labellink"] = "false"})
elseif cost == "special" then
-- having another option just in case
else -- default
s = s .. '‑ ' .. tostring(IL.basic{["link"] = "Coin_(Legends_of_Runeterra)", ["text"] = cost, ["alttext"] = cost .. " Coins", ["image"] = "Coin icon.png", ["border"] = "false", ["labellink"] = "false"})
end
s = s .. lib.ternary(distribution ~= nil, ' ' .. tostring(distribution), '') .. '</span>'
s = s .. '</div>'
s = s .. '<div style="font-size:11px">'
s = s .. lib.ternary(voiceactor ~= nil, '<div style="display:inline-block; padding-right:1em;">[[File:Actor.png|20px|link=]]' .. tostring(voiceactor) .. '</div>', '')
s = s .. lib.ternary(splashartist ~= nil, '<div style="display:inline-block; padding-right:1em;">[[File:Artist.png|20px|link=]]' .. tostring(splashartist) .. '</div>', '')
s = s .. lib.ternary(set ~= nil, '<div style="display:inline-block; padding-right:1em;">[[File:Set piece.png|20px|link=]]' .. tostring(set) .. '</div>', '')
s = s .. lib.ternary(lore ~= nil, '<div style="line-height: 1.7em; text-align: justify">' .. tostring(lore) .. '</div>', '')
if availability or filter or newquotes or newvoice or neweffects or newlevelanimation or extras then -- cut out a few options here that don't apply to LOR skins but to League
s = s .. '<div>'
if availability == 'Limited' then
s = s .. '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Limited skin.png|50px|link=]]</div><div>Limited Edition</div></div>'
elseif availability == 'Legacy' then
s = s .. '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Legacy skin.png|50px|link=]]</div><div>Legacy Vault</div></div>'
end
s = s .. lib.ternary(filter, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Voice filter.png|50px|link=]]</div><div>Voice Filter</div></div>', '')
s = s .. lib.ternary(newquotes, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Additional quotes.png|50px|link=]]</div><div>Additional Quotes</div></div>', '')
s = s .. lib.ternary(newvoice, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:New voice.png|50px|link=]]</div><div>New Voice</div></div>', '')
s = s .. lib.ternary(neweffects, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:New effects.png|50px|link=]]</div><div>New SFX/VFX</div></div>', '')
s = s .. lib.ternary(newlevelanimation, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:New animations.png|50px|link=]]</div><div>New Level-up animation</div></div>', '')
s = s .. lib.ternary(extras ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Includes extras.png|50px|link=]]</div><div>Includes Extras</div></div>', '')
s = s .. '</div>'
end
s = s .. '</div>'
s = s .. '</div>'
s = s .. '</div>'
return s
end
-- Creates all necessary categories for a skin image file.
function p.fileCategories(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local t, skinname, basecard = findSkinForCardcode(args['cardcode'], inflate(args['skin']))
local basecardname = get.name(basecard)
local name = get.name(args['cardcode'])
local s = "[[" .. "Category:LoR Card cosmetics]] [[Category:" .. name .. " Card Skins]] [[Category:" .. basecardname .. " Card Skins]]"
local introduction = ""
for i,v in ipairs(t.associatedCards) do
if v.cardcode == args['cardcode'] then name = v.name or name end -- can only replace it with the name from the skindata HERE beause above needs the real name
end
local cardset = lorData.getSetFromCardcode{args['cardcode']}
if cardset ~= 0 and cardset ~= 99 then
s = s .. "[[" .. "Category:LoR Set " .. cardset .. " Skin]]"
end
s = s .. require('Module:SkinThemes').handleThemes{theme = p.getSet{cardcode = basecard, skin = skinname}, date = t.release}
local cardContents = {}
-- This is the ...
if args['modifiers'].HD == true then
table.insert(cardContents, 'HD')
end
if args['modifiers'].alternate == true then
table.insert(cardContents, 'alternate')
end
if args['modifiers'].display == true then
table.insert(cardContents, 'League Displays')
end
if args['modifiers'].artwork == true then
table.insert(cardContents, 'artwork')
else
table.insert(cardContents, 'card image')
end
-- ... for "Cardname" with the "skinname" Skin.
local cardContent = table.concat(cardContents, " ")
local linktext = t.displayname or (skinname .. " " .. basecardname)
local skintext = "[[" .. basecardname .. " (Legends of Runeterra)#Skins|" .. linktext .. "]]"
introduction = mw.html.create('table')
:attr('align', 'center' )
:css('margin-top', '1em')
:css('width', '90%')
:css('border', '2px solid #FFFFFF')
:css('font-size', '95%')
:css('text-align', 'justify')
:css('border-collapse', 'collapse')
:tag('tr')
:tag('td')
:attr('colspan', '2')
:css('background-color', '#061E36')
:css('text-align', 'center')
:css('font-family', 'BeaufortLoL')
:css('font-size', '120%')
:css('font-weight', '700')
:css('padding', '0.2em 0.5em')
:css('border-bottom', '2px solid #C9AA71;')
:wikitext('This is the ' .. cardContent .. ' for [[' .. args['cardcode'] .. ' (Legends of Runeterra)|' .. name .. ']] of the ' .. skintext .. ' skin. ')
:wikitext('<br />')
:wikitext('You can also view all other [[:Category:' .. basecardname .. ' Card Skins|' .. basecardname .. ' Skins]].')
:done()
:done()
:done()
return tostring(introduction) .. s
end
-- Generates a list of skins an artist worked on.
function p.splashartistPage(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local s = ""
args['artist'] = args['artist'] or args[1] or mw.title.getCurrentTitle().text
local resulttable = {}
for keys, skin,_ in skinIter(lorSkindata) do
if skin.splashartist ~= nil then
for _, splashartistname in pairs(skin.splashartist) do
if splashartistname == args['artist'] then
table.insert(resulttable, {keys[1], (skin.formatname or (keys[2] .. " " .. get.name(keys[1]))), keys[2], skin})
end
end
end
end
table.sort(resulttable, function(a, b) return a[2] < b[2] end)
if #resulttable == 0 then
return userError("No results for " .. searchstring, "LuaError")
end
s = ";{{tip|Legends of Runeterra}} skin artworks\n{{Column|2|\n"
for _, skindata in ipairs(resulttable) do
s = s .. "* {{LoR|code=" .. skindata[1] .. "|text=" .. skindata[2] .. "}}: "
local skin = skindata[4]
for i, card in ipairs(skin.associatedCards) do
local name = card.name or get.name(card.cardcode)
if (i == 1) then -- first card
s = s .. "{{LoR|code=" .. card.cardcode .. "|text=" .. name .. "|skin=" .. skindata[3] .."|nolink=true|artwork=true|indicator=false}}"
else
s = s .. ", {{LoR|code=" .. card.cardcode .. "|text=" .. name .. "|skin=" .. skindata[3] .."|nolink=true|artwork=true|indicator=false}}"
end
end
local count = 0 -- if other people worked on that (not relevant rn)
for i, val in pairs (skin.splashartist) do
if val ~= args['artist'] then
if count == 0 then
s = s .. " <small>(Collaboration with "
else
s = s .. ", "
end
s = s .. skin.splashartist[i]
count = count + 1
end
end
if count ~= 0 then
s = s .. ")</small>"
end
s = s .. "\n"
end
s = s .. "}}"
return frame:preprocess(s)
end
-- Generates a list of skins in a table.
function p.skinlist(frame)
local lang = mw.language.new( "en" )
local sdtable = mw.html.create('table')
sdtable
:addClass('sortable article-table nopadding sticky-header')
:css('width','100%')
:css('text-align','center')
:newline()
-- TABLE HEADER
:tag('tr')
:tag('th')
:tag('span')
:attr('title','Mana Cost')
:wikitext('[[File:LoR mana icon.png|40px|link=|]]')
:done()
:done()
:tag('th')
:wikitext('Skin')
:done()
:tag('th')
:tag('span')
:attr('title','Availability')
:wikitext('[[File:Availability.png|40px|link=|]]')
:done()
:done()
:tag('th')
:tag('span')
:attr('title','Release')
:wikitext('[[File:Release.png|40px|link=|]]')
:done()
:done()
:tag('th')
:tag('span')
:attr('title','Cost')
:wikitext('[[File:Coin icon.png|40px|link=|]]')
:done()
:done()
:tag('th')
:css('width','40px')
:tag('span')
:attr('title','New lv up animations')
:wikitext('[[File:New animations.png|40px|link=|]]')
:done()
:done()
:tag('th')
:css('width','40px')
:tag('span')
:attr('title','Part of a Collection')
:wikitext('[[File:Set piece.png|40px|link=|]]')
:done()
:done()
:done()
:newline()
-- TABLE ENTRIES
local cardtable = {}
for x in pairs(lorSkindata) do
table.insert(cardtable, x)
end
table.sort(cardtable)
local availablenode = mw.html.create('span')
availablenode
:css('color', 'green')
:css('font-size', 'x-large')
:css('vertical-align', 'text-top')
:wikitext("✔")
local legacynode = mw.html.create('span')
legacynode
:css('color', 'yellow')
:css('font-size', 'x-large')
:css('font-weight', '600')
:css('vertical-align', 'text-top')
:wikitext("‒")
local limitednode = mw.html.create('span')
limitednode
:css('color', 'red')
:css('font-size', 'x-large')
:css('vertical-align', 'text-top')
:wikitext("✘")
local rarenode = mw.html.create('span')
rarenode
:css('color', 'orange')
:css('font-size', 'x-large')
:css('vertical-align', 'text-top')
:wikitext("⭐")
for _, cardcode in pairs(cardtable) do
local skintable = {}
for cardcode in pairs(lorSkindata[cardcode]) do
table.insert(skintable, cardcode)
end
table.sort(skintable)
for _, skinname in pairs(skintable) do
local t = lorSkindata[cardcode][skinname]
local sdnode = mw.html.create('tr')
local cardname = get.name(cardcode)
local cardcost = get.cost(cardcode)
-- Skin mana cost
local link = nil
local indicatorImage = 'File:LoR Champion Indicator.png'
local indicatorWidth = 30
local indicatorLeft = 1.5
local indicatorLink = formatnil('[[%s|%s|link=%s]]', indicatorImage, indicatorWidth .. 'px', cardname .. ' (Legends of Runeterra)')
link = '<span style="position:relative;text-indent:0;">' .. indicatorLink
link = link .. '<span style="position:absolute;left:' .. indicatorLeft .. 'px;top:50%;user-select:none;line-height:1.5;color:white;font-weight:normal;text-align:center;width:20px;height:20px;font-size:14px;-ms-transform:translateY(-50%);transform:translateY(-50%);">' .. cardcost .. '</span>'
link = link .. '</span>'
sdnode
:tag('td')
:attr('data-sort-value', cardcost .. cardname)
:wikitext(link)
:done()
-- Skinname
local s = ""
if (skinname == "Original") then
s = "!" .. t["release"]
else
s = t["release"]
end
sdnode
:tag('td')
:addClass('skin-icon')
:attr('data-sort-value', cardname .. s)
:attr('data-champion', cardname)
:attr('data-skin', skinname)
:attr('data-variant', cardcode)
:attr('data-game', "lor")
:css('text-align', 'left')
:wikitext(lib.ternary(t["displayname"] ~= nil, t["displayname"], skinname .. " " .. cardname))
:done()
-- Availability
local astring = '<span style="color: cornflowerblue;font-size: large;font-weight: 600;">⭘</span>'
if (t["availability"] == "Available") then
astring = tostring(availablenode)
end
if (t["availability"] == "Legacy") then
astring = tostring(legacynode)
end
if (t["availability"] == "Limited") then
astring = tostring(limitednode)
end
if (t["availability"] == "Rare") then
astring = tostring(rarenode)
end
sdnode
:tag('td')
:tag('span')
:attr('title', t["availability"] or 'Upcoming')
:wikitext(astring)
:done()
-- Release
local y, m, d = t["release"]:match("(%d+)-(%d+)-(%d+)")
if y == nil or m == nil or d == nil then
sdnode
:tag('td')
:attr('data-sort-value', t["release"])
:wikitext(t["release"])
:done()
else
sdnode
:tag('td')
:attr('data-sort-value', t["release"])
:wikitext(lang:formatDate('d-M-Y', t["release"]))
:done()
end
-- Cost
local skincolor = ""
local image = ""
if (tostring(t["cost"]) == "1290") then
skincolor = "mythic"
end
if (tostring(t["cost"]) == "700") then
skincolor = "standard"
end
if (tostring(t["cost"]) == "0") then
skincolor = "classic"
image = "[[File:LoR Champion Wildcard icon.png|20px|link=]]"
end
sdnode
:tag('td')
:attr('data-sort-value', t["cost"])
:tag('span')
:css('color', color.skin({skincolor}))
:wikitext(lib.ternary(tostring(t["cost"]) == "0", image .. "1", t["cost"]))
:done()
:done()
-- Newanimations
sdnode
:tag('td')
:attr('data-sort-value', lib.ternary(type(t["newLevelAnimation"]) ~= "nil", 1, 0))
:wikitext(lib.ternary(type(t["newLevelAnimation"]) ~= "nil", tostring(availablenode), ""))
:done()
-- Set
if (type(t["set"]) ~= "nil") then
local multiset = false
for i, setname in pairs(t["set"]) do
if i == 1 then
s = setname
else
multiset = true
s = s .. ", " .. setname
end
end
if multiset == true then
sdnode
:tag('td')
:attr('data-sort-value', '!Multiple')
:tag('span')
:attr('title', s)
:wikitext(tostring(availablenode))
:done()
:done()
else
sdnode
:tag('td')
:attr('data-sort-value', s)
:tag('span')
:attr('title', s)
:wikitext(tostring(availablenode))
:done()
:done()
end
else
sdnode
:tag('td')
:attr('data-sort-value', 0)
:done()
end
-- Add skin row to the table
sdtable
:node(sdnode)
:newline()
end
end
-- TABLE END
sdtable:allDone()
return tostring(sdtable)
end
-------------------------
-- COMPOSITE FUNCTIONS --
-------------------------
-- Displays full artworks, either limited or all of them, with a description of the skin.
-- For patch notes and other use cases, show only 2 artworks. On the full cosmetics site, show all of them?
function p.displaySkin(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local t, skinname, cardcode = findSkin(args)
return skinDisplay(cardcode, skinname, t, args['limit'])
end
-- Displays a link and tooltip for a given card and skin.
function p.linkSkin(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local t, skinname, cardcode = findSkin(args)
local s = ""
args['text'] = args['text'] or t.formatname or (skinname.. " " .. args['cardname'])
if ((args['card'] == "all") and (t.associatedCards[2] ~= nil)) then -- hack to see if more than one associated card exists, #t.associatedCards doesn't work
for i, card in ipairs(t.associatedCards) do
local name = card.name or get.name(card.cardcode)
if (i == 1) then -- first card
s = tostring(lorData.link{name = args['cardname'], code = card.cardcode, text = args['text'], skin = skinname}) .. "<small>("
else
s = s .. lib.ternary(i > 2, ", ", "") .. tostring(lorData.link{name=args['cardname'], code=card.cardcode, text = name, skin = skinname, indicator = false})
end
end
s = s .. ")</small>"
else -- args['card'] is a number: Only link to that card
local cardnumber = tonumber(args['card']) or 1
if t.associatedCards[cardnumber] == nil then cardnumber = 1 end
s = tostring(lorData.link{name = args['cardname'], code = t.associatedCards[cardnumber].cardcode, text = args['text'], skin = skinname})
end
return s
end
----------------------
-- GETTER FUNCTIONS --
----------------------
-- Returns the voiceactor of a skin, if possible
function p.getVoiceactor(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
args['skin'] = args['skin'] or "Original" -- add "original" if no skin is given
local t, skinname, cardcode = findSkin(args)
local voiceactor = nil
if t.voiceactor == nil and (t.voice == "original" or t.voice == "filtered" or t.voice == "added") then
voiceactor = lorSkindata[cardcode]['Original'].voiceactor -- try original VA if possible
else
voiceactor = t.voiceactor
end
if voiceactor == nil then
return "Unknown voice actor"
end
local s = ""
for i, voiceactorname in ipairs(voiceactor) do
if i ~= 1 then
s = s .. ", " .. voiceactorname:gsub("% ", " ")
else
s = voiceactorname
end
end
return s
end
function p.getSplashartist(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
args['skin'] = args['skin'] or "Original" -- add "original" if no skin is given
local t, skinname, cardcode = findSkin(args)
if t.splashartist == nil then
return "Unknown artist"
end
local s = ""
for i, splashartistname in ipairs(t.splashartist) do
if i ~= 1 then
s = s .. ", " .. splashartistname:gsub("% ", " ")
else
s = splashartistname
end
end
return s
end
-- Concatenates all set names of a skin
function p.getSet(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
args['skin'] = args['skin'] or "Original" -- add "original" if no skin is given
local t, skinname, cardcode = findSkin(args)
if t.set == nil then
return nil
end
local s = ""
for i, setname in ipairs(t.set) do
if i ~= 1 then
s = s .. ", " .. setname:gsub("% ", " ")
else
s = s .. setname
end
end
return s
end
-- Returns the flavor text of all changed artworks or of one specific card.
function p.getLore(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
args['skin'] = args['skin'] or "Original" -- add "original" if no skin is given
local t, skinname, cardcode = findSkin(args)
local s = ""
if ((args['card'] == "all") and (t.associatedCards[2] ~= nil)) then -- hack to see if more than one associated card exists, #t.associatedCards doesn't work
for i, card in ipairs(t.associatedCards) do
s = s .. card.flavor .. "<br />"
end
else -- args['card'] is a number: Only link to that card
local cardnumber = tonumber(args['card']) or 1
if t.associatedCards[cardnumber] == nil then cardnumber = 1 end
s = t.associatedCards[cardnumber].flavor
end
return s
end
-- getavailability, getprice, getartworks and other getter functions are also possible, whatever other modules / functions need
----------------------
-- HELPER FUNCTIONS --
----------------------
-- Generates the big display with all artworks of a skin.
function skinDisplay(cardcode, skin, skindata, limit)
local lang = mw.language.new("en")
local IL = require('Module:ImageLink')
local FN = require('Module:Filename')
local cardname = get.name(cardcode)
local formatname = skindata.formatname or skin .. ' ' .. cardname
local rarity = skindata.rarity or "Base"
local cost = skindata.cost
local release = skindata.release
local changedCards = skindata.associatedCards
local changedCount = 0
for k, v in pairs(changedCards) do
changedCount = changedCount + 1 -- "#"" does not work
end
-- really no need to validate the arguments, do it in the calling functions
if release ~= "N/A" then
release = lang:formatDate("d-M-Y", release)
end
if type(limit) == "string" then
limit = tonumber(limit)
end
if limit == nil then
limit = 99 -- some high number, I don't think any skin has 99 new artworks.
end
local s = '<div style="display:inline-block; margin:5px"><div class="skin-description" style="width: 342px;">' .. formatname .. ': ' .. rarity .. ' Skin <br />'
-- begin of description div
-- feature list
if (rarity ~= "Base") then
s = s .. "Features: <br /><ul>"
s = s .. "<li> " .. changedCount .. " new artworks </li>"
s = s .. lib.ternary(skindata.newLevelAnimation, "<li>New level-up animation </li>", "")
s = s .. '</ul>'
end
-- Availability notes: Available, Legacy, Rare, Limited, Partner or Upcoming
if skindata.availability == "Upcoming" then
s = s .. "This skin has been announced, but is not yet available in game."
elseif skindata.availability == "Available" then
s = s .. lib.ternary(rarity == "Base", "", "This skin is available for purchase.")
elseif skindata.availability == "Legacy" then
s = s .. "This legacy skin is not available for purchase."
else
-- other phrases here
end
-- right-floating div
s = s ..' <div style="float:right; line-height: 27px;">'
if cost == 'N/A' then
-- skip
elseif cost == 0 and rarity == "Base" then -- not "for free" but a basic card skin
s = s .. tostring(IL.basic{["link"] = "Wildcard (Legends of Runeterra)", ["text"] = 1, ["alttext"] = "1 Wildcards", ["image"] = "LoR " .. get.rarity(cardcode) .. " Wildcard icon.png", ["border"] = "false", ["labellink"] = "false"}) .. ' / '
elseif cost == "special" then
s = s .. "Special pricing" .. ' / '
else
s = s .. tostring(IL.basic{["link"] = "Coin_(Legends_of_Runeterra)", ["text"] = cost, ["alttext"] = cost .. " Coins", ["image"] = "Coin icon.png", ["border"] = "false", ["labellink"] = "false"}) .. ' / '
end
s = s .. release .. '</div>' -- end of the right-floating div
s = s .. '</div>' -- end of description div
-- begin artworks
for i, t in ipairs(changedCards) do
if (i <= limit and skindata.availability ~= "Upcoming") then
local changedName = t.name or get.name(t.cardcode)
s = s .. '<div class="skin-single-card" style="width: 342px; float:left; padding:10px;"><div class="skin-icon" data-game="lor" data-champion="' .. cardname .. '" data-skin="' .. skin .. '" data-variant="' .. t.cardcode .. '">[[File:' .. FN.lorskin{cardcode = t.cardcode, skin = skin} .. '|x170px|border]]</div><div style="float:left">'.. tostring(lorData.link{code = t.cardcode, text = changedName, indicator = "false", nolink = true}) ..'<p>' .. t.flavor.. '</p></div></div>'
end
end
s = s .. '</div><br />' -- end of entire div
return s
end
-- Finds an entry from the skindata based on various arguments. (base Card name or code) and (skinname or skin idx), also works with {"Cardname", "Skinname"}
function findSkin(args)
local cardcode = args['cardcode'] or nil
if cardcode == nil then
local cardname = args['cardname'] or args[1] or nil
cardcode = lorData.findCardsByName{search = cardname, firstOnly = true}
if cardcode == nil then -- couldn't find card by name
return userError("Can't find a card this way.", "LuaError")
end
end
if lorSkindata[cardcode] == nil then
return userError("Card ''" ..cardcode .. "'' does not exist in Module:LoRCosmetics/skins", "LuaError")
end
local skinname = args['skin'] or args[2] or nil
if skinname == nil then
for k, v in pairs(lorSkindata[cardcode]) do-- check all skins for the right index
if v.idx == args['skinindex'] then
skinname = k
end
end
if skinname == nil then
return userError ("Can't find a skin this way.", "LuaError")
end
end
if lorSkindata[cardcode][skinname] == nil then
return userError("Skin ''" .. skinname .. "'' does not exist for card ''".. get.name(cardcode) .. "'' (".. cardcode .. ")", "LuaError")
end
return lorSkindata[cardcode][skinname], skinname, cardcode -- skin data first, this is what you get returned when you use only one value
end
-- same as listing all skins, but includes a way to break the loops if the skin is found. Returns cardcode, skinname, skindata.
function findSkinForCardcode(cardcode, skin)
local basecardcode = cardcode
local isAssociated, wordTIndex = string.find(basecardcode, "[^A-Z]T"); -- can't look for just any T because MT
if isAssociated then
basecardcode = string.sub(basecardcode, 1, wordTIndex-1)
end
local t = lorSkindata[basecardcode]
if t ~= nil then
for skinname, skindata in pairs(t) do
if (skinname == skin) then
for i, card in ipairs(skindata.associatedCards) do
if card.cardcode == cardcode then
return skindata, skinname, basecardcode
end
end
-- skinname matches but didn't find the cardcode - this is fucked up
break
end
end
end -- end of associated card skins
for associatedcard, skins in pairs(lorSkindata) do
if (associatedcard ~= basecardcode) then -- skip card that is already handled
for skinname, skindata in pairs(skins) do -- check all other skins of all other cards
for i, card in ipairs(skindata.associatedCards) do
if card.cardcode == cardcode then
return skindata, skinname, associatedcard
end
end -- end of "all cards of this skin"
end-- end of "all skins of this card"
end
end -- end of "all other cards"
end
-- finds all skins that are related to the given card. First, returns the skins of the associated card (without the T), then ALL SKINS. Gonna be an expensive function to use!
-- returns a table of {skindata, skinname, associated_cardcode} if the given cardcode appears in skindata.
function findSkinsForCardcode(cardcode)
local basecardcode = cardcode
local isAssociated, wordTIndex = string.find(basecardcode, "[^A-Z]T"); -- can't look for just any T because MT
if isAssociated then
basecardcode = string.sub(basecardcode, 1, wordTIndex-1)
end
local skinstable = {}
local t = lorSkindata[basecardcode]
if t ~= nil then
for skinname, skindata in pairs(t) do
for i, card in ipairs(skindata.associatedCards) do
if card.cardcode == cardcode then
table.insert(skinstable, {basecardcode, skinname, skindata})
break
end
end
end
end -- end of associated card skins
for associatedcard, skins in pairs(lorSkindata) do
if (associatedcard ~= basecardcode) then -- skip card that is already handled
for skinname, skindata in pairs(skins) do -- check all other skins of all other cards
for i, card in ipairs(skindata.associatedCards) do
if card.cardcode == cardcode then
table.insert(skinstable, {associatedcard, skinname, skindata})
break
end
end -- end of "all cards of this skin"
end-- end of "all skins of this card"
end
end -- end of "all other cards"
return skinstable
end
function idxcomp(a, b)
local a = a.idx or -1
local b = b.idx or -1
return (a < b)
end
-- "Inflates" a reduced string with space characters before Uppercase letters
function inflate(s)
local str, number = s:gsub("%l%u", function (m) return string.sub(m,1,1) .. " " .. string.sub(m,2,2) end)
return str
end
-- creates an iteration function based on the given skin table, sorted by skin names? I'm open to other ways of sorting as well...
function skinIter(t)
local keys = {}
for cardcode, skins in pairs(t) do -- this is a loop over every card in the module!
local cardname = get.name(cardcode)
for skinname, skin in pairs(skins) do
local sortname = skin.formatname or (skinname .. " " .. cardname)
table.insert(keys, {sortname, cardcode, skinname})
end
end
table.sort(keys, function(a,b)
return (a[1] < b[1])
end)
-- return the iterator function
local i = 0
return function()
i = i + 1
if keys[i] then
return {keys[i][2], keys[i][3]}, t[keys[i][2]][keys[i][3]], i
end -- t is indexed by (card code) and then (skin name) so this is what is returned as well.
end
end
return p
-- </pre>
-- [[Category:Lua sandbox]]