Модуль:Инвентарный слот: различия между версиями
Внешний вид
Spark108 (обсуждение | вклад) Новая страница: «---------------------------------------------------------------------------- --- Модуль для отображения инвентарных слотов в Minecraft Wiki. --- ВНИМАНИЕ: Любые изменения в этом модуле отразятся на тысячах статей! ---------------------------------------------------------------------------- local p = {} ------------------------------------- -- Глобально...» |
Spark108 (обсуждение | вклад) м 1 версия импортирована |
(нет различий)
|
Версия от 10:40, 26 марта 2025
Для документации этого модуля может быть создана страница Модуль:Инвентарный слот/doc
----------------------------------------------------------------------------
--- Модуль для отображения инвентарных слотов в Minecraft Wiki.
--- ВНИМАНИЕ: Любые изменения в этом модуле отразятся на тысячах статей!
----------------------------------------------------------------------------
local p = {}
-------------------------------------
-- Глобально экспортируемые данные
-------------------------------------
-- Данные по интернационализации и локализации
local i18n = {
-- Стандартные наименования файлов
filename = 'Grid $1',
--legacyFilename = 'Grid $1',
commonsFilename = 'Invicon $1', -- для файлов из общего хранилища
-- Ссылка на статью, касающуюся модификации
modLink = '$1/$2',
-- Модули, отвечающие за псевдонимы
moduleAliases = [[Модуль:Инвентарный слот/Псевдонимы]],
moduleModAliases = [[Модуль:Инвентарный слот/Псевдонимы/$1]],
-- Модули, отвечающие за англоязычные названия (вместе с псевдонимами)
moduleEnglish = [[Модуль:Инвентарный слот/Англоязычные названия]],
moduleModEnglish = [[Модуль:Инвентарный слот/Англоязычные названия/$1]],
-- Спрайтовые модули
moduleSprite = [[Модуль:Спрайт]],
moduleInvData = [[Модуль:ИнвСпрайт]],
moduleModData = [[Модуль:ИнвСпрайт/$1]],
-- Служебные модули
moduleRandom = [[Модуль:Случайные числа]],
moduleUtils = [[Модуль:Специальные утилиты]],
moduleMods = [[Модуль:Модификации]],
-- Начальные формы приставок к названиям некоторых псевдонимов.
-- Для использования с модулем «Склонение прилагательных»
prefixes = {
any = "любой",
matching = "соответствующий",
damaged = "повреждённый",
unwaxed = "невощёный"
},
-- Выражения для поиска вышеуказанных приставок.
-- Так будет легче, например, убирать их из целей ссылок.
-- Именно их, а не prefixes, следует использовать при переводе
-- модулей с англовики в функциях gsub и match (причём с mw.ustring).
prefixesMatch = {
any = 'Люб[оаы][йяе]',
matching = 'Соответствующ[иае][йяе]',
damaged = 'Повреждённ[ыао][йяе]',
unwaxed = '[Нн]евощён[ыао][йяе]',
},
-- Список суффиксов
suffixes = {
be = 'BE',
lce = 'LCE',
},
-- Список цветов
colors = {
"белый", "оранжевый", "сиреневый", "голубой", "жёлтый", "лаймовый",
"розовый", "серый", "светло-серый", "бирюзовый", "фиолетовый", "синий",
"коричневый", "зелёный", "красный", "чёрный"
}
}
p.i18n = i18n
-- Для совместимости
p.prefixes = {
'Любой', 'Любая', 'Любое', 'Любые',
'Повреждённый', 'Повреждённая', 'Повреждённое', 'Повреждённые',
'Соответствующий', 'Соответствующая', 'Соответствующее', 'Соответствующие',
'Невощёный', 'Невощёная', 'Невощёное', 'Невощёные'
}
p.modAliases = mw.loadData("Модуль:Модификации")
-----------------------------------------
-- Внутренние глобальные данные модуля
-----------------------------------------
local modIds = {}
local modAliases = {}
local random = require(i18n.moduleRandom).random
local tryLoadData = require(i18n.moduleUtils).tryLoadData
local mergeList = require(i18n.moduleUtils).mergeList
local sprite = require(i18n.moduleSprite).sprite
local aliases = mw.loadData(i18n.moduleAliases)
local modNames = mw.loadData(i18n.moduleMods)
local vanilla = {v = 1, vanilla = 1, mc = 1, minecraft = 1}
local ids = mw.loadData(i18n.moduleInvData)["IDы"]
local pageName = mw.title.getCurrentTitle().text
-----------------------
-- Служебные функции
-----------------------
-- Разбор строки, разделённой точками с запятой.
-- Учитывает, что точка с запятой может быть внутри квадратных скобок.
local function splitOnUnenclosedSemicolons(text)
local semicolon, lbrace, rbrace = (";[]"):byte(1, 3)
local nesting = false
local splitStart = 1
local frameIndex = 1
local frames = {}
for index = 1, text:len() do
local byte = text:byte(index)
if byte == semicolon and not nesting then
frames[frameIndex] = text:sub(splitStart, index - 1)
frameIndex = frameIndex + 1
splitStart = index + 1
elseif byte == lbrace then
assert(not nesting, "Ошибка синтаксиса: чрезмерные квадратные скобки")
nesting = true
elseif byte == rbrace then
assert(nesting, "Ошибка синтаксиса: несбалансированные квадратные скобки")
nesting = false
end
end
assert(not nesting, "Ошибка синтаксиса: несбалансированные квадратные скобки")
frames[frameIndex] = text:sub(splitStart, text:len())
for index = 1, #frames do
frames[index] = (frames[index]:gsub("^%s+", ""):gsub("%s+$", "")) -- быстрее mw.text.trim
end
return frames
end
p.splitOnUnenclosedSemicolons = splitOnUnenclosedSemicolons -- для совместимости
-- Простая рекурсивная копия значений таблицы
local function cloneTable(origTable)
local newTable = {}
for k, v in pairs(origTable) do
if type(v) == "table" then
v = cloneTable(v)
end
newTable[k] = v
end
return newTable
end
-- Отделяет расширение от названия фрейма, если оно есть.
-- Возвращяет название без расширения и либо само расширение,
-- либо png в случае его отсутствия.
local function splitExtension(name)
if name:match('%.gif$') or name:match('%.png$') then
-- расширения англоязычные, представляют собой ASCII-символы,
-- поэтому обычные match и sub безопасны
return name:sub(0, -5), name:sub(-3)
elseif name:match('%.webp$') then
return name:sub(0, -6), 'webp'
else
return name, 'png'
end
end
-- Создаёт HTML-код для предмета.
-- args является таблицей аргументов, принятой самим модулем
local function makeItem(frame, args)
-- Создание HTML-элемента
local item = mw.html.create('span'):addClass('invslot-item')
if args["классизобр"] then
item:addClass(args["классизобр"])
end
if args["стильизобр"] then
item:cssText(args["стильизобр"])
end
local scale = tonumber(args["масштаб"]) or 1
local imgSize = 32 * scale
if scale ~= 1 then
item:css{
width = imgSize .. "px",
height = imgSize .. "px"
}
end
if not frame.name or frame.name == '' then
-- пустой фрейм
return item
end
local category -- категории
-- Параметры фрейма
local title = mw.text.trim(args["назв"] or '')
if mw.ustring.lower(title) ~= "нет" then
title = frame.title or title
end
local mod = frame.mod
local name = frame.name
local num = frame.num
local description = frame.text
local english = frame.english
-- Построение изображения
local img, idData, extension
-- Модификация?
if mod then
-- Пытаемся загрузить список ИнвСпрайтов для модификации
modData = modIds[mod]
if not modData then
modData = tryLoadData(i18n.moduleModData:gsub("%$1", mod))
if modData then
local idsOverride = modData["настройки"]["списокID"]
if idsOverride then
modData = tryLoadData("Модуль:" .. idsOverride)["IDы"]
else
modData = modData["IDы"]
end
end
modIds[mod] = modData
end
-- Импорт англоязычного названия из отдельного модуля (при наличии и необходимости)
if not english then
local enNames = tryLoadData(i18n.moduleModEnglish:gsub("%$1", mod))
english = enNames and enNames[name]
end
if modData and modData[name] then -- из ИнвСпрайта
idData = modData[name]
english = english or idData["en"] -- для совместимости
else -- из Grid-файла
name, extension = splitExtension(name)
img = i18n.filename:gsub("%$1", name .. ' (' .. mod .. ')') .. '.' .. extension
end
-- Конец обработки иконок из модификаций
else
-- Ванильная иконка
-- Импорт англоязычного названия из отдельного модуля (при необходимости)
if not english then
local enNames = mw.loadData(i18n.moduleEnglish)
english = enNames and enNames[name]
end
if type(frame.commons) == 'string' then
-- Ванильный Invicon-файл из общего хранилища
img, extension = splitExtension(frame.commons)
img = i18n.commonsFilename:gsub("%$1", img) .. '.' .. extension
elseif english and frame.commons ~= false then
-- Автоопределение Invicon-файла по англоязычному названию.
-- ВНИМАНИЕ: если вручную переопределяете англоназвание, укажите
-- явным образом Invicon-файл!
img, extension = splitExtension(english)
img = i18n.commonsFilename:gsub("%$1", img) .. '.' .. extension
elseif ids[name] then
-- Ванильный ИнвСпрайт
idData = ids[name]
else
-- Ванильный Grid-файл, загруженный локально
name, extension = splitExtension(name)
img = i18n.filename:gsub("%$1", name) .. '.' .. extension
end
end
-- К данному моменту задана переменная:
-- 1) idData, если иконка взята из таблицы спрайтов, либо
-- 2) img, если иконка берётся из Grid-файла.
-- Формирование цели ссылки
local link = mw.text.trim(args["ссылка"] or '')
if link == '' then -- поведение по умолчанию
if mod then
link = i18n.modLink:gsub('%$1', mod):gsub('%$2', name)
else
-- Убираем префикс повреждённых предметов
link = mw.ustring.gsub(name, '^'.. i18n.prefixesMatch.damaged .. ' ', '')
-- Убираем суффиксы изданий
for _, suffix in pairs(i18n.suffixes) do
link = mw.ustring.gsub(link, ' ' .. suffix .. '$', '')
end
end
elseif mw.ustring.lower(link) == "нет" then
-- Отключение ссылки
link = nil
end
if link and mw.ustring.gsub(link, "^%l", mw.ustring.upper) == pageName then
-- отключаем ссылку на текущую страницу
link = nil
end
-- Форматирование заголовка
local formattedTitle, plainTitle
if title == '' then
plainTitle = name
elseif mw.ustring.lower(title) ~= "нет" then
-- Временное преобразование экранированных служебных символов
plainTitle = title:gsub('\\\\', '\'):gsub('\\&', '&')
-- Очищаем «простой» заголовок от форматирования
local formatPattern = '&[0-9a-jl-qs-wr]'
if plainTitle:match(formatPattern) then
formattedTitle = title
plainTitle = plainTitle:gsub(formatPattern, '')
end
if plainTitle == '' then
plainTitle = name
else
-- Превращаем экранированные символы в финальную форму
plainTitle = plainTitle:gsub('\', '\\'):gsub('&', '&')
end
elseif link then
if img then
formattedTitle = ''
else
plainTitle = ''
end
end
-- Добавляем атрибуты для minetip
item:attr{
['data-minetip-title'] = formattedTitle,
['data-minetip-text'] = description,
['data-modinfo-text'] = mod,
['data-minetip-lowtitle'] = english
}
-- Иконка
if img then
-- Grid-файл
-- & экранируется повторно, так как mw.html считает атрибуты
-- простым текстом, а MediaWiki — нет.
local escapedTitle = (plainTitle or ''):gsub('&', '&')
item:addClass('invslot-item-image')
:wikitext('[[Файл:', img, '|', imgSize, 'x', imgSize, 'px|link=', link or '', '|', escapedTitle, ']]')
else
-- ИнвСпрайт
if link then -- начало ссылки
item:wikitext('[[', link, '|')
end
local image, spriteCat
local dataPage = mod and ("ИнвСпрайт/" .. mod) or "ИнвСпрайт"
image, spriteCat = sprite{
["масштаб"] = scale, ["данныеID"] = idData, ["назв"] = plainTitle,
["данные"] = dataPage
}
item:node(image)
category = spriteCat
end
-- Размер стопки
if num and num > 1 and num < 1000 then
if img and link then
-- Открываем ссылку, если используется Grid-файл.
-- Для ИнвСпрайта ссылка уже была открыта ранее.
item:wikitext('[[', link, '|')
end
local number = item:tag('span')
:addClass('invslot-stacksize')
:attr{ title = plainTitle }
:wikitext(num)
if args["стильцифр"] then
number:cssText(args["стильцифр"])
end
if img and link then
-- Закрываем ссылку, если используется Grid-файл
item:wikitext(']]')
end
end
if idData and link then
-- Закрываем ссылку, если используется ИнвСпрайт
item:wikitext(']]')
end
-- Добавляем категории
item:wikitext(category)
-- Возвращаем предмет
return item
end
----------------------------------
-- Общедоступные функции модуля
----------------------------------
-- Создаёт слот. Служит основной точкой входа
function p.slot(f)
-- Получение аргументов
local args = f.args or f
if f == mw.getCurrentFrame() and args[1] == nil then
args = f:getParent().args
end
if type(args[1]) == "string" then
-- Нормализация первого аргумента
args[1] = mw.text.trim(args[1] or '')
end
-- Если задан аргумент «обработанный», то подразумевается, что
-- args[1] — это список фреймов в табличном формате.
-- Модификация по умолчанию (не действует, если первый аргумент табличный)
local defaultMod = mw.text.trim(args["мод"] or '')
if defaultMod == '' then
defaultMod = nil
elseif modNames[defaultMod] then
defaultMod = modNames[defaultMod]
end
if defaultMod then
defaultMod = defaultMod:gsub('_', ' ')
defaultMod = mw.ustring.gsub(defaultMod, "^%l", mw.ustring.upper)
end
-- Сохраняем список фреймов в табличном формате
local frames
if args["обработанный"] then
frames = args[1]
elseif args[1] and args[1] ~= '' and args[1] ~= {} then
local randomise = args["класс"] == 'invslot-large' and "никогда" or nil
if args[1][1] then
frames = p.expandAliases(args[1], randomise, false)
else
frames = p.parseFrameText(args[1], randomise, false, defaultMod)
end
end
-- Слот анимированный?
local animated = frames and #frames > 1
-- Построение HTML-элемента
local body = mw.html.create('span'):addClass('invslot'):css{
['vertical-align'] = args["выравн"]
}
if animated then
-- включаем анимацию
body:addClass('animated')
end
-- Масштабирование слота
local scale = tonumber(args["масштаб"]) or 1
if scale ~= 1 then
local imgSize = 32 * scale
body:css{ width = imgSize .. "px", height = imgSize .. "px" }
if scale == 0.5 then
-- компенсация высоты для уменьшенного слота?
body:css{ top = '-1px' }
end
end
-- Добавляем дополнительные классы и стили
if args["класс"] then
body:addClass(args["класс"])
end
if args["стиль"] then
body:cssText(args["стиль"])
end
-- Добавляем фон умолчания
if (args["умолчание"] or "") ~= "" then
body:addClass(args["умолчание"] .. '-slot')
end
-- Фоновый спрайт умолчания для GregTech (временная реализация)
local backID = args["Фон ИД"]
if defaultMod and defaultMod:match("GregTech") and backID then
local pos = backID - 1
local left = (pos % 10) * 32
local top = math.floor(pos / 10) * 32
body:addClass('gt-invslot'):css{
['background-size'] = '320px auto',
['background-position'] = '-' .. left .. 'px -' .. top .. 'px'
}
end
if not frames or #frames == 0 then
-- Вырожденный случай (нет фреймов)
return tostring(body)
end
-- Активный фрейм для анимации
local activeFrame = frames["рандомизация"] == true and random(#frames) or 1
-- Добавление фреймов
for i, frame in ipairs(frames) do
local item
-- Проверка на наличие подфреймов
if frame[1] then
-- Контейнер подфреймов
item = body:tag('span'):addClass('animated-subframe')
local subActiveFrame = frame["рандомизация"] == true and random(#frame) or 1
for sI, sFrame in ipairs(frame) do
-- Добавляем подфрейм
local sItem = makeItem(sFrame, args)
item:node(sItem)
if sI == subActiveFrame then
-- задаём активным
sItem:addClass('animated-active')
end
end
else
-- Обычный фрейм
item = makeItem(frame, args)
body:node(item)
end
if i == activeFrame and animated then
-- задаём активным
item:addClass('animated-active')
end
end
-- Возвращаем готовый слот
return tostring(body)
end
-- Преобразует список фреймов из текстового формата в табличный
function p.convertFrameText(framesText, defaultMod)
-- Списки фреймов
local frames = {}
local subframes = {}
-- Является ли текущий фрейм подфреймом?
local subframe
-- Обрабатываем фреймы
for i, frameText in ipairs(splitOnUnenclosedSemicolons(framesText)) do
-- Подфреймы группируются в фигурные скобки
frameText = frameText:gsub('^%s*{%s*', function()
subframe = true
return ''
end )
if subframe then
-- Находим закрывающую фигурную скобку
frameText = frameText:gsub('%s*}%s*$', function()
subframe = "последний"
return ''
end )
end
-- Преобразуем фрейм в табличный формат с применением
-- модификации по умолчанию
local frame = p.makeFrame(frameText, defaultMod)
local newFrame = frame
-- Добавление фреймов
if subframe then
mergeList(subframes, newFrame)
if subframe == "последний" then
table.insert(frames, subframes)
subframes = {}
subframe = nil
end
else
mergeList(frames, newFrame)
end
end
-- Возвращаем последовательность фреймов
return frames
end
-- Раскрывает все псевдонимы в последовательности фреймов (в т. ч. подфреймов).
-- Позволяет сохранить ссылку на исходный псевдоним. Также определяет, нужно ли
-- рандомизировать слот.
function p.expandAliases(frames, randomize, aliasReference)
local newFrames = { ["рандомизация"] = randomize }
-- Раскрытые псевдонимы
local expandedAliases
-- Обрабатываем фреймы
for i, frame in ipairs(frames) do
local alias
if frame[1] then
-- Это контейнер подфреймов, осуществляем раскрытие рекурсивно
local subframes = p.expandAliases(frame, randomize, aliasReference)
if #subframes == 1 then
table.insert(newFrames, subframes[1])
else
table.insert(newFrames, subframes)
end
else
-- Выбираем таблицу псевдонимов в зависимости от указания модификации
if frame.mod then
if not modAliases[frame.mod] then
modAliases[frame.mod] = tryLoadData(i18n.moduleModAliases:gsub('%$1', frame.mod))
end
if modAliases[frame.mod] then
alias = modAliases[frame.mod][frame.name]
end
else
-- Используем ванильные псевдонимы
alias = aliases[frame.name]
end
-- Псевдоним найден
if alias then
-- Раскрываем его
newFrame = p.getAlias(alias, frame)
-- Сохраняем ссылку на исходный псевдоним
if aliasReference then
local curFrame = #newFrames + 1
local aliasData = { ["фрейм"] = frame, ["длина"] = #newFrame }
if not expandedAliases then
expandedAliases = {}
end
expandedAliases[curFrame] = aliasData
end
-- Добавляем фрейм(ы)
mergeList(newFrames, newFrame)
-- Включаем рандомизацию первого фрейма для псевдонимов вида
-- «любой предмет», если этот псевдоним является единственным
-- фреймом.
if newFrames["рандомизация"] ~= "никогда" and mw.ustring.match(frame.name, '^' .. i18n.prefixesMatch.any .. ' ') then
newFrames["рандомизация"] = true
else
newFrames["рандомизация"] = false
end
else
-- Не псевдоним; добавляем как есть
table.insert(newFrames, frame)
end
end
end
newFrames["ссылканапсевдонимы"] = expandedAliases
-- Возвращаем раскрытую последовательность фреймов
return newFrames
end
-- Преобразует текстовый список фреймов в таблицу фреймов и подфреймов.
-- Все псевдонимы раскрываются (с возможным сохранением ссылок).
-- Также функция определяет, нужно ли рандомизировать слот.
function p.parseFrameText(framesText, randomize, aliasReference, defaultMod)
-- Списки фреймов
local frames = { ["рандомизация"] = randomize }
local subframes = {}
-- Является ли текущий фрейм подфреймом?
local subframe
-- Раскрытые псевдонимы
local expandedAliases
-- Фреймы в текстовом виде
local splitFrames = splitOnUnenclosedSemicolons(framesText)
for i, frameText in ipairs(splitFrames) do
-- Подфреймы группируются в фигурные скобки
frameText = frameText:gsub('^%s*{%s*', function()
subframe = true
return ''
end )
if subframe then
-- Находим закрывающую фигурную скобку
frameText = frameText:gsub('%s*}%s*$', function()
subframe = "последний"
return ''
end )
end
-- Преобразуем фрейм в табличный формат с применением
-- модификации по умолчанию
local frame = p.makeFrame(frameText, defaultMod)
local newFrame = frame
-- Раскрываем псевдонимы
local alias
if frame.mod then
if not modAliases[frame.mod] then
modAliases[frame.mod] = tryLoadData(i18n.moduleModAliases:gsub('%$1', frame.mod))
end
if modAliases[frame.mod] then
alias = modAliases[frame.mod][frame.name]
end
else
alias = aliases[frame.name]
end
-- Псевдоним найден
if alias then
-- Раскрываем его
newFrame = p.getAlias(alias, frame)
if aliasReference then
-- Сохраняем ссылку на псевдоним
local curFrame = #frames + 1
local aliasData = { ["фрейм"] = frame, ["длина"] = #newFrame }
if subframe then
if not subframes["ссылканапсевдонимы"] then
subframes["ссылканапсевдонимы"] = {}
end
subframes["ссылканапсевдонимы"][#subframes+1] = aliasData
else
if not expandedAliases then
expandedAliases = {}
end
expandedAliases[curFrame] = aliasData
end
end
end
-- Конец обработки псевдонимов
-- Добавление фреймов и управление рандомизацией
if subframe then
mergeList(subframes, newFrame)
-- Включаем рандомизацию первого фрейма для псевдонима вида
-- «любой предмет», если этот псевдоним является единственным
-- подфреймом.
if frames["рандомизация"] ~= "никогда" and subframes["рандомизация"] == nil and mw.ustring.match(frame.name, '^' .. i18n.prefixesMatch.any .. ' ') then
subframes["рандомизация"] = true
else
subframes["рандомизация"] = false
end
if frames["рандомизация"] ~= "никогда" then
frames["рандомизация"] = false
end
if subframe == "последний" then
if #subframes == 1 or #splitFrames == i and #frames == 0 then
-- Если подфрейм единственный в своём контейнере, а тем более
-- во всей последовательности фреймов, то он «извлекается»
-- из контейнера
mergeList(frames, subframes)
else
table.insert(frames, subframes)
end
subframes = {}
subframe = nil
end
else
-- Включаем рандомизацию первого фрейма для псевдонимов вида
-- «любой предмет», если этот псевдоним является единственным
-- фреймом.
if frames["рандомизация"] ~= "никогда" and mw.ustring.match(frame.name, '^' .. i18n.prefixesMatch.any .. ' ') then
frames["рандомизация"] = true
else
frames["рандомизация"] = false
end
mergeList(frames, newFrame)
end -- конец добавления фреймов в последовательность
end
-- Сохраняем ссылку на псевдонимы, если сохранена
frames["ссылканапсевдонимы"] = expandedAliases
-- Возвращяем последовательность фреймов
return frames
end
-- Раскрывает заданный псевдоним в таблицу, дополнив её данными из материнского фрейма
function p.getAlias(aliasFrames, parentFrame)
-- Если псевдоним состоит лишь из названия, то используем его для переопределения
-- названия материнского фрейма
if type(aliasFrames) == 'string' then
local expandedFrame = mw.clone(parentFrame)
expandedFrame.name = aliasFrames
return { expandedFrame }
end
-- Если псевдоним является единичным фреймом, то помещаем его в список
if aliasFrames.name then
aliasFrames = { aliasFrames }
end
-- Общий случай: псевдоним для группы фреймов
local expandedFrames = {}
for i, aliasFrame in ipairs(aliasFrames) do
local expandedFrame
if type(aliasFrame) == 'string' then
-- Простой фрейм
expandedFrame = { name = aliasFrame }
else
-- Сложный фрейм.
-- Поскольку он импортирован через mw.loadData, то для изменения
-- содержимого его необходимо клонировать.
expandedFrame = cloneTable(aliasFrame)
end
expandedFrame.title = parentFrame.title or expandedFrame.title
expandedFrame.num = parentFrame.num or expandedFrame.num
expandedFrame.text = parentFrame.text or expandedFrame.text
expandedFrame.english = parentFrame.english or expandedFrame.english
expandedFrame.commons = parentFrame.commons or expandedFrame.commons
-- Если у фрейма в псевдонимах задана модификация, то она имеет приоритет
-- Так можно создавать для модов псевдонимы с ванильными вещами
if expandedFrame.mod then
if not vanilla[mw.ustring.lower(expandedFrame.mod)] then
expandedFrame.mod = modNames[expandedFrame.mod] or expandedFrame.mod
else
expandedFrame.mod = nil
end
else
expandedFrame.mod = parentFrame.mod
end
-- Добавляем фрейм в список
expandedFrames[i] = expandedFrame
end
return expandedFrames
end
-- Обёртка для обеспечения совместимости
function p.expandAlias(parentFrame, alias)
return p.getAlias(alias, parentFrame)
end
-- Преобразует фрейм в текстовый формат
function p.stringifyFrame(frame)
if not frame.name then
-- вырожденный случай
return ''
end
local title = frame.title and ('[' .. frame.title .. ']') or ''
local english = frame.english and ('[' .. frame.english .. ']') or ''
local commons = frame.commons and ('[' .. frame.commons .. ']') or ''
local mod = frame.mod or 'minecraft'
local num = frame.num or '1'
local text = frame.text and ('[' .. frame.text .. ']') or ''
return title .. english .. commons .. mod .. ':' .. frame.name .. ',' .. num .. text
end
-- Преобразует последовательность фреймов в текстовый формат
function p.stringifyFrames(frames)
local strFrames = {}
for i, frame in ipairs(frames) do
if frame[1] then
-- контейнер подфреймов
strFrames[i] = '{' .. p.stringifyFrames(frame) .. '}'
else
strFrames[i] = p.stringifyFrame(frame)
end
end
return table.concat(strFrames, ';')
end
-- Преобразует текстовое обозначение фрейма в табличный формат
function p.makeFrame(frameText, defaultMod)
-- Простейший случай: одно только название
if not frameText:match('[%[:,]') then
return { mod = defaultMod, name = mw.text.trim(frameText) }
end
-- Сложный фрейм
local frame = {}
-- Заголовок
local title, rest = mw.ustring.match(frameText, '^%s*%[([^%]]*)%]%s*(.*)')
if title then
frame.title = title
frameText = rest
end
-- Англоязычный заголовок
local english, rest = mw.ustring.match(frameText, '^%[([^%]]*)%]%s*(.*)')
if english then
frame.english = english
frameText = rest
end
-- Название файла в общем хранилище
local commons, rest = mw.ustring.match(frameText, '^%[([^%]]*)%]%s*(.*)')
if commons then
frame.commons = commons
frameText = rest
end
-- Дополнительный текст
local rest, text = mw.ustring.match(frameText, '([^%]]*)%s*%[([^%]]*)%]%s*$')
if text then
frame.text = text
frameText = rest
end
-- Модификация
local mod, rest = mw.ustring.match(frameText, '^([^:]+):%s*(.*)')
if mod then
if not vanilla[mw.ustring.lower(mod)] then
frame.mod = modNames[mod] or mod
frame.mod = frame.mod:gsub('_', ' ')
frame.mod = mw.ustring.gsub(frame.mod, "^%l", mw.ustring.upper)
end
frameText = rest
else
frame.mod = defaultMod
frameText = frameText:gsub('^:', '')
end
-- Название и размер стопки
local name, num = mw.ustring.match(frameText, '(.*),%s*(%d+)')
if num then
-- Есть размер
frame.name = mw.text.trim(name)
frame.num = math.floor(num)
if frame.num < 2 then
frame.num = nil
end
else
-- Размера нет
frame.name = mw.text.trim(frameText)
end
return frame
end
-- Псевдоним функции для совместимости
p.getParts = p.makeFrame
return p