Module:Recipe: Difference between revisions

From Subnautica Wiki
(de-specifying recipe if item in general cannot be found)
(Adding basic function descriptions)
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
--[[
This module standardizes the display of crafting recipes
and makes it easy to display a specified item's recipe
or all recipes that use a specified ingredient.
Thanks to User:BryghtShadow for helping out with the loops!
--]]

-- <nowiki>
-- <nowiki>
local p = {}
local p = {}
Line 14: Line 7:
local widthBig = 75
local widthBig = 75


-- verify which game is being used to make errors more helpful
function p.getGame(data)
function p.getGame(data)
if data == dataSN then
if data == dataSN then
Line 23: Line 17:
end
end


-- verify if item exists and return its ID
function p.getItemID(id, data)
function p.getItemID(id, data)
-- removing disambiguations from pagenames
-- removing disambiguations from pagenames
Line 43: Line 38:
end
end


-- generate an icon, using widths, heights, and offsets based on global variables to line everything up smoothly
function p.getIcon(item, quantity, data, mid)
function p.getIcon(item, quantity, data, mid)
if not data[item] then error("Could not generate icon for " .. p.getGame(data) .. " item '" .. item .. "'") end
if not data[item] then error("Could not generate icon for " .. p.getGame(data) .. " item '" .. item .. "'") end
Line 106: Line 102:
end
end


-- output every recipe using an item and a machine (all machines by default)
function p.getAllRecipes(id, machine, data)
function p.getAllRecipes(id, machine, data)
-- First, get the ID of the product item provided by template; pagename used by default
-- First, get the ID of the product item provided by template; pagename used by default
Line 146: Line 143:
end
end


-- test function to remove after testing all BZ recipes
function p.testAllRecipes()
function p.testAllRecipes()
local allProducts = {}
local allProducts = {}
Line 167: Line 165:
end
end


-- output a single recipe or a single item's power output
function p.getRecipe(id, power, data)
function p.getRecipe(id, power, data)
-- First, get the ID of the product item provided by template; pagename used by default
-- First, get the ID of the product item provided by template; pagename used by default
Line 258: Line 257:
end
end


-- main function called by the template
function p.main(frame)
function p.main(frame)
local args = getArgs(frame)
local args = getArgs(frame)
Line 277: Line 277:
return p.getRecipe(id, true, dataSrc)
return p.getRecipe(id, true, dataSrc)
end
end
end

function p.SN(frame)
local args = getArgs(frame)
local id = args[1] or mw.title.getCurrentTitle().text
return p.getRecipe(id, false, dataSN)
end

function p.allSN(frame)
local args = getArgs(frame)
local id = args[1] or mw.title.getCurrentTitle().text
local machine = args[2] or "all"
return p.getAllRecipes(id, machine, dataSN)
end

function p.powerSN(frame)
local args = getArgs(frame)
local id = args[1] or mw.title.getCurrentTitle().text
return p.getRecipe(id, true, dataSN)
end

function p.BZ(frame)
local args = getArgs(frame)
local id = args[1] or mw.title.getCurrentTitle().text
return p.getRecipe(id, false, dataBZ)
end

function p.allBZ(frame)
local args = getArgs(frame)
local id = args[1] or mw.title.getCurrentTitle().text
local machine = args[2] or "all"
return p.getAllRecipes(id, machine, dataBZ)
end

function p.powerBZ(frame)
local args = getArgs(frame)
local id = args[1] or mw.title.getCurrentTitle().text
return p.getRecipe(id, true, dataBZ)
end
end



Latest revision as of 02:02, 23 July 2022

This module standardizes the display of crafting recipes and makes it easy to display a specified item's recipe or all recipes that use a specified ingredient. See Template:RecipeNew for more information. Thanks to BryghtShadow for helping out with the loops!


-- <nowiki>
local p = {}
local dataSN = mw.loadData('Module:Recipe/SN')
local dataBZ = mw.loadData('Module:Recipe/BZ')
local getArgs = require('Dev:Arguments').getArgs
local width = 50
local widthBig = 75

-- verify which game is being used to make errors more helpful
function p.getGame(data)
	if data == dataSN then
		return "Subnautica"
	elseif data == dataBZ then
		return "Below Zero"
	end
	return ""
end

-- verify if item exists and return its ID
function p.getItemID(id, data)
	-- removing disambiguations from pagenames
	id = string.gsub(id, " %(Subnautica%)", "")
	id = string.gsub(id, " %(Below Zero%)", "")
	
	-- if item ID is provided directly...
	if data[id] then
		return id
	end
	
	-- ...otherwise try to find by item name
	for k, v in pairs(data) do
		if v.name == id then -- item found
			return k
		end
	end
	
	return nil -- Could not find item
end

-- generate an icon, using widths, heights, and offsets based on global variables to line everything up smoothly
function p.getIcon(item, quantity, data, mid)
	if not data[item] then error("Could not generate icon for " .. p.getGame(data) .. " item '" .. item .. "'") end
	local iconOut = ""
	
	local iconWidth = width
	if not mid then
		iconWidth = widthBig
	end
	local iconHeight = iconWidth
	local iconOffset = 0
	
	local name = data[item].name
	
	local image = data[item].image
	local iconBG
	if not image then
		if data[item].icon then
			local iconBGSize = data[item].icon.size or "1x1"
			local iconBGType = data[item].icon.bg or "default"
			image = data[item].icon.file or name .. " Icon.png"
			iconBG = iconBGSize .. " " .. iconBGType
			if iconBGSize == "1x2" then
				iconHeight = iconWidth * 2
			elseif iconBGSize == "3x2" then
				iconHeight = (iconWidth / 3) * 2
			elseif iconBGSize == "2x3" then
				iconHeight = (iconWidth / 2) * 3
			end
			iconOffset = math.max(0, ((iconHeight - iconWidth) / 2))
		else
			iconBG = "1x1 default"
			image = name .. " Icon.png"
		end
	end
	
	iconOut = "<div class='recipe__icon' style='width:" .. iconWidth .. "px;'>"
	
	if iconBG then
		iconOut = iconOut .. "<span class='recipe__icon__bg'>[[File:" .. iconBG .. " bg.png|" .. iconWidth .. "px|link=]]</span>"
	end
	
	-- disambiguation check
	local namefix = ""
	if data == dataBZ then
		namefix = name .. " (Below Zero)"
	else
		namefix = name .. " (Subnautica)"
	end
	local exists = mw.getCurrentFrame():callParserFunction('PROTECTIONEXPIRY:edit', namefix) ~= ''
	if not exists then
		-- disambiguated poge does not exist
		namefix = name
	end
	
	iconOut = iconOut .. "<span class='recipe__icon__img' style='top:" .. iconOffset .. "px;'>[[File:" .. image .. "|" .. iconWidth .. "px|link=" .. namefix .. "|" .. namefix .. "]]</span><span class='recipe__icon__pseudo' style='width:" .. iconWidth .. "px;'><span class='recipe__icon__pseudo__img' style='height:" .. iconHeight .. "px;width:" .. iconWidth .. "px;'></span>×0</span>"
	
	if quantity > 1 then
		iconOut = iconOut .. "<span class='recipe__icon__quantity' style='top:" .. iconHeight .. "px;'>×" .. quantity .. "</span>"
	end
	
	return iconOut .. "</div>"
end

-- output every recipe using an item and a machine (all machines by default)
function p.getAllRecipes(id, machine, data)
	-- First, get the ID of the product item provided by template; pagename used by default
	local itemID = p.getItemID(id, data)
	if not itemID then error("Could not find " .. p.getGame(data) .. " item '" .. id .. "'") end
	
	-- Item is found, start finding all recipes using it
	local allProducts = {}
	for productID, product in pairs(data) do
		productMachine = product.machine or ""
		if machine == "all" or machine == productMachine then
			for _, ingredient in ipairs(product.recipe or {}) do
				local ingredientID = ingredient[1]
				local count = ingredient[2]
				if ingredientID == itemID then
					allProducts[#allProducts+1] = productID
				end
			end
		end
	end
	
	if #allProducts == 0 then
		if machine == "all" then
			error("No " .. p.getGame(data) .. " recipes use item '" .. id .. "'")
		else
			if(data[machine]) then
				error("No " .. p.getGame(data) .. " recipes use item '" .. id .."' and machine '" .. machine .. "'")
			else
				error(p.getGame(data) .. " machine '" .. machine .. "' does not exist")
			end
		end
	end
	
	local output = ""
	for _, product in ipairs(allProducts) do
		output = output .. p.getRecipe(product, false, data)
	end
	
	return output
end

-- test function to remove after testing all BZ recipes
function p.testAllRecipes()
	local allProducts = {}
	for productID, product in pairs(dataBZ) do
		if dataBZ[productID].machine then
			allProducts[#allProducts+1] = productID
		end
	end
	
	local output = ""
	for _, product in ipairs(allProducts) do
		local ran, recipe = pcall(p.getRecipe, product, false, dataBZ)
		if ran then
			output = output .. recipe
		else
			output = output .. "<div class='recipe'>" .. recipe .. "</div>"
		end
	end

	return output
end

-- output a single recipe or a single item's power output
function p.getRecipe(id, power, data)
	-- First, get the ID of the product item provided by template; pagename used by default
	local itemID = p.getItemID(id, data)
	if not itemID then error("Could not find " .. p.getGame(data) .. " item '" .. id .. "'") end
	
	-- Item is found, start processing it
	local output = "<div class='recipe'>"
	local arrow = "<div class='recipe__step'><div class='recipe__step__arrow'>[[File:Item Arrow.png|20px|link=]]</div><span class='recipe__step__pseudo'><span class='recipe__step__pseudo__img'></span>×0</span></div>"
	
	if data[itemID].original and not power then
		-- If the item is made as part of a different item's recipe
		error (p.getGame(data) " item '" .. itemID .. "' cannot be directly crafted (use '" .. data[itemID].original .. "' instead)")
	elseif power then
		-- power
		output = output .. "<div class='recipe__machine'>"
		local machineID = ""
		local outNum = 0
		local usedRod = false
		if data[itemID].energy then
			machineID = "basebioreactor"
			outNum = data[itemID].energy
		elseif data[itemID].nuclear then
			machineID = "basenuclearreactor"
			outNum = data[itemID].nuclear
			usedRod = true
		else
			error(p.getGame(data) .. " item '" .. itemID .. "' does not generate power")
		end
		local iconMachine = p.getIcon(machineID, 0, data, false)
		output = output .. iconMachine .. "</div>"
			
		output = output .. arrow .. "<div class='recipe__ingredients'>"
		output = output .. p.getIcon(itemID, 1, data, true)
		output = output .. "</div>"
		
		output = output .. arrow .. "<div class='recipe__output'>"
		local iconProduct = p.getIcon("energy", outNum, data, false)
		output = output .. iconProduct
		if usedRod then
			local iconRod = p.getIcon("depletedreactorrod", 1, data, false)
			output = output .. iconRod
		end
		output = output .. "</div>"
			
		return output .. "</div>"
	else
		-- standard recipe
		if data[itemID].machine then
			-- Item is craftable, start writing the output
			output = output .. "<div class='recipe__machine'>"
			local machineID = data[itemID].machine
			if not data[machineID] then
				error ("Invalid machine listed in " .. p.getGame(data) .. " recipe for item '" .. itemID .. "'")
			end
			local iconMachine = p.getIcon(machineID, 0, data, false)
			output = output .. iconMachine .. "</div>"
			
			if data[itemID].recipe then
				output = output .. arrow .. "<div class='recipe__ingredients'>"
				for i,v in ipairs(data[itemID].recipe) do
					local icon = p.getIcon(v[1], v[2], data, true)
					output = output .. icon
				end
				output = output .. "</div>"
			end
			
			output = output .. arrow .. "<div class='recipe__output'>"
			local outNum = data[itemID].quantity or 1
			local iconProduct = p.getIcon(itemID, outNum, data, false)
			output = output .. iconProduct
			if data[itemID].additional then
				local addOut = data[itemID].additional
				local addIcon
				for i,v in ipairs(addOut) do
					addIcon = p.getIcon(v[1], v[2], data, false)
					output = output .. addIcon
				end
			end
			output = output .. "</div>"
			
			return output .. "</div>"
		else
			if data[itemID].recipe then
				error ("Machine is missing for " .. p.getGame(data) .. " item '" .. itemID .. "'")
			else
				error (p.getGame(data) .. " item '" .. itemID .. "' is not craftable")
			end
		end
	end
end

-- main function called by the template
function p.main(frame)
	local args = getArgs(frame)
	local id = args[1] or mw.title.getCurrentTitle().text
	local source = args[2] or "SN"
	local func = args[3] or "recipe"
	
	local dataSrc = dataSN
	if source == "BZ" then
		dataSrc = dataBZ
	end
	
	if func == "recipe" then
		return p.getRecipe(id, false, dataSrc)
	elseif func == "uses" then
		local machine = args[4] or "all"
		return p.getAllRecipes(id, machine, dataSrc)
	elseif func == "power" then
		return p.getRecipe(id, true, dataSrc)
	end
end

return p
-- </nowiki>