League of Legends Wiki
Advertisement

Данная группа модулей хранит информацию обо всех чемпионах из League of Legends. Перечень модулей:

From Модуль:ChampionData/doc


-- 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')

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
    
    local champname = _validateName(champname)
    
    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.championIcon(frame)
	local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
	
	args["champion"] = _validateName(args["champion"] or args[1])
	if(not(p.get{args["champion"], "exists"})) then
		userError("Указанный чемпион не найден в ChampionData/data", "LuaError")
	end
	local IL = require("Модуль:ImageLink")
	
	args["engname"] = args["engname"] or p.get{args["champion"], "engname"}
	
	return IL.champion(args)
end

function p.championSkinIcon(frame)
	local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
	
	args["champion"] = _validateName(args["champion"] or args[1])
	if(not(p.get{args["champion"], "exists"})) then
		userError("Указанный чемпион не найден в ChampionData/data", "LuaError")
	end
	local IL = require("Модуль:ImageLink")
	
	args["engname"] = args["engname"] or p.get{args["champion"], "engname"}
	return IL.skin(args)
end

function p.getRoster()
    local lolData  = mw.loadData('Module:ChampionData/data')
    local tftData  = mw.loadData('Module:TFTUnitData/data')
	local FN       = require('Module:Filename')
    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 == "Мега-Гнар" 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.getRosterNew()
    local lolData  = mw.loadData('Module:ChampionData/data')
    local tftData  = mw.loadData('Module:TFTUnitData/data')
	local FN       = require('Module:Filename')
    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)

    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('span')
        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

-- Составляет список основных категорий чемпиона League of Legends
function p.getCategories(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]
	
	if(not(p.get{champion, "exists"})) then
		return
	end
	
	local categories = {}
	
	local roles = p.get{champion, "role"}
	local rolesPlural = {
		["Ловец"] = "Ловцы",
		["Чародей"] = "Чародеи",
		["Убийца"] = "Убийцы",
		["Дуэлянт"] = "Дуэлянты",
		["Ныряльщик"] = "Ныряльщики",
		["Джаггернаут"] = "Джаггернауты",
		["Стрелок"] = "Стрелки",
		["Маг-артиллерист"] = "Маг-артиллерист",
		["Боевой маг"] = "Боевые маги",
		["Маг-подрывник"] = "Маги-подрывники",
		["Штурмовик"] = "Штурмовики",
		["Хранители"] = "Хранители",
		["Специалист"] = "Уникумы",
		["Уникум"] = "Уникумы"
	}
	
	local positions = p.get{champion, "positions"}
	local positionsPlural = {
		["Верхняя"]   = "Чемпионы верхней линии",
		["Средняя"]   = "Чемпионы средней линии",
		["Нижняя"]    = "Чемпионы нижней линии",
		["Поддержка"] = "Чемпионы поддержки",
		["Лес"]       = "Чемпионы-лесники",
	}
	
	if(roles ~= "") then
		for i, v in ipairs(roles) do
			table.insert(categories, mw.ustring.format("[[Категория:%s]]", rolesPlural[v] or "Неизвестный класс"))
		end
	end
	if(positions ~= "") then
		for i, v in ipairs(positions) do
			table.insert(categories, mw.ustring.format("[[Категория:%s]]", positionsPlural[v] or "Внеметовые чемпионы"))
		end
	else
		table.insert(categories, "[[Категория:Внеметовые чемпионы]]")
	end
	
	return table.concat(categories, "")
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 FN        = require('Module:Filename')
    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 FN = require("Модуль:Filename")
    local tableNode = mw.html.create("table")
    tableNode
        :addClass("article-table 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()
            :newline()
            :done()
    
    local champions  = mw.loadData("Module:ChampionData/data")
    for k, v in lib.pairsByAlphabeticalKeys(champions) do
        if(k ~= "Мега-Гнар" and k ~= "Клед и Скарл") then
        	local championNode = mw.html.create("div")
        	championNode
        		:cssText("width:100%; display:flex; align-items:center;")
        		:tag("div")
        			:css("margin", "5px")
        			:wikitext(
        				mw.ustring.format(
        					"[[File:%s|64px|link=%s]]",
        					FN.championsquare{
        						["champion"] = k,
        						["engname"] = p.get{k, "engname"}
        					},
        					k
        				)
        			)
        			:done()
        		:tag("div")
        			:wikitext(tostring(p.championIcon{
        				["champion"] = k,
        				["text"] = k .. "<br />" .. p.get{k, "title"},
        				["image"] = "*none*"
        			}))
        			:done()
        		:done()
        	
            local rowNode = mw.html.create("tr")
            rowNode
                :tag("td")
                    :css("text-align", "left")
                    :attr("data-sort-value", k)
                    :node(championNode)
                    :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()
                :newline()
            :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.createDialogue(frame)
	local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
	
	if(args[1] == nil) then
		return
	end
	
	-- Итератор по нечетным индексам массива
	function oddIterator(t)
      local current = -1
      local length = table.getn(t)
      return function ()
            current = current + 2
            if(current <= length) then
            	return current, t[current]
            end
		end
    end
	
	local dialogue = ""
	
	for i, v in oddIterator(args) do
		dialogue = dialogue .. mw.ustring.format("'''%s''': %s\n", args[i], args[i + 1] or "Реплика отсутствует")
	end
	
	return dialogue
end

--[[
Данная функция создает таблицу с рейтингом чемпионов по указанной характеристике на указанном уровне (1 по умолчанию)
Указываются первые и последние 5 чемпионов
Если у нескольких чемпионов одинаковое значение характеристики, они будут даны в одной ячейке
]]
function p.getMinMaxStatTable(frame)
	local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
	
	local stat = args["stat"] or args[1]
	local level = tonumber(args["level"] or args[2]) or 1
	local rows = tonumber(args["rows"] or args[3]) or 5
	
	local baseStat = stat .. "_base"
	local lvlStat = stat .. "_lvl"
	local champions = mw.loadData("Модуль:ChampionData/data")
	local FD = require("Модуль:Fd")
	
	-- Сортировка базовых значений по возрастанию
	-- Замыкание - зависит от level
	local function compareStatAsc(a, b)
		local firstValue = _statFormula(a["base"], a["lvl"], level)
		local secondValue = _statFormula(b["base"], b["lvl"], level)
		if(stat == "as") then
			firstValue = _statFormulaAS(a["base"], a["lvl"], level)
			secondValue = _statFormulaAS(b["base"], b["lvl"], level)
		end
		if(firstValue == secondValue) then return a["name"] < b["name"] end
		return firstValue < secondValue
	end
	-- Сортировка базовых значений по убыванию
	-- Замыкание - зависит от level
	local function compareStatDsc(a, b)
		local firstValue = _statFormula(a["base"], a["lvl"], level)
		local secondValue = _statFormula(b["base"], b["lvl"], level)
		if(stat == "as") then
			firstValue = _statFormulaAS(a["base"], a["lvl"], level)
			secondValue = _statFormulaAS(b["base"], b["lvl"], level)
		end
		if(firstValue == secondValue) then return a["name"] < b["name"] end
		return firstValue > secondValue
	end
	
	-- Таблица соответствий кода характеристики и родительного падежа (для итоговой таблицы)
	local codeToGenitive = {
		["dam"]  = "силы атаки",
		["as"]   = "скорости атаки",
		["hp"]   = "здоровья",
		["hp5"]  = "восстановления здоровья",
		["arm"]  = "брони",
		["mr"]   = "сопротивления магии",
		["mp"]   = "маны",
		["mp5"]  = "восстановления маны",
	}
	
	-- Таблица фильтрованных чемпионов
	local mappedChampions = {}
	
	local index = 1
	for k, v in pairs(champions) do
		if(v["stats"][baseStat]) then
			mappedChampions[index] = { ["name"] = k }
			
			-- Особый подсчет, если рассматривается скорость атаки
			if(stat == "as") then
				local baseAS = v["stats"]["as_base"]
		        local asRatio = v["stats"]["as_ratio"] or v["stats"]["as_base"]
		        local bonusAt1 = v["stats"]["as_lvl1_bonus"] or 0
		        mappedChampions[index]["base"] = baseAS * (1 + 0.01 * bonusAt1)
		        mappedChampions[index]["lvl"] = v["stats"]["as_lvl"]
			else
				mappedChampions[index]["base"] = v["stats"][baseStat]
				mappedChampions[index]["lvl"] = v["stats"][lvlStat]
			end
		end
		-- Если рассматривается мана, исключить чемпионов с альт. ресурсами
		if((stat == "mp" or stat == "mp5") and mw.ustring.lower(v["resource"]) ~= "мана") then
			mappedChampions[index] = nil
			index = index - 1
		end
		index = index + 1
	end
	
	local tableNode = mw.html.create("table")
	tableNode
		:addClass("wikitable")
		:attr("width", "90%")
		:done()
	
	-- Заголовок таблицы
	tableNode
		:tag("tr")
			:tag("th")
				:wikitext("Уровень чемпиона")
				:attr("width", "20%")
				:done()
			:tag("th")
				:wikitext("Первые 5 чемпионов")
				:attr("colspan", "2")
				:attr("width")
				:done()
			:tag("th")
				:wikitext("Последние 5 чемпионов")
				:attr("colspan", "2")
				:done()
			:done()
		:done()
	
	-- создаются две таблицы: чемпионы по возрастанию и по убыванию
	table.sort(mappedChampions, compareStatDsc)
	local championsDescending = lib.cloneTable(mappedChampions)
	table.sort(mappedChampions, compareStatAsc)
	local championsAscending = lib.cloneTable(mappedChampions)
	
	local rowIndex = 1 -- индекс строки таблицы рейтинга
	local descIndex = 1 -- Индекс чемпионов с наибольшего
	local ascIndex = 1 -- Индекс чемпионов с наименьшего
	repeat
		-- Если есть несколько чемпионов с одинаковым значением характеристики - объединить в список
		local currentTopList = {}
		local currentTopValue
		if(stat == "as") then
			currentTopValue = _statFormulaAS(
				championsDescending[descIndex]["base"],
				championsDescending[descIndex]["lvl"],
				level
			)
		else
			currentTopValue = _statFormula(
				championsDescending[descIndex]["base"],
				championsDescending[descIndex]["lvl"],
				level
			)
		end
		table.insert(currentTopList, tostring(p.championIcon{championsDescending[descIndex]["name"]}))
		repeat
			local nextTopValue
			if(stat == "as") then
				nextTopValue = _statFormulaAS(
					championsDescending[descIndex + 1]["base"],
					championsDescending[descIndex + 1]["lvl"],
					level
				)
			else
				nextTopValue = _statFormula(
					championsDescending[descIndex + 1]["base"],
					championsDescending[descIndex + 1]["lvl"],
					level
				)
			end
			if(currentTopValue == nextTopValue) then
				table.insert(currentTopList, tostring(p.championIcon{championsDescending[descIndex + 1]["name"]}))
				descIndex = descIndex + 1
			else
				descIndex = descIndex + 1
				break
			end
		until(descIndex > #championsDescending or currentTopValue ~= nextTopValue)
		local currentTopString = mw.ustring.format("%d. %s", rowIndex, table.concat(currentTopList, "<br />" .. rowIndex .. ". "))
		--mw.log(currentTopString)
		
		-- Если есть несколько чемпионов с одинаковым значением с конца - объединить в нумерованный список
		local currentBotList = {}
		local currentBotValue
		if(stat == "as") then
			currentBotValue = _statFormulaAS(
				championsAscending[ascIndex]["base"],
				championsAscending[ascIndex]["lvl"],
				level
			)
		else
			currentBotValue = _statFormula(
				championsAscending[ascIndex]["base"],
				championsAscending[ascIndex]["lvl"],
				level
			)
		end
		table.insert(currentBotList, tostring(p.championIcon{championsAscending[ascIndex]["name"]}))
		repeat
			local nextBotValue
			if(stat == "as") then
				nextBotValue = _statFormulaAS(
					championsAscending[ascIndex + 1]["base"],
					championsAscending[ascIndex + 1]["lvl"],
					level
				)
			else
				nextBotValue = _statFormula(
					championsAscending[ascIndex + 1]["base"],
					championsAscending[ascIndex + 1]["lvl"],
					level
				)
			end
			if(currentBotValue == nextBotValue) then
				table.insert(currentBotList, tostring(p.championIcon{championsAscending[ascIndex + 1]["name"]}))
				ascIndex = ascIndex + 1
			else
				ascIndex = ascIndex + 1
				break
			end
		until(ascIndex > #championsAscending or currentBotValue ~= nextBotValue)
		local currentBotString = mw.ustring.format("%d. %s", rowIndex, table.concat(currentBotList, "<br />" .. rowIndex .. ". "))
		--mw.log(currentBotString)
		
		local rowNode = mw.html.create("tr")
		if(rowIndex == 1) then
			rowNode
				:tag("th")
					:wikitext("Уровень " .. tostring(level))
					:attr("rowspan", tostring(rows))
					:done()
				:done()
		end
		
		-- Добавление сведений в таблицу
		rowNode
			:tag("td")
				:wikitext(currentTopString)
				:done()
			:tag("td")
				:wikitext(lib.round(currentTopValue, 4))
				:done()
			:tag("td")
				:wikitext(currentBotString)
				:done()
			:tag("td")
				:wikitext(lib.round(currentBotValue, 4))
				:done()
			:newline()
			:done()
		
		tableNode:node(rowNode):newline()
		
		rowIndex = rowIndex + 1
	until(rowIndex > rows)
	
	tableNode:allDone()
	
	return tostring(tableNode)
end

function p.getNoAPChampions(frame)
	local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
	
	local noAPChampions = mw.loadData("Модуль:ChampionData/NoAP")
	local SI = require("Модуль:Stats icon")
	local lang = mw.language.new("ru")
	
	local issuedChampion = args["champion"] or args[1]
	
	local result = ""
	--mw.log(IL.champion{"Анивия"})
	if(issuedChampion == nil or noAPChampions[issuedChampion] == false) then
		local iconTable = {}
		local championCount = 0
		for k in lib.pairsByAlphabeticalKeys(noAPChampions) do
			table.insert(iconTable, tostring(p.championIcon{k}))
			championCount = championCount + 1
		end
		result = mw.ustring.format(
			"Следующие %d %s не имеют ни одного умения, зависящего от %s: %s",
			championCount,
			lang:plural(championCount, {"чемпион", "чемпиона", "чемпионов"}),
			SI.statisticIcon{"силы умений", ["addlink"] = "true"},
			table.concat(iconTable, ", ")
			)
	else
		local iconTable = {}
		local championCount = 0
		for k in lib.pairsByAlphabeticalKeys(noAPChampions) do
			if(k ~= issuedChampion) then
				table.insert(iconTable, tostring(p.championIcon{k}))
			end
			championCount = championCount + 1
		end
		result = mw.ustring.format(
			"%s является одним из %d %s, которые не имеют ни одного умения, зависящего от %s. Остальные чемпионы: %s",
			tostring(p.championIcon{issuedChampion}),
			championCount,
			lang:plural(championCount, {"чемпион", "чемпионов"}),
			SI.statisticIcon{"силы умений", ["addlink"] = "true"},
			table.concat(iconTable, ", ")
			)
	end
	
	return result
end

--
-- local funtions
-- 

function _buildBaseStats(champions)
    local FD = require('Модуль:Fd')
	local FN = require('Module:Filename')
    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')
	local FN        = require('Module:Filename')
    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')
	local FN        = require('Module:Filename')
    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')
	local FN        = require('Module:Filename')
    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

--[[
Формула расчета характеристики в зависимости от уровня чемпиона
b - базовое значение
g - коэффициент прироста
n - уровень чемпиона
]]
function _statFormula(b, g, n)
	return b + g * (n - 1) * (0.685 + 0.0175 * n)
end

-- Модификация формулы для скорости атаки
function _statFormulaAS(b, g, n)
	return b * (1 + g * 0.01 * (n - 1) * (0.685 + 0.0175 * n))
end

-- Проверяет написание имени на частые ошибки или популярное альтернативное имя чемпиона
-- Если замена найдена, возващает её, иначе возвращает первоначально переданное имя
function _validateName(champion)
	local validator = mw.loadData("Модуль:ChampionData/Validator")
	return validator[champion] or champion
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]]
Advertisement