Module:Recipe: Difference between revisions
SlyAceZeta (talk | contribs) (Adding possibility for items to be craftable without using any ingredients (Coffee Americano)) |
SlyAceZeta (talk | contribs) (Adding basic function descriptions) |
||
(6 intermediate revisions 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 |
|||
⚫ | |||
⚫ | |||
return "Subnautica" |
|||
elseif data == dataBZ then |
|||
return "Below Zero" |
|||
⚫ | |||
return "" |
|||
⚫ | |||
-- 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 34: | 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 item '" .. item .. "'") end |
if not data[item] then error("Could not generate icon for " .. p.getGame(data) .. " item '" .. item .. "'") end |
||
local iconOut = "" |
local iconOut = "" |
||
Line 50: | Line 55: | ||
local iconBG |
local iconBG |
||
if not image then |
if not image then |
||
⚫ | |||
if data[item].icon then |
if data[item].icon then |
||
local iconBGSize = data[item].icon.size or "1x1" |
local iconBGSize = data[item].icon.size or "1x1" |
||
local iconBGType = data[item].icon.bg or "default" |
local iconBGType = data[item].icon.bg or "default" |
||
image = data[item].icon.file or name .. " Icon.png" |
|||
iconBG = iconBGSize .. " " .. iconBGType |
iconBG = iconBGSize .. " " .. iconBGType |
||
if iconBGSize == "1x2" then |
if iconBGSize == "1x2" then |
||
Line 65: | Line 70: | ||
else |
else |
||
iconBG = "1x1 default" |
iconBG = "1x1 default" |
||
⚫ | |||
end |
end |
||
end |
end |
||
Line 96: | 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 |
||
local itemID = p.getItemID(id, data) |
local itemID = p.getItemID(id, data) |
||
if not itemID then error("Could not find item '" .. id .. "'") end |
if not itemID then error("Could not find " .. p.getGame(data) .. " item '" .. id .. "'") end |
||
-- Item is found, start finding all recipes using it |
-- Item is found, start finding all recipes using it |
||
Line 118: | Line 125: | ||
if #allProducts == 0 then |
if #allProducts == 0 then |
||
if machine == "all" then |
if machine == "all" then |
||
error("No recipes use item '" .. id .. "'") |
error("No " .. p.getGame(data) .. " recipes use item '" .. id .. "'") |
||
else |
else |
||
if(data[machine]) then |
if(data[machine]) then |
||
error("No recipes use item '" .. id .."' and machine '" .. machine .. "'") |
error("No " .. p.getGame(data) .. " recipes use item '" .. id .."' and machine '" .. machine .. "'") |
||
else |
else |
||
error(" |
error(p.getGame(data) .. " machine '" .. machine .. "' does not exist") |
||
end |
end |
||
end |
end |
||
Line 136: | Line 143: | ||
end |
end |
||
-- test function to remove after testing all BZ recipes |
|||
function p.testAllRecipes() |
function p.testAllRecipes() |
||
local allProducts = {} |
local allProducts = {} |
||
for productID, product in pairs( |
for productID, product in pairs(dataBZ) do |
||
if |
if dataBZ[productID].machine then |
||
allProducts[#allProducts+1] = productID |
allProducts[#allProducts+1] = productID |
||
end |
end |
||
Line 146: | Line 154: | ||
local output = "" |
local output = "" |
||
for _, product in ipairs(allProducts) do |
for _, product in ipairs(allProducts) do |
||
local ran, recipe = pcall(p.getRecipe, product, false, |
local ran, recipe = pcall(p.getRecipe, product, false, dataBZ) |
||
if ran then |
if ran then |
||
output = output .. recipe |
output = output .. recipe |
||
Line 157: | 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 |
||
local itemID = p.getItemID(id, data) |
local itemID = p.getItemID(id, data) |
||
if not itemID then error("Could not find |
if not itemID then error("Could not find " .. p.getGame(data) .. " item '" .. id .. "'") end |
||
-- Item is found, start processing it |
-- Item is found, start processing it |
||
Line 168: | Line 177: | ||
if data[itemID].original and not power then |
if data[itemID].original and not power then |
||
-- If the item is made as part of a different item's recipe |
-- If the item is made as part of a different item's recipe |
||
error ( |
error (p.getGame(data) " item '" .. itemID .. "' cannot be directly crafted (use '" .. data[itemID].original .. "' instead)") |
||
elseif power then |
elseif power then |
||
-- power |
-- power |
||
Line 183: | Line 192: | ||
usedRod = true |
usedRod = true |
||
else |
else |
||
error(" |
error(p.getGame(data) .. " item '" .. itemID .. "' does not generate power") |
||
end |
end |
||
local iconMachine = p.getIcon(machineID, 0, data, false) |
local iconMachine = p.getIcon(machineID, 0, data, false) |
||
Line 209: | Line 218: | ||
local machineID = data[itemID].machine |
local machineID = data[itemID].machine |
||
if not data[machineID] then |
if not data[machineID] then |
||
error ("Invalid machine listed in recipe for item '" .. itemID .. "'") |
error ("Invalid machine listed in " .. p.getGame(data) .. " recipe for item '" .. itemID .. "'") |
||
end |
end |
||
local iconMachine = p.getIcon(machineID, 0, data, false) |
local iconMachine = p.getIcon(machineID, 0, data, false) |
||
Line 240: | Line 249: | ||
else |
else |
||
if data[itemID].recipe then |
if data[itemID].recipe then |
||
error ("Machine is missing for item '" .. itemID .. "'") |
error ("Machine is missing for " .. p.getGame(data) .. " item '" .. itemID .. "'") |
||
else |
else |
||
⚫ | |||
-- If there is no recipe for the item |
|||
⚫ | |||
⚫ | |||
else |
|||
error ("Cannot craft item '" .. itemID .. "' (use Template:UsesSN instead)") |
|||
end |
|||
end |
end |
||
end |
end |
||
Line 253: | Line 257: | ||
end |
end |
||
function |
-- main function called by the template |
||
⚫ | |||
local args = getArgs(frame) |
local args = getArgs(frame) |
||
local id = args[1] or mw.title.getCurrentTitle().text |
local id = args[1] or mw.title.getCurrentTitle().text |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
local dataSrc = dataSN |
|||
⚫ | |||
if source == "BZ" then |
|||
local args = getArgs(frame) |
|||
dataSrc = dataBZ |
|||
local id = args[1] or mw.title.getCurrentTitle().text |
|||
⚫ | |||
⚫ | |||
⚫ | |||
if func == "recipe" then |
|||
⚫ | |||
⚫ | |||
elseif func == "uses" then |
|||
function p.powerSN(frame) |
|||
local machine = args[4] or "all" |
|||
⚫ | |||
local id = args[1] or mw.title.getCurrentTitle().text |
|||
elseif func == "power" then |
|||
return p.getRecipe(id, true, dataSrc) |
|||
⚫ | |||
⚫ | |||
⚫ | |||
local args = getArgs(frame) |
|||
local id = args[1] or mw.title.getCurrentTitle().text |
|||
return p.getRecipe(id, false, dataBZ) |
|||
⚫ | |||
function p.allBZ(frame) |
|||
local args = getArgs(frame) |
|||
local id = args[1] or mw.title.getCurrentTitle().text |
|||
⚫ | |||
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>