League of Legends Wiki
League of Legends Wiki
м (Страница «Модуль:UniverseData» защищена: популярная страница (‎[edit=autoconfirmed] (истекает 21:12, февраля 6, 2021 (UTC)) ‎[move=autoconfirmed] (истекает 21:12, февраля 6, 2)
(getCategories: Исправлены ошибки)
Строка 81: Строка 81:
   
 
-- Выдает категории, соответствующие данному представителю лора игры
 
-- Выдает категории, соответствующие данному представителю лора игры
  +
-- Изменения в этой функции полноценное не обновляются на страницах
  +
-- Для подтверждения изменений необходимо сделать нулевую правку с помощью бота
 
function p.getCategories(frame)
 
function p.getCategories(frame)
 
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
 
 
local cData = require("Модуль:ChampionData")
 
local cData = require("Модуль:ChampionData")
 
local name = args['lore'] or args[1]
 
 
local s = ""
+
local lorePiece = loreData[name]
 
if lorePiece == nil then
local t = loreData[args[1]] or loreData["Что-то пошло не так"]
 
  +
return userError(
local loretype = t.loretype or "Недостаточно информации"
 
  +
'Указанный объект лора не найден в Модуль:UniverseData/data',
local starring = t.starring or {}
 
  +
'LuaError')
local mentioned = t.mentioned or {}
 
 
end
local region = t.region or {}
 
local outdated = t.outdated or {}
 
local count = 0
 
 
 
  +
local loretype = lorePiece.loretype
if outdated == true then
 
 
if loretype == nil then
s = s .. "[[Категория:Старый лор]]" .. "{{Устаревший лор}}"
 
  +
return userError(
else
 
  +
'Не указан тип лора для ' .. name .. 'Модуль:UniverseData/data',
if t.au == "True" then
 
if loretype == "Видео" then
+
'LuaError')
  +
end
s = s .. "[[Категория:Видеоролики АВ]]"
 
  +
 
local starring = lorePiece.starring or {}
 
local mentioned = lorePiece.mentioned or {}
  +
local count = 0 -- Счетчик для числа участвующих/упомянутых чемпионов (length не работает)
  +
  +
  +
-- Костыль: Lua не воспринимает таблицы от loadData за последовательности, даже если они являются таковыми
  +
local loreRegions = {}
  +
if lorePiece.region then
 
for k, v in pairs(lorePiece.region) do
  +
table.insert(loreRegions, v)
  +
end
  +
end
  +
  +
-- Заносит названия категорий в таблицу, а в конце собирает её в строку
  +
local categoryList = {}
 
local result = ""
  +
  +
-- Устаревший лор
 
if lorePiece.outdated then
  +
table.insert(categoryList, "Устаревший лор")
 
result = result .. "{{Устаревший лор}}"
 
else
  +
-- Альтернативные вселенные
 
if lorePiece.au then
  +
if loretype ~= "Вселенная" then
  +
table.insert(categoryList, mw.ustring.format(
  +
"%s альтернативных вселенных",
 
_loretypePlural(loretype))
  +
)
 
else
 
else
 
table.insert(categoryList, "Альтернативная вселенная")
s = s .. "[[Категория:" .. _loretypePlural(loretype) .. " АВ]]"
 
 
end
 
end
  +
table.insert(categoryList, lorePiece.au)
 
else
 
else
  +
-- Если указан регион (только для основной вселенной)
if region ~= nil then
 
for i, region in pairs(region) do
+
if #loreRegions > 0 then
s = s .. "[[Категория:Лор " .. _regionGenitive(region) .. "]]"
+
for i, region in ipairs(loreRegions) do
  +
table.insert(categoryList, "Лор " .. _regionGenitive(region))
 
end
 
end
 
else
 
else
s = s .. "[[Категория:Лор без указания места действия]]"
+
table.insert(categoryList, "Лор Рунтерры")
 
end
 
end
local pluralLoretype = _loretypePlural(loretype)
+
-- Категория по типу лора
  +
table.insert(categoryList, _loretypePlural(loretype))
s = s .. mw.ustring.format("[[Категория:%s]]", pluralLoretype)
 
 
end
 
end
 
 
  +
-- Чемпионы
 
for i, champion in pairs(starring) do
 
for i, champion in pairs(starring) do
s = s .. "[[Категория:Лор " .. cData.get({champion, "genitive"}) .. "]]"
+
table.insert(categoryList, "Лор " .. cData.get{champion, "genitive"})
 
count = count + 1
 
count = count + 1
 
end
 
end
 
 
 
for i, champion in pairs(mentioned) do
 
for i, champion in pairs(mentioned) do
s = s .. "[[Категория:Лор " .. cData.get({champion, "genitive"}) .. "]]"
+
table.insert(categoryList, "Лор " .. cData.get{champion, "genitive"})
 
end
 
end
 
 
 
if count == 0 then
 
if count == 0 then
s = s .. "[[Категория:Лор без участия чемпионов]]"
+
table.insert(categoryList, "Лор без чемпионов")
 
end
 
end
 
end
 
end
 
 
return s
+
for i, v in ipairs(categoryList) do
 
categoryList[i] = mw.ustring.format("[[Категория:%s]]", v)
  +
end
  +
  +
result = result .. table.concat(categoryList, "\r\n")
  +
  +
return result
 
end
 
end
   
Строка 910: Строка 950:
 
end
 
end
   
-- Выдает множественное число из списка, иначле просто возвращает аргумент
+
-- Выдает множественное число из списка, иначе просто возвращает аргумент
 
-- В Lua нет switch/case!!!
 
-- В Lua нет switch/case!!!
 
function _loretypePlural(ltype)
 
function _loretypePlural(ltype)
 
 
local loretypePlurals = {
 
local loretypePlurals = {
{"Биография", "Биографии"},
+
['Биография'] = "Биографии",
{"Видео", "Видеоролики"},
+
['Видео'] = "Видеоролики",
{"Комикс", "Комиксы"},
+
['Комикс'] = "Комиксы",
{"Рассказ", "Рассказы"},
+
['Рассказ'] = "Рассказы",
{"Территория", "Территории"},
+
['Территории']= "Территории",
{"Фракция", "Фракции"},
+
['Фракция'] = "Фракции",
{"Клип", "Клипы"},
+
['Клип'] = "Клипы",
  +
['Вселенная'] = "Альтернативная вселенная",
{"Music Video", "Клипы"},
 
{"Вселенная", "Альтернативная вселенная"},
 
 
}
 
}
  +
for _, v in ipairs(loretypePlurals) do
 
if ltype == v[1] then return v[2] end
+
if loretypePlurals[ltype] then
  +
return loretypePlurals[ltype]
 
end
 
end
 
 

Версия от 12:27, 7 августа 2020

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

Список модулей

From Модуль:UniverseData/doc

-- <pre>

local p = {}

local loreData  = mw.loadData('Модуль:UniverseData/data')
local lib       = require('Модуль:Feature')
local FN        = require('Модуль:Filename')
local IL        = require('Модуль:ImageLink')
local skinData  = require('Модуль:SkinData/data')
local userError = require('Dev:User error')

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:UniverseData/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 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.loreTemplate()
    local loreList = mw.html.create('ul')
    local lore = {}
 
    for x in pairs(loreData) do
        table.insert(lore, x)
    end
    table.sort(lore)
 
    for _, piece in pairs(lore) do
        local t = loreData[piece]
        local link = piece
        local name = piece
        local loretype = t.loretype or "N/A"
        local starring = t.starring
        local entry = ''
        
        if starring then
            entry = '[[' .. link .. '|' .. name .. ']] <small>('.. getChampions(starring) ..')</small>'
        else
            entry = '[[' .. link .. '|' .. name .. ']]'
        end
        
        if loretype == "Рассказ" then
            loreList
                :tag('li')
                    :tag('div')
                        :wikitext(entry)
                    :done()
                :done()
                :newline()
        end
    end
    
    return loreList
end

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

    return _bannerNew(args[1])
end


-- Выдает категории, соответствующие данному представителю лора игры
-- Изменения в этой функции полноценное не обновляются на страницах
-- Для подтверждения изменений необходимо сделать нулевую правку с помощью бота
function p.getCategories(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    
    local cData = require("Модуль:ChampionData")
    local name = args['lore'] or args[1]
    
    local lorePiece = loreData[name]
    if lorePiece == nil then
        return userError(
            'Указанный объект лора не найден в Модуль:UniverseData/data',
            'LuaError')
    end
    
    local loretype = lorePiece.loretype
    if loretype == nil then
        return userError(
            'Не указан тип лора для ' .. name .. 'Модуль:UniverseData/data',
            'LuaError')
    end
    
    local starring = lorePiece.starring or {}
    local mentioned = lorePiece.mentioned or {}
    local count = 0 -- Счетчик для числа участвующих/упомянутых чемпионов (length не работает)
    
    
    -- Костыль: Lua не воспринимает таблицы от loadData за последовательности, даже если они являются таковыми
    local loreRegions = {}
    if lorePiece.region then
        for k, v in pairs(lorePiece.region) do 
            table.insert(loreRegions, v)
        end
    end
    
    -- Заносит названия категорий в таблицу, а в конце собирает её в строку
    local categoryList = {}
    local result = ""
    
    -- Устаревший лор
    if lorePiece.outdated then
        table.insert(categoryList, "Устаревший лор")
        result = result .. "{{Устаревший лор}}"
    else
        -- Альтернативные вселенные
        if lorePiece.au  then
            if loretype ~= "Вселенная" then
                table.insert(categoryList, mw.ustring.format(
                    "%s альтернативных вселенных", 
                    _loretypePlural(loretype))
                )
            else
                table.insert(categoryList, "Альтернативная вселенная")
            end
            table.insert(categoryList, lorePiece.au)
        else
            -- Если указан регион (только для основной вселенной)
            if #loreRegions > 0 then
                for i, region in ipairs(loreRegions) do
                    table.insert(categoryList, "Лор " .. _regionGenitive(region))
                end
            else
                table.insert(categoryList, "Лор Рунтерры")
            end
            -- Категория по типу лора
            table.insert(categoryList, _loretypePlural(loretype))
        end
        
        -- Чемпионы
        for i, champion in pairs(starring) do
            table.insert(categoryList, "Лор " .. cData.get{champion, "genitive"})
            count = count + 1
        end
        
        for i, champion in pairs(mentioned) do
            table.insert(categoryList, "Лор " .. cData.get{champion, "genitive"})
        end
        
        if count == 0 then
           table.insert(categoryList, "Лор без чемпионов")
        end
    end
    
    for i, v in ipairs(categoryList) do
        categoryList[i] = mw.ustring.format("[[Категория:%s]]", v)
    end
    
    result = result .. table.concat(categoryList, "\r\n")
    
    return result
end

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

    return loreData[args[1]].author or "Неизвестен"
end

function p.getAuthorlist(frame)
    local authors = {}
    local hash = {}
    local authorList = mw.html.create('ul')
 
    authorList:newline()
 
    for _, x in pairs(loreData) do
        if x.author ~= nil then
            if type(x.author) == "table" then
                for _, value in pairs(x.author) do
                    if (not hash[value]) then
                        table.insert(authors, value)
                        hash[value] = true
                    end
                end
            else
                if (not hash[x.author]) then
                    table.insert(authors, x.author)
                    hash[x.author] = true
                end
            end
        end
    end
    table.sort(authors)
 
    for _, author in pairs(authors) do
        authorList
            :tag('li')
                :wikitext('[[' .. author .. ']]')
                :done()
            :done()
            :newline()
    end
 
    return authorList
end

function p.getLorelist(frame)
    local loreList = mw.html.create('ul')
    local lore = {}
 
    for x in pairs(loreData) do
        table.insert(lore, x)
    end
    table.sort(lore)
 
    for _, piece in pairs(lore) do
        local t = loreData[piece]
        local link = piece
        local name = piece
        local loretype = t.loretype or "N/A"
        
        if loretype == "Biography" or loretype == "Биография" then
            link = t.starring[1]
        end
        
        loreList
            :tag('li')
                :tag('div')
                    :wikitext('[[' .. link .. '|' .. name .. ']] ('.. loretype ..')')
                :done()
            :done()
            :newline()
    end
    
    return loreList
end

-- Выдает в форме баннеров объекты лора, связанные с указанным чемпионом/персонажем
function p.getMore(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local champion      = args[1]
    local loreList      = ""
    local mentionedList = ""
    local auList        = ""
    local lore          = {}
 
    for x in pairs(loreData) do
        table.insert(lore, x)
    end
    table.sort(lore)
 
    loreList = loreList .. "<h3>Подробнее о чемпионе</h3>"
    for _, piece in pairs(lore) do
        local hit = false
        local t = loreData[piece]
 
        if t.starring ~= nil and t.loretype ~= "Биография" and t.loretype ~= "Фракция" and t.loretype ~= "Территория" and t.outdated ~= true then
            
            for _, substarring in pairs(t.starring) do
                if substarring == champion then
                    hit = true
                end
            end
        end
        if hit == true then
            if not(t.au) then
                loreList = loreList .. _bannerNew(piece)
            else
                auList = auList .. _bannerNew(piece)
            end
        end
    end
 
    for _, piece in pairs(lore) do
        local hit = false
        local t = loreData[piece]
 
        if t.mentioned ~= nil then
            for _, submentioned in pairs(t.mentioned) do
                if submentioned == champion then
                    hit = true
                end
            end
        end
        
        if hit == true then
            if not(t.au) then
                mentionedList = mentionedList .. _bannerNew(piece)
            else
                auList = auList .. _bannerNew(piece)
            end
        end
 
    end
 
    if mentionedList ~= "" then 
       loreList = loreList .. "\n<div class='va-collapsible-content mw-collapsible mw-collapsed' data-expandtext='Показать' data-collapsetext='Скрыть'><h3>Упоминается</h3><div class='va-collapsible-content mw-collapsible-content'>" .. mentionedList .. "</div>"
    end
 
    if auList ~= "" then 
       loreList = loreList .. "\n<div class='va-collapsible-content mw-collapsible mw-collapsed' data-expandtext='Показать' data-collapsetext='Скрыть'><h3>Альтернативная вселенная</h3><div class='va-collapsible-content mw-collapsible-content'>" .. auList .. "</div>"
    end
    
    return loreList
end

function p.getRegionlore(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local loreList = ""
    local lore = {}
    local result = false
 
    for x in pairs(loreData) do
        table.insert(lore, x)
    end
    table.sort(lore)
 
    for _, piece in pairs(lore) do
        local hit = false
        local t = loreData[piece]
        
        if (t.region ~= nil) then
            if type(t.region) == "table" then
                for _, subregion in pairs(t.region) do
                    if subregion == args[1] then
                        hit = true
                        result = true
                    end
                end
            else
                if t.region == args[1] then
                    hit = true
                    result = true
                end
            end
        else 
            if args[1] == "Рунтерра" then 
                hit = true
                result = true
            end
            
        end
    
        if hit == true then
            loreList = loreList .. _bannerNew(piece, t)
        end
    end
 
    if result == false then 
       loreList = "No match found for " .. args[1] .. "."
    end
 
    return loreList .. "[[Category:Test]]"
end

-- Выдает галерею загрузочных иллюстраций чемпионов, принадлежащик к указанной фракции
function p.getRegionExhibition(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local IL = require('Модуль:ImageLink')
    
    local isList = args['islist'] or "false"
    local result = ""
    
    if(isList ~= "false") then
        local championList = args['list'] or args[1]
        championList = mw.text.split(championList, '[,;]%s*')
        for i, v in ipairs(championList) do 
            result = result .. tostring(IL.loading({
                ['champion'] = v,
                ['display'] = 'inline-grid',
                ['labelstyle'] = "background-color:black; text-align:center; padding:2px 0;"
            }))
        end
        return result
    end
    
    local region = args['region'] or args[1]
    local champions = loreData[region].starring
    table.sort(champions)
    
    for _, v in pairs(champions) do 
        result = result .. tostring(IL.loading({
            ['champion'] = v,
            ['display'] = 'inline-grid',
            ['labelstyle'] = "background-color:black; text-align:center; padding:2px 0;"
        }))
    end
    
    return result
end

function p.getSkinlineBanner(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    
    local skinlines = mw.loadData('Модуль:UniverseData/skinlines')
    local sLineName = args['skinline'] or args[1]
    local sLine = skinlines[sLineName]
    
    -- Если линейки нет
    if sLine == nil then
        return userError('Линейка образов не найдена', 'LuaError')
    end
    
    -- Костыль: Lua не считает таблицы, переданные через mw.loadData за последовательности, даже если они считаются таковыми
    local authorTable = {}
    if(sLine.author) then
        for i, v in pairs(sLine.author) do
            table.insert(authorTable, v)
        end
    end
    
    -- Контейнер баннера
    local bannerNode = mw.html.create('div')
    bannerNode
        :attr('id', 'champinfo-container')
        :cssText("width:100%; min-height: 290px; overflow:hidden; position:relative; font-size:14px; color: #dddddd; display:flex")
        :done()
    
    -- Блок изображения
    local imageNode = mw.html.create('div')
    imageNode
        :addClass('FillImage')
        :cssText("width:100%; height:100%; position:absolute; top: 0; left:0; opacity:0.2; z-index: -1")
        :wikitext(mw.ustring.format("[[File:%s|link=]]", sLine.artwork))
        :newline()
    
    -- Ссылки на редактирование
    local editNode = mw.html.create('div')
    editNode
        :cssText("position: absolute; top: 0.1em; right: 1em; font-size:85%;")
        :tag('span')
            :addClass('plainlinks')
            :wikitext("[https://leagueoflegends.fandom.com/ru/wiki/Модуль:UniverseData/skinlines?action=edit Ред.]")
            :done()
        :wikitext(" • [[:File:" .. sLine.artwork .. "|Изобр.]]")
        :done()
    if(sLine.reference) then
        editNode:wikitext(" • [" .. sLine.reference.. " Ссылка]")
    end
    editNode:newline()
    
    -- Блок ID
    local idNode = mw.html.create('div')
    if(sLine.id) then
        idNode
            :cssText("position: absolute; left: 1em; top:0.1em; font-size:70%;")
            :wikitext(sLine.id)
            :done()
        bannerNode:node(idNode)
    end
    
    -- Текст
    local contentNode = mw.html.create('div')
    contentNode
        :cssText("text-align:center; width: 500px; margin:auto")
        :newline()
    local titleNode = mw.html.create('div')
    -- Текст: общий заголовок
    titleNode
        :css('margin', '3em 0')
        :tag('p')
            :css('margin-top', '1em')
            :wikitext('Набор образов')
            :done()
        :tag('p')
            :attr('id', 'title')
            :cssText("font-size:250%; line-height:100%; margin:0;color:#c9aa71")
            :wikitext("[[" .. sLineName .. "]]")
            :done()
        :newline()
    -- Текст: Является частью альтернативной вселенной?
    if(sLine.au) then
        titleNode
            :tag('p')
                :css('margin-top', '1em')
                :wikitext(mw.ustring.format("Вселенная: [[%s]]", sLine.au))
                :done()
            :newline()
    end
    -- Текст: Авторы
    if(sLine.author) then
        titleNode
            :tag('p')
                :css('margin-top', '-1em')
                :wikitext(mw.ustring.format("%s: %s",
                    lib.ternary(#authorTable == 1, "Автор", "Авторы"),
                    mw.text.listToText(authorTable, ", ")
                    ))
                :done()
            :done()
    end
    -- Текст: Представленные чемпионы
    titleNode
        :tag('p')
            :attr('id', 'featured')
            :css('margin-top', '1em')
            :wikitext("Представители: " .. getChampions(sLine.starring))
            :done()
        :newline()
    contentNode:node(titleNode)
            
    -- Сборка
    bannerNode
        :node(imageNode)
        :node(editNode)
        :node(contentNode)
    
    return tostring(bannerNode)
end

function p.getSkinlineCategories(frame)
    -- TODO
end

function p.getSkinlineDescription(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]
    champion = lib.validateName(champion)
    local skin     = args['skin'] or args[2] or "Классический"
    local isListItem = args['li']
    if(champion == nil) then 
        return userError('Не указан чемпион', 'LuaError')
    end
    if(skin == "Классический" or skin == "Классическая") then return end
    
    local skinlineData = mw.loadData('Модуль:UniverseData/skinlines')
    local auData = mw.loadData('Модуль:UniverseData/au')
    
    local setName = skinData[champion]['skins'][skin]['set']
    if(setName == nil) then return end
    if(skinlineData[setName[1]] == nil) then
        return userError(
            'Линейка образов ' .. setName[1] .. ' не найдена в Модуль:UniverseData/skinlines',
            'LuaError')
    end
    
    -- Построение фразы типа:
    -- "Этот образ в ходит в линейку образов K/DA, которая является частью вселенной Музыкальные образы"
    local s = mw.ustring.format("Этот образ входит в линейку образов [[%s]]", setName[1])
    if(skinlineData[setName[1]].au) then
        s = s .. " из вселенной [[" .. skinlineData[setName[1]].au .. "]]"
    end
    s = s .. "."
    
    -- Все остальные чемпионы из этой линейки
    local skinlineChampions = {}
    for i, v in pairs(skinlineData[setName[1]].starring) do
        table.insert(skinlineChampions, v)
    end
    
    -- Список пар чемпион-образ из этой линейки
    local csPairs = {} -- csPairs = champion-skin pairs
    for i, slChampion in ipairs(skinlineChampions) do
        -- Найти все входящие в линейку пары "чемпион-образ"
        local currentPairs = _findSkinforSet(slChampion, setName[1])
        -- исключить добавление пустой пары
        if(#currentPairs > 0) then
            for j, pairValue in ipairs(currentPairs) do
                if(slChampion ~= champion or pairValue[2] ~= skin) then
                    table.insert(csPairs, pairValue)
                end
            end
        end
    end
    
    s = s .. " В эту линейку также входят:"
    
    local listNode = mw.html.create('ul')
    if(#csPairs > 5) then -- Если больше 5 образов, то разбить на колонки
        listNode
            :addClass('columntemplate')
            :cssText("-moz-column-count:2; -webkit-column-count:2; column-count:2")
    end
    
    for i, v in ipairs(csPairs) do
        listNode
            :tag('li')
                :wikitext(tostring(IL.skin{
                    ["champion"] = v[1],
                    ["skin"]     = v[2],
                    ["link"]     = v[1] .. "/Образы",
                    ["circle"]   = "true"
                    }))
                :newline()
            :done()
    end
    
    -- Если нужно сделать частью общего маркированного списка
    local textNode = mw.html.create('ul')
    if(isListItem) then
        textNode
            :tag('li')
                :wikitext(s)
                :newline()
                :node(listNode)
                :done()
            :done()
        return tostring(textNode)
    end
    
    return s .. tostring(listNode)
    
end

-- local functions
function _banner(name)
    local piece = loreData[name] or loreData["Что-то пошло не так"]
    local s = ""
    local lang = mw.language.new("ru")
    local bName = piece.displayname or name
    local artwork = piece.artwork or "Bard promo 2.jpg"
    local author = piece.author or "неизвестен"
    local reference = piece.reference or "https://universe.leagueoflegends.com/ru_RU/"
    local link = name
    local region = "Рунтерра"
    local duration = piece.duration or "0"
    local starring = "N/A"
    local mentioned = "N/A"
    local canon = piece.outdated or ""
    local loretype = piece.loretype or ""
    local description = piece.description or ""
    
    if loretype == "Биография" then link = piece.starring[1] end
    if piece.region ~= nil then region = piece.region[1] end
    if piece.starring ~= nil then starring = getChampions(piece.starring) end
    if piece.mentioned ~= nil then mentioned = getChampions(piece.mentioned) end
    
    s = s .. "<div id='champinfo-container' style='width:100%; min-height: 290px; overflow:hidden; position:relative; font-size:14px; color: #dddddd; display:flex;'>"
        --image
        s = s .. "<div class='FillImage' style='width:100%; height:100%; position:absolute; top: 0; left:0; opacity:0.2; z-index: -1;'>[[File:" .. artwork .."|link=]]</div>"
        --/image
        --edit
        s = s .. "<sup style='position: absolute; top: 1em; right: 1em;'><span class='plainlinks'>[https://leagueoflegends.fandom.com/ru/wiki/Модуль:UniverseData/data?action=edit Ред.]</span> • [[:File:" .. artwork .."|Изобр.]] • [" .. reference.. " Ссылка]</sup>"
        --/edit
        --content
        s = s .. "<div style='text-align:center; width: 500px; margin:auto;'><div style='margin:3em 0'>"
            
            s = s .. "<p id='title' style='margin:1em 0 1em 0;'>[[File:" .. region .. " Герб иконка.png|x56px|link=" .. region .."]]</p>"
            
            if loretype == "Рассказ" then
                if duration == "0" then
                    s = s .. "<p id='duration' style='margin:1em 0 0 0;'> Рассказ </p>"
                else
                    s = s .. "<p id='duration' style='margin:1em 0 0 0;'> Рассказ • На " .. duration .. " " .. lang:convertPlural(duration, 'минута', 'минуты', 'минут') .. " </p>"
                end
            else
                s = s .. "<p id='duration' style='margin:1em 0 0 0;'>" .. loretype .. "</p>"
            end
            
            if piece.previous ~= nil then
                s = s .. "<div style='position: absolute; top: 50%; left:1em; font-size:3em;'>[[" .. piece.previous .. "|◄]]</div>"
            end
            
            s = s .. "<p id='title' style='font-size:250%; line-height:100%; margin:0;color:#c9aa71;'>[[" .. link .. "|" .. bName .."]]</p>"
            
            if loretype ~= "Видео" then
                s = s .. "<p id='duration' style='margin:0 0 1em 0;'> "
                
                if type(author) == "table" then
                    s = s .. "Авторы: "
                    for i, value in ipairs(author) do
                        if i ~= 1 then
                            s = s  .. ", "
                        end
                        s = s .. value
                    end
                else
                    s = s .. "Автор: " .. author
                end
                s = s .. "</p>"
            end
            
            if piece.following ~= nil then
                s = s .. "<div style='position: absolute; top: 50%; right: 1em; font-size:3em;'>[[" .. piece.following .. "|►]]</div>"
            end
            
            if loretype ~= "Биография" then 
                s = s .. "<p id='blurb' style='margin:1em 0 1em 0; font-size: 89%; text-transform: initial;'>" .. description:gsub("//n", "<br/>") .."</p>"
            end
            
            if starring ~= nil and loretype ~= "Биография" then
                s = s .. "<p id='featured' style='margin:0 0 1em 0;'>"
                if loretype == "Фракция" or loretype == "Территория" then
                    s = s .. "Представители: "
                else
                    s = s .. "Действующие лица: "
                end    
                s = s .. starring .. "</p>"
            end
            
            if mentioned ~= "N/A" then
                s = s .. "<p id='featured' style='margin:0 0 1em 0;'>Упоминаются: " .. mentioned .. "</p>"
            end
        
        s = s .. "</div></div>"
        --/content
    s = s .. "</div>"

    return s
end

function _bannerNew(name)
    local lorePiece = loreData[name] or loreData["Что-то пошло не так"]
    local lang = mw.language.new('ru')
    local bName = lorePiece.displayname or name
    local artwork = lorePiece.artwork or "Bard promo 2.jpg"
    local author = lorePiece.author or {"неизвестен"}
    local reference = lorePiece.reference or "https://universe.leagueoflegends.com/ru_RU/"
    local link = name
    local region = "Рунтерра"
    local duration = lorePiece.duration or "0"
    local starring = "N/A"
    local mentioned = "N/A"
    local canon = lorePiece.outdated or ""
    local loretype = lorePiece.loretype or ""
    local description = lorePiece.description or ""
    local au = lorePiece.au or "Рунтерра"
    
    if loretype == "Биография" then link = lorePiece.starring[1] end
    if type(author) == "string" then author = {author} end
    if lorePiece.region ~= nil then region = lorePiece.region[1] end
    if lorePiece.starring ~= nil then 
        starring = getChampions(lorePiece.starring)
    elseif au ~= "Рунтерра" then
        starring = getChampions(_mergeSkinlines(au))
    end
    if lorePiece.mentioned ~= nil then mentioned = getChampions(lorePiece.mentioned) end
    
    --flag tables - для более быстрого поиска совпадений
    local restrictAuthors = { -- Не показывать блок "Авторы"
        ["Видео"] = true,
        ["Вселенная"] = true,
        ["Аудиоспектакль"] = true,
        ["Территория"] = true,
        ["Фракция"] = true,
    }
    local starringTable = { -- Не "Действующие лица" для некоторых типов лора
        ["Вселенная"] = "Представители",
        ["Территория"] = "Представители",
        ["Фракция"] = "Представители",
    }
    
    local bannerNode = mw.html.create('div')
    bannerNode
        :attr('id', 'champinfo-container')
        :cssText("width:100%; min-height: 290px; overflow:hidden; position:relative; font-size:14px; color: #dddddd; display:flex")
        :newline()
        :done()
    
    -- Блок изображения
    local imageNode = mw.html.create('div')
    imageNode
        :addClass('FillImage')
        :cssText("width:100%; height:100%; position:absolute; top: 0; left:0; opacity:0.2; z-index: -1")
        :wikitext(mw.ustring.format("[[File:%s|link=]]", artwork))
        :newline()
    
    -- Ссылки на редактирование
    local editNode = mw.html.create('div')
    editNode
        :cssText("position: absolute; top: 0.1em; right: 1em; font-size:85%;")
        :tag('span')
            :addClass('plainlinks')
            :wikitext("[https://leagueoflegends.fandom.com/ru/wiki/Модуль:UniverseData/data?action=edit Ред.]")
            :done()
        :wikitext(mw.ustring.format(
            " • [[:File:%s|Изобр.]] • [%s Ссылка]",
            artwork,
            reference))
        :newline()
        :done()
    
    -- Текст
    local contentNode = mw.html.create('div')
    contentNode
        :cssText("text-align:center; width: 500px; margin:auto")
        :newline()
        :done()
    
    local titleNode = mw.html.create('div')
    -- Текст: иконка региона
    titleNode
        :css('margin', '3em 0')
        :tag('p')
            :attr('id', 'title')
            :css('margin', '1em 0')
            :wikitext(mw.ustring.format(
                "[[File:%s|x56px|link=%s]]",
                FN.faction{['faction'] = region},
                region))
            :done()
        :newline()
    -- Текст: Типа лора (для рассказа - указать длительность)
    if(loretype == "Рассказ" and duration ~= "0") then
        titleNode
            :tag('p')
                :attr('id', 'duration')
                :css('margin-top', '1em')
                :wikitext(mw.ustring.format(
                    "Рассказ • На %d %s",
                    duration,
                    lang:convertPlural(duration, 'минута', 'минуты', 'минут')))
                :done()
            :newline()
    else
        titleNode
            :tag('p')
                :attr('id', 'duration')
                :css('margin-top', '1em')
                :wikitext(loretype)
                :done()
            :newline()
    end
    -- Текст: Название лора
    titleNode
        :tag('p')
            :attr('id', 'title')
            :cssText("font-size:250%; line-height:100%; margin:0; color:#c9aa71")
            :wikitext("[[" .. bName .. "]]")
            :done()
        :newline()
    -- Текст: Вселенная
    if(au ~= "Рунтерра" and loretype ~= "Вселенная") then
        titleNode
            :tag('p')
                :css('margin-top', '1em')
                :wikitext(mw.ustring.format("Вселенная: [[%s]]", au))
                :done()
            :newline()
    end
    -- Текст: Авторы
    if(not(restrictAuthors[loretype])) then
        if(author[1] == "Numerous creators") then
            titleNode
                :tag('p')
                    :css('margin-top', '-1em')
                    :wikitext("Несколько авторов")
                    :done()
                :done()
        else
            titleNode
                :tag('p')
                    :css('margin-top', '1em')
                    :wikitext(mw.ustring.format("%s: %s",
                        lib.ternary(#author == 1, "Автор", "Авторы"),
                        mw.text.listToText(author, ", ")
                        ))
                    :done()
                :done()
        end
    end
    -- Текст: Представленные чемпионы
    if(starring ~= "N/A") then
        titleNode
            :tag('p')
                :attr('id', 'featured')
                :css('margin-top', '1em')
                :wikitext(
                    mw.ustring.format("%s: %s",
                    lib.ternary(starringTable[loretype], "Представители", "Действующие лица"),
                    starring))
                :done()
            :newline()
    end
    -- Текст: Упоминаемые чемпионы
    if(mentioned ~= "N/A") then
        titleNode
            :tag('p')
                :attr('id', 'featured')
                :css('margin-top', '1em')
                :wikitext(
                    mw.ustring.format("%s: %s",
                    "Упоминаются",
                    mentioned))
                :done()
            :newline()
    end
    contentNode:node(titleNode)
    
    -- Стрелки
    local previousNode
    if(lorePiece.previous) then 
        previousNode = mw.html.create('div')
        previousNode
            :cssText("position: absolute; top: 50%; left:1em; font-size:3em;")
            :wikitext("[[" .. lorePiece.previous .. "|◄]]")
            :newline()
            :done()
        bannerNode:node(previousNode)
    end
    local followingNode
    if(lorePiece.following) then 
        followingNode = mw.html.create('div')
        followingNode
            :cssText("position: absolute; top: 50%; right: 1em; font-size:3em;")
            :wikitext("[[" .. lorePiece.following .. "|►]]")
            :newline()
            :done()
        bannerNode:node(followingNode)
    end
    
    -- Сборка
    bannerNode
        :node(imageNode)
        :node(editNode)
        :node(contentNode)
        :done()
    return tostring(bannerNode)
end


--[[
========================
Приватные функции модуля
========================
]]
function getChampions(t)
    local s = ""
 
    local championtable  = {}
    for i, champion in pairs(t) do
        table.insert(championtable, champion)
    end
    table.sort(championtable)
 
    for i, champion in pairs(championtable) do
        if i ~= 1 then
            s = s  .. ", "
        end
            s = s .. "<span style='white-space:nowrap'>[[File:" .. champion .. " OriginalSquare.png|20px|link=" .. champion .. "]] [[" .. champion .. "]]</span>"
    end
 
    return s
end

-- Выдает множественное число из списка, иначе просто возвращает аргумент
-- В Lua нет switch/case!!!
function _loretypePlural(ltype)
    local loretypePlurals = {
        ['Биография'] = "Биографии",
        ['Видео']     = "Видеоролики",
        ['Комикс']    = "Комиксы",
        ['Рассказ']   = "Рассказы",
        ['Территории']= "Территории",
        ['Фракция']   = "Фракции",
        ['Клип']      = "Клипы",
        ['Вселенная'] = "Альтернативная вселенная",
    }
    
    if loretypePlurals[ltype] then
        return loretypePlurals[ltype]
    end
    
    return ltype
end

-- Возвращает название региона в родительном падеже
function _regionGenitive(region)
    if region == "Бандл сити" then
        return region
    elseif region == "Сумрачные острова" then
        return "Сумрачных островов"
    end
    
    local lastLetter = mw.ustring.sub(region, -1)
    if lastLetter == "я" then
        return mw.ustring.sub(region, 0, -2) .. "и" -- Демасия - Демасии
    elseif lastLetter == "а" then
        return mw.ustring.sub(region, 0, -2) .. "ы" -- Бездна - Бездны
    elseif lastLetter == "ь" then
        return mw.ustring.sub(region, 0, -2) .. "я" -- Ишталь - Ишталя
    end
   return region .. "а"
end

-- Находит образ чемпиона, принадлежащий указанной линейке (если есть)
-- Принимает на вход имя чемпиона и название линейки образов
-- На выходе дает таблицу всех подходящих образов (в т.ч. Престижные и парные)
function _findSkinforSet(champion, set)
    if(skinData[champion] == nil) then return {} end
    local allSkins = skinData[champion].skins
    local result = {}
    for skinKey, skinValue in pairs(allSkins) do
        if(skinValue.set) then
            if(type(skinValue.set) == "table") then
                for setKey, setValue in pairs(skinValue.set) do
                    if(setValue == set) then
                        table.insert(result, {champion, skinKey})
                    end
                end
            elseif(type(skinValue.set) == "string") then
                if(skinValue.set == set) then 
                    table.insert(result, {champion, skinKey})
                end
            end
        end
    end
    return result
end

-- Собирает в одну последовательность всех чемпионов из одной вселенной
-- (если эта вселенная содержит несколько линеек образов)
function _mergeSkinlines(universe)
    local auData  = mw.loadData('Модуль:UniverseData/au')
    local slData  = mw.loadData('Модуль:UniverseData/skinlines')
    
    local fetchedLines = auData[universe]
    if(fetchedLines == nil) then
        return userError([[
            Ошибка при соединении линеек образов. Проверьте, дано ли соответсвие "Вселенная"-"линейки образов" в Модуль:UniverseData/au для 
            ]] .. universe, 'LuaError')
    end
    
    -- Костыль: Lua не воспринимает таблицы из mw.loadData за последовательности, даже если они являются таковыми
    local skinlines = {}
    for k, v in pairs(fetchedLines) do
        table.insert(skinlines, v)
    end
    
    local championsOfUniverse = {}
    for i, skinline in ipairs(skinlines) do
        local champions = slData[skinline].starring
        for k, champOfSkinline in pairs(champions) do
            if(lib.find(championsOfUniverse, champOfSkinline) == -1) then
                table.insert(championsOfUniverse, champOfSkinline)
            end
        end
    end
    
    return championsOfUniverse
end

return p

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