Для документации этого модуля может быть создана страница Модуль:ItemData/doc
-- Содержит функции для вызова сведений о предметах. Замена вызовам шаблонов
-- Author: Mortorium
-- <pre>
local p = {}
local items = mw.loadData('Модуль:ItemData/data')
local get = require("Модуль:ItemData/getter")
local IL = require('Модуль:ImageLink')
local lib = require('Модуль:Feature')
local uError= 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 item = args['item'] or args[1]
local datatype = args['datatype'] or args[2]
local output = args['output'] or args[3] or nil
local omitnil = args['omitnil'] or true
if(get[datatype] == nil) then
return uError('Указанный параметр не существует')
end
local result = get[datatype](item)
if output ~= nil and type(result) == "table" then
if(args["index"]) then
local i = tonumber(args["index"])
if(result[i]) then
return frame:preprocess(result[i])
else
return ""
end
end
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'] or "Ii") .. "|", append = "}}", separator = args['separator']})
end
elseif type(result) == "string" then
return frame:preprocess{text = tostring(result)}
elseif result == nil and omitnil then
return ""
else
return result
end
end
function p.itemIcon(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local link = IL.item(args)
if(items[lib.validateItemName(args['item'])] == nil) then return link end
-- Заменить класс item-icon на item-lua-icon (в mw.html нет removeClass())
local classes = link:getAttr('class')
classes = mw.ustring.gsub(classes, 'item%-icon', 'item-lua-icon')
link:attr('class', classes)
return link
end
function p.getRoster(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local removed = args['removed'] or 'true'
local starters = {}
local consumables = {}
local trinkets = {}
local distributives = {}
local basic = {}
local enhanced = {}
local finished = {}
local unsorted = {}
for k, v in lib.pairsByAlphabeticalKeys(items) do
if(get.itemtype(k) == "Начальный") then table.insert(starters, k)
elseif(get.itemtype(k) == "Расходуемый") then
table.insert(consumables, k)
elseif(get.itemtype(k) == "Аксессуар") then
table.insert(trinkets, k)
elseif(get.itemtype(k) == "Предоставляемый") then
table.insert(distributives, k)
elseif(get.itemtype(k) == "Базовый" and get.champion(k) == nil) then
table.insert(basic, k)
elseif(get.itemtype(k) == "Улучшенный") then table.insert(enhanced, k)
elseif(get.itemtype(k) == "Завершенный" or get.itemtype(k) == "Зачарование"
or get.champion(k) ~= nil) then
table.insert(finished, k)
else table.insert(unsorted, k) end
end
-- Создать блок
local gridContainer = mw.html.create('div')
gridContainer:attr('id', 'grid'):newline()
local tableContainer = mw.html.create('div')
:attr('id', 'item-grid')
:addClass('centered-grid')
:cssText('clear:both; align:center;')
tableContainer
:tag('dl')
:tag('dt')
:wikitext('Начальные предметы')
:done()
:done()
:node(_buildItemListContainer(starters))
:newline()
:tag('dl')
:tag('dt')
:wikitext('Расходуемые предметы')
:done()
:done()
:node(_buildItemListContainer(consumables))
:newline()
:tag('dl')
:tag('dt')
:wikitext('Аксессуары')
:done()
:done()
:node(_buildItemListContainer(trinkets))
:newline()
:tag('dl')
:tag('dt')
:wikitext('Предоставляемые предметы')
:done()
:done()
:node(_buildItemListContainer(distributives))
:newline()
:tag('dl')
:tag('dt')
:wikitext('Базовые предметы')
:done()
:done()
:node(_buildItemListContainer(basic))
:newline()
:tag('dl')
:tag('dt')
:wikitext('Улучшенные предметы')
:done()
:done()
:node(_buildItemListContainer(enhanced))
:newline()
:tag('dl')
:tag('dt')
:wikitext('Завершенные предметы')
:done()
:done()
:node(_buildItemListContainer(finished))
:newline()
if(#unsorted > 0) then
mw.log('Something wrong')
for _, v in ipairs(unsorted) do mw.log(v) end
end
if(args['removed'] ~= "false") then
tableContainer
:tag('dl')
:tag('dt')
:wikitext('Удаленные предметы')
:done()
:done()
:wikitext(
[[<DPL>
category = Удаленные предметы
skipthispage = no
namespace = 0
mode = userformat
format = <div class="tlist"><ul>,<li>{{Предметы/Предмет|%PAGE%}}</li>,,</ul></div>
allowcachedresults = true
</DPL>]])
end
tableContainer:allDone()
gridContainer:node(tableContainer)
return frame:preprocess(tostring(gridContainer))
end
function p.getCategories(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local item = args['item'] or args[1]
if (not(items[item])) then
return frame:expandTemplate{title = "Removed", args = {category = "предмет"}}
end
local categories = {}
if(items[item].champion) then
table.insert(categories, "[[Категория:Эксклюзивные предметы]]")
end
if(items[item].itemtype) then
for i, v in ipairs(items[item].itemtype) do
if(v == "Зачарование") then
table.insert(categories, "[[Категория:Зачарования]][[Категория:Завершенные предметы]]")
elseif(v == "Аксессуар") then
table.insert(categories, "[[Категория:Аксессуары]]")
else
table.insert(categories,
"[[Категория:" .. mw.ustring.sub(v, 1, -2) .. "е предметы]]")
end
end
else
table.insert(categories,
"[[Категория:" .. mw.ustring.sub(get.itemtype(item), 1, -2) .. "е предметы]]")
end
local categoryTable = {
{"ap", "силу умений"},
{"armor", "броню"},
{"arpen", "пробивание брони"},
{"lethality", "смертоносность"},
{"ad", "силу атаки"},
{"as", "скорость атаки"},
{"cdr", "сокращение перезарядки"},
{"cdrunique", "сокращение перезарядки"},
{"crit", "шанс критического удара"},
{"critunique","шанс критического удара"},
{"gp10", "золото"},
{"hsp", "ЭЩИ"},
{"hp", "здоровье"},
{"lifesteal", "вампиризм"},
{"hp5", "восстановление здоровья"},
{"mr", "сопротивление магии"},
{"mpen", "магическое пробивание"},
{"mana", "ману"},
{"mp5", "восстановление маны"},
{"mp5flat", "восстановление маны"},
{"ms", "скорость передвижения"},
{"msflat", "скорость передвижения"},
{"msunique", "скорость передвижения"},
}
local itemStats = p.get{item, "stats"}
-- Постановка категорий по характеристикам
for _, v in pairs(categoryTable) do
if(itemStats[v[1]]) then
table.insert(categories, "[[Категория:Предметы на " .. v[2] .. "]]")
end
end
if(items[item].active) then
table.insert(categories, "[[Категория:Активируемые предметы]]")
end
local passives = items[item].passive
if(passives) then
for i, v in ipairs(passives) do
-- Регулярное выражение: если есть первый параметр в шаблоне Unique
if(mw.ustring.match(v, "{{[Uu]nique|[%a%s]+|")) then
table.insert(categories, "[[Категория:Предметы с именованными эффектами]]")
end
end
end
return table.concat(categories)
end
-- Генерирует стандартное вступление к статье о предмете
function p.getIntroduction(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local item = args['item'] or args[1]
local append = args['append'] or args[2]
local itemData = items[item]
local str = mw.ustring.format("'''%s''' {{англ|%s}} – это ",
item,
itemData.engname)
local itemType = mw.ustring.lower(get.itemtype(item))
if((itemType == "аксессуар")
or (itemType == "зачарование")) then
str = str .. itemType
else
str = str .. itemType .. " предмет в [[League of Legends]]"
end
if(itemData.champion) then
str = str .. mw.ustring.format(" для чемпиона {{ci|%s}}", itemData.champion)
end
if(get.maps(item) ~= nil) then
if(get.SR(item)) then
str = str .. ". Доступен исключительно в {{tip|Ущелье призывателей}}"
elseif(get.HA(item)) then
str = str .. ". Доступен исключительно в {{tip|Воющая бездна|Воющей бездне}}"
end
end
str = str .. "."
if(append ~= nil) then str = str .. " " .. append end
return frame:preprocess(str)
end
-- Выводит состав предмета в виде строчной суммы из иконок
function p.getInfoboxRecipe(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local item = args['item'] or args[1]
local size = args['size'] or "32"
-- Если такого предмета нет
if(not(items[item])) then
return uError('Указанный предмет не найден')
end
-- Если у предмета нет состава
if(not(items[item].recipe)) then
return
end
local s = ""
for i, v in pairs(items[item].recipe) do
s = s .. tostring(p.itemIcon({
["item"] = v,
["size"] = size,
["text"] = "*none*"
}))
if(i < #item - 1) then
s = s .. "{{plus}}"
end
end
s = s .. "{{g|" .. (items[item].comb or 0) .. "}}"
return frame:preprocess(s)
end
function p.getInfoboxBuilds(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local item = args['item'] or args[1]
-- TODO: После заполнения данных заменить на обработку объектов-предметов
local builds = p.get({item, "builds"})
if(builds == nil or builds == "") then
return ""
end
table.sort(builds)
return frame:preprocess(lib.tbl_concat({
["tbl"] = builds,
["prepend"] = "'''{{Ii|",
["append"] = "|size=32|labelstyle=font-size:14px;}}'''",
["separator"] = "<br/>"
}))
end
-- Выводит список возможных улучшений предмета для показа в статье
function p.getPageBuilds(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local item = args['item'] or args[1]
if(item == nil) then uError('Не указан предмет', 'LuaError') end
local builds = items[item].builds
if(builds == nil) then return end
local s = ""
for i, v in ipairs(builds) do
s = s .. ": '''{{Ii|" .. v .. "|size=32|labelstyle=font-size:14px;}}'''\n"
end
return frame:preprocess(s)
end
-- Выводит иконки предметов, в которые можно превратить данный. Используется во всплывающей подсказке
function p.getTooltipBuilds(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local item = args['item'] or args[1]
if(item == nil) then uError('Не указан предмет', 'LuaError') end
local builds = items[item].builds
if(builds == nil) then return end
local s = ""
for i, v in ipairs(builds) do
if(i == 10) then s = s .. "<br/>" end
s = s .. tostring(p.itemIcon{
['item'] = v,
['text'] = "*none*"
})
end
return s
end
-- Обертка для _buildRecipeTree, чтобы проносить итоговый результат через frame:preprocess
function p.getRecipeTree(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
return frame:preprocess(tostring(_buildRecipeTree(args)))
end
-- Обертка для p.costAnalysis, чтобы обойти баг с отсутствием frame
function p.getCostAnalysis(frame)
return frame:preprocess(tostring(p.costAnalysis(frame)))
end
-- Производит анализ стоимости характеристик
function p.costAnalysis(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local item = args['item'] or args[1]
local output = args['output'] or args[2] or 'default'
local sum = 0
if(items[item] == nil) then
uError('Предмет не найдет в Модуль:ItemData/data', 'LuaError')
end
-- Таблица эталонов стоимости характеристик
-- Последняя проверка: V10.3, 17.02.20
local STANDARTS = {
["ap"] = 21.75,
["armor"] = 20,
["lethality"] = 5,
["ad"] = 35,
["as"] = 25,
["cdr"] = 26.666667,
["cdrunique"] = 26.666667,
["crit"] = 40,
["critunique"] = 40,
["hp"] = 2.666667,
["hp5"] = 3,
["hsp"] = 56.666667,
["lifesteal"] = 37.5,
["mr"] = 18,
["mpen"] = 31.111111,
["mana"] = 1.4,
["mp5"] = 5,
["mp5flat"] = 60,
["ms"] = 39.5,
["msflat"] = 12,
["msunique"] = 39.5,
["onhit"] = 25
}
-- Таблица родительных падежей характеристик
local STAT_GENITIVES = {
["ap"] = {"сила умений", "силы умений"},
["armor"] = {"броня", "брони"},
["lethality"] = {"смертоносность", "смертоносности"},
["ad"] = {"сила атаки", "силы атаки"},
["as"] = {"скорость атаки", "скорости атаки"},
["cdr"] = {"сокращение перезарядки", "сокращения перезарядки"},
["cdrunique"] = {"сокращение перезарядки", "сокращения перезарядки"},
["crit"] = {"шанс критического удара", "шанса критического удара"},
["critunique"] = {"шанс критического удара", "шанса критического удара"},
["hp"] = {"здоровье", "здоровья"},
["hp5"] = {"восстановление здоровья", "восстановления здоровья"},
["hsp"] = {"ЭЩИ", "ЭЩИ"},
["lifesteal"] = {"вампиризм", "вампиризма"},
["mr"] = {"сопротивление магии", "сопротивления магии"},
["mpen"] = {"магическое пробивание", "магического пробивания"},
["mana"] = {"мана", "маны"},
["mp5"] = {"восстановление маны", "восстановления маны"},
["mp5flat"] = {"восстановление маны", "восстановления маны"},
["ms"] = {"скорость передвижения", "скорости передвижения"},
["msflat"] = {"скорость передвижения", "скорости передвижения"},
["msunique"] = {"скорость передвижения", "скорости передвижения"},
["onhit"] = {"урон при попадании", "урона при попадании"}
}
local statsTable = items[item].stats
for k, v in pairs(statsTable) do
if k ~= "gp10" and k ~= "spec" then
sum = sum + v * STANDARTS[k]
end
end
-- Если нужна только сумма
if(args['output'] == "sum only") then return tostring(sum) end
-- По умолчанию - повторяет функциональность Шаблон:Gold value math
local unorderedListNode = mw.html.create('ul')
for k, v in pairs(statsTable) do
mw.log(k)
if k ~= "gp10" and k ~= "spec" then
unorderedListNode
:tag('li')
:wikitext(mw.ustring.format(
"%d%s [[%s|%s]] {{equals}} {{g|%s}} (из расчета {{g|%s}} за 1%s {{as|%s}})",
v,
lib.ternary(_isPercentile(k), "%", ""),
STAT_GENITIVES[k][1],
STAT_GENITIVES[k][2],
_round2(v * STANDARTS[k]),
_round2(STANDARTS[k]),
lib.ternary(_isPercentile(k), "%", ""),
STAT_GENITIVES[k][2]
))
:done()
:newline()
end
end
if(args['output'] == "no sum") then
return unorderedListNode
end
unorderedListNode
:tag('li')
:wikitext("'''Итоговая стоимость характеристик {{equals}} {{g|" .. tostring(_round2(sum)) .. "}}'''")
:done()
:allDone()
return unorderedListNode
end
function p.getItemTableByStat(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]
if(stat == nil) then
return uError('Характеристика не указана', 'LuaError')
end
local tableNode = mw.html.create('table')
tableNode
:addClass('wikitable sortable')
:cssText("width:93%;margin-left:5%;text-align:center")
:newline()
:tag('tr')
:tag('th')
:wikitext('Предмет')
:done()
:tag('th')
:attr('data-sort-type', 'number')
:wikitext('Цена')
:done()
:tag('th')
:wikitext('Прибавка')
:done()
:tag('th')
:wikitext('Доступность')
:done()
:done()
:newline()
:done()
-- [1] - название, [2] - размер характеристики, [3] - является уникальной
local filteredItems = {}
if(stat == 'crit' or stat == 'cdr' or stat == "ms") then
for k, v in lib.pairsByAlphabeticalKeys(items) do
if(v.stats[stat] ~= nil) then
table.insert(filteredItems, {k, v.stats[stat], false})
elseif(v.stats[stat .. "unique"] ~= nil) then
table.insert(filteredItems, {k, v.stats[stat .. "unique"], true})
end
end
else
for k, v in lib.pairsByAlphabeticalKeys(items) do
if(v.stats[stat] ~= nil) then
table.insert(filteredItems, {k, v.stats[stat], false})
end
end
end
for i, v in ipairs(filteredItems) do
local maps
if(items[v[1]].maps == nil) then maps = "Любая карта"
elseif(p.get{v[1], "SR"}) then maps = "{{tip|Ущелье призывателей}}"
elseif(p.get{v[1], "HA"}) then maps = "{{tip|Воющая Бездна}}"
end
tableNode
:tag('tr')
:tag('td')
:wikitext(tostring(p.itemIcon{["item"] = v[1]}))
:done()
:tag('td')
:wikitext(mw.ustring.format(
"{{g|%s}}",
p.get{v[1], "buy"}
))
:done()
:tag('td')
:wikitext(mw.ustring.format("%s%s%s",
v[2],
lib.ternary(_isPercentile(stat), "%", ""),
lib.ternary(v[3], " (Уникально)", "")))
:done()
:tag('td')
:wikitext(maps)
:done()
:done()
:newline()
:done()
end
return frame:preprocess(tostring(tableNode))
end
--[[================
Приватные методы
================]]
-- Отрисовывает состав предмета в виде дерева. Рекуррентная функция
function _buildRecipeTree(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local item = args['item'] or args[1]
local recipe = get.recipe(item)
local tableNode = mw.html.create('table')
tableNode:css('border-collapse', 'collapse'):newline()
local tableRow = mw.html.create('tr')
tableRow
:tag('td')
:attr('colspan', '3')
:css('padding-left', '0px')
:node(_buildRecipeTreeItem(item))
:done()
:done()
tableNode:node(tableRow):newline()
if(recipe == nil) then
tableNode:allDone()
return tableNode
end
local firstComponentRow = mw.html.create('tr')
firstComponentRow
:tag('td')
:attr('rowspan', tostring(#recipe*2 - 1))
:cssText('width:15px;border-right:1px solid #124b71;')
:done()
:tag('td')
:cssText('height:17px;width:17px;border-bottom:1px solid #124b71;')
:done()
:tag('td')
:attr('rowspan', '2')
:node(_buildRecipeTree{recipe[1]})
:done()
:done()
tableNode:node(firstComponentRow)
for i, v in ipairs(recipe) do
if(i ~= 1) then
tableNode
:tag('tr')
:tag('td')
:done()
:done()
:newline()
local recipeRow = mw.html.create('tr')
recipeRow
:tag('td')
:cssText('height:17px;width:17px;border-bottom:1px solid #124b71;')
:done()
:tag('td')
:attr('rowspan', '2')
:node(_buildRecipeTree{v})
:done()
:done()
tableNode:node(recipeRow):newline()
end
end
tableNode
:tag('tr')
:tag('td')
:done()
:tag('td')
:done()
:done()
tableNode:allDone()
return tableNode
end
-- Реализует тот же функционал, что и Шаблон:Рецепт/Предмет
-- Создает блок, в котором дается иконка предмета, подпись и стоимость
-- Является составной частью дерева состава предмета
-- Возвращает mw.html объект
function _buildRecipeTreeItem(item)
--Состоит из трех блоков: иконки, текста и цены под ним
local itemNode = mw.html.create('div')
itemNode
:addClass('item')
:css(
{
['clear'] = 'left',
['padding'] = '1px'
}):done()
local iconNode = mw.html.create('div')
iconNode:wikitext(tostring(p.itemIcon{
['item'] = item,
['text'] = '*none*',
['class'] = 'icon',
['border'] = 'false',
['size'] = '32',
['iconstyle'] = 'position:absolute;margin-right:4px;border-radius:2px;overflow:hidden;border:1px solid #' .. lib.ternary(_isTitular(item), 'FFD700', '257372'),
})):done()
local labelNode = mw.html.create('div')
if(items[item] ~= nil) then
labelNode:addClass('item-lua-icon')
else
labelNode:addClass('item-icon')
end
labelNode
:addClass('name')
:attr('data-param', item)
:css{
['white-space'] = 'nowrap',
['padding-left'] = '40px',
['font-size'] = '14px',
['height'] = lib.ternary(_isTransformation(item), '33px', '20px'),
['line-height'] = lib.ternary(_isTransformation(item), '33px', '20px')
}
:wikitext("'''[[" .. get.name(item) .. "]]'''")
:done()
local costNode = mw.html.create('div')
costNode
:addClass('gold')
:css{
['white-space'] = 'nowrap',
['padding-left'] = '40px',
['font-size'] = '11px',
['color'] = '#FFD700',
['height'] = '12px',
['line-height'] = '12px'
}
:wikitext(_getCostString(item))
:done()
itemNode
:node(iconNode)
:node(labelNode)
if(not(_isTransformation(item))) then itemNode:node(costNode) end
itemNode:allDone()
return itemNode
end
-- Является ли название страницы, где вызван скрипт, названием предмета-корня дерева состава
function _isTitular(item)
return item == mw.title.getCurrentTitle()
end
-- Является трансформацией предмета? (имеет что-то в составе, но стоимость сборки равна 0)
function _isTransformation(item)
if(items[item].comb == 0) then return true end
return false
end
-- Возвращает строку со стоимостью предмета и стоимостью сборки
-- На страницах выглядит как подпись под предметом в дереве состава предмета
function _getCostString(item)
local cost = ""
if(get.buy(item) ~= nil) then
cost = cost .. mw.ustring.format("{{g|%s|size=16}}", tostring(get.buy(item)))
end
if(items[item].comb ~= nil) then
cost = cost .. mw.ustring.format(" ({{g|%s|size=16}})", tostring(get.comb(item)))
end
return cost
end
-- Проверяет, является ли характеристика процентной
function _isPercentile(stat)
return (stat == "as" or stat == "cdr"
or stat == "cdruniqie" or stat == "crit"
or stat == "hp5" or stat == "mp5"
or stat == "critunique" or stat == "lifesteal"
or stat == "ms" or stat == "msunique"
or stat == "hsp")
end
-- Округляет до 2 знаков после запятой. Убирает незначащие нули в любом случае
function _round2(num)
return math.floor(num * 100 + 0.5) / 100
end
-- Создает блок из предметов, сгруппированных по типу
function _buildItemListContainer(itemList)
local itemListContainer = mw.html.create('div')
itemListContainer:addClass('tlist')
local HTMLList = mw.html.create('ul')
itemListContainer:node(HTMLList)
for k, item in ipairs(itemList) do
mw.log(item)
HTMLList
:tag('li')
:wikitext(tostring(p.itemIcon
{
['item'] = item,
['border'] = 'false',
['iconstyle'] = 'margin: 1px -1px; border-radius:2px; border:1px solid #' .. lib.ternary(item == tostring(mw.title.getCurrentTitle()), 'FFD700', '257372'),
['image'] = get.engname(item) .. " item.png",
['size'] = '42px',
['text'] = '*none*'
}))
:done()
:newline()
end
return itemListContainer
end
return p
-- </pre>
-- [[Категория:Lua]]
Материалы сообщества доступны в соответствии с условиями лицензии CC-BY-SA, если не указано иное.