Module:Recipe: Difference between revisions
From Against the Storm Official Wiki
(Created to replace RenderRecipe with new version of template code that is easier to maintain and can also do ingredients) |
m (Shrinking icon sizes) |
||
(23 intermediate revisions by the same user not shown) | |||
Line 31: | Line 31: | ||
-- @module Recipe | -- @module Recipe | ||
local Recipe = {} | local Recipe = {} | ||
--- | --- | ||
-- Constants | -- Constants | ||
--- | -- | ||
-- Currently this is the max number of ingredients a recipe can have | |||
local RECIPE_INGRED_MAX = 3 | |||
-- Indexes to use for recipe records as they come from the CSV data | |||
local INDEX_RECIPE_GRADE = 2 | local INDEX_RECIPE_GRADE = 2 | ||
local INDEX_RECIPE_PRODTIME = 3 | local INDEX_RECIPE_PRODTIME = 3 | ||
Line 41: | Line 45: | ||
local INDEX_RECIPE_PRODUCT_ID = 5 | local INDEX_RECIPE_PRODUCT_ID = 5 | ||
local INDEX_RECIPE_INGREDIENTS = 6 | local INDEX_RECIPE_INGREDIENTS = 6 | ||
-- Indexes to use for workshop records as they come from the CSV data | |||
local INDEX_WORKSHOP_ID = 1 | local INDEX_WORKSHOP_ID = 1 | ||
local INDEX_WORKSHOP_NAME = 2 | local INDEX_WORKSHOP_NAME = 2 | ||
-- CSS styling for the recipe table... for now | |||
local CSS_CLASS_WIKITABLE = "wikitable sortable mw-collapsible" | |||
local | -- Shortcut markup to go after the filename to add the extension and display parameters | ||
local | local WIKI_MED_ICON_MARKUP = ".png|24px|alt=" | ||
local | local WIKI_LARGE_ICON_MARKUP = ".png|42px|alt=" | ||
-- Shortcut markup that's easier for Lua string concatenations | |||
local BR = "<br />" | local BR = "<br />" | ||
local NBSP = " " | |||
local BOLD = "'''" | |||
-- Shortcuts for displaying the efficency grades as stars or the "low meter" | |||
local GRADE_TO_STARS = { | local GRADE_TO_STARS = { | ||
["Grade0"] = "[[File:Grade Stars 0.png|12px|link=|alt=0 Stars]]", | ["Grade0"] = "[[File:Grade Stars 0.png|12px|link=|alt=0 Stars]]", | ||
Line 59: | Line 65: | ||
["Grade3"] = "★★★" | ["Grade3"] = "★★★" | ||
} | } | ||
--- | --- | ||
-- Member variables | -- Member variables | ||
--- | --- | ||
local RecipeData = require('Module: | local RecipeData = require('Module:RecipeData') | ||
Line 69: | Line 77: | ||
--- | --- | ||
-- Called from Template:Recipe to render a table displaying the information. | -- Called from Template:Recipe to render a table displaying the information. | ||
-- Retrieves data from Module:RecipeData. The data retrieved looks like this: | |||
-- | -- | ||
-- | -- (sometimes there's an extra first variable like workshop or ingredient) | ||
-- targetRecipeMatches = { | |||
-- [recipeID] match between recipe and workshops = { | |||
-- [1] = { recipe data }, | |||
-- [2] = list of workshops that make it = { | |||
-- { workshop data }, | |||
-- { workshop data }, | |||
-- { workshop data } | |||
-- } | |||
-- }, | |||
-- [recipeID] match between recipe and workshops = { | |||
-- similar | |||
-- } | |||
-- } | |||
-- | -- | ||
-- @param frame the template | -- @param frame the template passes parameters and page data via frame | ||
-- @return the formatted wikitext/HTML | -- @return the formatted wikitext/HTML | ||
function Recipe.render(frame) | function Recipe.render(frame) | ||
Line 79: | Line 101: | ||
local productName = frame.args.product or frame.args[1] | local productName = frame.args.product or frame.args[1] | ||
local buildingName = frame.args.building or frame.args[2] | local buildingName = frame.args.building or frame.args[2] | ||
local | local ingredientName = frame.args.ingredient | ||
local display = frame.args.display | |||
local displayListOverride = false | |||
if display == "list" then | |||
displayListOverride = true | |||
end | |||
-- At least one parameter is required. | -- At least one parameter is required. | ||
if | if productName == "" and buildingName == "" and ingredientName == "" then | ||
return " | return "The Recipe template requires that you specify at least one of the following: product, building, or ingredient." | ||
end | end | ||
-- | -- Decide according to parameters | ||
if | if ingredientName and ingredientName ~= "" then | ||
return buildIngredientWikitext( | return buildIngredientWikitext(ingredientName, displayListOverride) | ||
else | else | ||
if productName and buildingName then | if productName and productName ~= "" and buildingName and buildingName ~= "" then | ||
return buildProductBuildingWikitext(productName, buildingName) | return buildProductBuildingWikitext(productName, buildingName, displayListOverride) | ||
else | else | ||
if productName then | if productName and productName ~= "" then | ||
return buildProductWikitext(productName) | return buildProductWikitext(productName, displayListOverride) | ||
else | else | ||
if buildingName then | if buildingName and buildingName ~= "" then | ||
return buildBuildingWikitext(buildingName) | return buildBuildingWikitext(buildingName, displayListOverride) | ||
else | else | ||
return "Error: Unknown parameter error." | return "Error in Recipe template: Unknown parameter error." | ||
end | end | ||
end | end | ||
Line 109: | Line 136: | ||
--- | --- | ||
-- Renders the table for the specified product. | -- Renders the table for the specified product. | ||
-- | -- | ||
-- @param productName the name of the product | -- @param productName the name of the product | ||
-- @return the wikitext that renders the table | -- @return the wikitext that renders the table | ||
function buildProductWikitext(productName) | function buildProductWikitext(productName, displayListOverride) | ||
local targetRecipeMatches = RecipeData.getAllRecipesForProduct(productName) | local targetRecipeMatches = RecipeData.getAllRecipesForProduct(productName) | ||
if not targetRecipeMatches then | if not targetRecipeMatches then | ||
return "There are no recipes for product " .. productName .. "." | |||
end | end | ||
local wikiTable = startNewWikiTable("Recipes for " .. productName .. ".") | -- Start a wiki table the same way each time, and then populate each row. | ||
local wikiTable | |||
if displayListOverride then | |||
wikiTable = startList() | |||
else | |||
wikiTable = startNewWikiTable("Recipes for " .. productName .. ".") | |||
end | |||
-- Add the data retrieved to the wiki table | |||
for _, match in pairs(targetRecipeMatches) do | for _, match in pairs(targetRecipeMatches) do | ||
local recipe = match[1] | local recipe = match[1] | ||
for _, | |||
wikiTable = addRowToTable(wikiTable, recipe, | for _, workshop in ipairs(match[2]) do | ||
wikiTable = addRowToTable(wikiTable, recipe, workshop, displayListOverride) | |||
end | end | ||
end | end | ||
Line 153: | Line 175: | ||
--- | --- | ||
-- Renders the table for the specified building. | -- Renders the table for the specified building. | ||
-- | -- | ||
-- @param buildingName the name of the building | -- @param buildingName the name of the building | ||
-- @return the wikitext that renders the table | -- @return the wikitext that renders the table | ||
function buildBuildingWikitext(buildingName) | function buildBuildingWikitext(buildingName, displayListOverride) | ||
-- Ignore the workshop also returned. | |||
local _, targetRecipeMatches = RecipeData.getAllRecipesAtBuilding(buildingName) | local _, targetRecipeMatches = RecipeData.getAllRecipesAtBuilding(buildingName) | ||
if not targetRecipeMatches then | if not targetRecipeMatches then | ||
return "There are no recipes in the building " .. buildingName .. "." | |||
end | end | ||
local wikiTable = startNewWikiTable("Recipes in the " .. buildingName .. ".") | -- Start a wiki table the same way each time, and then populate each row. | ||
local wikiTable | |||
if displayListOverride then | |||
wikiTable = startList() | |||
else | |||
wikiTable = startNewWikiTable("Recipes in the " .. buildingName .. ".") | |||
end | |||
-- Add the data retrieved to the wiki table | |||
for _, match in pairs(targetRecipeMatches) do | for _, match in pairs(targetRecipeMatches) do | ||
local recipe = match[1] | local recipe = match[1] | ||
for _, | |||
wikiTable = addRowToTable(wikiTable, recipe, | for _, workshop in ipairs(match[2]) do | ||
wikiTable = addRowToTable(wikiTable, recipe, workshop, displayListOverride) | |||
end | end | ||
end | end | ||
Line 199: | Line 215: | ||
--- | --- | ||
-- Renders the table for the specified product and building. | -- Renders the table for the specified product and building. | ||
-- | -- | ||
-- @param productName the name of the product | -- @param productName the name of the product | ||
-- @param buildingName the name of the building | -- @param buildingName the name of the building | ||
-- @return the wikitext that renders the table | -- @return the wikitext that renders the table | ||
function buildProductBuildingWikitext(productName, buildingName) | function buildProductBuildingWikitext(productName, buildingName, displayListOverride) | ||
local targetRecipeMatches = RecipeData.getOneRecipeAtBuilding(productName, buildingName) | local targetRecipeMatches = RecipeData.getOneRecipeAtBuilding(productName, buildingName) | ||
if not targetRecipeMatches then | if not targetRecipeMatches then | ||
return "There is no recipe for product " .. productName .. " in the building " .. buildingName .. "." | |||
end | end | ||
local wikiTable = startNewWikiTable("Recipe for " .. productName .. " in the " .. buildingName .. ".") | -- Start a wiki table the same way each time, and then populate each row. | ||
local wikiTable | |||
if displayListOverride then | |||
wikiTable = startList() | |||
else | |||
wikiTable = startNewWikiTable("Recipe for " .. productName .. " in the " .. buildingName .. ".") | |||
end | |||
-- Add the data retrieved to the wiki table | |||
for _, match in pairs(targetRecipeMatches) do | for _, match in pairs(targetRecipeMatches) do | ||
local recipe = match[1] | local recipe = match[1] | ||
for _, | |||
wikiTable = addRowToTable(wikiTable, recipe, | for _, workshop in ipairs(match[2]) do | ||
wikiTable = addRowToTable(wikiTable, recipe, workshop, displayListOverride) | |||
end | end | ||
end | end | ||
Line 239: | Line 255: | ||
--- | --- | ||
-- Renders the table for the specified ingredient. | -- Renders the table for the specified ingredient. | ||
-- | -- | ||
-- @param ingredientName the name of the ingredient | -- @param ingredientName the name of the ingredient | ||
-- @return the wikitext that renders the table | -- @return the wikitext that renders the table | ||
function buildIngredientWikitext(ingredientName) | function buildIngredientWikitext(ingredientName, displayListOverride) | ||
-- Ignore the ingredient also returned | |||
local _, targetRecipeMatches = RecipeData.getAllRecipesWithIngredient(ingredientName) | local _, targetRecipeMatches = RecipeData.getAllRecipesWithIngredient(ingredientName) | ||
if not targetRecipeMatches then | if not targetRecipeMatches then | ||
return "There are no recipes for ingredient " .. ingredientName .. "." | |||
end | end | ||
local wikiTable = startNewWikiTable("Recipes that require " .. ingredientName .. ".") | -- Start a wiki table the same way each time, and then populate each row. | ||
local wikiTable | |||
if displayListOverride then | |||
wikiTable = startList() | |||
else | |||
wikiTable = startNewWikiTable("Recipes that require " .. ingredientName .. ".") | |||
end | |||
-- Add the data retrieved to the wiki table | |||
for _, match in pairs(targetRecipeMatches) do | for _, match in pairs(targetRecipeMatches) do | ||
local recipe = match[1] | local recipe = match[1] | ||
for _, | |||
wikiTable = addRowToTable(wikiTable, recipe, | for _, workshop in ipairs(match[2]) do | ||
wikiTable = addRowToTable(wikiTable, recipe, workshop, displayListOverride) | |||
end | end | ||
end | end | ||
Line 348: | Line 359: | ||
-- @param workshop the workshop to pull data from | -- @param workshop the workshop to pull data from | ||
-- @return wikiTable, augmented with the new row | -- @return wikiTable, augmented with the new row | ||
function addRowToTable(wikiTable, recipe, workshop) | function addRowToTable(wikiTable, recipe, workshop, displayListOverride) | ||
if not wikiTable then | if not wikiTable then | ||
Line 360: | Line 371: | ||
-- Get everything extracted and ready to go for easier code below | -- Get everything extracted and ready to go for easier code below | ||
local buildingName = workshop[INDEX_WORKSHOP_NAME] | local buildingName = workshop[INDEX_WORKSHOP_NAME] | ||
-- Do not add the extension here | |||
local buildingIconFile = workshop[INDEX_WORKSHOP_ID] .. "_icon | local buildingIconFile = workshop[INDEX_WORKSHOP_ID] .. "_icon" | ||
local recipeGrade = recipe[INDEX_RECIPE_GRADE] | local recipeGrade = recipe[INDEX_RECIPE_GRADE] | ||
Line 367: | Line 378: | ||
local recipeProductStackSize = recipe[INDEX_RECIPE_PRODUCT_STACK_SIZE] | local recipeProductStackSize = recipe[INDEX_RECIPE_PRODUCT_STACK_SIZE] | ||
local recipeProductID = recipe[INDEX_RECIPE_PRODUCT_ID] | local recipeProductID = recipe[INDEX_RECIPE_PRODUCT_ID] | ||
-- Now build the table tags. We're going to add everything to this row, so | -- Now build the table tags. We're going to add everything to this row, so | ||
-- save the row itself to keep the hierarchy straight. | -- save the row itself to keep the hierarchy straight. | ||
local wikiTableRow = wikiTable:tag('tr') | local wikiTableRow = wikiTable:tag('tr') | ||
wikiTableRow:wikitext(" | wikiTableRow:newline() | ||
-- Simple name and stars if display overriding | |||
if displayListOverride then | |||
wikiTableRow:tag("td") | |||
:wikitext("[[" .. buildingName .. "]]" .. NBSP) | |||
:wikitext("(" .. GRADE_TO_STARS[recipeGrade] .. ")" .. BR) | |||
:allDone():newline() | |||
return wikiTable | |||
end | |||
wikiTableRow:tag('td') | wikiTableRow:tag('td') | ||
:wikitext(writeBuildingCellContent(buildingIconFile, buildingName, recipeGrade, recipeProdTime)) | :wikitext(writeBuildingCellContent(buildingIconFile, buildingName, recipeGrade, recipeProdTime)) | ||
:done() | :done():newline() | ||
-- Skip empty cells | -- Skip empty cells of ingredients in this recipe | ||
local blanks = 0 | local blanks = 0 | ||
for i, tableToCheck in ipairs(recipe[INDEX_RECIPE_INGREDIENTS]) do | for i, tableToCheck in ipairs(recipe[INDEX_RECIPE_INGREDIENTS]) do | ||
Line 386: | Line 404: | ||
end | end | ||
end | end | ||
for i = 1,blanks do | for i = 1,blanks do | ||
wikiTableRow:tag('td'):done() | wikiTableRow:tag('td'):done():newline() | ||
end | end | ||
Line 396: | Line 412: | ||
for _, optionsGroup in ipairs(recipe[INDEX_RECIPE_INGREDIENTS]) do | for _, optionsGroup in ipairs(recipe[INDEX_RECIPE_INGREDIENTS]) do | ||
local innerTable = wikiTableRow:tag('td'):tag('table') | -- Skip blank groups; we already inserted blanks earlier. | ||
if #optionsGroup > 0 then | |||
local innerTable = wikiTableRow:tag('td'):tag('table') | |||
innerTable:newline() | |||
-- Loop through each option, but only up until they are blank | |||
for _, option in ipairs(optionsGroup) do | |||
local ingredientStackSize = option[1] | |||
local ingredientGoodID = option[2] | |||
innerTable:tag('tr') | |||
:tag('td'):wikitext(BOLD .. ingredientStackSize .. BOLD):done() | |||
:tag('td'):wikitext(writeIngredientCellContent(ingredientGoodID)):done() | |||
:done() | |||
innerTable:wikitext("\n") | |||
end | |||
end | end | ||
end | end | ||
wikiTableRow:tag('td') | local productCell, productName = writeProductCellContent(recipeProductID) | ||
:wikitext( | |||
-- Sort on product name, not the stack size | |||
wikiTableRow:tag('td'):attr("data-sort-value", productName) | |||
:wikitext(BOLD .. recipeProductStackSize .. BOLD .. NBSP .. productCell) | |||
:done() | :done() | ||
wikiTableRow:wikitext("\n") | wikiTableRow:wikitext("\n") | ||
Line 432: | Line 456: | ||
function writeIngredientCellContent(ingredientGoodID) | function writeIngredientCellContent(ingredientGoodID) | ||
local goodName, goodIconFile = getGoodNameAndIcon(ingredientGoodID) | local goodName, goodIconFile = RecipeData.getGoodNameAndIcon(ingredientGoodID) | ||
local iconMarkup = "[[File:" .. goodIconFile .. | local iconMarkup = "[[File:" .. goodIconFile .. WIKI_MED_ICON_MARKUP .. goodName .. "|link=" .. goodName .. "#Product]]" | ||
local linkMarkup = "[[" .. goodName .. "]]" | local linkMarkup = "[[" .. goodName .. "#Product|" .. goodName .. "]]" | ||
return iconMarkup .. linkMarkup | return iconMarkup .. NBSP .. linkMarkup | ||
end | end | ||
Line 447: | Line 471: | ||
-- @param productGoodID the good ID to use to create the link | -- @param productGoodID the good ID to use to create the link | ||
-- @return a string of wiki markup | -- @return a string of wiki markup | ||
-- @return the string name of the product | |||
function writeProductCellContent(productGoodID) | function writeProductCellContent(productGoodID) | ||
local goodName, goodIconFile = getGoodNameAndIcon(productGoodID) | local goodName, goodIconFile = RecipeData.getGoodNameAndIcon(productGoodID) | ||
local iconMarkup = "[[File:" .. goodIconFile .. | local iconMarkup = "[[File:" .. goodIconFile .. WIKI_LARGE_ICON_MARKUP .. goodName .. "|link=" .. goodName .. "#Ingredient]]" | ||
local linkMarkup = "[[" .. goodName .. "]]" | local linkMarkup = "[[" .. goodName .. "#Ingredient|" .. goodName .. "]]" | ||
return iconMarkup .. linkMarkup | return iconMarkup .. NBSP .. linkMarkup, goodName | ||
end | end | ||
Line 463: | Line 488: | ||
-- in a call to wikitext() | -- in a call to wikitext() | ||
-- | -- | ||
-- @param buildingIconFile icon filename, excluding 'File:' | -- @param buildingIconFile icon filename, excluding 'File:', including extension | ||
-- @param buildingName plain text name of the building to display | -- @param buildingName plain text name of the building to display | ||
-- @param recipeGrade efficiency of the recipe | -- @param recipeGrade efficiency of the recipe | ||
Line 470: | Line 495: | ||
function writeBuildingCellContent(buildingIconFile, buildingName, recipeGrade, recipeProdTime) | function writeBuildingCellContent(buildingIconFile, buildingName, recipeGrade, recipeProdTime) | ||
local iconMarkup = "[[File:" .. buildingIconFile .. | local iconMarkup = "[[File:" .. buildingIconFile .. WIKI_LARGE_ICON_MARKUP .. buildingName .. "|link=" .. buildingName .. "]]" | ||
local linkMarkup = "[[" .. buildingName .. "]]" | local linkMarkup = "[[" .. buildingName .. "]]" | ||
Line 478: | Line 503: | ||
end | end | ||
local innerTable = mw.ustring.format("<table><tr><td>%s</td><td>%s<br />%s<br />%s</td></tr></table>", iconMarkup, linkMarkup, grade, formatTime(recipeProdTime)) | |||
return innerTable | |||
end | end | ||
Line 499: | Line 526: | ||
--- | --- | ||
-- Start all the tables the same way so they look the same | -- Start all the tables the same way so they look the same | ||
-- @param the caption, if wanted | -- @param the caption, if wanted | ||
-- @return the wikitext | -- @return the wikitext | ||
function startNewWikiTable(caption) | function startNewWikiTable(caption) | ||
local wikiTable = mw.html.create('table'):addClass( | local wikiTable = mw.html.create('table'):addClass(CSS_CLASS_WIKITABLE) | ||
wikiTable: | wikiTable:newline() | ||
if caption then | if caption then | ||
wikiTable:tag('caption'):wikitext(caption):done() | wikiTable:tag('caption'):wikitext(caption):done():newline() | ||
end | end | ||
wikiTable:tag('tr') | wikiTable:tag('tr') | ||
:tag('th'):wikitext("Building"):done() | :tag('th'):wikitext("Building"):done() | ||
:tag('th'):wikitext("Ingredient #1"):done() | :tag('th'):wikitext("Ingredient #1 options"):done() | ||
:tag('th'):wikitext("Ingredient #2"):done() | :tag('th'):wikitext("Ingredient #2 options"):done() | ||
:tag('th'):wikitext("Ingredient #3"):done() | :tag('th'):wikitext("Ingredient #3 options"):done() | ||
:tag('th'):wikitext("Product"):done() | :tag('th'):wikitext("Product"):done() | ||
:done():newline() | |||
wikiTable: | |||
return wikiTable | |||
end | |||
--- | |||
-- Start the simple list display | |||
-- | |||
-- @return the wikitext | |||
function startList() | |||
local wikiTable = mw.html.create('table') | |||
wikiTable:newline() | |||
return wikiTable | return wikiTable |
Latest revision as of 02:58, 12 November 2023
Documentation for this module may be created at Module:Recipe/doc
------------------------------------------------------------------------------- -- This module renders the {{Recipe}} template with a nice wikitable. -- https://hoodedhorse.com/wiki/Against_the_Storm/Template:Recipe. -- -- The template #invokes Recipe.render(frame), with provided parameters. -- The template requires at least one of its three parameters, or it will -- return an error. -- -- The first parameter `product` specifies that you want a table rendered to -- show all recipes that result in the specified product. Make sure it is -- spelled correctly, as it appears in the game. -- -- The second parameter `building` species that you want a table rendered to -- show all recipes that are produced in the specified building. Again, make -- sure it is spelled and puncutated (apostrophes) correctly. -- -- The third, parameter `ingredient` species that you want a table rendered to -- show all the recipes that take that ingredient to produce, whether -- specifically (like Wood for Planks) or as an option among many. This -- parameter is intended to be used by itself, without a product or building -- named. -- -- The data for the recipes is retrieved from Module:RecipeData, which hides the -- variations in the original data from this module that extracts only what's -- needed to display one or more wikitables on a wiki page. Using the data, this -- module creates an HTML table. -- -- The table will have exactly one row if both the product and building are -- specified. If either is missing, then expect a table with multiple rows. -- If an ingredient is specified, then the table will likely be very long. -- @module Recipe local Recipe = {} --- -- Constants -- -- Currently this is the max number of ingredients a recipe can have local RECIPE_INGRED_MAX = 3 -- Indexes to use for recipe records as they come from the CSV data local INDEX_RECIPE_GRADE = 2 local INDEX_RECIPE_PRODTIME = 3 local INDEX_RECIPE_PRODUCT_STACK_SIZE = 4 local INDEX_RECIPE_PRODUCT_ID = 5 local INDEX_RECIPE_INGREDIENTS = 6 -- Indexes to use for workshop records as they come from the CSV data local INDEX_WORKSHOP_ID = 1 local INDEX_WORKSHOP_NAME = 2 -- CSS styling for the recipe table... for now local CSS_CLASS_WIKITABLE = "wikitable sortable mw-collapsible" -- Shortcut markup to go after the filename to add the extension and display parameters local WIKI_MED_ICON_MARKUP = ".png|24px|alt=" local WIKI_LARGE_ICON_MARKUP = ".png|42px|alt=" -- Shortcut markup that's easier for Lua string concatenations local BR = "<br />" local NBSP = " " local BOLD = "'''" -- Shortcuts for displaying the efficency grades as stars or the "low meter" local GRADE_TO_STARS = { ["Grade0"] = "[[File:Grade Stars 0.png|12px|link=|alt=0 Stars]]", ["Grade1"] = "★", ["Grade2"] = "★★", ["Grade3"] = "★★★" } --- -- Member variables --- local RecipeData = require('Module:RecipeData') --- -- Called from Template:Recipe to render a table displaying the information. -- Retrieves data from Module:RecipeData. The data retrieved looks like this: -- -- (sometimes there's an extra first variable like workshop or ingredient) -- targetRecipeMatches = { -- [recipeID] match between recipe and workshops = { -- [1] = { recipe data }, -- [2] = list of workshops that make it = { -- { workshop data }, -- { workshop data }, -- { workshop data } -- } -- }, -- [recipeID] match between recipe and workshops = { -- similar -- } -- } -- -- @param frame the template passes parameters and page data via frame -- @return the formatted wikitext/HTML function Recipe.render(frame) -- Extract the passed parameters. local productName = frame.args.product or frame.args[1] local buildingName = frame.args.building or frame.args[2] local ingredientName = frame.args.ingredient local display = frame.args.display local displayListOverride = false if display == "list" then displayListOverride = true end -- At least one parameter is required. if productName == "" and buildingName == "" and ingredientName == "" then return "The Recipe template requires that you specify at least one of the following: product, building, or ingredient." end -- Decide according to parameters if ingredientName and ingredientName ~= "" then return buildIngredientWikitext(ingredientName, displayListOverride) else if productName and productName ~= "" and buildingName and buildingName ~= "" then return buildProductBuildingWikitext(productName, buildingName, displayListOverride) else if productName and productName ~= "" then return buildProductWikitext(productName, displayListOverride) else if buildingName and buildingName ~= "" then return buildBuildingWikitext(buildingName, displayListOverride) else return "Error in Recipe template: Unknown parameter error." end end end end end --- -- Renders the table for the specified product. -- -- @param productName the name of the product -- @return the wikitext that renders the table function buildProductWikitext(productName, displayListOverride) local targetRecipeMatches = RecipeData.getAllRecipesForProduct(productName) if not targetRecipeMatches then return "There are no recipes for product " .. productName .. "." end -- Start a wiki table the same way each time, and then populate each row. local wikiTable if displayListOverride then wikiTable = startList() else wikiTable = startNewWikiTable("Recipes for " .. productName .. ".") end -- Add the data retrieved to the wiki table for _, match in pairs(targetRecipeMatches) do local recipe = match[1] for _, workshop in ipairs(match[2]) do wikiTable = addRowToTable(wikiTable, recipe, workshop, displayListOverride) end end wikiTable = endWikiTable(wikiTable) return wikiTable end --- -- Renders the table for the specified building. -- -- @param buildingName the name of the building -- @return the wikitext that renders the table function buildBuildingWikitext(buildingName, displayListOverride) -- Ignore the workshop also returned. local _, targetRecipeMatches = RecipeData.getAllRecipesAtBuilding(buildingName) if not targetRecipeMatches then return "There are no recipes in the building " .. buildingName .. "." end -- Start a wiki table the same way each time, and then populate each row. local wikiTable if displayListOverride then wikiTable = startList() else wikiTable = startNewWikiTable("Recipes in the " .. buildingName .. ".") end -- Add the data retrieved to the wiki table for _, match in pairs(targetRecipeMatches) do local recipe = match[1] for _, workshop in ipairs(match[2]) do wikiTable = addRowToTable(wikiTable, recipe, workshop, displayListOverride) end end wikiTable = endWikiTable(wikiTable) return wikiTable end --- -- Renders the table for the specified product and building. -- -- @param productName the name of the product -- @param buildingName the name of the building -- @return the wikitext that renders the table function buildProductBuildingWikitext(productName, buildingName, displayListOverride) local targetRecipeMatches = RecipeData.getOneRecipeAtBuilding(productName, buildingName) if not targetRecipeMatches then return "There is no recipe for product " .. productName .. " in the building " .. buildingName .. "." end -- Start a wiki table the same way each time, and then populate each row. local wikiTable if displayListOverride then wikiTable = startList() else wikiTable = startNewWikiTable("Recipe for " .. productName .. " in the " .. buildingName .. ".") end -- Add the data retrieved to the wiki table for _, match in pairs(targetRecipeMatches) do local recipe = match[1] for _, workshop in ipairs(match[2]) do wikiTable = addRowToTable(wikiTable, recipe, workshop, displayListOverride) end end wikiTable = endWikiTable(wikiTable) return wikiTable end --- -- Renders the table for the specified ingredient. -- -- @param ingredientName the name of the ingredient -- @return the wikitext that renders the table function buildIngredientWikitext(ingredientName, displayListOverride) -- Ignore the ingredient also returned local _, targetRecipeMatches = RecipeData.getAllRecipesWithIngredient(ingredientName) if not targetRecipeMatches then return "There are no recipes for ingredient " .. ingredientName .. "." end -- Start a wiki table the same way each time, and then populate each row. local wikiTable if displayListOverride then wikiTable = startList() else wikiTable = startNewWikiTable("Recipes that require " .. ingredientName .. ".") end -- Add the data retrieved to the wiki table for _, match in pairs(targetRecipeMatches) do local recipe = match[1] for _, workshop in ipairs(match[2]) do wikiTable = addRowToTable(wikiTable, recipe, workshop, displayListOverride) end end wikiTable = endWikiTable(wikiTable) return wikiTable end --- -- Adds a row to the existing wiki table based on the recipe and building -- provided. -- -- The structures look like this: -- recipe { -- id -- efficiency grade -- production time -- product stack size -- product good's id -- ingredients { -- options for ingredient #1 { -- { option #1 good's stack size, option #1 good's id } -- { option #2 good's stack size, option #2 good's id } -- { option #3 good's stack size, option #3 good's id } -- etc. -- } -- options for ingredient #2 { -- same as above -- } -- options for ingredient #3 { -- same as above -- } -- } -- } -- -- workshop { -- id -- display name -- description -- category -- size x -- size y -- city score -- movable -- initially essential -- storage -- construction time -- required goods { -- required good #1 stack size -- required good #1 id -- required good #2 stack size -- required good #2 id -- required good #3 stack size -- required good #3 id -- } -- workplaces { -- workplace #1 -- workplace #2 -- workplace #3 -- workplace #4 -- } -- recipes { -- recipe #1 -- recipe #2 -- recipe #3 -- recipe #4 -- } -- } -- -- @param wikiTable the table to continue adding to -- @param recipe the recipe to pull data from -- @param workshop the workshop to pull data from -- @return wikiTable, augmented with the new row function addRowToTable(wikiTable, recipe, workshop, displayListOverride) if not wikiTable then error("Wikitable in-progress is not set up correctly.") else if not recipe or not workshop then error("Recipe and workshop to display not set up correctly.") end end -- Get everything extracted and ready to go for easier code below local buildingName = workshop[INDEX_WORKSHOP_NAME] -- Do not add the extension here local buildingIconFile = workshop[INDEX_WORKSHOP_ID] .. "_icon" local recipeGrade = recipe[INDEX_RECIPE_GRADE] local recipeProdTime = recipe[INDEX_RECIPE_PRODTIME] local recipeProductStackSize = recipe[INDEX_RECIPE_PRODUCT_STACK_SIZE] local recipeProductID = recipe[INDEX_RECIPE_PRODUCT_ID] -- Now build the table tags. We're going to add everything to this row, so -- save the row itself to keep the hierarchy straight. local wikiTableRow = wikiTable:tag('tr') wikiTableRow:newline() -- Simple name and stars if display overriding if displayListOverride then wikiTableRow:tag("td") :wikitext("[[" .. buildingName .. "]]" .. NBSP) :wikitext("(" .. GRADE_TO_STARS[recipeGrade] .. ")" .. BR) :allDone():newline() return wikiTable end wikiTableRow:tag('td') :wikitext(writeBuildingCellContent(buildingIconFile, buildingName, recipeGrade, recipeProdTime)) :done():newline() -- Skip empty cells of ingredients in this recipe local blanks = 0 for i, tableToCheck in ipairs(recipe[INDEX_RECIPE_INGREDIENTS]) do if #tableToCheck == 0 then blanks = blanks + 1 end end for i = 1,blanks do wikiTableRow:tag('td'):done():newline() end -- Then fill in the rest with the remaining ingredients, with inner tables -- to keep things aligned well for _, optionsGroup in ipairs(recipe[INDEX_RECIPE_INGREDIENTS]) do -- Skip blank groups; we already inserted blanks earlier. if #optionsGroup > 0 then local innerTable = wikiTableRow:tag('td'):tag('table') innerTable:newline() -- Loop through each option, but only up until they are blank for _, option in ipairs(optionsGroup) do local ingredientStackSize = option[1] local ingredientGoodID = option[2] innerTable:tag('tr') :tag('td'):wikitext(BOLD .. ingredientStackSize .. BOLD):done() :tag('td'):wikitext(writeIngredientCellContent(ingredientGoodID)):done() :done() innerTable:wikitext("\n") end end end local productCell, productName = writeProductCellContent(recipeProductID) -- Sort on product name, not the stack size wikiTableRow:tag('td'):attr("data-sort-value", productName) :wikitext(BOLD .. recipeProductStackSize .. BOLD .. NBSP .. productCell) :done() wikiTableRow:wikitext("\n") wikiTableRow:done() wikiTable:wikitext("\n") return wikiTable end --- -- Writes an icon and link to a resource page. -- -- @param ingredientGoodID the good ID to use to create the link -- @return a string of wiki markup function writeIngredientCellContent(ingredientGoodID) local goodName, goodIconFile = RecipeData.getGoodNameAndIcon(ingredientGoodID) local iconMarkup = "[[File:" .. goodIconFile .. WIKI_MED_ICON_MARKUP .. goodName .. "|link=" .. goodName .. "#Product]]" local linkMarkup = "[[" .. goodName .. "#Product|" .. goodName .. "]]" return iconMarkup .. NBSP .. linkMarkup end --- -- Writes an icon and link to a resource page. -- -- @param productGoodID the good ID to use to create the link -- @return a string of wiki markup -- @return the string name of the product function writeProductCellContent(productGoodID) local goodName, goodIconFile = RecipeData.getGoodNameAndIcon(productGoodID) local iconMarkup = "[[File:" .. goodIconFile .. WIKI_LARGE_ICON_MARKUP .. goodName .. "|link=" .. goodName .. "#Ingredient]]" local linkMarkup = "[[" .. goodName .. "#Ingredient|" .. goodName .. "]]" return iconMarkup .. NBSP .. linkMarkup, goodName end --- -- Writes the contents of the building cell and returns a string to be used -- in a call to wikitext() -- -- @param buildingIconFile icon filename, excluding 'File:', including extension -- @param buildingName plain text name of the building to display -- @param recipeGrade efficiency of the recipe -- @param recipeProdTime production time in seconds -- @return a string of wiki markup function writeBuildingCellContent(buildingIconFile, buildingName, recipeGrade, recipeProdTime) local iconMarkup = "[[File:" .. buildingIconFile .. WIKI_LARGE_ICON_MARKUP .. buildingName .. "|link=" .. buildingName .. "]]" local linkMarkup = "[[" .. buildingName .. "]]" local grade = GRADE_TO_STARS[recipeGrade] if not grade then error("Incorrectly formatted efficiency grade: " .. recipeGrade) end local innerTable = mw.ustring.format("<table><tr><td>%s</td><td>%s<br />%s<br />%s</td></tr></table>", iconMarkup, linkMarkup, grade, formatTime(recipeProdTime)) return innerTable end --- -- Formats seconds as mm:ss format, with leading zeros where necessary. -- -- @param seconds number of seconds to reformat -- @return a string representing mm:ss time format function formatTime(seconds) local minutes = math.floor(seconds/60) local remainingSeconds = seconds % 60 return string.format("%02d:%02d", minutes, remainingSeconds) end --- -- Start all the tables the same way so they look the same -- @param the caption, if wanted -- @return the wikitext function startNewWikiTable(caption) local wikiTable = mw.html.create('table'):addClass(CSS_CLASS_WIKITABLE) wikiTable:newline() if caption then wikiTable:tag('caption'):wikitext(caption):done():newline() end wikiTable:tag('tr') :tag('th'):wikitext("Building"):done() :tag('th'):wikitext("Ingredient #1 options"):done() :tag('th'):wikitext("Ingredient #2 options"):done() :tag('th'):wikitext("Ingredient #3 options"):done() :tag('th'):wikitext("Product"):done() :done():newline() return wikiTable end --- -- Start the simple list display -- -- @return the wikitext function startList() local wikiTable = mw.html.create('table') wikiTable:newline() return wikiTable end --- -- Finishes the wikitext by closing out remaining tags. -- -- @paramn wikiTable the table to close out -- @return the wikitext to display function endWikiTable(wikiTable) -- There might be more later. wikiTable:done() return wikiTable end return Recipe