ФЭНДОМ


-- <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 rusLib    = require('Модуль:RusLocalization')
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 ~= "Классический" or skinname ~= "Классическая") 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]["availability"] == "Rare" and price ~= 2450)
                    or
                        (skinname == "Новая PAX" and championname == "Сивир")
                    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(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    local searchstring = args[1] or mw.title.getCurrentTitle().text
 
    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 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|Пример работ.]]"
        end
        hash[rnd] = true
    end
 
    -- Splash Art list
    local s2 = "<dl><dt>Иллюстрации</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>\n<li>"
            end
            tempval = championname
        end
        s2 = s2 .. tostring(IL.skin({
            ["champion"] = championname,
            ["skin"] = skinname,
            ["link"] = championname .. "/Образы",
            ["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.chromagallery(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local t = skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])]
    if t == nil or t.chromas == nil then
        return userError("Отсутствуют цветовые схемы для данного образа ''" .. args[2] .. "'' в Module:SkinData/data", "LuaError")
    end
    t = t.chromas
 
    local header = "Цветовые схемы"
    local frame = mw.getCurrentFrame()
 
    if skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].forms ~= nil then
        header = "Модели"
    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 = mw.text.split(chromastring, ",")
    end
    table.sort(chromatable)
 
    local champname  = args[1]
    local skinname   = args[2] or rusLib.adjustOriginal(champname)
    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">\n<b>' .. lib.ternary(formatname, formatname, skinname .. " " .. champname) .. " - " .. header .. "</b>"
 
    if key == "true" and header == "Цветовые схемы" then
        s = s .. "<div class='glossary' style='position:absolute; top:5px; right: 5px; z-index:20;' data-param='Рамки цс'>[[File:Information.svg|30px|link=]]</div>\n"
    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, "Обычная"}) .. '|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>\n"
        end
    end
 
    s = s .. '</div></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 title = mw.title.getCurrentTitle().rootText
    local champname = args[1] or title
 
    if champname == nil then
        return userError("Не указан чемпион", "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("ru")
        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      = ''
        local distribution = data[2].distribution
 
        if data[2].release == "N/A" then
            release  = "N/A"
        else
            release  = lang:formatDate("d-m-Y", data[2].release)
        end
 
        local s = ""
 
        s = s .. '<div style="display:inline-block; margin:5px; width:342px">\n    <div class="skin-icon" data-champion="' .. champname .. '" data-skin="' .. skinname .. '">[[File:' .. FN.skin({champname, skinname}) .. '|340px|border]]</div>\n    <div>\n      <div style="float:left">' .. formatname
 
        if skinid ~= nil then
            s = s .. ' [https://teemo.gg/model-viewer?skinid=' .. champid .. string.format("%03d",skinid) .. ' <span class="button" title="3D" style="text-align:center; border-radius: 2px;">\'\'\'3D\'\'\'</span>]'
        end
 
        s = s .. '</div>\n      <div style="float:right">'
 
        if cost == 'N/A' then
            -- skip
        elseif cost == 150000 then
            s = s .. tostring(IL.basic({["link"] = "Синяя эссенция", ["text"] = cost, ["alttext"] = cost .. " СЭ", ["image"] = "BE icon.png", ["border"] = "false", ["labellink"] = "false"})).. ' / ' 
        elseif cost == 10 then
            s = s .. tostring(IL.basic({["link"] = "Самоцвет", ["text"] = cost, ["alttext"] = cost .. " Самоцветов", ["image"] = "Rare Gem.png", ["border"] = "false", ["labellink"] = "false"})).. ' / ' 
        elseif cost == 100 then
            s = s .. tostring(IL.basic({["link"] = "Очки престижа", ["text"] = cost, ["alttext"] = cost .. " Очков престижа", ["image"] = "Hextech_Crafting_Prestige_token.png", ["border"] = "false", ["labellink"] = "false"})).. ' / '  
        elseif cost == "special" then
            s = s .. "Особая цена / "
        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>\n  </div>\n  </div>\n'
 
        return s
    end
 
    function chroma(chromatable)
        s = ""
        if #chromatable > 0 then
            for i in ipairs(chromatable) do
                s = s .. '<div style="clear:both"></div>\n' .. p.chromagallery{champname, chromatable[i]} .. '\n'
            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 = 'Доступные'},
            {legacytable,    text = 'Архивные'},
            {limitedtable,   text = 'Редкие и ограниченные'},
            {upcomingtable,  text = 'Будущие'},
            {canceledtable,  text = 'Отмененные'}
        }
    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">\n  ')
            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>\n\n'
            table.sort(chromatable)
 
            s = s .. chroma(chromatable)
        end
    end
 
    s = s .. '<div style="clear:both"></div>'
 
    -- Секция загрузочных иллюстраций
 
    s = s .. "<br/><h2><span class=\"mw-headline\">Загрузочные иллюстрации</span></h2>"
 
    s = s .. p.getLoadings{['champion'] = champname}
 
    return s
end
 
function p.getLoadings(frame)
    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
        return false
    end
 
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local champion = args['champion'] or args[1]
    local size = args['size'] or args[2] or '150'
 
    local skins = skinData[champion].skins
    local wrapper = {}
 
    -- table.sort не умеет сортировать таблицы с нечисловыми индексами, так что костыль
    for k, v in pairs(skins) do 
        table.insert(wrapper, {k, v})
    end
 
    table.sort(wrapper, comp)
    local loadings = {}
    for i, value in pairs(wrapper) do
        table.insert(loadings, mw.ustring.format("[[File:%s|%spx]]", 
            tostring(FN.loading{
                ['champion'] = champion, 
                ['skin'] = value[1]
            }),
            size
        ))
    end
 
    return table.concat(loadings, "")
end
 
function p.getAllchampionskins(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]]
end
 
function p.getChampionskin(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])]
end
 
function p.getFormatname(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].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 genderOriginal;
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].availability
end
 
function p.getDistribution(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return lib.ternary(skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].distribution == "Limited Distribution", "Ограниченное издание", "")
end
 
function p.getCost(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] 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
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].release
end
 
function p.getRetired(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].retired
end
 
function p.getEarlysale(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].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 t = skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].set
 
    if t == nil then
        return nil
    elseif type(t) == 'string' then
        return t
    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
                if type(t.set) == "table" then
                    for _, value in pairs(t.set) do
                        if (not hash[value]) then
                            table.insert(sets, value)
                            hash[value] = true
                        end
                    end
                else
                    if (not hash[t.set]) then
                        table.insert(sets, t.set)
                        hash[t.set] = 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
                if type(t.set) == "table" then
                    for _, subset in pairs(t.set) do
                        if subset == args[1] then
                            hit = true
                            result = true
                        end
                    end
                else
                    if t.set == args[1] then
                        hit = true
                        result = true
                    end
                end
            end
            if hit == true then
                skinList
                    :tag('li')
                        :tag('span')
                            :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
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].neweffects
end
 
function p.getNewanimations(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].newanimations
end
 
function p.getTransforming(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].transforming
end
 
function p.getFilter(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].filter
end
 
function p.getNewquotes(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].newquotes
end
 
function p.getNewvoice(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].newvoice
end
 
function p.getExtras(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].extras
end
 
function p.getLore(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].lore
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 rusLib.adjustOriginal(args['champion'] or args[1])].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 t = skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args['champion'] or args[1])].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 rusLib.adjustOriginal(args['champion'] or args[1])]
    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
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].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 t = skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].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
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].formicon
end
 
function p.getVu(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    return skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].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 t = skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].splashartist
    local s = ""
 
    if t == nil then
        return "Неизвестный художник"
    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
                if type(t.splashartist) == "table" then
                    for _, value in pairs(t.splashartist) do
                        if (not hash[value]) then
                            table.insert(artists, value)
                            hash[value] = true
                        end
                    end
                else
                    if (not hash[t.splashartist]) then
                        table.insert(artists, t.splashartist)
                        hash[t.splashartist] = 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 searchid = skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].variant
    local skintable = {}
 
    if searchid == nil then
        return nil
    end
 
    for skinname, data in pairs(skinData[args[1]]["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 t = skinData[args[1]].skins[args[2] or rusLib.adjustOriginal(args[1])].voiceactor
    local s = ""
 
    if t == nil then
        return "Неизвестный актер озвучки"
    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( "ru" )
    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('Образ')
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Доступность')
                    :wikitext('[[File:Availability.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Дата выхода')
                    :wikitext('[[File:Release.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Стоимость')
                    :wikitext('[[File:RP icon.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Фильтр голоса')
                    :wikitext('[[File:Voice filter.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Дополнительные/Уникальные эффекты')
                    :wikitext('[[File:Additional quotes.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Новая озвучка')
                    :wikitext('[[File:New voice.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Новые визуальные и/или звуковые эффекты')
                    :wikitext('[[File:New effects.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Новые анимации')
                    :wikitext('[[File:New animations.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Внешний вид меняется по ходу игры или может быть переключен; но не является частью игровой механики.')
                    :wikitext('[[File:Transforming.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Часть линейки образов')
                    :wikitext('[[File:Set piece.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Содержит художественное описание')
                    :wikitext('[[File:Mission icon.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Цветовые схемы')
                    :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 == "Акали"      and skinname == "Алая" 
                    or 
                    championname == "Амуму"      and skinname == "Лоскутный хаос"
                    or
                    championname == "Блицкранк" and skinname == "Лоскутный хаос"
                    or
                    championname == "Райз"       and skinname == "Человек"
                ) then
                    -- skip
                else
                    local t = skinData[championname]["skins"][skinname]
                    local sdnode = mw.html.create('tr')
                    local temp = ""
 
                    -- Skincircle
                    if (skinname == "Классический" or skinname == "Классическая") 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
                    local currentSet = t["set"]
                    if(type(currentSet) == "string") then
                        currentSet = {currentSet}
                    end
                    if (type(currentSet) ~= "nil") then
                        local s = ""
 
                        for i, setname in pairs(currentSet) 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.newestSkins2(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, 
                skinData[championname]["skins"][skinname].cost})
        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("ru")
    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] -- nil output error
        local cost       = releasetable[i][4]
        local release    = releasetable[i][3]
 
        if release > lang:formatDate("Y-m-d") then
            -- skip if releasedate is in the future
        else
            if skin == "Классический" or skin == "Классическая" then
                -- skip
            else 
                if count >= 1 then
                    count = count - 1
                    local currency
                    if cost == 10 then currency = 'Gems'
                    elseif cost == 100 then currency = 'ОП'
                    else currency = 'none' end
                    s = s .. _skinPortrait(
                        champ, 
                        skin, 
                        p.getFormatname or champ .. " " .. skin,
                        currency,
                        cost,
                        lang:formatDate("d-M-Y", release)
                    )
                end
            end
        end
    end
 
    return preprocess(s)
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, 
                skinData[championname]["skins"][skinname].cost})
        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("ru")
    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] -- nil output error
        local cost       = releasetable[i][4]
        local release    = releasetable[i][3]
 
        if release > lang:formatDate("Y-m-d") then
            -- skip if releasedate is in the future
        else
            if skin == "Классический" or skin == "Классическая" 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("j xg", release) .. "}}\n"
                end
            end
        end
    end
 
    return frame:preprocess(s)
end
 
function p.skinCatalog(frame)
    local dlib          = require("Dev:Datecalc")
    local lang          = mw.language.new( "ru" )
    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('Чемпион')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('<div title="Доступны в магазине или через Хекстековое ремесло.">Доступные</div>')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('<div title="Доступны через Хекстековое ремесло или ограниченные распродажи.">Архивные</div>')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('<div title="Доступны периодически или могут быть получены при особых условиях.">Редкие</div>')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('Недоступные')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('Всего')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "isoDate")
                :wikitext('Последний образ')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('Дней назад')
            :done()
            :newline()
        :done()
        :newline()
 
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)
 
    for _, championname in pairs(championtable) do
        local t              = skinData[championname]["skins"]
        local availablecount = 0
	    local availablecircles = ""
        local legacycount    = 0
	    local legacycircles = ""
        local limitedcount   = 0
	    local rarecircles = ""
        local rarecount   = 0
	    local limitedcircles = ""
        local result         = {"","",""}
        local sdnode         = mw.html.create('tr')
        local border         = ""
        local skintable      = {}
 
        for skinname in pairs(t) do
            if (skinname == "Классический"
                or
                skinname == "Классическая"
                or
                skinname == "Original"
                or
                championname == "Акали"      and skinname == "Алая" 
                or 
                championname == "Амуму"      and skinname == "Лоскутный хаос"
                or
                championname == "Блицкранк" and skinname == "Лоскутный хаос"
                or
                championname == "Райз"       and skinname == "Человек"
            ) 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 i == #skintable 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
                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
                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
                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
                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 ~= "N/A" then
                if t[skinname].release > result[2] then
                    result[1] = skinname
                    result[2] = t[skinname].release
                    result[3] = t[skinname].formatname
                end
            end
        end
 
        sdnode
            :tag('td')
                :addClass('skin-icon')
                :attr('data-sort-value', championname)
                :attr('data-champion', championname)
                :attr('data-skin', rusLib.adjustOriginal(championname))
                :css('text-align', 'left')
                :wikitext('[[File:' .. FN.championcircle({championname, rusLib.adjustOriginal(championname)}) .. '|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')
                :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')
                    :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')
                    :wikitext(dlib.main{"diff", lang:formatDate('Y-m-d'), result[2]})
                :done()
        end
 
        -- Add skin row to the table
        sdtable
            :newline()
            :node(sdnode)
    end
 
    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 rusLib.adjustOriginal(championname)
    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 newanimations= t["newanimations"]
    local transforming = t["transforming"]
    local extras       = t["extras"]
    local chromas      = t["chromas"]
    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 = 'Самоцвет', text = cost, image = 'Rare Gem.png', alttext = cost .. ' Самоцветов}', 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 = 'Синяя эссенция', text = cost, image = 'BE icon.png', alttext = cost .. ' СЭ', 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(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 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>Ограниченное издание</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>Архивный</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>Фильтр голоса</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>Дополнительные фразы</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>Новая озвучка</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>Новые эффекты</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>Новые анимации</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>Изменяющийся</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>Содержит доп. материалы</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>Цв. схемы</div></div>', '')
                s = s .. '</div>'
            end
            s = s .. lib.ternary(variantof ~= nil, '<div>Этот образ является вариацией образа ' .. tostring(IL.skin{champion = championname, skin = variantof, circle = "true", link = '*none*'}) .. '.</div>', '')
        s = s .. '</div>'
    s = s .. '</div>'
 
    return s
end
 
function p.getVoiceActorRoster()
    local tableNode = mw.html.create('table')
    tableNode
        :addClass('sortable article-table')
        :css('width','100%')
        :css('text-align','left')
        :newline()
        :tag('tr')
            :tag('th')
                :wikitext('Чемпион')
                :css('width', '40%')
                :done()
            :tag('th')
                :wikitext('Актер дубляжа')
                :done()
            :done()
        :newline()
 
    for k, v in lib.pairsByAlphabeticalKeys(skinData) do
        local original = rusLib.adjustOriginal(k)
        local defaultActor = v['skins'][original].voiceactor or "Неизвестный актер озвучки"
 
        if(type(defaultActor) == 'table') then
            defaultActor = lib.tbl_concat{['tbl'] = defaultActor, ['sep'] = ",&nbsp;"}
        end
 
        local rowNode = mw.html.create('tr')
        rowNode
            :tag('td')
                :attr('data-sort-value', k)
                :wikitext(tostring(IL.champion{
                    ['champion'] = k,
                    ['skin'] = original,
                    ['circle'] = "true"
                }))
            :done()
            :tag('td')
                :wikitext(defaultActor)
                :done()
            :newline()
 
        tableNode:node(rowNode):newline()
 
        for k2, v2 in pairs(v.skins) do
            if(v2.voiceactor ~= nil) then
                local currentActor = lib.tbl_concat{
                    ['tbl'] = v2.voiceactor,
                    ['sep'] = ",&nbsp;"
                }
 
                if(currentActor ~= defaultActor) then
                    local skinNode = mw.html.create('tr')
                    skinNode
                        :tag('td')
                            :attr('data-sort-value', k)
                            :wikitext(tostring(IL.champion{
                                ['champion'] = k,
                                ['skin'] = k2,
                                ['text'] = p.getFormatname{k, k2} or (k2 .. " " .. k),
                                ['circle'] = "true",
                                }))
                            :done()
                        :tag('td')
                            :wikitext(currentActor)
                            :done()
                        :newline()
                    tableNode:node(skinNode):newline()
                end
            end
        end
    end
 
    return tostring(tableNode)
 
end
 
-- Input: "skins" Tabelle eines Champs in Modul:SkinData/data
-- Output: Iterator über nach Skin-ID sortierte Tabelle mit 3 nutzbaren return values:
    -- k, v, i -> Key, Value -> Iterationszähler i -> Bsp Ahri: Standard Ahri   table   1
        -- table ist die Tabelle aus "skins" hinter dem Key ["Standard Ahri"]
    -- Nutzungsmögl.: for k, v, i in skinIter(t) - for k, v in skinIter(t) - for k in skinIter(t)
    -- entfernte skins werden aktuell übersprungen (sollte vllt an und ausschaltbar sein)
function skinIter(t)
    local keys = {}
    for k in pairs(t) do
        if t[k]['id'] ~= nil then
            keys[#keys+1] = k
        end
    end
 
    table.sort(keys, function(a,b) return t[a]['id'] < t[b]['id'] end)
 
    -- return the iterator function
    local i = 0
    return function()
        i = i + 1
        if keys[i] then
            return keys[i], t[keys[i]], i
        end
    end
end
 
-- Выводит стилизованную галерею образов чемпионов с меню выбора текущего образа для просмотра
-- Автор: de:Benutzer:TheTimebreaker (редактор немецкой Вики по League of Legends)
function p.skinslider(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local championData = require('Модуль:ChampionData')
    local lang = mw.language.new('ru')
 
    local champname = lib.validateName(args['champion'] or args[1] or mw.title.getCurrentTitle().rootText)
 
    if skinData[champname] == nil then
        return userError("Чемпион ''" .. champname .. "'' не найден в Модуль:SkinData/data", "LuaError")
    end
 
    local t = skinData[champname]["skins"]
    local standardizedname = championData.get{champname, "apiname"}
 
    local container = mw.html.create('div'):addClass('lazyimg-wrapper')
    local navContainer = mw.html.create('div')
        :addClass('skinviewer-nav')
        :addClass('hidden')
        :css({
            ['display'] = 'flex',
            ['justify-content'] = 'center',
            ['margin-bottom'] = '10px',
        })
    local tabContainer = mw.html.create('div'):addClass('skinviewer-tab-container')
 
    local futureSkins = {}
 
    for k,v,i in skinIter(t) do
        local releaseSplit
        if(v['release'] == "N/A") then releaseSplit = v['release']
        else releaseSplit = lang:formatDate('d-m-Y', v['release']) end
 
        local cost
        if type(v['cost']) ~= 'number' then
            cost = '<div class="skinviewer-price" title="'.. (v['distribution'] and v['distribution'] or 'Этот образ нельзя приобрести за игровую валюту') ..'">Особая цена</div>'
        elseif v['cost'] == 10 then
            cost = '<div class="skinviewer-price" title="Этот образ можно приобрести в системе Хекстекового ремесла.">[[Файл:Rare Gem.png|20px|link=Самоцвет]] 10</div>'
        elseif v['cost'] == 100 then
            cost = '<div class="skinviewer-price" title="Этот образ можно купить за Очки престижа в системе Хекстекового ремесла.">[[Файл:Hextech Crafting Prestige token.png|20px|link=Очки престижа|alt=ОП]] 100</div>'
        elseif v['cost'] == 150000 then
            cost = '<div class="skinviewer-price" title="Этот образ можно было приобрести во время особенного события">Ограниченное издание ([[Файл:BE icon.png|20px]] 150000)</div>' 
        else
            cost = '<div class="skinviewer-price" title="Этот образ можно купить за RP по обычным правилам.">[[File:RP icon.png|20px|link=RP|alt=RP]] '.. v["cost"] ..'</div>'
        end
        if(v['availability'] == "Upcoming") then
            table.insert(futureSkins, {k, v, i})
        else
            navContainer
                :tag('span')
                    :attr('id', i)
                    :addClass('show')
                    :css({
                        ['position'] = 'relative',
                        ['width'] = '52px',
                        ['height'] = '52px'
                    })
                    :wikitext(v['chromas'] and '[[File:Chromaskins.png|x52px||link=]]' or '')
                    :tag('span')
                        :css({
                            ['position'] = 'absolute',
                            ['top'] = 0,
                            ['left'] = 0,
                            ['right'] = 0,
                            ['bottom'] = 0,
                            ['z-index'] = 100,
                            ['padding'] = '2px'
                        })
                        :attr('title', k)
                        :wikitext(string.format('[[Файл:%s||link=|x48px]]', FN.championcircle({ champname, k })))
                        :done()
                    :done()
 
            tabContainer
                :tag('div')
                    :addClass('skinviewer-tab-content')
                    :addClass(i==1 and 'skinviewer-active-tab' or '')
                    :attr('id', 'item-'..i)
                    :css('display', i~=1 and 'none' or 'block')
                    :tag('div')
                        :addClass('skinviewer-tab-skin')
                        :css('position', 'relative')
                        :css('font-family', 'BeaufortLoL')
                        :wikitext(string.format('[[Файл:%s||link=]]', FN.skin({ champname, k })))
                        :wikitext(cost)
                        :tag('div')
                            :css({
                                ['position'] = 'absolute',
                                ['bottom'] = 0,
                                ['left'] = 0,
                                ['right'] = 0,
                                ['z-index'] = '100',
                                ['display'] = 'flex',
                                ['justify-content'] = 'space-between',
                                ['align-items'] = 'flex-end',
                                ['background-color'] = 'rgba(0,0,0,0.6)',
                                ['border-top'] = '1px solid rgba(0,0,0,0.25)',
                                ['border-left'] = '1px solid rgba(0,0,0,0.25)',
                                ['border-right'] = '1px solid rgba(0,0,0,0.25)',
                                ['height'] = '24px',
                                ['line-height'] = '24px',
                                ['font-size'] = '20px'
                            })
                            :tag('div')
                                :css({
                                    ['flex'] = '1 1 0px',
                                    ['text-align'] = 'left'
                                })-- Кнопка "посмотреть в 3D"
                                :wikitext('<span class="plainlinks">[https://teemo.gg/model-viewer?model-type=champions&skinid=' .. standardizedname .. ' <span class="button button-gold" title="Посмотреть модель" style="text-align:center; border-radius: 2px;"><b>3D модель</b></span>]</span>')
                                :done()
                            :tag('div')
                                :css({
                                    ['flex'] = '2 1 0px',
                                    ['text-align'] = 'center',
                                    ['color'] = '#d3c7aa',
                                    ['font-weight'] = 700
                                })
                                :wikitext(p.getFormatname{champname, k} or (k .. " " .. champname))
                                :done()
                            :tag('div')
                                :css({
                                    ['flex'] = '1 1 0px',
                                    ['text-align'] = 'right',
                                    ['color'] = '#c9aa71',
                                    ['font-size'] = 'smaller',
                                    ['padding-right'] = '2px'
                                })
                                :wikitext(releaseSplit)
                                :done()
                            :done()
                        :done()
                    :tag('div')
                        :addClass('skinviewer-info')
                        :css({
                            ['padding'] = '15px',
                            ['background-color'] = 'rgba(1, 10, 19, 0.9)',
                            ['font-family'] = 'BeaufortLoL',
                            ['font-size'] = '14px'
                        })
                            :tag('div')
                                :addClass('skinviewer-info-lore')
                                :wikitext(lib.ternary(v['lore'] ~= nil, '<div style="line-height: 1.6em; text-align: center; font-size: 15px;">' .. tostring(v['lore']) .. '</div>', ''))
                                :done()
                            :tag('div')
                                :addClass('skinviewer-info-small-icons hideHyperlinkColor')
                                :css({
                                    ['display'] = 'flex',
                                    ['justify-content'] = 'center'
                                })
                                :wikitext(lib.ternary(p.getVoiceactor{champname, k} ~= nil, '<div style="padding-right:1em; text-align:center;">[[File:Actor.png|20px|link=]][[Актеры озвучивания|' .. tostring(p.getVoiceactor{champname, k}) .. ']]</div>', ''))
                                :wikitext(lib.ternary(p.getSplashartist{champname, k} ~= nil, '<div style="padding-right:1em; text-align:center;">[[File:Artist.png|20px|link=]]' .. tostring(p.getSplashartist{champname, k}) .. '</div>', ''))
                                :wikitext(lib.ternary(p.getSet{champname, k} ~= nil, '<div style="padding-right:1em; text-align:center;">[[File:Set piece.png|20px|link=]]' .. tostring(p.getSet{champname, k}) .. '</div>', ''))
                                :wikitext(lib.ternary(v['looteligible'] ~= false, '<div style="padding-right:1em; text-align:center;">[[File:Loot eligible.png|20px|link=]] [[Хекстековое ремесло|Выпадает из Хекстекового сундука]]</div>', ''))
                                :wikitext(lib.ternary(v['looteligible'] == false, '<div style="padding-right:1em; text-align:center;">[[File:Loot ineligible.png|20px|link=]] Не выпадает из сундуков </div>', ''))
                                :done()
                            :tag('div')
                                :addClass('skinviewer-info-medium-icons')
                                :css({
                                    ['display'] = 'flex',
                                    ['justify-content'] = 'center',
                                    ['padding-top'] = '5px'
                                })
                                :wikitext(v['availability'] == 'Limited' and '<div style="padding:0 1em; text-align:center;"><div>[[File:Limited skin.png|50px|link=]]</div><div>Ограниченное издание</div></div>' or (v['availability'] == 'Legacy' and '<div style="padding:0 1em; text-align:center;"><div>[[File:Legacy skin.png|50px|link=]]</div><div>Архив</div></div>' or ''))
                                :wikitext(lib.ternary(v['filter'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Voice filter.png|50px|link=]]</div><div>Фильтр голоса</div></div>', ''))
                                :wikitext(lib.ternary(v['newquotes'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Additional quotes.png|50px|link=]]</div><div>Дополнительные фразы</div></div>', ''))
                                :wikitext(lib.ternary(v['newvoice'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:New voice.png|50px|link=]]</div><div>Новая озвучка</div></div>', ''))
                                :wikitext(lib.ternary(v['neweffects'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:New effects.png|50px|link=]]</div><div>Новые эффекты</div></div>', ''))
                                :wikitext(lib.ternary(v['newanimations'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:New animations.png|50px|link=]]</div><div>Новые анимации</div></div>', ''))
                                :wikitext(lib.ternary(v['transforming'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Transforming.png|50px|link=]]</div><div>Изменяющийся</div></div>', ''))
                                :wikitext(lib.ternary(v['extras'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Includes extras.png|50px|link=]]</div><div>Содержит доп. материалы</div></div>', ''))
                                :wikitext(lib.ternary(v['chromas'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Chromas available.png|50px|link=]]</div><div>Цв. схемы</div></div>', ''))
                                :done()
                            :tag('div')
                                :addClass('skinviewer-info-variantof')
                                :css('text-align', 'center')
                                :wikitext(lib.ternary(p.getVariant{champname, k} ~= nil, '<div>Этот образ является вариацией образа ' .. tostring(IL.skin{champion = champname, skin = p.getVariant{champname, k}, circle = "true", link = '*none*', text = p.getVariant{champname, k}}) .. '.</div>', ''))
                                :done()
                        :done()
                    :tag('div')
                        :addClass('skinviewer-tab-chroma')
                        :wikitext(v['chromas'] and p.chromagallery{champname, k} or '')
                        :done()
        end
    end
 
    local resultContainer = container:node(navContainer):node(tabContainer)
 
    if(#futureSkins > 0) then
        local futureSkinsNode = mw.html.create('div')
        futureSkinsNode
            :tag('h2')
                :wikitext('Будущие')
                :done()
            :done()
 
        for i, fskin in ipairs(futureSkins) do
            local imageNode = mw.html.create('div')
            imageNode
                :cssText('display:inline-block; margin:5px; width:342px')
                :wikitext(mw.ustring.format(
                    "[[File:%s|340px|border]]",
                    FN.skin{champname, fskin[1]}
                    ))
                :tag('div')
                    :cssText('text-align:center; font-size:90%;')
                    :wikitext(p.getFormatname{champname, fskin[1]} or fskin[1] .. " " .. champname)
                :done()
            futureSkinsNode
                :node(imageNode)
                :tag('div')
                    :addClass('skinviewer-tab-chroma')
                    :wikitext(fskin[2]['chromas'] and p.chromagallery{champname, fskin[1]} or '')
                    :done()
                :done()
 
        end
 
        resultContainer:node(futureSkinsNode)
    end
 
    local loadingsNode = mw.html.create('div')
    loadingsNode
        :tag('h2')
            :wikitext('Загрузочные иллюстрации')
            :done()
        :wikitext(p.getLoadings{['champion'] = champname, ['size'] = '120'})
        :done()
 
    resultContainer:node(loadingsNode)
 
    return resultContainer
end
 
-- Замена шаблону SkinPortrait
function _skinPortrait(champion, skin, text, cost, currency, release)
    local portraitBlock = mw.html.create('div')
    portraitBlock
        :addClass('skin_portrait skin-icon')
        :css('width', '120px')
        :attr('data-champion', champion)
        :attr('data-skin', skin)
        :wikitext(mw.ustring.format(
            '[[Файл:%s|120px|link=%s/Образы]]', 
            tostring(FN.loading{
                ['champion'] = champion, 
                ['skin'] = skin
            }), champion))
        :tag('div')
            :wikitext(mw.ustring.format('[[%s/Образы|%s]]', champion, text))
            :done()
        :tag('div')
            :wikitext(lib.ternary(currency == 'none', 'Особая цена', mw.ustring.format('{{%s|%s}}', currency, cost)))
            :done()
        :tag('div')
            :tag('span')
                :addClass('date')
                :wikitext(release)
                :done()
            :done()
        :done()
 
    return tostring(portraitBlock)
end
 
return p
 
-- </pre>
-- [[Category:Lua]]
Материалы сообщества доступны в соответствии с условиями лицензии CC-BY-SA , если не указано иное.