Модуль:Использование для крафта — различия между версиями

Материал из Playzone Minecraft Wiki
Перейти к: навигация, поиск
 
м (1 версия импортирована)
 
(нет различий)

Текущая версия на 01:27, 18 января 2017

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

-- Модуль для отображения списка рецептов крафта, в котором тот или иной предмет используется.

local p = {}
function p.dpl( f )
	local args = f:getParent().args
	local slot = require("Модуль:Инвентарный слот")
	local ingredients = args[1] and mw.text.split( args[1], '%s*,%s*' ) or { mw.title.getCurrentTitle().text }
	local matchTypes = args["фрагмент"] and mw.ustring.find(args["фрагмент"], ',' ) and mw.text.split( args["фрагмент"], '%s*,%s*' ) or args["фрагмент"]

	local argList = {
		'игнорировать', 'запланированное', 'имя', 'ингредиенты', 'группыарг',
		1, 2, 3, 4, 5, 6, 7, 8, 9,
		'A1', 'B1', 'C1', 'A2', 'B2', 'C2', 'A3', 'B3', 'C3',
		'Выход', 'описание', 'фиксированный', 'нефиксировано'
	}
	local anonToShaped = { 'A1', 'B1', 'C1', 'A2', 'B2', 'C2', 'A3', 'B3', 'C3' }
	local shapedToAnon = { A1 = 1, B1 = 2, C1 = 3, A2 = 4, B2 = 5, C2 = 6, A3 = 7, B3 = 8, C3 = 9 }

	local data = ''
	if args["категория"] then
		data = f:callParserFunction( '#dpl:', {
			category = args["категория"],
			nottitleregexp = args["игнорировать"],
			include = '{Крафт}:' .. table.concat( argList, ':' ),
			mode = 'userformat',
			secseparators = '====',
			multisecseparators = '====',
		} )
	else
		-- #dpl может обрабатывать максимум 4 категории сразу, поэтому обрабатываем группами по 4
		for i = 1, #ingredients, 4 do
			data = data .. f:callParserFunction( '#dpl:', {
				category = table.concat( ingredients, ' как ингредиент для крафта|', i, math.min( i + 3, #ingredients ) ) .. ' как ингредиент для крафта',
				nottitleregexp = args["игнорировать"],
				include = '{Крафт}:' .. table.concat( argList, ':' ),
				mode = 'userformat',
				secseparators = '====',
				multisecseparators = '====',
			} )
		end
	end
	
	-- Закомментируйте следующую строку, если псевдонимы не поддерживаются
	local aliases = mw.loadData( 'Модуль:Инвентарный слот/Псевдонимы' )
	
	local function matchPattern( ingredient, ingredientNum )
		local matchType = matchTypes
		if type( matchType ) == 'table' then
			matchType = matchTypes[ingredientNum]
		end
		local pattern
		local escaped = mw.ustring.lower(mw.ustring.gsub(ingredient, '([%(%)])', '%%%1' ))
		if matchType == 'начало' then
			pattern = '[;:%]]%s*' .. escaped
		elseif matchType == 'конец' then
			pattern = escaped .. '%s*[,;%[]'
		elseif matchType == 'любое' then
			pattern = escaped
		else
			pattern = '[;:%]]%s*' .. escaped .. '%s*[,;%[]'
		end
		
		return pattern
	end

	local function compareTables( a, b )
		for k, v in pairs( a ) do
			if type( b[k] ) ~= type( v ) then
				return false
			end
			if type( v ) == 'table' then
				if not compareTables( v, b[k] ) then
					return false
				end
			elseif v ~= b[k] then
				return false
			end
		end
		for k, v in pairs( b ) do
			if a[k] == nil then
				return false
			end
		end
		return true
	end

	local out = {}
	local showDesciption
	local templates = {}
	for template in mw.text.gsplit( data, '====' ) do
		-- Если параметр «игнорировать» не установлен...
		if mw.ustring.find(template, '^%s*|' ) then
			local tArgs = {}
			local i = 0
			-- Разбор аргументов из запроса DPL
			for tArg in mw.text.gsplit( template, '\n|' ) do
				i = i + 1
				if tArg ~= '' then
					local key = argList[i]
					tArgs[key] = tArg
				end
			end
			
			local craftingArgs = {
				tArgs[1] or tArgs.A1 or '', tArgs[2] or tArgs.B1 or '', tArgs[3] or tArgs.C1 or '',
				tArgs[4] or tArgs.A2 or '', tArgs[5] or tArgs.B2 or '', tArgs[6] or tArgs.C2 or '',
				tArgs[7] or tArgs.A3 or '', tArgs[8] or tArgs.B3 or '', tArgs[9] or tArgs.C3 or '',
				["Выход"] = tArgs["Выход"]
			}
			
			local expandedFrames = {}
			local hasIngredient
			local argsWithIngredient = {}
			local argGroups = {}
			for i, v in pairs( craftingArgs ) do
				if v ~= '' then
					if aliases then
						expandedFrames[i] = {}
						local expandedFrame = {}
						for frame in mw.text.gsplit( v, '%s*;%s*' ) do
							local parts = slot.getParts( frame )
							local alias = aliases[parts.name]
							if alias then
								local expandedAlias = mw.ustring.gsub(slot.expandAlias( parts, alias ), '%s*([%[%]:,;])%s*', '%1' )
								expandedFrames[i][frame] = mw.ustring.gsub(expandedAlias, '([%(%)])', '%%%1' )
								table.insert( expandedFrame, expandedAlias )
							else
								table.insert( expandedFrame, frame )
							end
						end
						
						v = table.concat( expandedFrame, ';' )
						craftingArgs[i] = v
					end
					if i ~= 'Выход' then
						local delimitedFrames = ';' .. mw.ustring.lower(v) .. ';'
						for ingredientNum, ingredient in pairs( ingredients ) do
							if mw.ustring.find(delimitedFrames, matchPattern( ingredient, ingredientNum ) ) then
								if not mw.ustring.find(v, ';' ) then
									hasIngredient = 'static'
								elseif not hasIngredient then
									hasIngredient = 'animated'
								end
								
								argsWithIngredient[i] = true
							end
						end
					end
					
					if not tArgs["группыарг"] and hasIngredient ~= 'static' then
						local _, frameCount = v:gsub( ';', '' )
						if frameCount > 0 then
							frameCount = frameCount + 1
							local group = argGroups[frameCount]
							if not group then
								group = { args = {} }
								argGroups[frameCount] = group
							end
							group.count = frameCount
							group.args[i] = true
						end
					end
				end
			end
			
			if hasIngredient then
				if tArgs["описание"] then
					showDescription = true
				end
				
				if hasIngredient == 'animated' then
					if tArgs["группыарг"] then
						for argGroup in mw.text.gsplit( tArgs["группыарг"], '%s*;%s*' ) do
							local group = {}
							local _, frameCount
							for arg in mw.text.gsplit( argGroup, '%s*,%s*' ) do
								if not tArgs[1] then
									arg = shapedToAnon[arg]
								end
								if not frameCount then
									_, frameCount = mw.ustring.gsub(craftingArgs[arg], ';', '' )
								end
								group[arg] = true
							end
							table.insert( argGroups, { count = frameCount + 1, args = group } )
						end
					end
					
					for _, groupData in pairs( argGroups ) do
						local frameCount = groupData.count
						local group = groupData.args
						local requiredFrames = {}
						local requiredFramesCount = 0
						for arg in pairs( group ) do
							if argsWithIngredient[arg] then
								local frames = craftingArgs[arg]
								local frameNum = 0
								for frame in mw.text.gsplit( frames, '%s*;%s*' ) do
									frameNum = frameNum + 1
									if not requiredFrames[frameNum] then
										local delimitedFrame = ';' .. frame .. ';'
										for ingredientNum, ingredient in pairs( ingredients ) do
											if mw.ustring.find(delimitedFrame, matchPattern( ingredient, ingredientNum ) ) then
												requiredFrames[frameNum] = true
												requiredFramesCount = requiredFramesCount + 1
											end
										end
									end
								end
							end
						end
						
						-- Будут показаны не все фреймы...
						if requiredFramesCount > 0 and requiredFramesCount < frameCount then
							for arg in pairs( group ) do
								local frames = craftingArgs[arg]
								local newFrames = {}
								local frameNum = 0
								for frame in mw.text.gsplit( frames, '%s*;%s*' ) do
									frameNum = frameNum + 1
									if requiredFrames[frameNum] then
										table.insert( newFrames, frame )
									end
								end
								newFrames = table.concat( newFrames, ';' )
								
								-- Если весь разобранный псевдоним остался, заново соберём его
								if expandedFrames[arg] then
									for frame, expandedAlias in pairs( expandedFrames[arg] ) do
										--newFrames = 'blah' .. expandedAlias
										newFrames = mw.ustring.gsub(newFrames, expandedAlias, frame )
									end
								end
								
								local tArg = arg
								if arg ~= 'Выход' and not tArgs[1] then
									tArg = anonToShaped[arg]
								end
								tArgs[tArg] = newFrames
							end
							
							-- Заботу о колонках имени и ингредиентов возложим на модуль Крафт
							tArgs["имя"] = nil
							tArgs["ингредиенты"] = nil
						end
					end
				end
				
				tArgs["некат"] = '1'

				local found = false
				for i, v in ipairs( templates ) do
					if compareTables( v, tArgs ) then
						found = true
						break
					end
				end
				if not found then
					table.insert( templates, tArgs )
				end
			end
		end
	end
	if #templates == 0 then
		return '[[Категория:Пустые перечисления использования для крафта]]'
	end
	
	templates[1]["глава"] = '1'
	templates[1]["показатьимя"] = '1'
	if showDescription and args["показатьописание"] ~= '0' or args["показатьописание"] == '1' then
		templates[1]["показатьописание"] = '1'
	end
	if not args["продолжить"] then
		templates[#templates]["подвал"] = '1'
	end
	
	local crafting = require( 'Модуль:Крафт' )
	local out = {}
	for i, v in ipairs( templates ) do
		table.insert( out, crafting.table( v ) )
	end
	
	return table.concat( out, '\n' )
end
return p