Jump to content

Module:Recipe table

From Tensura Wiki

Template:Documentation header This module creates the table for {{crafting}}, {{brewing}}, {{smelting}} and {{looming}}. It can only be invoked within other modules.

Usage

The entry point is the table function. The first argument should be whatever arguments you want to pass through, the second argument should be a table of settings.

Setting Use
type What type of recipe, e.g.: 'Crafting'
ingredientArgs A table of the args which contain the ingredients, e.g.: { 'Input' }
outputArgs A table of the args which contain the outputs, e.g.: { 'Output' }
uiFunc The function to call from Module:UI, e.g.: 'craftingTable'

The module returns the wikitext table as the first parameter, and a table of unique ingredients as the second output.

Dependencies


es:Módulo:Recipe table fr:Module:Tableau de recette ja:モジュール:Recipe table pt:Módulo:Recipe table ru:Модуль:Таблица рецептов uk:Модуль:Recipe table



local m = {}

local i18n = {
	headingDescription = 'Description',
	headingIngredients = 'Ingredients',
	headingName = 'Name',
	headingRecipe = '[[$1]] recipe',
	moduleSlot = [[Module:Inventory slot]],
	moduleUi = [[Module:UI]],
	separator = ' +',
	setSeparator = ' or',
	tableDescription = '$1 recipes',
}

local slot = require(i18n.moduleSlot)
local prefixes = slot.i18n.prefixes
local aliases = mw.loadData('Module:Inventory slot/Aliases') -- Load aliases

-- Function to remove Minecraft formatting codes
local function removeFormattingCodes(text)
    return text:gsub("&[0-9a-fk-or]", "")
end

-- Parses recipe arguments into structured frames
local function parseRecipeArgs(args, ingredientArgVals, outputArgs)
	local recipeArgs = {}
	for _, arg in pairs(ingredientArgVals) do
		recipeArgs[arg] = args[arg]
	end
	for _, arg in pairs(outputArgs) do
		recipeArgs[arg] = args[arg]
	end
	
	local parsedFrameText = {}
	local parsedRecipeArgs = {}
	for arg, frameText in pairs(recipeArgs) do
		if frameText then
			-- Clean formatting codes from the frame text
			frameText = removeFormattingCodes(frameText)
			
			local randomise
			for _, oArg in pairs(outputArgs) do
				if arg == oArg then
					randomise = 'never'
					break
				end
			end
			local frames = not randomise and parsedFrameText[frameText]
			if not frames then
				frames = slot.parseFrameText(frameText, randomise, true)
				parsedFrameText[frameText] = frames
			end
			parsedRecipeArgs[arg] = frames
		end
	end
	
	return parsedRecipeArgs
end

-- Creates the table header
m.makeHeader = function(recipeType, class, showName, showDescription, multirow)
	class = class or ''
	
	local nameCell = ''
	if showName then
		nameCell = i18n.headingName .. '!!'
	end
	
	local descriptionCell = ''
	if showDescription then
		descriptionCell = '!!class="unsortable"|' .. i18n.headingDescription
	end
	
	local recipeAttribs = ''
	if multirow then
		class = 'sortable ' .. class
		recipeAttribs = 'class="unsortable"|'
	end
	
	local header = table.concat({
		' {| class="wikitable crafting ' .. class .. '" data-description="' .. i18n.tableDescription:gsub('%$1', recipeType) .. '"',
		'!' .. nameCell ..
		i18n.headingIngredients .. '!!' ..
		recipeAttribs .. i18n.headingRecipe:gsub('%$1', recipeType) ..
		descriptionCell
	}, '\n')
	return header
end

-- Creates links for the name/ingredients columns out of item sets
function m.makeItemLinks(itemSets, removePrefixes)
	local links = {}
	for i, itemSet in ipairs(itemSets) do
		local linkSet = {}
		for i2, item in ipairs(itemSet) do
			local name = item.name
			local mod = item.mod
			
			-- Clean formatting codes from the item name
			name = removeFormattingCodes(name)
			
			-- Resolve alias if available
			local aliasData = aliases[name]
			if aliasData then
				-- Use alias-provided link and title (clean formatting codes)
				local link = aliasData.link or name
				local displayName = removeFormattingCodes(aliasData.title or name)
				linkSet[i2] = string.format("[[%s|%s]]", link, displayName)
			else
				-- Fallback to default prefixed link
				if removePrefixes then
					name = name
						:gsub('^' .. prefixes.any .. ' ', '')
						:gsub('^' .. prefixes.matching .. ' ', '')
						:gsub('^%l', string.upper)
				end
				linkSet[i2] = m.prefixedLink(name, mod)
			end
		end
		links[i] = table.concat(linkSet, i18n.setSeparator .. '<br>')
	end

	return table.concat(links, i18n.separator .. '<br>')
end

-- Create the contents for the ingredients cell
function m.makeIngredientsCell(ingredients, itemSets)
	return ingredients or m.makeItemLinks(itemSets)
end

-- Main entry point, creates the table with the relevant DPL vars
function m.makeItemSets(argVals, parsedArgs)
    local usedItems = {}
    local function addItem(items, arg, frame, alias)
        if alias then
            frame = alias.frame
        end

        -- Clean formatting codes from the frame name
        frame.name = removeFormattingCodes(frame.name)

        local uniqName = (frame.mod or '') .. ':' .. frame.name
        if not usedItems[uniqName] then
            usedItems[uniqName] = true
            items[#items + 1] = frame
        end

        return alias and alias.length or 1
    end

    local itemSets = {}
    local i = 1
    for _, arg in ipairs(argVals) do
        local frames = parsedArgs[arg]
        if frames then
            local items = {}
            local frameNum = 1
            while frameNum <= #frames do
                local frame = frames[frameNum]
                if frame[1] then
                    local subframeNum = 1
                    while subframeNum <= #frame do
                        local subframe = frame[subframeNum]
                        if subframe.name ~= '' then
                            local alias = frame.aliasReference and frame.aliasReference[subframeNum]
                            subframeNum = subframeNum + addItem(items, arg, subframe, alias)
                        else
                            subframeNum = subframeNum + 1
                        end
                    end
                    frameNum = frameNum + 1
                elseif frame.name ~= '' then
                    local alias = frames.aliasReference and frames.aliasReference[frameNum]
                    frameNum = frameNum + addItem(items, arg, frame, alias)
                else
                    frameNum = frameNum + 1
                end
            end
            if #items > 0 then
                itemSets[i] = items
                i = i + 1
            end
        end
    end

    return itemSets
end

function m.table(args, settings)
	local f = mw.getCurrentFrame()
	
	local multirow = f:callParserFunction('#dplvar', 'recipetable-multirow')
	if multirow == '' then
		multirow = nil
	end
	
	local showHead = args.head
	local showFoot = args.foot
	if multirow then
		showHead = nil
	elseif showHead and not showFoot then
		multirow = true
		f:callParserFunction('#dplvar:set', 'recipetable-multirow', '1')
	else
		showHead = true
		showFoot = true
	end
		
	local showName = args.showname
	local showDescription = args.showdescription
	if multirow then
		if showHead then
			showName = args.showname or '1'
			f:callParserFunction('#dplvar:set', 'recipetable-name', showName, 'recipetable-description', showDescription)
		else
			showName = f:callParserFunction('#dplvar', 'recipetable-name')
			showDescription = f:callParserFunction('#dplvar', 'recipetable-description')
		end
	end
	if showName ~= '1' then
		showName = nil
	end
	if showDescription == '' then
		showDescription = nil
	end
	
	local out = {}
	
	if showHead then
		out[1] = m.makeHeader(settings.type, args.class, showName, showDescription, multirow)
	end
	
	local ingredientArgVals = settings.ingredientArgs
	local outputArgs = settings.outputArgs
	
	local parsedRecipeArgs = args
	if not args.parsed then
		parsedRecipeArgs = parseRecipeArgs(args, ingredientArgVals, outputArgs)
	end
	
	local cells = {}
	
	local outputItemSets = m.makeItemSets(outputArgs, parsedRecipeArgs)
	if showName then
		cells[1] = '!' .. m.makeNameCell(args.name, outputItemSets)
	end
	
	local ingredientsItemSets = m.makeItemSets(ingredientArgVals, parsedRecipeArgs)
	cells[#cells + 1] = '|' .. m.makeIngredientsCell(args.ingredients, ingredientsItemSets)
	
	cells[#cells + 1] = '|style="padding:1px;text-align:center"|' .. require(i18n.moduleUi)[settings.uiFunc](args)
	
	if showDescription then
		cells[#cells + 1] = '|' .. (args.description or '')
	end
	
	out[#out + 1] = table.concat(cells, '\n')
	
	out[#out + 1] = showFoot and '|}' or ''
	if showFoot then
		f:callParserFunction('#dplvar:set',
			'recipetable-multirow', '',
			'recipetable-name', '',
			'recipetable-description', ''
		)
	end
	
	return table.concat(out, '\n|-\n'), ingredientsItemSets, outputItemSets
end

return m