ФЭНДОМ


-- Authors: Ninjamask, Emptylord (Eng Wiki)
-- Modification and l11n: Mortorium
-- <pre>
local p    = {}
 
local lib       = require('Module:Feature')
local userError = require('Dev:User error')
local cmd       = require('Module:Maintenance data')
local FN        = require('Module:Filename')
 
function p.get(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local get       = require ('Module:ChampionData/getter')
    local champname = args['champname'] or args[1]
    local datatype  = args['datatype']  or args[2]
    local output    = args['output']    or args[3] or nil
 
    champname = lib.validateName(champname) --corrects for acceptable misspellings (e.g. Nunu -> Nunu & Willump)
 
    local result = get[datatype](champname)
 
    if output ~= nil and type(result) == "table" then
        if output == "csv" then
            return lib.tbl_concat{result}
        elseif output == "custom" then 
            return frame:preprocess(lib.tbl_concat({result, prepend = args['prepend'], append = args['append'], separator = args['separator'], index = args["index"]}))
        elseif output == "template" then 
            return frame:preprocess(lib.tbl_concat{result, prepend = "{{" .. args['t_name'] .. "|", append = "}}", separator = args['separator']})
        end
    elseif result == nil then
        return ""
    else
        return result
    end
end
 
function p.getRoster()
    local lolData  = mw.loadData('Module:ChampionData/data')
    local tftData  = mw.loadData('Module:TFTUnitData/data')
    local lorData  = require('Модуль:LoRData')
    local lolTable = {}
    local s        = ""
 
    for k, x in pairs(lolData) do
        if x['date'] == ("Upcoming" or "N/A" or "Cancelled" or "") or k == "Мега-Гнар" then
            --ignore champion
        else
            table.insert(lolTable, k)
        end
 
    end
    table.sort(lolTable)
 
    mw.log(type(lolTable))
 
    for i, champion in ipairs(lolTable) do
 
        --custom searches
        local search = champion
        search = search .. "," .. p.get{champion, 'title'}
 
        if lolData[champion]["fullname"] then search = search .. "," .. lolData[champion]["fullname"] end
        if lolData[champion]["nickname"] then search = search .. "," .. lolData[champion]["nickname"] end
 
        --game titles
        local games = "LOL"
 
        -- Добавляет атрибут, показывающий, что чемпион есть в TFT
        if tftData[champion] ~= nil then
            games = games .. ",TFT"
            -- Указывает членство в определенном наборе TFT
            for k, v in pairs(tftData[champion]) do
                games = games .. ",TFT" .. k
            end
        end
 
        -- Добавляет атрибут, показывающий, что чемпион есть в LoR
        if lorData.cardExists{champion} then
            games = games .. ",LOR"
        end
 
        --champion roles
        local role = p.mainrole{champion} .. "," .. p.get{champion, "role", "csv"}
        local rangetype = lolData[champion]["rangetype"]
 
        local listNode = mw.html.create('li')
        listNode
            :tag('span')
                :addClass('grid-icon champion-icon')
                :attr('data-champion', champion)
                :attr('data-search', search)
                :attr('data-game', games)
                :attr('data-role', role)
                :attr('data-type', rangetype)
                :wikitext(
                    mw.ustring.format("[[File:%s|48px|alt=%s|link=%s]]",
                    FN.championsquare{champion},
                    champion,
                    champion)
                )
                :done()
            :done()
        listNode:newline()
 
        s = s .. tostring(listNode)
    end
 
    return s
end
 
function p.getAbilityDataLinks(frame)
    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 abilities = p.get({champion, args['ability'] or args[2]})
    local separator = args['separator'] or args[3] or ", "
    local s = ""
 
    local i = 1
    while(abilities[i]) do
        if i == #abilities then 
            s = s .. "[[Шаблон:Data " .. champion .. "/" .. abilities[i] .. "]]"
        else
            s = s .. "[[Шаблон:Data " .. champion .. "/" .. abilities[i] .. "]]" .. separator
        end
        i = i + 1
    end
 
    return s
end
 
function p.buildStatTable(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local champions = mw.loadData('Модуль:ChampionData/data')
    local stat = args['stat'] or args[1]
 
    if(stat == nil) then
        return userError('Не указана характеристика', 'LuaError')
    end
 
    stat = mw.ustring.lower(stat)
 
    if stat == "base" then 
        return tostring(_buildBaseStats(champions))
    elseif stat == "auto" then
        return tostring(_buildAutoattackStats(champions))
    elseif stat == "hidden" then
        return tostring(_buildHiddenStats(champions))
    elseif stat == "as" then
        return tostring(_buildAttackSpeedTable(champions))
    elseif stat == "mp" or stat == "mp5" then
        -- Функция-предикат
        local isManaUser = function(champ)
            return mw.ustring.lower(champ.resource) == 'мана'
        end
 
        local manaChampions = lib.predicate(champions, isManaUser)
        local manaChampionTable = {}
        for i, v in ipairs(manaChampions) do
            manaChampionTable[v] = champions[v]
        end
        return tostring(_buildDefaultStats(manaChampionTable, stat))
    elseif stat =="ms" then
        local tableNode = mw.html.create('table')
        tableNode
            :addClass('sortable wikitable sticky-header')
            :css{
                ['width'] = '80%',
                ['text-align'] = 'right',
                ['white-space'] = 'nowrap'
            }
            :newline()
 
        -- Заголовок таблицы
        tableNode
            :tag('tr')
                :tag('th')
                    :css('width', '200px')
                    :wikitext('[[Чемпион]]')
                    :done()
                :tag('th')
                    :wikitext('Значение')
                    :done()
                :done()
            :newline()
        for k, v in lib.pairsByAlphabeticalKeys(champions) do
            tableNode
                :tag('tr')
                    :tag('td')
                        :attr('data-sort-value', k)
                        :css('text-align', 'left')
                        :wikitext(mw.ustring.format(
                            '[[File:%s|20px|alt=%s|link=%s]] [[%s]]', FN.championcircle{k}, k, k, k)
                        ):done()
                    :tag('td')
                        :wikitext(v.stats.ms)
                        :done()
                    :done()
                :newline()
 
        end
        return tostring(tableNode)
    else
        return tostring(_buildDefaultStats(champions, stat))
    end
 
end
 
function p.getChampionTable(frame)
    local tableNode = mw.html.create('table')
    tableNode
        :addClass('wikitable sortable')
        :cssText('width:100%; text-align:center')
        :newline()
 
    tableNode
        :tag('tr')
            :css('white-space', 'nowrap')
            :tag('th')
                :wikitext('Чемпион')
                :done()
            :tag('th')
                :css('width', '80px')
                :wikitext('Класс')
                :done()
            :tag('th')
                :wikitext('Дата выпуска')
                :done()
            :tag('th')
                :wikitext('Изменения')
                :done()
            :tag('th')
                :wikitext('{{СЭ|&nbsp;|20}}')
                :done()
            :tag('th')
                :wikitext('{{RP|&nbsp;|20}}')
                :done()
            :done()
 
    local champions  = mw.loadData('Module:ChampionData/data')
    for k, v in lib.pairsByAlphabeticalKeys(champions) do
        if(k ~= 'Мега-Гнар') then
            local rowNode = mw.html.create('tr')
            rowNode
                :tag('td')
                    :css('text-align', 'left')
                    :attr('data-sort-value', k)
                    :wikitext(mw.ustring.format('{{ci|%s|%s, %s|size=30px}}', k, k, v['title']))
                    :done()
                :tag('td')
                    :attr('data-sort-value', v['role'][1])
                    :wikitext(mw.ustring.format('{{tip|%s}}', v['role'][1]))
                    :done()
                :tag('td')
                    :attr('data-sort-type', 'date')
                    :attr('data-sort-value', v['date'])
                    :wikitext(mw.ustring.format('{{#time:d-m-Y|%s}}', v['date']))
                    :done()
                :tag('td')
                    :attr('data-sort-value', v['changes'])
                    :wikitext(mw.ustring.format('[[%s]]', v['changes']))
                    :done()
                :tag('td')
                    :wikitext(v['be'])
                    :done()
                :tag('td')
                    :wikitext(v['rp'])
                    :done()
                :done()
            :done()
            tableNode:node(rowNode):newline()
        end
    end
 
    return frame:preprocess(tostring(tableNode))
end
 
-- Генерирует таблицу модификаторов урона, лечения и щитов для указанного игрового режима
-- Смотрит на значения в ChampionData/data
function p.getModeSpecificModsTable(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    local gamemode = args['mode'] or args[1] or "aram"
    local champions = mw.loadData('Модуль:ChampionData/data')
    local modifiedChamps = {}
 
    for k, v in lib.pairsByAlphabeticalKeys(champions) do
        if(
            v.stats[gamemode .. "_dmg_dealt"] or
            v.stats[gamemode .. "_dmg_taken"] or
            v.stats[gamemode .. "_healing"] or
            v.stats[gamemode .. "_shielding"]
        ) then
            table.insert(modifiedChamps, k)
        end
    end
 
    local tableNode = mw.html.create('table')
    tableNode
        :addClass('article-table sortable')
        :cssText('width:100%; text-align:center')
        :newline()
        :tag('tr')
            :tag('th')
                :wikitext('[[Чемпион]]')
                :done()
            :tag('th')
                :wikitext('Наносимый урон')
                :attr('data-sort-type', 'number')
                :cssText('width:15%')
                :done()
            :tag('th')
                :wikitext('Получаемый урон')
                :attr('data-sort-type', 'number')
                :cssText('width:15%')
                :done()
            :tag('th')
                :wikitext('Исцеление')
                :attr('data-sort-type', 'number')
                :cssText('width:15%')
                :done()
            :tag('th')
                :wikitext('Прочность щитов')
                :attr('data-sort-type', 'number')
                :cssText('width:15%')
                :done()
            :done()
        :newline()
 
    for i, v in ipairs(modifiedChamps) do
        local rowNode = mw.html.create('tr')
        local dmg_dealt = (p.get{v, gamemode .. "_dmg_dealt"} - 1) * 100
        local dmg_taken = (p.get{v, gamemode .. "_dmg_taken"} - 1) * 100
        local healing   = (p.get{v, gamemode .. "_healing"} - 1) * 100
        local shielding = (p.get{v, gamemode .. "_shielding"} - 1) * 100
        rowNode
            :tag('td')
                :wikitext(mw.ustring.format("{{ci|%s|circle=true}}", v))
                :css('text-align', 'left')
                :attr('data-sort-value', v)
                :done()
            :tag('td')
                -- Украшение: если бонус положительный, ставит плюс
                :wikitext(string.format("%s%d%%",
                    lib.ternary(dmg_dealt > 1.0, "+", ""),
                    dmg_dealt)
                )
                -- Если равно 1.0 (т.е. стандарт) - перекрасить в серый
                :css('background-color', lib.ternary(p.get{v, gamemode .. "_dmg_dealt"} == 1.0, 'inherit', '#202A3B'))
                :done()
            :tag('td')
                :wikitext(string.format("%s%d%%",
                    lib.ternary(dmg_taken > 1.0, "+", ""),
                    dmg_taken)
                )
                :css('background-color', lib.ternary(p.get{v, gamemode .. "_dmg_taken"} == 1.0, 'inherit', '#202A3B'))
                :done()
            :tag('td')
                :wikitext(string.format("%s%d%%",
                    lib.ternary(healing > 1.0, "+", ""),
                    healing)
                )
                :css('background-color', lib.ternary(p.get{v, gamemode .. "_healing"} == 1.0, 'inherit', '#202A3B'))
                :done()
            :tag('td')
                :wikitext(string.format("%s%d%%",
                    lib.ternary(shielding > 1.0, "+", ""),
                    shielding)
                )
                :css('background-color', lib.ternary(p.get{v, gamemode .. "_shielding"} == 1.0, 'inherit', '#202A3B'))
                :done()
            :done()
        tableNode:node(rowNode):newline()
    end
    return frame:preprocess(tostring(tableNode))
end
 
 
-- Не используется. Не удалять (тем не менее)
function p.main(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local patchid      = args[1] or args['patchid'] or cmd.main{"PatchId"}
    local luadata      = loadData(patchid)
    local o            = mw.loadData('Module:StatTable/data/' .. patchid)
    local s            = ""
    local championdata = {}
 
    for championname in pairs(o) do
        table.insert(championdata, championname)
    end
    table.sort(championdata)
 
    -- ============================
    -- = Generate lua data output =
    -- ============================
 
    s = s .. '-- <pre>\n'
    s = s .. '-- Champion data for patch version: ' .. patchid .. '\n'
    s = s .. '\n'
    s = s .. 'return {\n'
 
 
    for i, champname in pairs(championdata) do
        local t = o[champname]
 
        -- StatTable data 
        s = s .. '  ["' .. champname .. '"] = {\n'
        s = s .. '    ["id"]         = '  .. t['id']                            .. ',\n'
        s = s .. '    ["apiname"]    = "' .. t['apiname']                       .. '",\n'
        s = s .. '    ["title"]      = "' .. t['title']                         .. '",\n'
 
        s = s .. '    ["attack"]     = '  .. t['attack']                        .. ',\n'
        s = s .. '    ["defense"]    = '  .. t['defense']                       .. ',\n'
        s = s .. '    ["magic"]      = '  .. t['magic']                         .. ',\n'
        s = s .. '    ["difficulty"] = '  .. t['difficulty']                    .. ',\n'
 
        s = s .. '    ["herotype"]   = "'  .. t['herotype']                     .. '",\n'
        if t['alttype'] ~= nil then
            s = s .. '    ["alttype"]    = "'  .. t['alttype']                  .. '",\n'
        end
 
        s = s .. '    ["resource"]   = "'  .. t['resource']                     .. '",\n'
        s = s .. '    ["stats"] = {\n'
        s = s .. '      ["hp_base"]  = '  .. pst2(champname, "hp_base")         .. ',\n'
        s = s .. '      ["hp_lvl"]   = '  .. pst2(champname, "hp_lvl")         .. ',\n'
        s = s .. '      ["mp_base"]  = '  .. pst2(champname, "mp_base")         .. ',\n'
        s = s .. '      ["mp_lvl"]   = '  .. pst2(champname, "mp_lvl")         .. ',\n'
        s = s .. '      ["arm_base"] = '  .. pst2(champname, "arm_base")         .. ',\n'
        s = s .. '      ["arm_lvl"]  = '  .. pst2(champname, "arm_lvl")         .. ',\n'
        s = s .. '      ["mr_base"]  = '  .. pst2(champname, "mr_base")         .. ',\n'
        s = s .. '      ["mr_lvl"]   = '  .. pst2(champname, "mr_lvl")         .. ',\n'
        s = s .. '      ["hp5_base"] = '  .. pst2(champname, "hp5_base")         .. ',\n'
        s = s .. '      ["hp5_lvl"]  = '  .. pst2(champname, "hp5_lvl")         .. ',\n'
        s = s .. '      ["mp5_base"] = '  .. pst2(champname, "mp5_base")         .. ',\n'
        s = s .. '      ["mp5_lvl"]  = '  .. pst2(champname, "mp5_lvl")         .. ',\n'
        s = s .. '      ["dam_base"] = '  .. pst2(champname, "dam_base")         .. ',\n'
        s = s .. '      ["dam_lvl"]  = '  .. pst2(champname, "dam_lvl")         .. ',\n'
        s = s .. '      ["as_base"]  = '  .. pst2(champname, "as_base")         .. ',\n'
        as_lvl1 = pst2(champname, "as_lvl1")
        if as_lvl1 ~= "{{{as_lvl1}}}" then
            s = s .. '      ["as_lvl1"]  = '  .. pst2(champname, "as_lvl1")         .. ',\n'
        end
        as_lvl1 = pst2(champname, "as_lvl1_bonus")
        if as_lvl1 ~= "{{{as_lvl1_bonus}}}" then
            s = s .. '      ["as_lvl1_bonus"]  = '  .. pst2(champname, "as_lvl1_bonus")         .. ',\n'
        end
        s = s .. '      ["as_lvl"]   = '  .. t['stats']['as_lvl']               .. ',\n'
        s = s .. '      ["range"]    = '  .. t['stats']['range']                .. ',\n'
        s = s .. '      ["ms"]       = '  .. t['stats']['ms']                   ..  '\n'
        s = s .. '    },\n'
 
        -- Additional data from champion data templates
        fullname = pst2(champname, "fullname")
        if fullname ~= "{{{fullname}}}" then
            s = s .. '    ["fullname"]   = "' .. fullname                       .. '",\n'
        end
 
        nickname = pst2(champname, "nickname")
        if nickname ~= "{{{nickname}}}" then
            s = s .. '    ["nickname"]   = "' .. nickname                       .. '",\n'
        end
 
        s = s .. '    ["rangetype"]   = "' .. pst2(champname, "rangetype")           .. '",\n'
        s = s .. '    ["date"]        = "' .. pst2(champname, "date")                .. '",\n'
        s = s .. '    ["patch"]       = "' .. pst2(champname, "patch")               .. '",\n'
        s = s .. '    ["changes"]     = "' .. pst2(champname, "changes")             .. '",\n'
        s = s .. '    ["role"]        = {' .. strtoluadata(pst2(champname, "role"), ",") .. '},\n'
        s = s .. '    ["damage"]      = '  .. pst2(champname, "damage")              .. ',\n'
        s = s .. '    ["toughness"]   = '  .. pst2(champname, "toughness")           .. ',\n'
        s = s .. '    ["control"]     = '  .. pst2(champname, "control")             .. ',\n'
        s = s .. '    ["mobility"]    = '  .. pst2(champname, "mobility")            .. ',\n'
        s = s .. '    ["utility"]     = '  .. pst2(champname, "utility")             .. ',\n'
        s = s .. '    ["style"]       = '  .. pst2(champname, "style")               .. ',\n'
        s = s .. '    ["adaptivetype"]= "' .. pst2(champname, "adaptivetype")        .. '",\n'
        s = s .. '    ["be"]          = '  .. pst2(champname, "be")                  .. ',\n'
        s = s .. '    ["rp"]          = '  .. pst2(champname, "rp")                  .. ',\n'
        s = s .. '    ["skill_i"]     = {' .. strtoluadatai(pst2(champname, "skill_i"), ";") .. '},\n'
        s = s .. '    ["skill_q"]     = {' .. strtoluadatai(pst2(champname, "skill_q"), ";") .. '},\n'
        s = s .. '    ["skill_w"]     = {' .. strtoluadatai(pst2(champname, "skill_w"), ";") .. '},\n'
        s = s .. '    ["skill_e"]     = {' .. strtoluadatai(pst2(champname, "skill_e"), ";") .. '},\n'
        s = s .. '    ["skill_r"]     = {' .. strtoluadatai(pst2(champname, "skill_r"), ";") .. '}\n'
        s = s .. '  }' .. lib.ternary(i ~= #championdata, ',\n','\n')
    end
 
    s = s .. '}\n'
    s = s .. '-- </' .. 'pre>\n' -- pre needs to be splitted with, because of Lua weirdness
    s = s .. '-- [[Category:Lua]]'
 
    return '<pre>' .. mw.text.nowiki(s) .. '</pre>'
end
 
function p.main2(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local patchid      = args[1] or args['patchid'] or cmd.main{"PatchId"}
    local luadata      = loadData(patchid)
    local o            = mw.loadData('Module:StatTable/data/' .. patchid)
    local s            = ""
    local championdata = {}
 
    if type(luadata)     == nil then
        return userError("No data available for patch " .. patchid, "LuaError")
    end
 
    for championname in pairs(o) do
        table.insert(championdata, championname)
    end
    table.sort(championdata)
 
    -- ============================
    -- = Generate lua data output =
    -- ============================
 
    s = s .. '-- <pre>\n'
    s = s .. '-- Champion data for patch version: ' .. patchid .. '\n'
    s = s .. '\n'
    s = s .. 'return {\n'
 
 
    for i, champname in pairs(championdata) do
        local t = o[champname]
 
        -- StatTable data 
        s = s .. '  ["' .. champname .. '"] = {\n'
        s = s .. '    ["id"]         = '  .. t['id']                            .. ',\n'
        s = s .. '    ["apiname"]    = "' .. t['apiname']                       .. '",\n'
        s = s .. '    ["title"]      = "' .. t['title']                         .. '",\n'
 
        s = s .. '    ["attack"]     = '  .. t['attack']                        .. ',\n'
        s = s .. '    ["defense"]    = '  .. t['defense']                       .. ',\n'
        s = s .. '    ["magic"]      = '  .. t['magic']                         .. ',\n'
        s = s .. '    ["difficulty"] = '  .. t['difficulty']                    .. ',\n'
 
        s = s .. '    ["herotype"]   = "'  .. t['herotype']                     .. '",\n'
        if t['alttype'] ~= nil then
            s = s .. '    ["alttype"]    = "'  .. t['alttype']                  .. '",\n'
        end
 
        s = s .. '    ["resource"]   = "'  .. t['resource']                     .. '",\n'
        s = s .. '    ["stats"] = {\n'
        s = s .. '      ["hp_base"]  = '  .. t['stats']['hp_base']              .. ',\n'
        s = s .. '      ["hp_lvl"]   = '  .. t['stats']['hp_lvl']               .. ',\n'
        s = s .. '      ["mp_base"]  = '  .. t['stats']['mp_base']              .. ',\n'
        s = s .. '      ["mp_lvl"]   = '  .. t['stats']['mp_lvl']               .. ',\n'
        s = s .. '      ["arm_base"] = '  .. t['stats']['arm_base']             .. ',\n'
        s = s .. '      ["arm_lvl"]  = '  .. t['stats']['arm_lvl']              .. ',\n'
        s = s .. '      ["mr_base"]  = '  .. t['stats']['mr_base']              .. ',\n'
        s = s .. '      ["mr_lvl"]   = '  .. t['stats']['mr_lvl']               .. ',\n'
        s = s .. '      ["hp5_base"] = '  .. t['stats']['hp5_base']             .. ',\n'
        s = s .. '      ["hp5_lvl"]  = '  .. t['stats']['hp5_lvl']              .. ',\n'
        s = s .. '      ["mp5_base"] = '  .. t['stats']['mp5_base']             .. ',\n'
        s = s .. '      ["mp5_lvl"]  = '  .. t['stats']['mp5_lvl']              .. ',\n'
        s = s .. '      ["dam_base"] = '  .. t['stats']['dam_base']             .. ',\n'
        s = s .. '      ["dam_lvl"]  = '  .. t['stats']['dam_lvl']              .. ',\n'
        s = s .. '      ["as_base"]  = '  .. pst2(champname, "as_base")         .. ',\n'
        if t['stats']['as_lvl1'] ~= nil and t['stats']['as_lvl1'] ~= tonumber(pst2(champname, "as_base")) then
            s = s .. '      ["as_lvl1"]  = '     .. t['stats']['as_lvl1']       .. ',\n'
        end
        if t['stats']['attack_delay'] ~= nil then
            s = s .. '      ["attack_delay"] = ' .. t['stats']['attack_delay']  .. ',\n'
        end
        as_lvl1 = pst2(champname, "as_lvl1_bonus")
        if as_lvl1 ~= "{{{as_lvl1_bonus}}}" then
            s = s .. '      ["as_lvl1_bonus"]  = '  .. pst2(champname, "as_lvl1_bonus")         .. ',\n'
        end
        s = s .. '      ["as_lvl"]   = '  .. t['stats']['as_lvl']               .. ',\n'
        s = s .. '      ["range"]    = '  .. pst2(champname, "range")           .. ',\n'
        s = s .. '      ["ms"]       = '  .. pst2(champname, "ms")              ..  '\n'
        s = s .. '    },\n'
 
        -- Additional data from champion data templates
        fullname = pst2(champname, "fullname")
        if fullname ~= "{{{fullname}}}" then
            s = s .. '    ["fullname"]   = "' .. fullname                       .. '",\n'
        end
 
        nickname = pst2(champname, "nickname")
        if nickname ~= "{{{nickname}}}" then
            s = s .. '    ["nickname"]   = "' .. nickname                       .. '",\n'
        end
 
        s = s .. '    ["rangetype"]   = "' .. pst2(champname, "rangetype")           .. '",\n'
        s = s .. '    ["date"]        = "' .. pst2(champname, "date")                .. '",\n'
        s = s .. '    ["patch"]       = "' .. pst2(champname, "patch")               .. '",\n'
        s = s .. '    ["changes"]     = "' .. pst2(champname, "changes")             .. '",\n'
        s = s .. '    ["role"]        = {' .. strtoluadata(pst2(champname, "role"), ",") .. '},\n'
        s = s .. '    ["damage"]      = '  .. pst2(champname, "damage")              .. ',\n'
        s = s .. '    ["toughness"]   = '  .. pst2(champname, "toughness")           .. ',\n'
        s = s .. '    ["control"]     = '  .. pst2(champname, "control")             .. ',\n'
        s = s .. '    ["mobility"]    = '  .. pst2(champname, "mobility")            .. ',\n'
        s = s .. '    ["utility"]     = '  .. pst2(champname, "utility")             .. ',\n'
        s = s .. '    ["style"]       = '  .. pst2(champname, "style")               .. ',\n'
        s = s .. '    ["adaptivetype"]= "' .. pst2(champname, "adaptivetype")        .. '",\n'
        s = s .. '    ["be"]          = '  .. pst2(champname, "be")                  .. ',\n'
        s = s .. '    ["rp"]          = '  .. pst2(champname, "rp")                  .. ',\n'
        s = s .. '    ["skill_i"]     = {' .. strtoluadatai(pst2(champname, "skill_i"), ";") .. '},\n'
        s = s .. '    ["skill_q"]     = {' .. strtoluadatai(pst2(champname, "skill_q"), ";") .. '},\n'
        s = s .. '    ["skill_w"]     = {' .. strtoluadatai(pst2(champname, "skill_w"), ";") .. '},\n'
        s = s .. '    ["skill_e"]     = {' .. strtoluadatai(pst2(champname, "skill_e"), ";") .. '},\n'
        s = s .. '    ["skill_r"]     = {' .. strtoluadatai(pst2(champname, "skill_r"), ";") .. '}\n'
        s = s .. '  }' .. lib.ternary(i ~= #championdata, ',\n','\n')
    end
 
    s = s .. '}\n'
    s = s .. '-- </' .. 'pre>\n' -- pre needs to be splitted with, because of Lua weirdness
    s = s .. '-- [[Category:Lua]]'
 
    return '<pre>' .. mw.text.nowiki(s) .. '</pre>'
end
 
function p.mainrole(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local parentroletable = {
        ["Ловец"]           = "Манипулятор",
        ["Чародей"]         = "Манипулятор",
        ["Ныряльщик"]       = "Воин",
        ["Джаггернаут"]     = "Воин",
        ["Боевой маг"]      = "Маг",
        ["Маг-подрывник"]   = "Маг",
        ["Маг-артиллерист"] = "Маг",
        ["Убийца"]          = "Истребитель",
        ["Дуэлянт"]         = "Истребитель",
        ["Штурмовик"]       = "Танк",
        ["Хранитель"]       = "Танк",
        ["Стрелок"]         = "",
        ["Уникум"]          = "",
    }
 
    local champname = args[1] or args['champname'] 
    local get       = require ('Module:ChampionData/getter')
    local item      = get.role(champname)
    local s         = ""
 
    for i, subrole in pairs(item) do
        if i ~= 1 then
            s = s .. ","
        end
        s = s .. parentroletable[subrole]
    end
 
    return s
end
 
function p.minmaxstattable()
    local o            = mw.loadData('Module:ChampionData/data')
    local stat         = 'hp5_lvl'
    local stattable    = {}
 
    for champion in pairs(o) do
        -- mw.log(champion, o[champion].stats.hp5_base)
        table.insert(stattable, {champion, o[champion].stats.hp5_base, o[champion].stats.hp5_lvl, o[champion].stats.hp5_base + o[champion].stats.hp5_lvl * (18-1) * (0.7025 + 0.0175 * (18 - 1))})
    end
    table.sort(stattable, function(a, b) return a[2] > b[2] end)
    -- mw.log(lib.tbl(stattable))
 
    result ={}
    size = 0
    for i, t in ipairs(stattable) do
        if i == 1 then
            table.insert(result, t)
            size = size + 1
        elseif result[i-1][2] ~= t[2] then
            table.insert(result, t)
            size = size + 1
        elseif size <= 5 then
            table.insert(result, t)
        else
            break
        end
    end
 
        -- if i == 1 then
        --     table.insert(result, t)
        --     size = size + 1
        -- elseif size < 5 then
        --     if result[i-1][2] ~= t[2] then
        --         table.insert(result, t)
        --         size = size + 1
        --     end
        -- else
        --     break
        -- end
 
 
    table.sort(result, function(a, b) return a[2] < b[2] end)
    mw.log(lib.tbl(result))
end
 
--
-- local funtions
-- 
 
function _buildBaseStats(champions)
    local FD = require('Модуль:Fd')
    local tableNode = mw.html.create('table')
 
    -- Задать внешний вид заголовка
    addCSS(
        tableNode, 
        'sortable wikitable sticky-header',
        {
            ['width'] = '100%',
            ['text-align'] = 'right',
            ['white-space'] = 'nowrap'
        })
    tableNode:newline()
 
    -- Ячейки заголовка
    tableNode
        :tag('tr')
            :tag('th')
                :wikitext('[[Чемпион]]ы')
                :done()
            :tag('th')
                :wikitext('[[Здоровье|HP]]')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('HP+')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('[[Восстановление здоровья|HP5]]')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('HP5+')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('[[Мана|MP]]')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('MP+')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('[[Восстановление маны|MP5]]')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('MP5+')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('[[Сила атаки|AD]]')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('AD+')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('[[Скорость атаки|AS]]')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('AS+')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('[[Броня|Ar]]')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('Ar+')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('[[Сопротивление магии|MR]]')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('MR+')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('[[Скорость передвижения|MS]]')
                :css('width', '4em')
                :done()
            :tag('th')
                :wikitext('[[Дальность атаки|Rg]]')
                :css('width', '4em')
                :done()
            :done()
        :newline()
 
    -- k - champion name, v - its data table
    for k, v in pairsByKeys(champions) do
        local statTable = v['stats']
        local tableRow = mw.html.create('tr')
 
        local hp_base = FD.get{["args"]={tostring(statTable["hp_base"])}}
        local hp_lvl  = FD.get{["args"]={tostring(statTable["hp_lvl"])}}
        local hp5_base = FD.get{["args"]={tostring(statTable["hp5_base"])}}
        local hp5_lvl  = FD.get{["args"]={tostring(statTable["hp5_lvl"])}}
        local mp_base = FD.get{["args"]={tostring(statTable["mp_base"])}}
        local mp_lvl  = FD.get{["args"]={tostring(statTable["mp_lvl"])}}
        local mp5_base = FD.get{["args"]={tostring(statTable["mp5_base"])}}
        local mp5_lvl  = FD.get{["args"]={tostring(statTable["mp5_lvl"])}}
        local dam_base = FD.get{["args"]={tostring(statTable["dam_base"])}}
        local dam_lvl  = FD.get{["args"]={tostring(statTable["dam_lvl"])}}
        local as_base = FD.get{["args"]={tostring(statTable["as_base"])}}
        local as_lvl  = FD.get{["args"]={tostring(statTable["as_lvl"])}}
        local arm_base = FD.get{["args"]={tostring(statTable["arm_base"])}}
        local arm_lvl  = FD.get{["args"]={tostring(statTable["arm_lvl"])}}
        local mr_base = FD.get{["args"]={tostring(statTable["mr_base"])}}
        local mr_lvl  = FD.get{["args"]={tostring(statTable["mr_lvl"])}}
        local ms  = FD.get{["args"]={tostring(statTable["ms"])}}
        local range = FD.get{["args"]={tostring(statTable["range"])}}
 
 
        if(not(v["date"] == ("Upcoming" or "N/A" or "Cancelled" or ""))) then
            tableRow
                :tag('td')
                    :attr('data-sort-value', k)
                    :css('text-align', 'left')
                    :wikitext(mw.ustring.format(
                        '[[File:%s|20px|alt=%s|link=%s]] [[%s]]', FN.championcircle{k}, k, k, k)
                    )
                    :done()
                :tag('td')
                    :wikitext(hp_base)
                    :done()
                :tag('td')
                    :wikitext('+' .. hp_lvl)
                    :done()
                :tag('td')
                    :wikitext(hp5_base)
                    :done()
                :tag('td')
                    :wikitext('+' .. hp5_lvl)
                    :done()
                :tag('td')
                    :wikitext(mp_base)
                    :done()
                :tag('td')
                    :wikitext('+' .. mp_lvl)
                    :done()
                :tag('td')
                    :wikitext(mp5_base)
                    :done()
                :tag('td')
                    :wikitext('+' .. mp5_lvl)
                    :done()
                :tag('td')
                    :wikitext(dam_base)
                    :done()
                :tag('td')
                    :wikitext('+' .. dam_lvl)
                    :done()
                :tag('td')
                    :wikitext(as_base)
                    :done()
                :tag('td')
                    :wikitext('+' .. as_lvl .. '%')
                    :done()
                :tag('td')
                    :wikitext(arm_base)
                    :done()
                :tag('td')
                    :wikitext('+' .. arm_lvl)
                    :done()
                :tag('td')
                    :wikitext(mr_base)
                    :done()
                :tag('td')
                    :wikitext('+' .. mr_lvl)
                    :done()
                :tag('td')
                    :wikitext(ms)
                    :done()
                :tag('td')
                    :wikitext(range)
                    :done()
                :done()
 
            tableNode:node(tableRow):newline()
        end
    end
 
    tableNode:allDone()
    return tableNode
end
 
function _buildAutoattackStats(champions)
    local tableNode = mw.html.create('table')
    tableNode
        :addClass('sortable wikitable sticky-header')
        :css{
            ['width'] = '100%',
            ['text-align'] = 'center',
            ['white-space'] = 'nowrap'
        }
        :newline()
 
    -- Заголовок таблицы
    tableNode
        :tag('tr')
            :tag('th')
                :css('width', '180px')
                :wikitext('[[Чемпион]]')
                :done()
            :tag('th')
                :wikitext('Дальность')
                :done()
            :tag('th')
                :wikitext('Тип дальности')
                :done()
            :tag('th')
                :wikitext('Коэффициент завершения')
                :done()
            :tag('th')
                :wikitext('Модификатор КЗ')
                :done()
            :done()
        :newline()
 
    -- Заполнение    
    for k, v in pairsByKeys(champions) do
        local tableRow = mw.html.create('tr')
        local windup
        if (v['stats']["attack_cast_time"] and v['stats']["attack_total_time"]) then
            windup = v['stats']["attack_cast_time"] / v['stats']["attack_total_time"]
        else
            windup = 0.3 + (v['stats']["attack_delay_offset"] or 0)
        end
 
        local windup_mod
        if v['stats']["windup_modifier"] == nil then
            windup_mod = "N/A"
        else
            windup_mod = math.floor(v['stats']["windup_modifier"] * 1000 + 0.5) / 1000
        end
        tableRow
            :tag('td')
                :attr('data-sort-value', k)
                :css('text-align', 'left')
                :wikitext(mw.ustring.format(
                    '[[File:%s|20px|alt=%s|link=%s]] [[%s]]', FN.championcircle{k}, k, k, k)
                ):done()
            :tag('td')
                :wikitext(tostring(v['stats']['range'] or 'N/A'))
                :done()
            :tag('td')
                :wikitext(tostring(v['rangetype']))
                :done()
            :tag('td')
                :wikitext(tostring((math.floor(math.floor(windup*100*1000+0.5)/1000*100+0.5)/100)) .. "%")
                :done()
            :tag('td')
                :wikitext(tostring(windup_mod))
                :done()
            :done()
 
        tableNode:node(tableRow):newline()
    end
    tableNode:allDone()
 
    return tableNode
end
 
function _buildDefaultStats(champions, stat)
    local tableNode = mw.html.create('table')
    tableNode
        :addClass('sortable wikitable sticky-header')
        :css{
            ['width'] = '100%',
            ['text-align'] = 'center',
            ['white-space'] = 'nowrap'
        }
        :newline()
 
    -- Заголовок таблицы
    tableNode
        :tag('tr')
            :tag('th')
                :css('width', '180px')
                :wikitext('[[Чемпион]]')
                :done()
            :tag('th')
                :wikitext('Начальное значение')
                :done()
            :tag('th')
                :wikitext('Коэффициент прироста')
                :done()
            :tag('th')
                :wikitext('Значение на 18 уровне')
                :done()
            :done()
        :newline()
 
    -- Заполнение    
    for k, v in pairsByKeys(champions) do
        local tableRow = mw.html.create('tr')
        local baseStat = v['stats'][stat .. "_base"]
        local statGrowth = v['stats'][stat .. "_lvl"]
        tableRow
            :tag('td')
                :attr('data-sort-value', k)
                :css('text-align', 'left')
                :wikitext(mw.ustring.format(
                    '[[File:%s|20px|alt=%s|link=%s]] [[%s]]', FN.championcircle{k}, k, k, k)
                ):done()
            :tag('td')
                :wikitext(tostring(baseStat))
                :done()
            :tag('td')
                :wikitext(tostring(statGrowth))
                :done()
            :tag('td')
                :wikitext(tostring(baseStat + statGrowth * 17))
                :done()
            :done()
 
        tableNode:node(tableRow):newline()
    end
    tableNode:allDone()
 
    return tableNode
end
 
function _buildAttackSpeedTable(champions)
    local tableNode = mw.html.create('table')
    tableNode
        :addClass('sortable wikitable sticky-header')
        :css{
            ['width'] = '97%',
            ['text-align'] = 'center',
        }
        :newline()
 
    -- Заголовок таблицы
    tableNode
        :tag('tr')
            :tag('th')
                :css('width', '180px')
                :wikitext('Чемпион')
                :done()
            :tag('th')
                :wikitext('На 1 уровне')
                :css('width', '10px')
                :done()
            :tag('th')
                :wikitext('Коэффициент скорости')
                :css('width', '10px')
                :done()
            :tag('th')
                :wikitext('Доп. скорость на 1 уровне')
                :css('width', '10%')
                :done()
            :tag('th')
                :wikitext('Прирост')
                :css('width', '10%')
                :done()
            :tag('th')
                :wikitext('Бонус на 18 уровне')
                :css('max-width', '10%')
                :done()
            :tag('th')
                :wikitext('На 18 уровне')
                :done()
            :tag('th')
                :wikitext('Остается до предела')
                :done()
            :done()
        :newline()
 
    -- Заполнение    
    for k, v in lib.pairsByAlphabeticalKeys(champions) do
        local tableRow = mw.html.create('tr')
        local baseAS = lib.round(v.stats['as_base'], 3)
        local growthAS = v.stats['as_lvl']
        local asRatio = v.stats['as_ratio'] or v.stats['as_base']
        local bonusAt1 = v.stats['as_lvl1_bonus'] or 0
        local level1AS = baseAS * (1 + 0.01 * bonusAt1)
        local maxAS = level1AS * (1 + growthAS * 0.01 * 17)
        tableRow
            :tag('td')
                :attr('data-sort-value', k)
                :css('text-align', 'left')
                :wikitext(mw.ustring.format(
                    '[[File:%s|20px|alt=%s|link=%s]] [[%s]]', FN.championcircle{k}, k, k, k)
                ):done()
            :tag('td')
                :wikitext(tostring(lib.round(level1AS, 3)))
                :done()
            :tag('td')
                :wikitext(tostring(lib.round(asRatio, 3)))
                :done()
            :tag('td')
                :wikitext(tostring(bonusAt1) .. "%")
                :done()
            :tag('td')
                :wikitext(tostring(growthAS) .. "%")
                :done()
            :tag('td')
                :wikitext(tostring(growthAS * 17) .. "%")
                :done()
            :tag('td')
                :wikitext(tostring(lib.round(maxAS, 3)))
                :done()
            :tag('td')
                :wikitext(tostring(lib.round((2.5 / maxAS) * 100)) .. "%")
                :done()
            :done()
        tableNode:node(tableRow):newline()
    end
    return tableNode
end
 
-- Добавляет классы и CSS стили к указанному HTML узлу
-- css - обязательно таблица!
function addCSS(node, classes, css)
    node
        :addClass(classes)
        :css(css)
end
 
function wrapInHiddenSortKey(name) 
    return '<span class="sortkey" style="display:none;">' .. name .. '</span>'
end
 
-- Возвращает итератор по ключам, сортированным по алфавиту
-- https://www.lua.org/pil/19.3.html
function pairsByKeys(t, f)
    local a = {}
    for n in pairs(t) do table.insert(a, n) end
        table.sort(a, f)
        local i = 0      -- iterator variable
        local iter = function ()   -- iterator function
        i = i + 1
        if a[i] == nil then return nil
        else return a[i], t[a[i]]
        end
    end
    return iter
end
 
function strtoluadata(str, sep)
    x = mw.text.split(str, sep)
    i = 1
    s = '"' .. mw.text.trim(x[i]) .. '"'
    i = i + 1
    while i <= #x do
        s = s .. ', "' .. mw.text.trim(x[i]) .. '"'
        i = i + 1
    end
    return s
end
 
function strtoluadatai(str, sep)
    x = mw.text.split(str, sep)
    i = 1
    s = '[' .. i .. '] = "' .. mw.text.trim(x[i]) .. '"'
    i = i + 1
    while i <= #x do
        s = s .. ', [' .. i .. '] = "' .. mw.text.trim(x[i]) .. '"'
        i = i + 1
    end
    return s
end
 
function pst2(champion, stat)
    local frame = mw.getCurrentFrame()
 
    return frame:expandTemplate{
        title = 'Data ' .. champion, args = {'pst2', stat}
    }
end
 
function loadData(patchid)
    if exists('Module:StatTable/data/' .. patchid) then
        return mw.loadData('Module:StatTable/data/' .. patchid)
    end
 
    return nil
end
 
function exists(page)
    local sPage = page
 
    if sPage then 
        local _, val = pcall(package.loaders[2], sPage)
 
        if type(val) == "function" or type(val) == "string" then
           return true
        end
    end
 
    return false
end
 
return p
-- </pre>
-- [[Category:Lua]]
-- [[en:Module:ChampionData]]
Материалы сообщества доступны в соответствии с условиями лицензии CC-BY-SA , если не указано иное.