League of Legends Wiki

Want to contribute to this wiki?
Sign up for an account, and get started!
You can even turn off ads in your preferences.

Come join the LoL Wiki community Discord server!

READ MORE

League of Legends Wiki
No edit summary
No edit summary
Line 238: Line 238:
 
 
 
if key == "true" then
 
if key == "true" then
s = s .. "<div class='glossary' data-param='chroma exhibition' style='position:absolute; top:5px; right: 5px; z-index:20;'>[[File:Information.svg|30px|link=]]</div>"
+
s = s .. "<div class='glossary' data-param='Chroma exhibition' style='position:absolute; top:5px; right: 5px; z-index:20;'>[[File:Information.svg|30px|link=]]</div>"
 
end
 
end
 
 

Revision as of 14:36, 20 May 2020

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

-- <pre>
local p = {}

local skinData  = mw.loadData('Module:SkinData/data')
local lib       = require('Module:Feature')
local color     = require('Module:Color')
local FN        = require('Module:Filename')
local IL        = require('Module:ImageLink')
local userError = require('Dev:User error')

function p.skinscount()
    local s           = ""
    local resulttable = {}
    local prices      = {}
    local limited     = 0
    local rare        = 0
    local total       = 0
    local cost        = 0

    for championname in pairs(skinData) do
        local t = skinData[championname]["skins"]
        for skinname in pairs(t) do
            if skinname ~= "Original" and t[skinname]["id"] ~= nil and t[skinname]["release"] ~= "N/A" and t[skinname]["availability"] ~= "Upcoming" then
                if t[skinname]["availability"] == "Limited" then
                        limited = limited + 1
                        total   = total   + 1
                else
                    local price = t[skinname]["cost"]
                    if price == 10 or price == 100 or price == "special" then
                        price = 2450
                    end
                    
                    if t[skinname]["looteligible"] == false then
                        rare  = rare  + 1
                        total = total + 1
                    else
                        if resulttable[price] == nil then
                            resulttable[price] = 0
                            table.insert(prices, price)
                        end
                        resulttable[price] = resulttable[price] + 1
                        total = total + 1
                        cost  = cost + price
                    end
                end
            end
        end
    end
    table.sort(prices)
    
    s = '<table class="wikitable sortable">'
    s = s .. '  <tr><th data-sort-type="number">Price</th><th>Count</th></tr>'
    for _, price in pairs(prices) do
        s = s ..'  <tr><td data-sort-value="' .. price .. '" style="text-align:right">' .. price .. '</td><td style="text-align:right">' .. resulttable[price] .. '</td></tr>'
    end
    
    s = s .. '  <tr><td data-sort-value="50000" style="text-align:right">Rare</td><td style="text-align:right">' .. rare .. '</td></tr>'
    s = s .. '  <tr><td data-sort-value="60000" style="text-align:right">Limited</td><td style="text-align:right">' .. limited .. '</td></tr>'
    s = s .. '</table>'
    s = s .. 'Total: ' .. total ..' skins (Total: ' .. cost .. ' RP)'
    
    return s
end

function p.splashartistpage()
    local searchstring = mw.title.getCurrentTitle().text

    local championtable = {}
    for championname in pairs(skinData) do
        table.insert(championtable, championname)
    end
    table.sort(championtable)

    local resulttable = {}
    for _, championname in pairs(championtable) do
        local skintable  = {}
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)

        for _, skinname in pairs(skintable) do
            local t = skinData[championname]["skins"][skinname]
            
            if t.splashartist ~= nil then
                for _, splashartistname in pairs(t.splashartist) do
                    if splashartistname == searchstring then
                        table.insert(resulttable, {championname, skinname, t.formatname, t.splashartist})
                    end
                end
            end
        end
    end
    
    if #resulttable == 0 then
        return userError("No results for " .. searchstring, "LuaError")
    end
    
    -- Three random images of work examples
    math.randomseed(os.time())
    local hash = {}
    local rnd  = 0
    local s1   = ""
    
    for i = 1, 3 do
        rnd = math.random(#resulttable)
        if hash[rnd] ~= true then
            s1 = s1 .. "[[File:" .. FN.skin({resulttable[rnd][1], resulttable[rnd][2]}) .. "|thumb|200px|Work example.]]"
        end
        hash[rnd] = true
    end
    
    -- Splash Art list
    local s2 = "<dl><dt>Splash Art</dt></dl><ul><li>"
    local tempval = ""
    for i, val in pairs(resulttable) do
        local championname = val[1]
        local skinname     = val[2]
        local formatname   = val[3]
        local splashartist = val[4]
        
        if tempval == championname then
            s2 = s2 .. ", "
        else
            if i ~= 1 then
                s2 = s2 .. "</li><li>"
            end
            tempval = championname
        end
        s2 = s2 .. tostring(IL.skin{
            ["champion"] = championname,
            ["skin"] = skinname,
            ["link"] = championname .. "/Skins",
            ["text"] = lib.ternary(formatname, formatname, skinname .. " " .. championname),
            ["circle"] = "true"
        })
        
        count = 0
        for i, val in pairs (splashartist) do
            if val ~= searchstring then
                if count == 0 then
                    s2 = s2 .. " <small>(Collaboration with "
                else
                    s2 = s2 .. ", "
                end
                s2 = s2 .. splashartist[i]
                count = count + 1
            end
        end
        if count ~= 0 then
            s2 = s2 .. ")</small>"
        end
    end
    s2 = s2 .. "</li></ul>"
    
    return s1 .. s2
end

function p.chromapartner(frame)
    local s = ''
    
    s = s .. '<div id="chromaexhibition" style="position:relative">'
    s = s .. '<b>Partner Program Chromas</b>'
    s = s .. '<div class="chroma-gallery" style="width:718px; text-align:center"><div class="base">[[File:Partner Program LoL Logo.png|150px]]</div>'
    
    local championtable = {}
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)
    
    local resulttable = {}
    for _, championname in pairs(championtable) do
        local skintable  = {}
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)
 
        for _, skinname in pairs(skintable) do
            local chromatable = {}
            local t           = skinData[championname]["skins"][skinname]
            local formatname  = t.formatname
            
            if t.chromas ~= nil then
                t = t.chromas
                for chromaname in pairs(t) do
                    if t[chromaname].distribution == "Partner Program" then
                        s = s .. '<div class="skin-icon" data-champion="' .. championname .. '" data-skin="' .. skinname .. '"><div class="chroma partner-border">[[File:' .. FN.chroma({championname, skinname, chromaname}) .. '|100px|border|link=]]</div> <div class="chroma-caption">[[File:' .. FN.championcircle({championname, skinname}) .. '|20px|link=' .. championname .. ']] [[' .. championname .. '|' .. lib.ternary(formatname, formatname, skinname .. ' ' .. championname) .. ']]</div></div>'
                    end
                    
                end
            end
        end
    end
    s = s .. '</div>'
    
    return s
end



function p.chromagallery(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2] or "Original"
    
    local t = skinData[champname].skins[skinname]
    if t == nil or t.chromas == nil then
        return userError("No chromas specified for skin ''" .. skinname .. "'' in Module:SkinData/data", "LuaError")
    end
    t = t.chromas
    
    local header = "Chromas"
    local frame = mw.getCurrentFrame()
    
    if skinData[champname].skins[skinname].forms ~= nil then
        header = "forms"
    end
    
    local chromatable  = {}
    local chromastring = args['chromas'] or "true"
    if chromastring == "true" then
        for chromaname in pairs(t) do
            table.insert(chromatable, chromaname)
        end
    else
        chromatable = lib.split(chromastring, ",")
    end
    table.sort(chromatable)
    
    local formatname = skinData[champname].skins[skinname].formatname
    local key        = args["key"] or "true" 
    local imagewidth = "100px"
    local s = ''
    s = s .. '<div id="chromaexhibition" style="position:relative"><b>' .. lib.ternary(formatname, formatname, skinname .. " " .. champname) .. " " .. header .. "</b>"
    
    if key == "true" then
        s = s .. "<div class='glossary' data-param='Chroma exhibition' style='position:absolute; top:5px; right: 5px; z-index:20;'>[[File:Information.svg|30px|link=]]</div>"
    end
    
    if #chromatable > 8 then
        imagewidth = "80px"
        s = s .. '<div class="chroma-gallery-large" style="width:718px; text-align:center">'
    else
        s = s .. '<div class="chroma-gallery" style="width:718px; text-align:center">'
    end
    
    s = s .. '<div class="base">[[File:' .. FN.chroma({champname, skinname, "Base"}) .. '|183px]]</div>'
    
    for i, chromaname in pairs(chromatable) do
        if skinData[champname].skins[skinname].chromas[chromaname] == nil then
            return userError("Chroma ''" .. chromaname .. "'' not specified in Module:SkinData/data for " .. lib.ternary(formatname, formatname, skinname .. " " .. champname), "LuaError")
        end
        
        local availability = skinData[champname].skins[skinname].chromas[chromaname].availability or "Available"
        
        if availability ~= "Canceled" then
            s = s .. "<div><div class='chroma " .. string.lower(availability) .. "-border'>[[File:" .. FN.chroma({champname, skinname, chromaname}) .. "|" .. imagewidth .. "|border]]</div> <div class='chroma-caption'>" .. chromaname .. "</div></div>"
        end
    end
    
    s = s .. '</div>'
    
    return frame:preprocess(s)
end

function p.skinpage(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    
    local champname = args['champion'] or args[1] or mw.title.getCurrentTitle().rootText
    
    if skinData[champname] == nil then
        return userError("Champion ''" .. champname .. "'' does not exist in Module:SkinData/data", "LuaError")
    end
    
    local t = skinData[champname]["skins"]
    
    local availabletable = {}
    local legacytable    = {}
    local limitedtable   = {}
    local upcomingtable  = {}
    local canceledtable  = {}

    for skinname in pairs(t) do
        if t[skinname].availability == "Available" then
            table.insert(availabletable, {skinname, t[skinname]})
        end
        if t[skinname].availability == "Legacy" then
            table.insert(legacytable,    {skinname, t[skinname]})
        end
        if t[skinname].availability == "Limited" or t[skinname].availability == "Rare" then
            table.insert(limitedtable,   {skinname, t[skinname]})
        end
        if t[skinname].availability == "Upcoming" then
            table.insert(upcomingtable,  {skinname, t[skinname]})
        end
        if t[skinname].availability == "Canceled" then
            table.insert(canceledtable,  {skinname, t[skinname]})
        end
    end

    function skinitem(data)
        local lang = mw.language.new("en")
        local skinname     = data[1]
        local formatname   = data[2].formatname or skinname .. ' ' .. champname
        local champid      = skinData[champname]["id"]
        local skinid       = data[2].id
        local cost         = data[2].cost
        local release      = data[2].release
        local distribution = data[2].distribution
        
        if release ~= "N/A" then
            release  = lang:formatDate("d-M-Y", data[2].release)
        end

        local s = ""
        
        s = s .. '<div style="display:inline-block; margin:5px; width:342px"><div class="skin-icon" data-champion="' .. champname .. '" data-skin="' .. skinname .. '">[[File:' .. FN.skin({champname, skinname}) .. '|340px|border]]</div><div><div style="float:left">' .. formatname
        
        if skinid ~= nil then
            standardizedname = string.lower(champname:gsub("[' ]", ""))
            if standardizedname == "wukong" then
                standardizedname = "monkeyking"
            end
            teemogg_skinid = standardizedname .. '-' .. skinid
            s = s .. ' <span class="plainlinks">[https://teemo.gg/model-viewer?model-type=champions&skinid=' .. teemogg_skinid .. ' <span class="button" title="View in 3D" style="text-align:center; border-radius: 2px;"><b>View in 3D</b></span>]</span>'
        end
        
        s = s .. '</div><div style="float:right">'
        
        if cost == 'N/A' then
            -- skip
        elseif cost == 150000 then
            s = s .. tostring(IL.basic{["link"] = "Blue Essence", ["text"] = cost, ["alttext"] = cost .. " Blue Essence", ["image"] = "BE icon.png", ["border"] = "false", ["labellink"] = "false"}) .. ' / ' 
        elseif cost == 100 then
            s = s .. tostring(IL.basic{["link"] = "Prestige Point", ["text"] = cost, ["alttext"] = cost .. " Prestige Points", ["image"] = "Hextech Crafting Prestige token.png", ["border"] = "false", ["labellink"] = "false"}) .. ' / ' 
        elseif cost == 10 then
            s = s .. tostring(IL.basic{["link"] = "Gemstone", ["text"] = cost, ["alttext"] = cost .. " Rare Gems", ["image"] = "Rare Gem.png", ["border"] = "false", ["labellink"] = "false"}) .. ' / ' 
        elseif cost == "special" then
            s = s .. "Special pricing" .. ' / ' 
        else
            s = s .. tostring(IL.basic{["link"] = "Riot Points", ["text"] = cost, ["alttext"] = cost .. " RP", ["image"] = "RP icon.png", ["border"] = "false", ["labellink"] = "false"}) .. ' / ' 
        end
        
        s = s .. lib.ternary(release == 'N/A', 'N/A', release) .. '  </div></div></div>'

        return s
    end

    function chroma(chromatable)
        s = ""
        if #chromatable > 0 then
            for i in ipairs(chromatable) do
                s = s .. '<div style="clear:both"></div>' .. p.chromagallery{champname, chromatable[i]}
            end
        end
        return s
    end
    
    function comp(a, b)
        local a = a[2].id or -1
        local b = b[2].id or -1
        
        if a < b then
            return true
        end
    end
    
    local skintable = {
            {availabletable, text = 'Available'},
            {legacytable,    text = 'Legacy Vault'},
            {limitedtable,   text = 'Rare & Limited'},
            {upcomingtable,  text = 'Upcoming'},
            {canceledtable,  text = 'Canceled'}
        }
    local s = ''
    for i, value in ipairs(skintable) do
        table.sort(skintable[i][1], comp)
        local chromatable = {}
        if #value[1] > 0 then
            s = s .. ('<div style="clear:both"></div>\n==' .. value.text .. '==\n<div style="font-size:small">')
            for i in pairs(value[1]) do
                s = s .. skinitem(value[1][i])
                if value[1][i][2].chromas then
                    table.insert(chromatable, value[1][i][1])
                end
            end
            s = s .. '</div>'
            table.sort(chromatable)
            
            s = s .. chroma(chromatable)
        end
    end
    
    s = s .. '<div style="clear:both"></div>'
    return s
end

function p.getAllchampionskins(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])

    return skinData[champname]
end

function p.getChampionskin(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"]
end

function p.getFormatname(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].formatname
end

function p.getAvailability(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].availability
end

function p.getDistribution(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].distribution
end

function p.getCost(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].cost
end

function p.getRelease(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].release
end

function p.getRetired(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].retired
end

function p.getEarlysale(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].earlysale
end

function p.getSet(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Original"].set
    
    if t == nil then
        return nil
    end
    
    for i, setname in ipairs(t) do
        if i ~= 1 then
            s = s .. ", " .. setname:gsub("% ", "&nbsp;")
        else
            s = setname
        end
    end

    return s
end

function p.getSetlist(frame)
    local championtable = {}
    local sets = {}
    local hash = {}
    local setList = mw.html.create('ul')
    
    setList:newline()
    
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)

    for _, championname in pairs(championtable) do
        local skintable  = {}
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)

        for _, skinname in pairs(skintable) do
            local t = skinData[championname]["skins"][skinname]
            
            if t.set ~= nil then
                for _, value in pairs(t.set) do
                    if (not hash[value]) then
                        table.insert(sets, value)
                        hash[value] = true
                    end
                end
            end
        end
    end
    
    table.sort(sets)
    
    for _, setname in pairs(sets) do
        setList
            :tag('li')
                :wikitext('[[' .. setname .. ']]')
                :done()
            :done()
            :newline()
    end
 
    return setList
end

function p.getSetskins(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local skinList = mw.html.create('ul')
    local championtable = {}
    local result = false
    
    skinList:newline()
    
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)
 
    for _, championname in pairs(championtable) do
        local skintable  = {}
        
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)
        
        for _, skinname in pairs(skintable) do
            local hit = false
            local t = skinData[championname]["skins"][skinname]
            
            if t.set ~= nil then
                for _, subset in pairs(t.set) do
                    if subset == args[1] then
                        hit = true
                        result = true
                    end
                end
            end
            if hit == true then
                skinList
                    :tag('li')
                        :tag('div')
                            :addClass('skin-icon')
                            :attr('data-champion', championname)
                            :attr('data-skin', skinname)
                            :wikitext('[[File:' .. FN.championcircle({championname, skinname}) .. '|20px|link=' .. championname .. ']] [[' .. championname .. '|' .. lib.ternary(t["formatname"] ~= nil, t["formatname"], skinname .. " " .. championname) .. ']]')
                        :done()
                    :done()
                    :newline()
            end
        end
    end

    if result == false then 
        skinList
            :tag('li')
                :wikitext('No match found for ' .. args[1] .. '.')
            :done()
            :newline()
    end
 
    return skinList
end

function p.getNeweffects(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].neweffects
end

function p.getNewrecall(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].newrecall
end

function p.getNewanimations(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].newanimations
end

function p.getTransforming(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].transforming
end

function p.getFilter(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].filter
end

function p.getNewquotes(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].newquotes
end

function p.getNewvoice(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].newvoice
end

function p.getExtras(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].extras
end

function p.getLore(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].lore
end

function p.getLootEligible(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].looteligible
end

function p.getChromas(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].chromas
end

function p.getChromacount(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Original"].chromas
    local s = ""
    
    local chromatable  = {}
    for chromaname in pairs(t) do
        table.insert(chromatable, chromaname)
    end
    
    return #chromatable or "N/A"
end

function p.getChromanames(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Original"]
    if t == nil or t.chromas == nil then
        return ""
    end
    t = t.chromas
    
    local chromatable  = {}
    for chromaname in pairs(t) do
        table.insert(chromatable, chromaname)
    end
    table.sort(chromatable)

    local s = ""
    for i, chromaname in pairs(chromatable) do
        if i ~= 1 then
            s = s  .. ", " .. chromaname
        else
            s = s .. chromaname
        end
    end
    
    return s
end

function p.getForms(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].forms
end

function p.getFormnames(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Original"].forms
    local s = ""
    
    local formtable  = {}
    for formname in pairs(t) do
        table.insert(formtable, formname)
    end
    table.sort(formtable)

    for i, formname in pairs(formtable) do
        if i ~= 1 then
            s = s  .. ", " .. formname
        else
            s = s .. formname
        end
    end
    
    return s
end

function p.getFormicon(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].formicon
end

function p.getVu(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Original"].vu
end

function p.getSplashartist(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Original"].splashartist
    local s = ""
    
    if t == nil then
        return "Unknown artist"
    end
    
    for i, splashartistname in ipairs(t) do
        if i ~= 1 then
            s = s .. ", " .. splashartistname:gsub("% ", "&nbsp;")
        else
            s = splashartistname
        end
    end
    return s
end

function p.getArtistlist(frame)
    local championtable = {}
    local artists = {}
    local hash = {}
    local artistList = mw.html.create('ul')
    
    artistList:newline()
    
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)

    for _, championname in pairs(championtable) do
        local skintable  = {}
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)

        for _, skinname in pairs(skintable) do
            local t = skinData[championname]["skins"][skinname]
            
            if t.splashartist ~= nil then
                for _, value in pairs(t.splashartist) do
                    if (not hash[value]) then
                        table.insert(artists, value)
                        hash[value] = true
                    end
                end
            end
        end
    end
    table.sort(artists)
        
    for _, artist in pairs(artists) do
        artistList
            :tag('li')
                :wikitext('[[' .. artist .. ']]')
                :done()
            :done()
            :newline()
    end
    
    return artistList
end

function p.getVariant(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local searchid = skinData[champname].skins[skinname or "Original"].variant
    local skintable = {}
    
    if searchid == nil then
        return nil
    end
    
    for skinname, data in pairs(skinData[champname]["skins"]) do
        if data.id == searchid then
            return skinname
        end
    end

    return nil
end

function p.getVoiceactor(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Original"].voiceactor
    local s = ""
    
    if t == nil then
        return "Unknown voice actor"
    end
    
    for i, voiceactorname in ipairs(t) do
        if i ~= 1 then
            s = s .. ", " .. voiceactorname:gsub("% ", "&nbsp;")
        else
            s = voiceactorname
        end
    end

    return s
end

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()
        :tag('tr')
            :tag('th')
                :css('width','26px')
            :done()
            :newline()
            :tag('th')
                :wikitext('Skin')
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Availability')
                    :wikitext('[[File:Availability.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Release')
                    :wikitext('[[File:Release.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Cost')
                    :wikitext('[[File:RP icon.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Voice filter')
                    :wikitext('[[File:Voice filter.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Additional/unique quotes')
                    :wikitext('[[File:Additional quotes.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','New voiceover')
                    :wikitext('[[File:New voice.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','New visual and/or sound effects')
                    :wikitext('[[File:New effects.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','New animations and/or new recall animation')
                    :wikitext('[[File:New animations.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Appearance can be toggled in-game [e.g. Ctrl + 5], or the skin "evolves" over the course of the game that is not part of the champion&#39;s base mechanics.')
                    :wikitext('[[File:Transforming.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Part of a Collection')
                    :wikitext('[[File:Set piece.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Features lore')
                    :wikitext('[[File:Mission icon.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:Chromaskins.png|30px|link=|]]')
                :done()
            :done()
        :done()
        :newline()
        
        
        -- START
        local championtable = {}
        for x in pairs(skinData) do
            table.insert(championtable, x)
        end
        table.sort(championtable)
        
        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 _, championname in pairs(championtable) do
            local skintable  = {}
            for championname in pairs(skinData[championname]["skins"]) do
                table.insert(skintable, championname)
            end
            table.sort(skintable)
    
            for _, skinname in pairs(skintable) do
                if (
                    championname == "Akali"      and skinname == "Crimson" 
                    or 
                    championname == "Amumu"      and skinname == "Sewn Chaos"
                    or
                    championname == "Blitzcrank" and skinname == "Sewn Chaos"
                    or
                    championname == "Ryze"       and skinname == "Human"
                ) then
                    -- skip
                else
                    local t = skinData[championname]["skins"][skinname]
                    local sdnode = mw.html.create('tr')
                    local temp = ""
                    
                    -- Skincircle
                    if (skinname == "Original") then
                        temp = "!" .. t["release"]
                    else 
                        temp = t["release"]
                    end
                    
                    sdnode
                        :tag('td')
                            :addClass('champion-icon')
                            :attr('data-sort-value', championname .. temp)
                            :attr('data-champion', championname)
                            :attr('data-skin', skinname)
                            :wikitext('[[File:' .. FN.championcircle({championname, skinname}) .. '|20px|link=' .. championname .. ']]')
                        :done()
                    
                    -- Skinname
                    sdnode
                        :tag('td')
                            :addClass('skin-icon')
                            :attr('data-champion', championname)
                            :attr('data-skin', skinname)
                            :css('text-align', 'left')
                            :wikitext(lib.ternary(t["formatname"] ~= nil, t["formatname"], skinname .. " " .. championname))
                        :done()
                    
                    -- Availability
                    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 image = ""
                    if (tostring(t["cost"]) == "150000") then
                        image = "[[File:BE icon.png|20px|link=]]"
                    end 
                    if (tostring(t["cost"]) == "100") then
                        image = "[[File:Hextech Crafting Prestige token.png|20px|link=]]"
                    end
                    if (tostring(t["cost"]) == "10") then
                        image = "[[File:Rare Gem.png|20px|link=]]"
                    end
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(tostring(t["cost"]) == "10" or tostring(t["cost"]) == "100", "2450", t["cost"]))
                            :tag('span')
                                :css('color', color.skin({t["cost"] .. ""}))
                                :wikitext(image .. t["cost"])
                            :done()
                        :done()
                    
                    -- Filter
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["filter"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["filter"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Newquotes
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["newquotes"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["newquotes"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Newvoice
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["newvoice"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["newvoice"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Neweffects
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["neweffects"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["neweffects"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Newanimations
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["newanimations"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["newanimations"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Transforming
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["transforming"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["transforming"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                    
                    -- Set
                    local multiset = false
                    if (type(t["set"]) ~= "nil") then
                        local s = ""
                        
                        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', '1 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
                    
                    -- Transforming
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["lore"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["lore"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                    
                    -- Chromas
                    if (type(t["chromas"]) ~= "nil") then
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-champion', championname)
                                :attr('data-skin', skinname)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    -- Add skin row to the table
                    sdtable
                        :newline()
                        :node(sdnode)
                end
            end
        end
        -- END
    
    sdtable:allDone()
    return tostring(sdtable)
end

function p.newestSkins(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end

    local championtable = {}
    local releasetable = {}

    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)

    for _, championname in pairs(championtable) do
        local skintable  = {}
        
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        
        for _, skinname in pairs(skintable) do
            table.insert(releasetable, {championname, skinname, skinData[championname]["skins"][skinname].release})
        end
    end
    
    function comp(a, b)
        if a[3] == "Upcoming" or b[3] == "Upcoming" then return false end
        if a[3] > b[3] then
            return true
        end
    end

    table.sort(releasetable, function(a, b) return a[2] > b[2] end)
    table.sort(releasetable, comp)
    
    local lang = mw.language.new("en")
    local count = tonumber(args[1]) or 7
    local s = ""
    
    for i in pairs(releasetable) do
        local champ      = releasetable[i][1]
        local skin       = releasetable[i][2]
        local formatname = releasetable[i][4]
        local cost       = p.getCost({champ, skin})
        local release    = releasetable[i][3]
        
        if release > lang:formatDate("Y-m-d") then
            -- skip if releasedate is in the future
        else
            if skin == "Original" then
                -- skip
            else 
                if count >= 1 then
                    count = count - 1
                    s = s .. "{{Skin portrait|" .. champ .. "|" .. skin
                    if     cost == 10  then s = s .. "|gems="
                    elseif cost == 100 then s = s .. "|prestige="
                    else                    s = s .. "|rp="
                    end
                    s = s .. cost .. "|date=" .. lang:formatDate("d-M-Y", release) .. "}}"
                end
            end
        end
    end
    
    return frame:preprocess(s)
end

function p.skinCatalog(frame)
    local dlib          = require("Dev:Datecalc")
    local lang          = mw.language.new( "en" )
    local championtable = {}
    local sdtable       = mw.html.create('table')
    
    sdtable
        :addClass('sortable article-table novpadding hcpadding sticky-header')
        :css('width','100%')
        :css('text-align','center')
        :css('font-size','12px')
        :newline()
        :tag('tr')
            :tag('th')
                :css('font-size','12px')
                :css('width','140x')
                :wikitext('Champion')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('<div title="Available in-store or through Hextech Crafting.">Available</div>')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('<div title="Available through Hextech Crafting or limited sales.">Legacy Vault</div>')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('<div title="Only periodically available or acquired through special means.">Rare</div>')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('Unavailable')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('Total')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "isoDate")
                :wikitext('Last Skin')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('Days Ago')
            :done()
            :newline()
        :done()
        :newline()
    
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)
    
    local availablecounttotal = 0
    local legacycounttotal    = 0
    local rarecounttotal      = 0
    local limitedcounttotal   = 0
    for _, championname in pairs(championtable) do
        local t                = skinData[championname]["skins"]
        local availablecount   = 0
	    local availablecircles = ""
        local legacycount      = 0
	    local legacycircles    = ""
        local rarecount        = 0
	    local rarecircles      = ""
        local limitedcount     = 0
	    local limitedcircles   = ""
        local result           = {"","",""}
        local sdnode           = mw.html.create('tr')
        local border           = ""
        local skintable        = {}
        
        for skinname in pairs(t) do
            if (
                championname        == "Akali"      and skinname == "Crimson" 
                or 
                championname        == "Amumu"      and skinname == "Sewn Chaos"
                or
                championname        == "Blitzcrank" and skinname == "Sewn Chaos"
                or
                championname        == "Ryze"       and skinname == "Human"
                or
                skinname            == "Original"
                or
                t[skinname].release == "N/A"
            ) then
                -- skip
            else
                table.insert(skintable, skinname)
            end
        end
        table.sort(skintable, function(a, b) return t[a].release < t[b].release end)
        
        for i, skinname in pairs(skintable) do
            if t[skintable[i]].release == t[skintable[#skintable]].release then
                border = "border-radius:13px; width:26px; height:26px; box-shadow: 0 0 2px 2px #70fff2, 0 0 4px #111;"
            end
            
            if t[skinname].availability == "Available" then
                availablecount      = availablecount      + 1
                availablecounttotal = availablecounttotal + 1
                availablecircles = availablecircles .. '<li class="skin-icon" data-champion="' .. championname ..'" data-skin="' .. skinname .. '" style="'.. border ..'">[[File:' .. FN.championcircle({championname, skinname}) .. '|26px|link=]]'
            end
            if t[skinname].availability == "Legacy" then
                legacycount         = legacycount         + 1
                legacycounttotal    = legacycounttotal    + 1
                legacycircles = legacycircles .. '<li class="skin-icon" data-champion="' .. championname ..'" data-skin="' .. skinname .. '" style="'.. border ..'">[[File:' .. FN.championcircle({championname, skinname}) .. '|26px|link=]]'
            end
            if t[skinname].availability == "Rare" then
                rarecount           = rarecount           + 1
                rarecounttotal      = rarecounttotal      + 1
                rarecircles = rarecircles .. '<li class="skin-icon" data-champion="' .. championname ..'" data-skin="' .. skinname .. '" style="'.. border ..'">[[File:' .. FN.championcircle({championname, skinname}) .. '|26px|link=]]'
            end
            if t[skinname].availability == "Limited" then
                limitedcount        = limitedcount        + 1
                limitedcounttotal   = limitedcounttotal   + 1
                limitedcircles = limitedcircles .. '<li class="skin-icon" data-champion="' .. championname ..'" data-skin="' .. skinname .. '" style="'.. border ..'">[[File:' .. FN.championcircle({championname, skinname}) .. '|26px|link=]]'
            end
            
            if t[skinname].release > result[2] then
                    result[1] = skinname
                    result[2] = t[skinname].release
                    result[3] = t[skinname].formatname
            end
        end
        
        sdnode
            :tag('td')
                :addClass('skin-icon')
                :attr('data-sort-value', championname)
                :attr('data-champion', championname)
                :attr('data-skin', "Original")
                :css('text-align', 'left')
                :wikitext('[[File:' .. FN.championcircle({championname, "Original"}) .. '|26px|link=' .. championname .. ']] ' .. championname)
            :done()
        
        -- Available skins
        sdnode
            :tag('td')
                :addClass('icon_list')
                :attr('data-sort-value', availablecount)
                :css('text-align', 'left')
                :css('background-color', '#0a1827')
                :wikitext(availablecircles)
            :done()
            
        -- Legacy skins
        sdnode
            :tag('td')
                :addClass('icon_list')
                :attr('data-sort-value', legacycount)
                :css('text-align', 'left')
                :wikitext(legacycircles)
            :done()
            
        -- Rare skins
        sdnode
            :tag('td')
                :addClass('icon_list')
                :attr('data-sort-value', rarecount)
                :css('text-align', 'left')
                :css('background-color', '#0a1827')
                :wikitext(rarecircles)
            :done()
         
        -- Limited skins
        sdnode
            :tag('td')
                :addClass('icon_list')
                :attr('data-sort-value', limitedcount)
                :css('text-align', 'left')
                :wikitext(limitedcircles)
            :done()   
           
        -- Total
            
        sdnode
            :tag('td')
                :css('text-align','right')
                :wikitext(availablecount + legacycount + rarecount + limitedcount)
            :done()

        -- Last Skin
        local y, m, d = result[2]:match("(%d+)-(%d+)-(%d+)")
        if y == nil or m == nil or d == nil then
            sdnode
                :tag('td')
                    :addClass('skin-icon')
                    :css('white-space', 'nowrap')
                    :attr('data-sort-value', result[2])
                    :attr('data-champion', championname)
                    :attr('data-skin', result[1])
                    :wikitext(result[2])
                :done()
                :tag('td')
                    :css('text-align','right')
                    :wikitext(result[2])
                :done()
        else
            sdnode
                :tag('td')
                    :addClass('skin-icon')
                    :css('white-space', 'nowrap')
                    :attr('data-sort-value', result[2])
                    :attr('data-champion', championname)
                    :attr('data-skin', result[1])
                    :wikitext(lang:formatDate('d-M-Y', result[2]))
                :done()
                :tag('td')
                    :css('text-align','right')
                    :wikitext(dlib.main{"diff", lang:formatDate('Y-m-d'), result[2]})
                :done()
        end
        
        -- Add skin row to the table
        sdtable
            :newline()
            :node(sdnode)
            
    end
    local sdfooter = mw.html.create('tr')
    sdfooter
        :tag('th')
            :css('font-size','12px')
            :wikitext('Total')
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(availablecounttotal)
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(legacycounttotal)
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(rarecounttotal)
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(limitedcounttotal)
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(availablecounttotal + legacycounttotal + rarecounttotal + limitedcounttotal)
        :done()
        :newline()
        :tag('th')
        :done()
        :newline()
        :tag('th')
        :done()
        
    sdtable
        :newline()
        :node(sdfooter)

    return sdtable
end

function p.skintooltip(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    
    local championname = args["champion"]
    local skinname     = args["skin"] or "Original"
    local variant      = args["variant"]
    
    local filename     = FN.skin{championname, skinname, variant}
    local t            = skinData[championname]["skins"][skinname]
    local newrecall    = t["newrecall"]
    local formatname   = t["formatname"]
    local cost         = t["cost"]
    local distribution = t["distribution"]
    local voiceactor   = p.getVoiceactor{championname, skinname}
    local splashartist = p.getSplashartist{championname, skinname}
    local set          = p.getSet{championname, skinname}
    local lore         = t["lore"]
    local filter       = t["filter"]
    local newquotes    = t["newquotes"]
    local newvoice     = t["newvoice"]
    local neweffects   = t["neweffects"]
    --local newrecall    = t["newrecall"]
    local newanimations= t["newanimations"]
    local transforming = t["transforming"]
    local extras       = t["extras"]
    local chromas      = t["chromas"]
    local looteligible = t["looteligible"]
    local variantof    = p.getVariant{championname, skinname}
    
    local rpskins      = {[260]=true, [585]=true, [790]=true, [880]=true, [390]=true, [460]=true, [500]=true, [520]=true, [750]=true, [975]=true, [1350]=true, [1820]=true, [2775]=true, [3250]=true, [5000]=true}
    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 .. lib.ternary(formatname ~= nil, formatname, skinname .. ' ' .. championname) .. lib.ternary(variant ~= nil, '&nbsp;<small>(' .. tostring(variant) .. ')</small>', '')
                s = s .. '</span>&nbsp;<span style="font-size:14px; color:#c9aa71; width:100%;">'
                
                    if cost == 10 then
                        s = s .. '&#x2011;&nbsp;' .. tostring(IL.basic{link = 'Gemstone', text = cost, image = 'Rare Gem.png', alttext = cost .. ' Rare Gems}', border = "false", labellink = "false"})
                    elseif cost == 100 then
                        -- Prestige: distribution string
                    elseif rpskins[cost] == true then
                        s = s .. '&#x2011;&nbsp;' .. tostring(IL.basic{link = 'Riot Points', text = cost, image = 'RP icon.png', alttext = cost .. ' RP', border = "false", labellink = "false"})
                    elseif cost == 150000 then
                        s = s .. '&#x2011;&nbsp;' .. tostring(IL.basic{link = 'Blue Essence', text = cost, image = 'BE icon.png', alttext = cost .. ' BE', border = "false", labellink = "false"})
                    else
                        -- default: do nothing
                    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(looteligible ~= false, '<div style="display:inline-block; padding-right:1em;">[[File:Loot eligible.png|20px|link=]] Loot eligible</div>', '')
                s = s .. lib.ternary(looteligible == false, '<div style="display:inline-block; padding-right:1em;">[[File:Loot ineligible.png|20px|link=]] Loot ineligible </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 newanimations or transforming or extras or chromas or looteligible then
                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 ~= nil, '<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 ~= nil, '<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 ~= nil, '<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 ~= nil, '<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(newanimations ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:New animations.png|50px|link=]]</div><div>New Animations</div></div>', '')
                s = s .. lib.ternary(transforming ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Transforming.png|50px|link=]]</div><div>Transforming</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 .. lib.ternary(chromas ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Chromas available.png|50px|link=]]</div><div>Chromas</div></div>', '')
                s = s .. '</div>'
            end
            s = s .. lib.ternary(variantof ~= nil, '<div>This skin is a variant of ' .. tostring(IL.skin{champion = championname, skin = variantof, circle = "true", link = '*none*'}) .. '.</div>', '')
        s = s .. '</div>'
    s = s .. '</div>'
    
    return s
end


function p.chromaList(frame)
    local lang = mw.language.new( "en" )
    local sdtable = mw.html.create('table')
    
    sdtable
        :addClass('sortable article-table nopadding sticky-header')
        :css('text-align','center')
        :newline()
        :tag('tr')
            :tag('th')
                :css('width','26px')
            :done()
            :newline()
            :tag('th')
                :wikitext('Skin')
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Availability')
                    :wikitext('[[File:Availability.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Cost')
                    :wikitext('[[File:RP icon.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Store Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:Chromaskins.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Bundle Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:Legendary_Skin.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Partner Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:China Skin Tier 2.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Loot Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:China Skin Tier 1.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Distributed Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:Limited skin.png|30px|link=|]]')
                :done()
            :done()
        :done()
        :newline()
        
        -- START
        local championtable = {}
        for x in pairs(skinData) do
            table.insert(championtable, x)
        end
        table.sort(championtable)
        
        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 _, championname in pairs(championtable) do
            local skintable  = {}
            for championname in pairs(skinData[championname]["skins"]) do
                table.insert(skintable, championname)
            end
            table.sort(skintable)
    
            for _, skinname in pairs(skintable) do
                if skinData[championname]["skins"][skinname]["chromas"] == nil then
                    -- skip
                else
                    local t = skinData[championname]["skins"][skinname]
                    local sdnode = mw.html.create('tr')
                    local temp = ""
                    
                    -- Skincircle
                    if (skinname == "Original") then
                        temp = "!" .. t["release"]
                    else 
                        temp = t["release"]
                    end
                    
                    sdnode
                        :tag('td')
                            :addClass('champion-icon')
                            :attr('data-sort-value', championname .. temp)
                            :attr('data-champion', championname)
                            :attr('data-skin', skinname)
                            :wikitext('[[File:' .. FN.championcircle({championname, skinname}) .. '|20px|link=' .. championname .. ']]')
                        :done()
                    
                    -- Skinname
                    sdnode
                        :tag('td')
                            :addClass('skin-icon')
                            :attr('data-champion', championname)
                            :attr('data-skin', skinname)
                            :css('text-align', 'left')
                            :wikitext('[[' .. championname .. '|' .. lib.ternary(t["formatname"] ~= nil, t["formatname"], skinname .. " " .. championname) .. ']]')
                        :done()
                    
                    -- Availability
                    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()
                    
                    -- Cost
                    local image = ""
                    if (tostring(t["cost"]) == "150000") then
                        image = "[[File:BE icon.png|20px|link=]]"
                    end 
                    if (tostring(t["cost"]) == "100") then
                        image = "[[File:Hextech Crafting Prestige token.png|20px|link=]]"
                    end
                    if (tostring(t["cost"]) == "10") then
                        image = "[[File:Rare Gem.png|20px|link=]]"
                    end
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(tostring(t["cost"]) == "10" or tostring(t["cost"]) == "100", "2450", t["cost"]))
                            :tag('span')
                                :css('color', color.skin({t["cost"] .. ""}))
                                :wikitext(image .. t["cost"])
                            :done()
                        :done()
                    
                    -- Chromas
                    local availtable   = {}
                    local bundletable  = {}
                    local partnertable = {}
                    local loottable    = {}
                    local rewardtable  = {}
                    local futuretable  = {}
                    
                    for chromaname in pairs(t["chromas"]) do
                        if     t["chromas"][chromaname]["source"] == "Bundle" then
                            table.insert(bundletable, chromaname)
                        elseif t["chromas"][chromaname]["source"] == "Partner" then
                            table.insert(partnertable, chromaname)
                        elseif t["chromas"][chromaname]["source"] == "Loot" then
                            table.insert(loottable, chromaname)
                        elseif t["chromas"][chromaname]["source"] == "Reward" then
                            table.insert(rewardtable, chromaname)
                        elseif t["chromas"][chromaname]["source"] == "Upcoming" then
                            table.insert(futuretable, chromaname)
                        else
                            table.insert(availtable, chromaname)
                        end
                    end
                    
                    --normal
                    if (#availtable ~= 0) then
                        local s = table.concat(availtable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-champion', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    --bundle
                    if (#bundletable ~= 0) then
                        local s = table.concat(bundletable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-champion', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    --partner
                    if (#partnertable ~= 0) then
                        local s = table.concat(partnertable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-champion', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    --loot
                    if (#loottable ~= 0) then
                        local s = table.concat(loottable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-champion', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    --distributed
                    if (#rewardtable ~= 0) then
                        local s = table.concat(rewardtable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-champion', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    -- Add skin row to the table
                    sdtable
                        :newline()
                        :node(sdnode)
                end
            end
        -- END
        end
    
    sdtable:allDone()
    return tostring(sdtable)
end

return p

-- </pre>
-- [[Category:Lua]]