Перейти к содержанию

Модуль:Крафт: различия между версиями

Материал из LemonCraft Wiki
Новая страница: «---------------------------------------------------------------------------------- --- Модуль для создания таблиц с рецептами для крафта. --- ВНИМАНИЕ: Изменения на этом модуле отразятся на большом количестве статей! ---------------------------------------------------------------------------------- local p = {} --- Интернационализация...»
м 1 версия импортирована
 
(нет различий)

Текущая версия от 10:40, 26 марта 2025

Для документации этого модуля может быть создана страница Модуль:Крафт/doc

----------------------------------------------------------------------------------
--- Модуль для создания таблиц с рецептами для крафта.
--- ВНИМАНИЕ: Изменения на этом модуле отразятся на большом количестве статей!
----------------------------------------------------------------------------------

local p = {}

--- Интернационализация и локализация
local i18n = {
	-- Зависимости
	moduleArgs = [[Модуль:ProcessArgs]],
	moduleSlot = [[Модуль:Инвентарный слот]],
	moduleRecipe = [[Модуль:Таблица рецептов]],
	jsonMergeRules = [[Модуль:Крафт/Правила группировки.json]],
	
	-- Параметры процесса
	type = "крафт",
	typeGenitive = "крафта",
	
	-- Форматы категорий
	categoryRecipeType = "[[Категория:Рецепты/$1]]",
	
	-- В оригинале название следующей категории имеет формат «Recipe using
	-- <предмет>». Прямо переводится эта конструкция как «Рецепт, использующий
	-- <предмет>». При этом название предмета должно было быть в винительном
	-- падеже, но на данный момент быстро склонять название предметов  в имени-
	-- тельном падеже с помощью модулей не представляется возможным. Поэтому в
	-- качестве перевода используется близкая по смыслу конструкция, не тре-
	-- бующая склонения.
	categoryIngredientUsage = "[[Категория:$1 как ингредиент для крафта]]",
	
	-- В отличие от англоязычной версии модуля, преобразования для категорий
	-- выведены в отдельную функцию. Здесь соответствующие строки не указываются
}

--- Внутренние глобальные данные модуля
local title = mw.title.getCurrentTitle()

-- Зависимости
local slot = require(i18n.moduleSlot)
local recipeTable = require(i18n.moduleRecipe).table

-- Аргументы, задающие ячейки
local cArgVals = {'A1', 'B1', 'C1', 'A2', 'B2', 'C2', 'A3', 'B3', 'C3'}
p.cArgVals = cArgVals

--- Служебные функции

-- Автоматически раскладывает бесформенный рецепт, определяемый нумерованными
-- параметрами
local function arrangeShapelessRecipe(args)
	if args[1] then
		args["бесформенный"] = 1
		if args[7] then
			args.A1 = args[1]
			args.B1 = args[2]
			args.C1 = args[3]
			args.A2 = args[4]
			args.B2 = args[5]
			args.C2 = args[6]
			if args[8] then
				-- ◼◼◼       ◼◼◼
				-- ◼◼◼  или  ◼◼◼
				-- ◼◼◼       ◼◼◻
				args.A3 = args[7]
				args.B3 = args[8]
				args.C3 = args[9]
				if args[9] then
					-- Если все слоты равны, то рецепт явно не бесформенный
					local identical = true
					for i = 1, 8 do
						if args[i] ~= args[i + 1] then
							identical = false
							break
						end
					end
					if identical then
						args["бесформенный"] = nil
					end
				end
			else
				-- ◼◼◼
				-- ◼◼◼
				-- ◻◼◻
				args.B3 = args[7]
			end
		elseif args[2] then
			args.A2 = args[1]
			args.B2 = args[2]
			if args[5] then
				-- ◻◻◻       ◻◻◻
				-- ◼◼◼  или  ◼◼◼
				-- ◼◼◼       ◼◼◻
				args.C2 = args[3]
				args.A3 = args[4]
				args.B3 = args[5]
				args.C3 = args[6]
			elseif args[4] then
				-- ◻◻◻
				-- ◼◼◻
				-- ◼◼◻
				args.A3 = args[3]
				args.B3 = args[4]
			else
				-- ◻◻◻       ◻◻◻
				-- ◼◼◻  или  ◼◼◻
				-- ◻◼◻       ◻◻◻
				args.B3 = args[3]
			end
		else
			-- ◻◻◻
			-- ◻◼◻
			-- ◻◻◻
			-- Рецепт из одного ингредиента по определению не может быть
			-- бесформенным
			args.B2 = args[1]
			args["бесформенный"] = nil
		end
		
		for i = 1, 9 do
			args[i] = nil
		end
	end
end

-- Следующая функция добавляет категории использования. Именно с их помощью
-- работает модуль «Использование для крафта».
-- Некоторые варианты ингредиентов описываются на общей статье, некоторые -
-- на раздельных. За разрешение таких случаев отвечает специальный JSON-файл.
-- Обязательно вносите или запрашивайте изменения туда в случае слияния
-- или разбиения статей!
local mergeRules = mw.loadJsonData(i18n.jsonMergeRules)
local prefixesMatch = slot.i18n.prefixesMatch

local function addUsageCategories(ingredientSets, categories)
	-- Уже обработанные ингредиенты на всякий случай кэшируются
	local usedNames = {}
	local function addName(name)
		if not usedNames[name] then
			local cat = i18n.categoryIngredientUsage:gsub("%$1", name)
			table.insert(categories, cat)
			usedNames[name] = true
		end
	end
	local function addNames(names)
		if names[1] then
			for _, name in ipairs(names) do
				addName(name)
			end
		else
			addName(names)
		end
	end
	
	-- Обрабатываем все наборы ингредиентов
	for _, ingredientSet in ipairs(ingredientSets) do
		for _, ingredient in ipairs(ingredientSet) do
			local name = ingredient.name
			if not ingredient.mod and not usedNames[name] then
				-- Сначала попытаемся прямо заменить то или иное название статьи
				local directReplace = mergeRules["прямая замена"][name]
				if directReplace then
					addNames(directReplace)
				else
					-- Теперь приступаем к обработке по шаблонам замены
					local replaced = false
					for _, patternReplace in ipairs(mergeRules["замена по шаблону"]) do
						if mw.ustring.find(name, patternReplace[1]) then
							addNames(patternReplace[2])
							replaced = true
							break
						end
					end
					
					if not replaced then
						-- Если шаблон не найден, то делается общая обработка
						
						-- Убираем типовые прилагательные
						for _, prefixMatch in pairs(prefixesMatch) do
							if mw.ustring.find(name, prefixMatch .. " ") then
								name = mw.ustring.gsub(name, prefixMatch .. " ", "")
								break
							end
						end
						
						-- Убираем специфические прилагательные для медных блоков
						if mw.ustring.find(name, "медн[ыао][йяе]") then
							name = mw.ustring.gsub(name, "^[Нн]евощён[ыао][йяе] ", "")
							name = mw.ustring.gsub(name, "^[Вв]ощён[ыао][йяе] ", "")
							name = mw.ustring.gsub(name, "^[Пп]отемневш[иае][йяе] ", "")
							name = mw.ustring.gsub(name, "^[Сс]остаренн[ыао][йяе] ", "")
							name = mw.ustring.gsub(name, "^[Оо]кисленн[ыао][йяе] ", "")
						end
						
						-- Обработка строк вида "А или Б"
						local orA, orB = mw.ustring.match(name, "(.-) или (.+)")
						if orA then
							addName(orA)
							addName(orB)
						else
							addName(name)
						end
					end
				end
			end
		end
	end
end

--- Основная функция
--- Строительство таблицы крафта
function p.table(f)
	-- Принимаем аргументы
	local args = f
	if f == mw.getCurrentFrame() then
		args = require('Модуль:ProcessArgs').merge(true)
	else
		f = mw.getCurrentFrame()
	end
	
	-- Автоматически раскладываем бесформенный рецепт
	arrangeShapelessRecipe(args)
	
	-- Строим таблицу и получаем списки ингредиентов
	local out, ingredientSets = recipeTable(args, {
		["функция интерфейса"] = 'craftingTable',
		["тип"] = i18n.type,
		["типа"] = i18n.typeGenitive,
		["аргументы ингредиентов"] = cArgVals,
		["аргументы выхода"] = {'Выход'},
	})
	
	if args["некат"] == "1" or args["игнорировать"] == "1" or title.namespace ~= 0 or title.isSubpage then
		return out
	else
		-- Простановка категорий. Она автоматически отключена вне пространства статей, а
		-- также на подстраницах (в т. ч. для модификаций). Для модов ещё не реализована
		-- адекватная поддержка механизма «Использование для крафта» — это предполагается
		-- сделать после переписывания модуля на базе Semantic MediaWiki.
		local categories = {}
		
		-- Тип рецепта
		if args["тип"] then
			local cat = i18n.categoryRecipeType:gsub("%$1", mw.text.trim(args["тип"]))
			table.insert(categories, cat)
		end
		
		-- Использование ингредиентов
		addUsageCategories(ingredientSets, categories)
		
		return out, table.concat(categories, "")
	end
end

return p