Данная группа модулей содержит функции и списки по работе с предметами из игры League of Legends. Перечень модулей:
- Модуль:ItemData - общая логика и основные функции
- Модуль:ItemData/data - список актуальных предметов игры
- Модуль:ItemData/data/removed - список удаленных из игры предметов
- Модуль:ItemData/data/old - список предметов со старой структурой полей
- Модуль:ItemData/getter - список функций- геттеров
- Модуль:ItemData/LimitTemplates - список шаблонных ограничений, которые могут иметь предметы.
- Модуль:ItemData/Standards - список эталонных стоимостей характеристик предметов.
- Модуль:ItemData/Misspellings - список популярных ошибочных написаний предметов.
- Модуль:ItemData/Percents - список характеристик, которые измеряются в процентах.
From Модуль:ItemData/doc
-- <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')
--[[================
Приватные методы
================]]
-- Является ли название страницы, где вызван скрипт, названием предмета-корня дерева состава
local function _isTitular(item)
return item == mw.title.getCurrentTitle()
end
-- Является трансформацией предмета? (имеет что-то в составе, но стоимость сборки равна 0)
local function _isTransformation(itemData)
return (itemData.comb == 0 or not(itemData.comb)) and itemData.recipe and not(itemData.builds)
end
-- Возвращает строку со стоимостью предмета и стоимостью сборки
-- На страницах выглядит как подпись под предметом в дереве состава предмета
local function _getCostString(item)
local cost = ""
if(get.buy(item) ~= nil and get.buy(item) ~= 0) then
cost = cost .. mw.ustring.format("{{g|%s|size=16}}", tostring(get.buy(item)))
end
if(get.comb(item) ~= nil and get.comb(item) ~= 0) then
cost = cost .. mw.ustring.format(" ({{g|%s|size=16}})", tostring(get.comb(item)))
end
return cost
end
-- Проверяет, является ли характеристика процентной
local function _isPercentile(stat)
local PERCENTILES = {
["as"] = true,
["cdr"] = true,
["cdrunique"] = true,
["crit"] = true,
["lifesteal"] = true,
["crit"] = true,
["critunique"] = true,
["hppct"] = true,
["hp5"] = true,
["mp5"] = true,
["ms"] = true,
["msunique"] = true,
["hsp"] = true,
}
return PERCENTILES[stat]
end
-- Округляет до 2 знаков после запятой. Убирает незначащие нули в любом случае
local function _round2(num)
return math.floor(num * 100 + 0.5) / 100
end
-- Реализует тот же функционал, что и Шаблон:Рецепт/Предмет
-- Создает блок, в котором дается иконка предмета, подпись и стоимость
-- Является составной частью дерева состава предмета
-- Возвращает mw.html объект
local function _buildRecipeTreeItem(item)
--Состоит из трех блоков: иконки, текста и цены под ним
local itemNode = mw.html.create("div"):addClass("lit__leaf")
itemNode:wikitext(tostring(p.itemIcon{
["item"] = item,
["text"] = "*none*",
["size"] = "32",
["class"] = "lit__leaf-spanned",
["iconclass"] = "lit__leaf-icon"
}))
local labelNode = mw.html.create("div")
labelNode
:addClass("item-lua-icon lit__leaf-title")
:attr("data-param", item)
:attr("data-game", "lol")
:wikitext(mw.ustring.format("[[%s]]", get.formatname(item)))
:done()
local costNode = mw.html.create("div")
costNode
:addClass("lit__leaf-cost")
:wikitext(_getCostString(item))
:done()
itemNode
:node(iconNode)
:node(labelNode)
itemNode:node(costNode)
itemNode:allDone()
return itemNode
end
-- Отрисовывает состав предмета в виде дерева. Рекуррентная функция
local 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) or nil
local tableNode = mw.html.create("table")
tableNode:addClass("lol-item-tree"):newline()
local tableRow = mw.html.create("tr")
tableRow
:tag("td")
:attr("colspan", "3")
:addClass("lit__root")
:node(_buildRecipeTreeItem(item))
:done()
:done()
tableNode:node(tableRow):newline()
if(recipe == nil) then
tableNode:allDone()
return tableNode
end
local num_components = 0
for k in ipairs(recipe) do num_components = num_components + 1 end
local firstComponentRow = mw.html.create("tr")
firstComponentRow
:tag("td")
:attr("rowspan", tostring(num_components * 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
-- Создает блок из предметов, сгруппированных по типу
local function _buildItemRosterBlock(itemList)
local itemRosterBlock = mw.html.create("div")
:addClass("lol-item-roster__group")
:done()
for itemKey, itemValue in lib.pairsByAlphabeticalKeys(itemList) do
itemRosterBlock
:tag("div")
:addClass("lol-item-roster__item")
:wikitext(tostring(p.itemIcon
{
["item"] = itemKey,
["border"] = "false",
["iconclass"] = "lol-item-roster__item-icon " .. lib.ternary(
itemKey == tostring(mw.title.getCurrentTitle()),
"lol-item-roster__item-icon--selected",
"lol-item-roster__item-icon--default"
),
["size"] = "42px",
["text"] = "*none*"
}))
:done()
:newline()
end
return itemRosterBlock
end
function p.get(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
-- Строки, которые нужно подвергать frame:preprocess
local PREPROCESSED = {
["limit"] = true,
["fulllimit"] = true,
["req"] = true,
["consume"] = true,
["consume2"] = true,
["pass1"] = true,
["pass2"] = true,
["pass3"] = true,
["pass4"] = true,
["pass5"] = true,
["pass6"] = true,
["aura"] = true,
["active"] = true,
["mythicdescription"] = true
}
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
item = lib.validateItemName(item)
if(not(get.exists(item))) then
return uError("Указанный предмет отсутствует в Модуль:ItemData/data")
end
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
if(PREPROCESSED[datatype]) then
return frame:preprocess(result)
else
return result
end
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 misspellings = mw.loadData("Модуль:ItemData/Misspellings")
args['item'] = args['item'] or args[1]
if(misspellings[args["item"]]) then
args["item"] = misspellings[args["item"]]
end
local result
if(get.exists(args['item'])) then
args['engname'] = p.get{args['item'], "engname"}
result = IL.item(args)
return result
else
result = IL.itemOld(args)
return result
end
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 boots = {}
local epic = {}
local legendary = {}
local transformation= {}
local mythic = {}
local ornn = {}
local championic = {}
local unsorted = {}
for k, v in lib.pairsByAlphabeticalKeys(items) do
if(get.itemtype(k) == "Начальный") then
starters[k] = v
elseif(get.itemtype(k) == "Расходуемый") then
consumables[k] = v
elseif(get.itemtype(k) == "Аксессуар") then
trinkets[k] = v
elseif(get.itemtype(k) == "Предоставляемый") then
distributives[k] = v
elseif(get.itemtype(k) == "Базовый") then
basic[k] = v
elseif(get.itemtype(k) == "Обувь") then
boots[k] = v
elseif(get.itemtype(k) == "Эпический") then
epic[k] = v
elseif(get.itemtype(k) == "Легендарный" and not(_isTransformation(v) or get.itemtype(k) == "Зачарование")) then
legendary[k] = v
elseif(get.itemtype(k) == "Легендарный" and _isTransformation(v)) then
transformation[k] = v
mw.log(k)
elseif(get.itemtype(k) == "Мифический") then
mythic[k] = v
elseif(get.itemtype(k) == "Орн") then
ornn[k] = v
elseif(get.itemtype(k) == "Чемпионский") then
championic[k] = v
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")
:cssText("clear:both; display: block; text-align: center;")
:done()
tableContainer
:tag("dl")
:tag("dt")
:wikitext("Начальные предметы")
:done()
:done()
:node(_buildItemRosterBlock(starters))
:newline()
:tag("dl")
:tag("dt")
:wikitext("Расходуемые предметы")
:done()
:done()
:node(_buildItemRosterBlock(consumables))
:newline()
:tag("dl")
:tag("dt")
:wikitext("Аксессуары")
:done()
:done()
:node(_buildItemRosterBlock(trinkets))
:newline()
:tag("dl")
:tag("dt")
:wikitext("Предоставляемые предметы")
:done()
:done()
:node(_buildItemRosterBlock(distributives))
:newline()
:tag("dl")
:tag("dt")
:wikitext("Базовые предметы")
:done()
:done()
:node(_buildItemRosterBlock(basic))
:newline()
:tag("dl")
:tag("dt")
:wikitext("Обувь")
:done()
:done()
:node(_buildItemRosterBlock(boots))
:newline()
:tag("dl")
:tag("dt")
:wikitext("Эпические предметы")
:done()
:done()
:node(_buildItemRosterBlock(epic))
:newline()
:tag("dl")
:tag("dt")
:wikitext("Легендарные предметы")
:done()
:done()
:node(_buildItemRosterBlock(legendary))
:node(_buildItemRosterBlock(transformation))
:newline()
:tag("dl")
:tag("dt")
:wikitext("Несравненные предметы Орна")
:done()
:done()
:node(_buildItemRosterBlock(ornn))
:newline()
:tag("dl")
:tag("dt")
:wikitext("Эксклюзивные предметы")
:done()
:done()
:node(_buildItemRosterBlock(championic))
: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
local removed = mw.loadData("Модуль:ItemData/data/removed")
local removedTable = {}
for k, v in lib.pairsByAlphabeticalKeys(removed) do
removedTable[k] = v
end
tableContainer
:tag("dl")
:tag("dt")
:wikitext("Удаленные предметы")
:done()
:done()
:node(_buildItemRosterBlock(removedTable))
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]
-- Характеристики в винительном падеже
-- Список должен быть согласован со всеми существующими/существовавшими статами
local ACCUSATIVES = {
["ap"] = "силу умений",
["armor"] = "броню",
["arpen"] = "пробивание брони",
["lethality"] = "смертоносность",
["lethalityunique"] = "смертоносность",
["ad"] = "силу атаки",
["as"] = "скорость атаки",
["ah"] = "ускорение умений",
["cdr"] = "сокращение перезарядки",
["cdrunique"] = "сокращение перезарядки",
["crit"] = "шанс критического удара",
["critunique"] = "шанс критического удара",
["gp10"] = "золото",
["hsp"] = "эффективность лечения и щитов",
["hspunique"] = "эффективность лечения и щитов",
["hp"] = "здоровье",
["hppct"] = "здоровье",
["hp5"] = "восстановление здоровья",
["hp5flat"] = "восстановление здоровья",
["lifesteal"] = "вампиризм",
["mr"] = "сопротивление магии",
["mpen"] = "магическое пробивание",
["mpenflat"] = "магическое пробивание",
["mana"] = "ману",
["mp5"] = "восстановление маны",
["mp5flat"] = "восстановление маны",
["ms"] = "скорость передвижения",
["msunique"] = "скорость передвижения",
["msflat"] = "скорость передвижения",
["pvamp"] = "физическое вытягивание жизни",
["omnivamp"] = "всестороннее вытягивание жизни",
}
local categories = {}
-- Категория для чемпионских предметов
if(p.get{item, "champion"} ~= "") then
table.insert(categories, "[[Категория:Эксклюзивные предметы]]")
end
-- Категории по типу предмета (первому из таблицы)
local itemType = p.get{item, "itemtype"}
if(itemType == "Зачарование") then
table.insert(categories, "[[Категория:Зачарования]]")
elseif(itemType == "Аксессуар") then
table.insert(categories, "[[Категория:Аксессуары]]")
elseif(itemType == "Обувь") then
table.insert(categories, "[[Категория:Обувь]]")
elseif(itemType == "Орн") then
table.insert(categories, "[[Категория:Несравненные предметы Орна]]")
else
table.insert(categories, "[[Категория:" .. mw.ustring.sub(itemType, 1, -2) .. "е предметы]]")
end
local itemStats = p.get{item, "stats"}
-- Постановка категорий по имеющимся характеристикам
if(type(itemStats) ~= "string") then
for k, v in pairs(itemStats) do
if(ACCUSATIVES[k]) then
table.insert(categories, mw.ustring.format("[[Категория:Предметы на %s]]", ACCUSATIVES[k]))
end
end
end
if(get.active(item) or nil ~= nil) then
table.insert(categories, "[[Категория:Активируемые предметы]]")
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]
if(not(p.get{item, "exists"})) then
return uError("Указанный предмет не найден в ItemData/data или ItemData/data/removed", "LuaError")
end
local introductionText = ""
-- X - это ...
introductionText = introductionText .. mw.ustring.format("'''%s''' {{англ|%s}} — это ",
item,
p.get{item, "engname"})
-- Предмет/Зачарование/Аксессуар
local itemType = mw.ustring.lower(p.get{item, "itemtype"})
-- Список типов предметов, для которых строится фраза не "...это [какой-то] предмет..."
local ITEMTYPE_EXCEPTIONS = {
["аксессуар"] = true,
["зачарование"] = true,
["обувь"] = true,
["орн"] = true
}
if(ITEMTYPE_EXCEPTIONS[itemType]) then
if(itemType == "орн") then
introductionText = introductionText .. " один из несравненных предметов {{ci|Орн|Орна}} в ''[[League of Legends]]''"
elseif(itemType == "обувь") then
introductionText = introductionText .. " вид обуви в ''[[League of Legends]]''"
else
introductionText = introductionText .. itemType .. " в ''[[League of Legends]]''"
end
else
introductionText = introductionText .. itemType .. " предмет в ''[[League of Legends]]''"
end
if(p.get{item, "champion"} ~= "") then
introductionText = introductionText .. mw.ustring.format(" для чемпиона {{ci|%s}}", p.get{item, "champion"})
end
if(p.get{item, "maps"} ~= nil) then
if(not(p.get{item, "HA"}) and not(p.get{item, "NB"})) then
introductionText = introductionText .. ". Доступен исключительно в {{tip|Ущелье призывателей}}"
elseif(not(p.get{item, "SR"}) and not(p.get{item, "NB"})) then
introductionText = introductionText .. ". Доступен исключительно в {{tip|Воющая бездна|Воющей бездне}}"
elseif(not(p.get{item, "SR"}) and not(p.get{item, "HA"})) then
introductionText = introductionText .. ". Доступен исключительно в режиме {{tip|Штурм Нексуса}}"
end
end
introductionText = introductionText .. "."
if(append ~= nil) then introductionText = introductionText .. " " .. append end
return frame:preprocess(introductionText)
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(p.get{item, "exists"})) then
return uError('Указанный предмет не найден')
end
-- Если у предмета нет состава
if(not(p.get{item, "recipe"})) then return end
local recipeHtml = ""
local itemRecipe = lib.cloneTable(p.get{item, "recipe"})
if(itemRecipe == "") then return end
for i, component in ipairs(itemRecipe) do
recipeHtml = recipeHtml .. tostring(p.itemIcon{
["item"] = component,
["size"] = size,
["text"] = "*none*"
})
if(i < #itemRecipe) then
recipeHtml = recipeHtml .. "{{plus}}"
end
end
recipeHtml = recipeHtml .. "<br />{{g|" .. (get.comb(item) or 0) .. "}}"
return frame:preprocess(recipeHtml)
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]
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 = get.builds(item)
if(builds == nil) then return end
local buildsTable = {}
for i, v in ipairs(builds) do
if(i == 10) then table.insert(buildsTable, "<br />") end
table.insert(buildsTable, tostring(p.itemIcon{
['item'] = v,
['text'] = "*none*"
}))
end
return table.concat(buildsTable, "")
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(not(p.get{item, "exists"})) then
uError('Предмет не найден в Модуль:ItemData/data или ItemData/data/removed', 'LuaError')
end
local STANDARDS = mw.loadData("Модуль:ItemData/Standards")
local PERCENTS = mw.loadData("Модуль:ItemData/Percents")
-- Таблица родительных падежей характеристик
local GENITIVES = {
["ap"] = "силы умений",
["armor"] = "брони",
["arpen"] = "пробивания брони",
["lethality"] = "смертоносности",
["lethalityunique"] = "смертоносности",
["ad"] = "силы атаки",
["as"] = "скорости атаки",
["ah"] = "ускорения умений",
["cdr"] = "сокращения перезарядки",
["cdrunique"] = "сокращения перезарядки",
["crit"] = "шанса критического удара",
["critunique"] = "шанса критического удара",
["gp10"] = "золота",
["hsp"] = "эффективности лечения и щитов",
["hspunique"] = "эффективности лечения и щитов",
["hp"] = "здоровья",
["hppct"] = "здоровья",
["hp5"] = "восстановления здоровья",
["hp5flat"] = "восстановления здоровья",
["lifesteal"] = "вампиризма",
["mr"] = "сопротивления магии",
["mpen"] = "магического пробивания",
["mpenflat"] = "магического пробивания",
["mana"] = "маны",
["mp5"] = "восстановления маны",
["mp5flat"] = "восстановления маны",
["ms"] = "скорости передвижения",
["msunique"] = "скорости передвижения",
["msflat"] = "скорости передвижения",
["ohdmg"] = "урона при попадании",
["pvamp"] = "физического вытягивание жизни",
["omnivamp"] = "всестороннего вытягивания жизни",
}
local statsTable = lib.cloneTable(p.get{item, "stats"})
-- Заменяеет значения statsTable на переданные в invoke (если есть)
for k, v in pairs(STANDARDS) do
if(args[k] ~= nil) then
statsTable[k] = args[k]
end
end
for k, v in pairs(statsTable) do
if(k ~= "gp10" and k ~= "spec") then
if(STANDARDS[k]) then
sum = sum + STANDARDS[k]["val"] * v
end
end
end
-- Если нужна только сумма
if(args['output'] == "sum only") then return tostring(sum) end
local tableNode = mw.html.create("table")
tableNode
:addClass("wikitable")
:attr("width", "60%")
:tag("tr")
:tag("th")
:wikitext("Характеристика")
:attr("width", "35%")
:done()
:tag("th")
:wikitext("Стоимость")
:done()
:tag("th")
:wikitext("Заметка")
:done()
:done()
:done()
local isEmptyTable = true
for k, v in pairs(statsTable) do
if(k ~= "gp10" and k ~= "spec" and k ~= "spec2") then
if(STANDARDS[k]) then
isEmptyTable = false
tableNode
:tag("tr")
:tag("td")
:wikitext(mw.ustring.format(
"{{as|%d%s %s}}",
v,
lib.ternary(PERCENTS[k], "%", ""),
GENITIVES[k]
))
:done()
:tag("td")
:wikitext(mw.ustring.format("{{g|%s}}", tostring(_round2(STANDARDS[k]["val"] * v))))
:done()
:tag("td")
:wikitext(mw.ustring.format(
"Из расчета {{g|%s}} за {{as|1%s %s}}.",
tostring(_round2(STANDARDS[k]["val"])),
lib.ternary(PERCENTS[k], "%", ""),
GENITIVES[k]
))
:done()
:done()
:done()
end
end
end
if(isEmptyTable) then
tableNode = ""
else
tableNode
:tag("tr")
:tag("th")
:attr("colspan", "3")
:wikitext(mw.ustring.format("Итоговая стоимость: {{G|%0.2f}}", _round2(sum)))
:done()
:done()
:done()
end
return tableNode
end
function p.getStandard(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local statistic = args["statistic"] or args[1]
local standards = mw.loadData("Модуль:ItemData/Standards")
if(standards[statistic]~= nil) then
return standards[statistic]["val"]
else
return 0
end
end
-- Выводит процентное соотношение выгодности покупки
-- Повторяет функции шаблона Выгодность
function p.getGoldEfficiency(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 itemCost = p.get{item, "buy"}
local statCost = args[2] or p.costAnalysis{["item"] = item, ["output"] = "sum only"}
local efficiency = _round2(statCost / itemCost * 100)
local costDiff = _round2(statCost - itemCost)
return frame:preprocess(mw.ustring.format(
"{{tt|%s%%|%s%s золота}}",
tostring(efficiency),
lib.ternary(costDiff > 0, "+", ""),
tostring(costDiff)
))
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 = {}
local percentStats = mw.loadData("Модуль:ItemData/Percents")
for k, v in lib.pairsByAlphabeticalKeys(items) do
if(v["stats"] and v["stats"][stat] ~= nil) then
table.insert(filteredItems, {k, v.stats[stat], false})
elseif(v["stats"] and v["stats"][stat .. "unique"] ~= nil) then
table.insert(filteredItems, {k, v["stats"][stat .. "unique"], true})
end
end
for i, v in ipairs(filteredItems) do
local maps = p.get{v[1], "maps"}
if(maps["sr"] and not(maps["ha"] or maps["nb"])) then maps = "{{tip|Ущелье призывателей}}"
elseif(maps["ha"] and not(maps["sr"] or maps["nb"])) then maps = "{{tip|Воющая бездна}}"
elseif(maps["nb"] and not(maps["sr"] or maps["ha"])) then maps = "{{tip|Штурм Нексуса}}"
else maps = "Любая карта" 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(percentStats[stat], "%", ""),
lib.ternary(v[3], " (Уникально)", "")))
:done()
:tag('td')
:wikitext(maps)
:done()
:done()
:newline()
:done()
:allDone()
end
return frame:preprocess(tostring(tableNode))
end
-- Создает старинный вариант информации об предмете в виде Data-шаблона
-- Используется для предметов, выводимых в архив
function p.generateLegacyPage(frame)
local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
local itemName = args['item'] or args[1]
local itemData = items[itemName]
if(itemData == nil) then
return uError("Предмет не найден в ItemData/data", "LuaError")
end
local result = {"{{{{{1<noinclude>|Item data</noinclude>}}}|" .. itemName .."|{{{2|}}}|{{{3|}}}|{{{4|}}}|{{{5|}}}"}
table.insert(result, "|engname = " .. itemData.engname)
table.insert(result, "|code = " .. itemData.id)
table.insert(result, "|tier = Tier " .. itemData.tier)
if(itemData.itemtype) then table.insert(result, "|type = " .. itemData.itemtype) end
if(itemData.champion) then table.insert(result, "|champion = " .. itemData.champion) end
if(itemData.maps) then table.insert(result, "|maps = " .. itemData.maps) end
if(itemData.caption) then table.insert(result, "|caption = " .. itemData.caption) end
if(itemData.consume) then table.insert(result, "|consume = " .. itemData.consume) end
if(itemData.consume2) then table.insert(result, "|consume2 = " .. itemData.consume2) end
-- Характеристики
if(itemData.stats) then
for k, v in pairs(itemData.stats) do
local key = k
if(k == "hp") then key = "health" end
table.insert(result, "|" .. key .. " = " .. tostring(v))
end
end
if(itemData.passive) then
for i, v in ipairs(itemData.passive) do
if(i == 1) then
table.insert(result, "|pass = " .. v)
else
table.insert(result, "|pass" .. i .. " = " .. v)
end
end
end
if(itemData.aura) then
for i, v in ipairs(itemData.aura) do
if(i == 1) then
table.insert(result, "|aura = " .. v)
else
table.insert(result, "|aura" .. i .. " = " .. v)
end
end
end
if(itemData.active) then table.insert(result, "|act = " .. itemData.active) end
if(itemData.activecd) then table.insert(result, "|act_cd = " .. itemData.activecd) end
if(itemData.recipe) then
-- Костыль: таблица из loadData не поддерживает конкатенацию
local recipeText = ""
for i, v in pairs(itemData.recipe) do
recipeText = recipeText .. v .. ","
end
table.insert(result, "|recipe = " .. mw.ustring.sub(recipeText, 0, -2))
end
if(itemData.builds) then
-- Костыль: таблица из loadData не поддерживает конкатенацию
local buildsText = ""
for i, v in pairs(itemData.builds) do
buildsText = buildsText .. v .. ","
end
table.insert(result, "|builds = " .. mw.ustring.sub(buildsText, 0, -2))
end
if(itemData.buy) then
table.insert(result, "|buy = " .. tostring(itemData.buy))
table.insert(result, "|sell = " .. p.get{itemName, "sell"})
end
if(itemData.comb) then table.insert(result, "|comb = " .. tostring(itemData.comb)) end
if(itemData.limit) then table.insert(result, "|limit = " .. itemData.limit) end
if(itemData.req) then table.insert(result, "|req = " .. itemData.req) end
table.insert(result, "|removed = true")
table.insert(result, "}}")
return table.concat(result, "\n")
end
-- Реструктурирует старый вариант ItemData/data (ItemData/data/old) в новый в соответствии с обновленной спецификацией полей
function p.restructureItemData()
local items = mw.loadData("Модуль:ItemData/data/removed")
local result = {}
local tab = " " -- 4 пробела
for itemKey, itemValue in lib.pairsByAlphabeticalKeys(items) do
--start
local itemInstance = { mw.ustring.format("[\"%s\"] = {", itemKey) }
--id
if(itemValue.id ~= nil) then
table.insert(itemInstance, mw.ustring.format("%s[\"id\"] = %d,", tab, itemValue.id))
end
-- engname
table.insert(itemInstance, mw.ustring.format("%s[\"engname\"] = \"%s\",", tab, itemValue.engname))
-- champion
if(itemValue.champion ~= nil) then
table.insert(itemInstance, mw.ustring.format("%s[\"champion\"] = \"%s\",", tab, itemValue.champion))
end
-- caption
if(itemValue.caption ~= nil) then
table.insert(itemInstance, mw.ustring.format("%s[\"caption\"] = \"%s\",", tab, itemValue.caption))
end
-- tier
table.insert(itemInstance, mw.ustring.format("%s[\"tier\"] = %d,", tab, itemValue.tier))
-- itemtype
local itemtypeTable = { tab .. "[\"itemtype\"] = {" }
if(itemValue.champion ~= nil) then
table.insert(itemtypeTable, "\"Чемпионский\",")
elseif(itemValue.limit ~= nil and mw.ustring.find(itemValue.limit, "Может быть создано только") ~= nil) then
table.insert(itemtypeTable, "\"Орн\",")
else
if(itemValue.itemtype) then
for i, v in ipairs(itemValue.itemtype) do
table.insert(itemtypeTable, mw.ustring.format("\"%s\",", v))
end
else
if itemValue.tier == 1 then
table.insert(itemtypeTable, "\"Базовый\"")
elseif itemValue.builds then
table.insert(itemtypeTable, "\"Эпический\"")
else
table.insert(itemtypeTable, "\"Легендарный\"")
end
end
end
table.insert(itemtypeTable, "},")
table.insert(itemInstance, table.concat(itemtypeTable, " "))
--maps - доступные карты
local mapsTable = {"[\"maps\"] = {"}
if(itemValue.maps == nil) then
table.insert(mapsTable, tab .. tab .. "[\"sr\"] = true,")
table.insert(mapsTable, tab .. tab .. "[\"ha\"] = true,")
table.insert(mapsTable, tab .. tab .. "[\"nb\"] = true")
else
if(p.get{itemKey, "SR"}) then
table.insert(mapsTable, tab .. tab .. "[\"sr\"] = true,")
else
table.insert(mapsTable, tab .. tab .. "[\"sr\"] = false,")
end
if(p.get{itemKey, "HA"}) then
table.insert(mapsTable, tab .. tab .. "[\"ha\"] = true,")
else
table.insert(mapsTable, tab .. tab .. "[\"ha\"] = false,")
end
table.insert(mapsTable, tab .. tab .. "[\"nb\"] = false")
end
table.insert(mapsTable, tab .. "},")
table.insert(itemInstance, tab .. table.concat(mapsTable, "\r\n"))
-- req
if(itemValue.req) then
table.insert(itemInstance, mw.ustring.format("%s[\"req\"] = \"%s\",", tab, itemValue.req))
end
-- limit
if(itemValue.limit) then
table.insert(itemInstance, mw.ustring.format("%s[\"limit\"] = \"%s\",", tab, itemValue.limit))
end
-- stats
if(itemValue.stats.noe ~= true) then
local statsTable = { tab .. "[\"stats\"] = {" }
for statKey, statValue in pairs(itemValue.stats) do
if(type(statValue) == "number") then
table.insert(statsTable, mw.ustring.format(
"%s[\"%s\"] = %d,",
string.rep(tab, 2),
statKey,
statValue))
elseif(statValue == "string") then
table.insert(statsTable, mw.ustring.format(
"%s[\"%s\"] = \"%s\",",
string.rep(tab, 2),
statKey,
statValue))
end
end
table.insert(statsTable, tab .. "},")
table.insert(itemInstance, table.concat(statsTable, "\r\n"))
end
-- passives
if(itemValue.passive) then
for passiveIndex, passiveValue in ipairs(itemValue.passive) do
local passiveTable = { tab .. mw.ustring.format("[\"pass%d\"] = {", passiveIndex) }
local passiveText = passiveValue
--Уникальные активные эффекты с именем
if(mw.ustring.match(passiveText, "{{[Uu]nique|[%s%d%a]-|") ~= nil) then
-- Захватить название эффекта
table.insert(passiveTable, mw.ustring.format("%s[\"name\"] = \"%s\",",
mw.ustring.rep(tab, 2),
mw.ustring.match(passiveText, "|([%s%d%a]-)|")
))
table.insert(passiveTable, mw.ustring.format("%s[\"unique\"] = true,",
mw.ustring.rep(tab, 2)
))
-- Захватить описание
table.insert(passiveTable, mw.ustring.format("%s[\"description\"] = \"%s\",",
mw.ustring.rep(tab, 2),
mw.ustring.match(passiveText, "{{[Uu]nique|[%s%d%a]-|(.*)}}")
))
-- Уникальные активные эффекты без имени
elseif(mw.ustring.match(passiveText, "{{[Uu]nique|*") ~= nil) then
table.insert(passiveTable, mw.ustring.format("%s[\"unique\"] = true,",
mw.ustring.rep(tab, 2)
))
table.insert(passiveTable, mw.ustring.format("%s[\"description\"] = \"%s\",",
mw.ustring.rep(tab, 2),
mw.ustring.match(passiveText, "{{[Uu]nique|(.*)}}")
))
else
-- Захватить описание
table.insert(passiveTable, mw.ustring.format("%s[\"description\"] = \"%s\",",
mw.ustring.rep(tab, 2),
passiveText
))
end
table.insert(passiveTable, tab .. "},")
table.insert(itemInstance, table.concat(passiveTable, "\r\n"))
end
end
-- active
if(itemValue.active) then
local activeTable = { tab .. "[\"active\"] = {" }
local activeText = itemValue.active
--Уникальные активные эффекты с именем
if(mw.ustring.match(activeText, "{{[Uu]nique|[%s%d%a]-|") ~= nil) then
-- Захватить название эффекта
table.insert(activeTable, mw.ustring.format("%s[\"name\"] = \"%s\",",
mw.ustring.rep(tab, 2),
mw.ustring.match(activeText, "|(.-)|")
))
table.insert(activeTable, mw.ustring.format("%s[\"unique\"] = true,",
mw.ustring.rep(tab, 2)
))
-- Захватить описание
table.insert(activeTable, mw.ustring.format("%s[\"description\"] = \"%s\",",
mw.ustring.rep(tab, 2),
mw.ustring.match(activeText, "{{[Uu]nique|[%s%d%a]-|(.*)}}")
))
if(itemValue.activecd) then
table.insert(activeTable, mw.ustring.format("%s[\"cd\"] = \"%s\",",
mw.ustring.rep(tab, 2),
tostring(itemValue.activecd)
))
end
-- Уникальные активные эффекты без имени
elseif(mw.ustring.match(activeText, "{{[Uu]nique|.*") ~= nil) then
table.insert(activeTable, mw.ustring.format("%s[\"unique\"] = true,",
mw.ustring.rep(tab, 2)
))
table.insert(activeTable, mw.ustring.format("%s[\"description\"] = \"%s\",",
mw.ustring.rep(tab, 2),
mw.ustring.match(activeText, "{{[Uu]nique|(.*)}}")
))
if(itemValue.activecd) then
table.insert(activeTable, mw.ustring.format("%s[\"cd\"] = \"%s\",",
mw.ustring.rep(tab, 2),
tostring(itemValue.activecd)
))
end
else
-- Захватить описание
table.insert(activeTable, mw.ustring.format("%s[\"description\"] = \"%s\",",
mw.ustring.rep(tab, 2),
activeText
))
if(itemValue.activecd) then
table.insert(activeTable, mw.ustring.format("%s[\"cd\"] = \"%s\",",
mw.ustring.rep(tab, 2),
tostring(itemValue.activecd)
))
end
end
table.insert(activeTable, tab .. "},")
table.insert(itemInstance, table.concat(activeTable, "\r\n"))
end
-- consume
if(itemValue.consume) then
local consumeTable = { tab .. "[\"consume\"] = {" }
local consumeText = itemValue.consume
--Уникальные эффекты при использовании с именем
if(mw.ustring.match(consumeText, "{{[Uu]nique|[%s%d%a]-|") ~= nil) then
-- Захватить название эффекта
table.insert(consumeTable, mw.ustring.format("%s[\"name\"] = \"%s\",",
mw.ustring.rep(tab, 2),
mw.ustring.match(consumeText, "|(.-)|")
))
table.insert(consumeTable, mw.ustring.format("%s[\"unique\"] = true,",
mw.ustring.rep(tab, 2)
))
-- Захватить описание
table.insert(consumeTable, mw.ustring.format("%s[\"description\"] = \"%s\",",
mw.ustring.rep(tab, 2),
mw.ustring.match(consumeText, "{{[Uu]nique|[%s%d%a]-|(.*)}}")
))
-- Уникальные эффекты при использовании без имени
elseif(mw.ustring.match(consumeText, "{{[Uu]nique|.*") ~= nil) then
table.insert(consumeTable, mw.ustring.format("%s[\"unique\"] = true,",
mw.ustring.rep(tab, 2)
))
table.insert(consumeTable, mw.ustring.format("%s[\"description\"] = \"%s\",",
mw.ustring.rep(tab, 2),
mw.ustring.match(consumeText, "{{[Uu]nique|(.*)}}")
))
else
-- Захватить описание
table.insert(consumeTable, mw.ustring.format("%s[\"description\"] = \"%s\",",
mw.ustring.rep(tab, 2),
consumeText
))
end
table.insert(consumeTable, tab .. "},")
table.insert(itemInstance, table.concat(consumeTable, "\r\n"))
end
-- recipe
if(itemValue.recipe) then
local recipeTable = { tab .. "[\"recipe\"] = {"}
local recipeClone = lib.cloneTable(itemValue.recipe)
local recipeText
for recipeIndex, recipeValue in ipairs(recipeClone) do
table.insert(recipeTable, mw.ustring.format("\"%s\",", recipeValue))
end
if(#recipeClone > 2) then
recipeText = table.concat(recipeTable, "\r\n" .. mw.ustring.rep(tab, 2))
recipeText = recipeText .. "\r\n" .. tab .. "},"
else
recipeText = table.concat(recipeTable, " ") .. "},"
end
table.insert(itemInstance, recipeText)
end
--builds
if(itemValue.builds) then
local buildsTable = { tab .. "[\"builds\"] = {"}
local buildsClone = lib.cloneTable(itemValue.builds)
local buildsText
for buildsIndex, buildsValue in ipairs(buildsClone) do
table.insert(buildsTable, mw.ustring.format("\"%s\",", buildsValue))
end
if(#buildsClone > 2) then
buildsText = table.concat(buildsTable, "\r\n" .. mw.ustring.rep(tab, 2))
buildsText = buildsText .. "\r\n" .. tab .. "},"
else
buildsText = table.concat(buildsTable, " ") .. "},"
end
table.insert(itemInstance, buildsText)
end
-- buy
if(itemValue.buy) then
table.insert(itemInstance, mw.ustring.format("%s[\"buy\"] = %d,", tab, itemValue.buy))
end
-- comb
if(itemValue.comb) then
table.insert(itemInstance, mw.ustring.format("%s[\"comb\"] = %d,", tab, itemValue.comb))
end
-- sell
if(itemValue.sell) then
table.insert(itemInstance, tab .. "[\"sellratio\"] = 0.4,")
end
table.insert(itemInstance, "},")
table.insert(result, table.concat(itemInstance, "\r\n"))
end
return table.concat(result, "\r\n")
end
function p.createItemCheatSheet()
local tableNode = mw.html.create("table")
tableNode
:addClass("wikitable sortable")
:attr("width", "100%")
:newline()
:done()
tableNode
:tag("tr")
:tag("th")
:attr("width", "40%")
:wikitext("Предмет")
:done()
:tag("th")
:attr("width", "40%")
:wikitext("Английское название")
:done()
:tag("th")
:wikitext("ID")
:attr("data-sort-type", "number")
:done()
:done()
:done()
for k, v in lib.pairsByAlphabeticalKeys(items) do
local rowNode = mw.html.create("tr")
rowNode
:tag("td")
:wikitext(k)
:newline()
:done()
:tag("td")
:wikitext(v.engname)
:newline()
:done()
:tag("td")
:wikitext(v.id)
:newline()
:done()
:newline()
:done()
tableNode
:node(rowNode)
:newline()
:done()
end
return tostring(tableNode)
end
function p.createOldItemCheatSheet()
local tableNode = mw.html.create("table")
tableNode
:addClass("wikitable sortable")
:attr("width", "100%")
:newline()
:done()
tableNode
:tag("tr")
:tag("th")
:attr("width", "40%")
:wikitext("Предмет")
:done()
:tag("th")
:attr("width", "40%")
:wikitext("Английское название")
:done()
:tag("th")
:wikitext("ID")
:attr("data-sort-type", "number")
:done()
:done()
:done()
local oldItems = mw.loadData("Модуль:ItemData/data/removed")
for k, v in lib.pairsByAlphabeticalKeys(oldItems) do
local rowNode = mw.html.create("tr")
rowNode
:tag("td")
:wikitext(k)
:newline()
:done()
:tag("td")
:wikitext(v.engname)
:newline()
:done()
:tag("td")
:wikitext(v.id)
:newline()
:done()
:newline()
:done()
tableNode
:node(rowNode)
:newline()
:done()
end
return tostring(tableNode)
end
-- Данная функция сверяет целостность полей состава предметов и списка улучшений у их компонентов
function p.checkItemDataConsistency()
local inconsistentRecipe = {}
local inconsistentUpgrade = {}
-- Проигнорировать предоставляемые предметы
IGNORED_ITEMS = {
["Сломанный секундомер"] = true,
["Заведенный секундомер"] = true,
["Ботинки с капелькой магии"] = true
}
for k, v in pairs(items) do
repeat
if(IGNORED_ITEMS[k] == true) then
break
end
local itemRecipe = v["recipe"]
if(itemRecipe ~= nil) then
for _, recipeComponent in ipairs(itemRecipe) do
if(items[recipeComponent] == nil) then
table.insert(inconsistentUpgrade, {recipeComponent, "(Не найдено)"})
break
end
local itemUpgrades = items[recipeComponent]["builds"]
if(itemUpgrades ~= nil) then
if(lib.find(itemUpgrades, k) < 0) then
table.insert(inconsistentUpgrade, {k, recipeComponent})
end
end
end
end
local itemBuilds = v["builds"]
if(v["builds"] ~= nil) then
for _, upgrade in ipairs(itemBuilds) do
if(items[upgrade] == nil) then
table.insert(inconsistentRecipe, {upgrade, "(Не найдено)"})
break
end
local recipe = items[upgrade]["recipe"]
if(recipe ~= nil) then
if(lib.find(recipe, k) < 0) then
table.insert(inconsistentRecipe, {k, upgrade})
end
end
end
end
until true
end
local result = {""}
for _, v in ipairs(inconsistentRecipe) do
table.insert(result, mw.ustring.format(
"Несоответствие: '''%s''' указан как улучшение '''%s''', но тот в составе '''%s''' он не указан",
v[2],
v[1],
v[2])
)
end
for _, v in ipairs(inconsistentUpgrade) do
table.insert(result, mw.ustring.format(
"Несоответствие: '''%s''' указан в составе '''%s''', но тот не указан как улучшение у '''%s'''",
v[2],
v[1],
v[2])
)
end
if(#result == 1) then result = {"Ошибок не обнаружено"} end
return table.concat(result, "<br />")
end
return p
-- </pre>
-- [[Категория:Lua]]