<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.hoodedhorse.com/Against_the_Storm/index.php?action=history&amp;feed=atom&amp;title=Module%3ARecipeData%2FData</id>
	<title>Module:RecipeData/Data - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.hoodedhorse.com/Against_the_Storm/index.php?action=history&amp;feed=atom&amp;title=Module%3ARecipeData%2FData"/>
	<link rel="alternate" type="text/html" href="https://wiki.hoodedhorse.com/Against_the_Storm/index.php?title=Module:RecipeData/Data&amp;action=history"/>
	<updated>2026-10-18T12:15:34Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.5</generator>
	<entry>
		<id>https://wiki.hoodedhorse.com/Against_the_Storm/index.php?title=Module:RecipeData/Data&amp;diff=10954&amp;oldid=prev</id>
		<title>76561198157077871: Created page with &quot;local CsvUtils = require(&quot;Module:CsvUtils&quot;)  -- Constants for this module --- local RECIPE_DATA_TEMPLATE_NAME = &quot;Template:Workshops_Recipes_csv&quot; local WORKSHOPS_DATA_TEMPLATE_NAME = &quot;Template:Workshops_csv&quot; local GOODS_DATA_TEMPLATE_NAME = &quot;Template:Goods_csv&quot;  local HEADER_ROW = 1 local DATA_ROWS = 2  local PATTERN_SPLIT_STACK_AND_ID = &quot;(%d+)%s([%[%]%s%a]+)&quot;  local INDEX_RECIPE_ID = 1 local INDEX_RECIPE_GRADE = 2 local INDEX_RECIPE_PRODTIME = 3 local INDEX_RECIPE_PRODUC...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.hoodedhorse.com/Against_the_Storm/index.php?title=Module:RecipeData/Data&amp;diff=10954&amp;oldid=prev"/>
		<updated>2025-08-31T20:39:27Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;local CsvUtils = require(&amp;quot;Module:CsvUtils&amp;quot;)  -- Constants for this module --- local RECIPE_DATA_TEMPLATE_NAME = &amp;quot;Template:Workshops_Recipes_csv&amp;quot; local WORKSHOPS_DATA_TEMPLATE_NAME = &amp;quot;Template:Workshops_csv&amp;quot; local GOODS_DATA_TEMPLATE_NAME = &amp;quot;Template:Goods_csv&amp;quot;  local HEADER_ROW = 1 local DATA_ROWS = 2  local PATTERN_SPLIT_STACK_AND_ID = &amp;quot;(%d+)%s([%[%]%s%a]+)&amp;quot;  local INDEX_RECIPE_ID = 1 local INDEX_RECIPE_GRADE = 2 local INDEX_RECIPE_PRODTIME = 3 local INDEX_RECIPE_PRODUC...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local CsvUtils = require(&amp;quot;Module:CsvUtils&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
-- Constants for this module&lt;br /&gt;
---&lt;br /&gt;
local RECIPE_DATA_TEMPLATE_NAME = &amp;quot;Template:Workshops_Recipes_csv&amp;quot;&lt;br /&gt;
local WORKSHOPS_DATA_TEMPLATE_NAME = &amp;quot;Template:Workshops_csv&amp;quot;&lt;br /&gt;
local GOODS_DATA_TEMPLATE_NAME = &amp;quot;Template:Goods_csv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local HEADER_ROW = 1&lt;br /&gt;
local DATA_ROWS = 2&lt;br /&gt;
&lt;br /&gt;
local PATTERN_SPLIT_STACK_AND_ID = &amp;quot;(%d+)%s([%[%]%s%a]+)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local INDEX_RECIPE_ID = 1&lt;br /&gt;
local INDEX_RECIPE_GRADE = 2&lt;br /&gt;
local INDEX_RECIPE_PRODTIME = 3&lt;br /&gt;
local INDEX_RECIPE_PRODUCT_STACK_SIZE = 4&lt;br /&gt;
local INDEX_RECIPE_PRODUCT_ID = 5&lt;br /&gt;
local INDEX_RECIPE_INGREDIENTS = 6&lt;br /&gt;
&lt;br /&gt;
local INDEX_RECIPE_INGREDIENT_OPTION_GOODID = 2&lt;br /&gt;
&lt;br /&gt;
local INDEX_WORKSHOP_ID = 1&lt;br /&gt;
local INDEX_WORKSHOP_NAME = 2&lt;br /&gt;
local INDEX_WORKSHOP_DESCRIPTION = 3&lt;br /&gt;
local INDEX_WORKSHOP_CATEGORY = 4&lt;br /&gt;
local INDEX_WORKSHOP_SIZE_X = 5&lt;br /&gt;
local INDEX_WORKSHOP_SIZE_Y = 6&lt;br /&gt;
local INDEX_WORKSHOP_CITY_SCORE = 7&lt;br /&gt;
local INDEX_WORKSHOP_MOVABLE = 8&lt;br /&gt;
local INDEX_WORKSHOP_INITIALLY_ESSENTIAL = 9&lt;br /&gt;
local INDEX_WORKSHOP_STORAGE = 10&lt;br /&gt;
local INDEX_WORKSHOP_CONSTRUCTION_TIME = 11&lt;br /&gt;
local INDEX_WORKSHOP_REQUIRED_GOODS = 12&lt;br /&gt;
local INDEX_WORKSHOP_WORKPLACES = 13&lt;br /&gt;
local INDEX_WORKSHOP_RECIPES = 14&lt;br /&gt;
&lt;br /&gt;
local INDEX_GOOD_ID = 1&lt;br /&gt;
local INDEX_GOOD_NAME = 2&lt;br /&gt;
local INDEX_GOOD_DESCRIPTION = 3&lt;br /&gt;
local INDEX_GOOD_CATEGORY = 4&lt;br /&gt;
local INDEX_GOOD_EATABLE = 5&lt;br /&gt;
local INDEX_GOOD_CAN_BE_BURNED = 6&lt;br /&gt;
local INDEX_GOOD_BURNING_TIME = 7&lt;br /&gt;
local INDEX_GOOD_TRADING_SELL_VALUE = 8&lt;br /&gt;
local INDEX_GOOD_TRADING_BUY_VALUE = 9&lt;br /&gt;
local INDEX_GOOD_ICON_FILENAME = 10&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- @param oldRecipeTable the CSV-based table, with a header row then data rows&lt;br /&gt;
-- @param recipeHeaderLookup the lookup table built from the CSV data&lt;br /&gt;
-- @return a new table for use in looking up recipe data&lt;br /&gt;
function restructureRecipeTable(oldRecipeTable, recipeHeaderLookup)&lt;br /&gt;
	&lt;br /&gt;
	-- New table structure is only data rows, no header row needed. Therefore, &lt;br /&gt;
	-- the new table is one degree flatter, like this:&lt;br /&gt;
	-- oldRecipeTable[2][1] contains the same data as newRecipeTable[1]&lt;br /&gt;
	-- (but with subtables)&lt;br /&gt;
	local newRecipeTable = {}&lt;br /&gt;
	oldRecipeTable = oldRecipeTable[DATA_ROWS]&lt;br /&gt;
	&lt;br /&gt;
	-- A few constants we need only in this function&lt;br /&gt;
	local INDEX_OLD_RECIPE_ID = 1&lt;br /&gt;
	local INDEX_OLD_RECIPE_GRADE = 2&lt;br /&gt;
	local INDEX_OLD_RECIPE_PRODTIME = 3&lt;br /&gt;
	local INDEX_OLD_RECIPE_PRODUCT = 4&lt;br /&gt;
	&lt;br /&gt;
	for i, oldRecipe in ipairs(oldRecipeTable) do&lt;br /&gt;
		&lt;br /&gt;
		local newRecipe = {}&lt;br /&gt;
		&lt;br /&gt;
		-- Copy over the flat information from the old recipe.&lt;br /&gt;
		local newRecipeID = oldRecipe[INDEX_OLD_RECIPE_ID]&lt;br /&gt;
		newRecipe[INDEX_RECIPE_ID] = newRecipeID&lt;br /&gt;
		newRecipe[INDEX_RECIPE_GRADE] = oldRecipe[INDEX_OLD_RECIPE_GRADE]&lt;br /&gt;
		newRecipe[INDEX_RECIPE_PRODTIME] = oldRecipe[INDEX_OLD_RECIPE_PRODTIME]&lt;br /&gt;
		&lt;br /&gt;
		-- Split the digit part into the product stack size and the rest of the &lt;br /&gt;
		-- text into the product good&amp;#039;s id.&lt;br /&gt;
		newRecipe[INDEX_RECIPE_PRODUCT_STACK_SIZE], newRecipe[INDEX_RECIPE_PRODUCT_ID] = oldRecipe[INDEX_OLD_RECIPE_PRODUCT]:match(PATTERN_SPLIT_STACK_AND_ID)&lt;br /&gt;
		&lt;br /&gt;
		newRecipe[INDEX_RECIPE_INGREDIENTS] = makeIngredientsSubtable(oldRecipe,recipeHeaderLookup)&lt;br /&gt;
		&lt;br /&gt;
		newRecipeTable[newRecipeID] = newRecipe&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return newRecipeTable&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Loops through the old recipe, extracting ingredient options and putting them&lt;br /&gt;
-- into new subtables. Uses the lookup table from the CSV extraction to &lt;br /&gt;
-- keep the data in the same order.&lt;br /&gt;
--&lt;br /&gt;
-- @param oldRecipe the recipe from which to extract ingredient information&lt;br /&gt;
-- @param recipeHeaderLookup the lookup table built from the CSV data&lt;br /&gt;
-- @return a subtable with the ingredients information from oldRecipe&lt;br /&gt;
function makeIngredientsSubtable(oldRecipe, recipeHeaderLookup)&lt;br /&gt;
	&lt;br /&gt;
	-- A few constants we&amp;#039;ll need only within this function.&lt;br /&gt;
	local RECIPE_INGRED_MAX = 3&lt;br /&gt;
	local RECIPE_INGRED_OPTION_MAX = 6&lt;br /&gt;
	local LOOKUP_INGREDIENT_BASE_STRING = &amp;quot;ingredient&amp;quot;&lt;br /&gt;
	local LOOKUP_OPTION_BASE_STRING = &amp;quot;Good&amp;quot;&lt;br /&gt;
	&lt;br /&gt;
	-- A subtable for the lists of ingredients and their options.&lt;br /&gt;
	local ingredients = {}&lt;br /&gt;
	&lt;br /&gt;
	for i = 1,RECIPE_INGRED_MAX do&lt;br /&gt;
		&lt;br /&gt;
		-- A subtable for the options for this ingredient.&lt;br /&gt;
		local options = {}&lt;br /&gt;
		for j = 1,RECIPE_INGRED_OPTION_MAX do&lt;br /&gt;
			&lt;br /&gt;
			local oldIndex = recipeHeaderLookup[LOOKUP_INGREDIENT_BASE_STRING .. i .. LOOKUP_OPTION_BASE_STRING .. j]&lt;br /&gt;
			&lt;br /&gt;
			-- Once it gets to a blank, can advance to the next group&lt;br /&gt;
			local oldOption = oldRecipe[oldIndex]&lt;br /&gt;
			if oldOption == &amp;quot;&amp;quot; then&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			&lt;br /&gt;
			-- Split the digit part into the ingredient stack size and the rest &lt;br /&gt;
			-- of the text into the ingredient good&amp;#039;s id.&lt;br /&gt;
			local stackSize, goodID = oldOption:match(PATTERN_SPLIT_STACK_AND_ID)&lt;br /&gt;
			&lt;br /&gt;
			table.insert(options, {stackSize, goodID})&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- Add finished options list to represent the ith ingredient&lt;br /&gt;
		ingredients[i] = options&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return ingredients&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Transforms the oldWorkshopsTable returned from CSV processing to be more &lt;br /&gt;
-- conducive to member functions looking up data. Essentially, we convert the &lt;br /&gt;
-- text strings into tables with the same base name and an index.&lt;br /&gt;
-- &lt;br /&gt;
-- Each item newWorkshopTable[i] looks like this:&lt;br /&gt;
-- workshop {&lt;br /&gt;
-- 		id&lt;br /&gt;
--		display name&lt;br /&gt;
--		description&lt;br /&gt;
--		category&lt;br /&gt;
--		size x&lt;br /&gt;
--		size y&lt;br /&gt;
--		city score&lt;br /&gt;
--		movable&lt;br /&gt;
--		initially essential&lt;br /&gt;
--		storage&lt;br /&gt;
--		construction time&lt;br /&gt;
--		required goods {&lt;br /&gt;
--			#1 { stack size, id }&lt;br /&gt;
--			#2 { stack size, id }&lt;br /&gt;
--			#3 { stack size, id }&lt;br /&gt;
--		}&lt;br /&gt;
--		workplaces {&lt;br /&gt;
--			workplace #1&lt;br /&gt;
--			workplace #2&lt;br /&gt;
--			workplace #3&lt;br /&gt;
--			workplace #4&lt;br /&gt;
--		}&lt;br /&gt;
--		recipes {&lt;br /&gt;
--			recipe #1&lt;br /&gt;
--			recipe #2&lt;br /&gt;
--			recipe #3&lt;br /&gt;
--			recipe #4&lt;br /&gt;
--		}&lt;br /&gt;
-- }&lt;br /&gt;
-- &lt;br /&gt;
-- @param oldRecipeTable the CSV-based table, with a header row then data rows&lt;br /&gt;
-- @param recipeHeaderLookup the lookup table built from the CSV data&lt;br /&gt;
-- @return a new table for use in looking up recipe data&lt;br /&gt;
function restructureWorkshopTable(oldWorkshopTable, workshopsHeaderLookup)&lt;br /&gt;
	&lt;br /&gt;
	-- New table structure is only data rows, no header row needed. Therefore, &lt;br /&gt;
	-- the new table is one degree flatter, like this:&lt;br /&gt;
	-- oldWorkshopTable[2][1] contains the same data as newWorkshopTable[1]&lt;br /&gt;
	-- (but organized by workshopID instead of by index and with subtables)&lt;br /&gt;
	local newWorkshopTable = {}&lt;br /&gt;
	oldWorkshopTable = oldWorkshopTable[DATA_ROWS]&lt;br /&gt;
	&lt;br /&gt;
	-- A few constants we need only in this function.&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_ID = 1&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_NAME = 2&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_DESCRIPTION = 3&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_CATEGORY = 4&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_SIZE_X = 5&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_SIZE_Y = 6&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_CONSTRUCTION_TIME = 10&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_CITY_SCORE = 11&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_MOVABLE = 12&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_INITIALLY_ESSENTIAL = 13&lt;br /&gt;
	local INDEX_OLD_WORKSHOP_STORAGE = 14&lt;br /&gt;
	&lt;br /&gt;
	for i, oldWorkshop in ipairs(oldWorkshopTable) do&lt;br /&gt;
		&lt;br /&gt;
		local newWorkshop = {}&lt;br /&gt;
		&lt;br /&gt;
		-- Copy over the flat information from the old recipe.&lt;br /&gt;
		local newWorkshopID = oldWorkshop[INDEX_OLD_WORKSHOP_ID]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_ID] = newWorkshopID&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_NAME] = oldWorkshop[INDEX_OLD_WORKSHOP_NAME]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_DESCRIPTION] = oldWorkshop[INDEX_OLD_WORKSHOP_DESCRIPTION]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_CATEGORY] = oldWorkshop[INDEX_OLD_WORKSHOP_CATEGORY]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_SIZE_X] = oldWorkshop[INDEX_OLD_WORKSHOP_SIZE_X]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_SIZE_Y] = oldWorkshop[INDEX_OLD_WORKSHOP_SIZE_Y]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_CITY_SCORE] = oldWorkshop[INDEX_OLD_WORKSHOP_CITY_SCORE]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_MOVABLE] = oldWorkshop[INDEX_OLD_WORKSHOP_MOVABLE]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_INITIALLY_ESSENTIAL] = oldWorkshop[INDEX_OLD_WORKSHOP_INITIALLY_ESSENTIAL]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_STORAGE] = oldWorkshop[INDEX_OLD_WORKSHOP_STORAGE]&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_CONSTRUCTION_TIME] = oldWorkshop[INDEX_OLD_WORKSHOP_CONSTRUCTION_TIME]&lt;br /&gt;
		&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_REQUIRED_GOODS] = makeRequiredGoodsSubtable(oldWorkshop, workshopsHeaderLookup)&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_WORKPLACES] = makeWorkplacesSubtable(oldWorkshop, workshopsHeaderLookup)&lt;br /&gt;
		newWorkshop[INDEX_WORKSHOP_RECIPES] = makeRecipesSubtable(oldWorkshop, workshopsHeaderLookup)&lt;br /&gt;
		&lt;br /&gt;
		newWorkshopTable[newWorkshopID] = newWorkshop&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return newWorkshopTable&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Loops through the old workshop, extracting req&amp;#039;d goods and putting them&lt;br /&gt;
-- into a new subtable. Uses the lookup table from the CSV extraction to &lt;br /&gt;
-- keep the data in the same order.&lt;br /&gt;
--&lt;br /&gt;
-- @param oldWorkshop the workshop from which to extract req&amp;#039;d goods information&lt;br /&gt;
-- @param workshopsHeaderLookup the lookup table built from the CSV data&lt;br /&gt;
-- @return a subtable with the req&amp;#039;d goods information from oldWorkshop&lt;br /&gt;
function makeRequiredGoodsSubtable(oldWorkshop, workshopsHeaderLookup)&lt;br /&gt;
	&lt;br /&gt;
	-- A few constants we&amp;#039;ll need only within this function.&lt;br /&gt;
	local REQ_GOOD_MAX = 3&lt;br /&gt;
	local LOOKUP_REQ_GOOD_BASE_STRING = &amp;quot;requiredGood&amp;quot;&lt;br /&gt;
	&lt;br /&gt;
	-- A subtable to return&lt;br /&gt;
	local requiredGoods = {}&lt;br /&gt;
	for i = 1,REQ_GOOD_MAX do&lt;br /&gt;
		&lt;br /&gt;
		local oldIndex = workshopsHeaderLookup[LOOKUP_REQ_GOOD_BASE_STRING .. i]&lt;br /&gt;
		&lt;br /&gt;
		local newGroup = {}&lt;br /&gt;
		-- Split the digit part into the req&amp;#039;d good stack size and the rest &lt;br /&gt;
		-- of the text into the req&amp;#039;d good&amp;#039;s id.&lt;br /&gt;
		newGroup[1], newGroup[2] = oldWorkshop[oldIndex]:match(PATTERN_SPLIT_STACK_AND_ID)&lt;br /&gt;
		table.insert(requiredGoods, newGroup)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return requiredGoods&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Loops through the old workshop, extracting workplaces and putting them&lt;br /&gt;
-- into a new subtable. Uses the lookup table from the CSV extraction to &lt;br /&gt;
-- keep the data in the same order.&lt;br /&gt;
--&lt;br /&gt;
-- @param oldWorkshop the workshop from which to extract workplaces information&lt;br /&gt;
-- @param workshopsHeaderLookup the lookup table built from the CSV data&lt;br /&gt;
-- @return a subtable with the workplaces information from oldWorkshop&lt;br /&gt;
function makeWorkplacesSubtable(oldWorkshop, workshopsHeaderLookup)&lt;br /&gt;
	&lt;br /&gt;
	-- A few constants we&amp;#039;ll need only within this function.&lt;br /&gt;
	local WORKPLACE_MAX = 4&lt;br /&gt;
	local LOOKUP_WORKPLACE_BASE_STRING = &amp;quot;workplace&amp;quot;&lt;br /&gt;
	&lt;br /&gt;
	-- A subtable to return&lt;br /&gt;
	local workplaces = {}&lt;br /&gt;
	&lt;br /&gt;
	for i = 1,WORKPLACE_MAX do&lt;br /&gt;
		&lt;br /&gt;
		local oldIndex = workshopsHeaderLookup[LOOKUP_WORKPLACE_BASE_STRING .. i]&lt;br /&gt;
		workplaces[i] = oldWorkshop[oldIndex]&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return workplaces&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Loops through the old workshop, extracting recipes and putting them&lt;br /&gt;
-- into a new subtable. Uses the lookup table from the CSV extraction to &lt;br /&gt;
-- keep the data in the same order.&lt;br /&gt;
--&lt;br /&gt;
-- @param oldWorkshop the workshop from which to extract recipes&lt;br /&gt;
-- @param workshopsHeaderLookup the lookup table built from the CSV data&lt;br /&gt;
-- @return a subtable with the recipes from oldWorkshop&lt;br /&gt;
function makeRecipesSubtable(oldWorkshop, workshopsHeaderLookup)&lt;br /&gt;
	&lt;br /&gt;
	-- A few constants we&amp;#039;ll need only within this function.&lt;br /&gt;
	local RECIPE_MAX = 4&lt;br /&gt;
	local LOOKUP_RECIPE_BASE_STRING = &amp;quot;recipe&amp;quot;&lt;br /&gt;
	&lt;br /&gt;
	-- A subtable to return&lt;br /&gt;
	local recipes = {}&lt;br /&gt;
	&lt;br /&gt;
	for i=1,RECIPE_MAX do&lt;br /&gt;
		&lt;br /&gt;
		local oldIndex = workshopsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. i]&lt;br /&gt;
		recipes[i] = oldWorkshop[oldIndex]&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return recipes&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Since the goods information is already flat and well structured, all this has &lt;br /&gt;
-- to do is swap out the integer keys for the good IDs and only return the data&lt;br /&gt;
-- rows, without the header row.&lt;br /&gt;
--&lt;br /&gt;
-- @param oldGoodsTable the CSV-based table, with a header row then data rows&lt;br /&gt;
-- @param goodsHeaderLookup the lookup table built from the CSV data&lt;br /&gt;
-- @return a new table for use in looking up goods data&lt;br /&gt;
function restructureGoodsTable(oldGoodsTable, goodsHeaderLookup)&lt;br /&gt;
	&lt;br /&gt;
	local newGoodsTable = {}&lt;br /&gt;
	&lt;br /&gt;
	for _, good in ipairs(oldGoodsTable[DATA_ROWS]) do&lt;br /&gt;
		&lt;br /&gt;
		newGoodsTable[good[INDEX_GOOD_ID]] = good&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return newGoodsTable&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Use the CSV utility module to load the data templates we need for &lt;br /&gt;
-- recipes, which are the recipes themselves and the workshops (production) &lt;br /&gt;
-- workshops.&lt;br /&gt;
local originalRecipeTable, recipeHeaderLookup = CsvUtils.luaTableFromCSV(CsvUtils.extractCSV(RECIPE_DATA_TEMPLATE_NAME))&lt;br /&gt;
local originalWorkshopTable, workshopsHeaderLookup = CsvUtils.luaTableFromCSV(CsvUtils.extractCSV(WORKSHOPS_DATA_TEMPLATE_NAME))&lt;br /&gt;
local originalGoodsTable, goodsHeaderLookup = CsvUtils.luaTableFromCSV(CsvUtils.extractCSV(GOODS_DATA_TEMPLATE_NAME))&lt;br /&gt;
&lt;br /&gt;
-- Now restructure the tables so subtables can be passed to member functions &lt;br /&gt;
-- for cleaner code.&lt;br /&gt;
recipeTable = restructureRecipeTable(originalRecipeTable, recipeHeaderLookup)&lt;br /&gt;
workshopTable = restructureWorkshopTable(originalWorkshopTable, workshopsHeaderLookup)&lt;br /&gt;
goodsTable = restructureGoodsTable(originalGoodsTable, goodsHeaderLookup)&lt;br /&gt;
&lt;br /&gt;
-- Build the recipeIDToWorkshopID table&lt;br /&gt;
recipeIDToWorkshopID = {}&lt;br /&gt;
		&lt;br /&gt;
for workshopID, workshop in pairs(workshopTable) do&lt;br /&gt;
	&lt;br /&gt;
	for j, thisRecipeID in ipairs(workshop[INDEX_WORKSHOP_RECIPES]) do&lt;br /&gt;
		&lt;br /&gt;
		-- Once found, add it to the list above but keep traversing&lt;br /&gt;
		-- entirely to fill in the lookup table.&lt;br /&gt;
		if targetRecipeID == thisRecipeID then&lt;br /&gt;
			table.insert(workshopIDsFound, workshopID)&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- Add every workshop&amp;#039;s index to the appropriate recipe&amp;#039;s ID.&lt;br /&gt;
		-- NOT the target but this one iterated over right now.&lt;br /&gt;
		if not recipeIDToWorkshopID[thisRecipeID] then&lt;br /&gt;
			recipeIDToWorkshopID[thisRecipeID] = {}&lt;br /&gt;
		end&lt;br /&gt;
		table.insert(recipeIDToWorkshopID[thisRecipeID], workshopID)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Build workshopNameToWorkshopID table&lt;br /&gt;
workshopNameToWorkshopID = {}&lt;br /&gt;
&lt;br /&gt;
for workshopID, workshop in pairs(workshopTable) do&lt;br /&gt;
	&lt;br /&gt;
	if not foundWorkshopID and workshop[INDEX_WORKSHOP_NAME] == displayName then&lt;br /&gt;
		-- Found it, but keep traversing to build the rest of the map.&lt;br /&gt;
		foundWorkshopID = workshopID&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	workshopNameToWorkshopID[workshop[INDEX_WORKSHOP_NAME]] = workshopID&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Build goodsNameToGoodID&lt;br /&gt;
goodsNameToGoodID = {}&lt;br /&gt;
&lt;br /&gt;
for goodID, good in pairs(goodsTable) do&lt;br /&gt;
	&lt;br /&gt;
	if not foundGoodID and good[INDEX_GOOD_NAME] == displayName then&lt;br /&gt;
		-- Found it, keep traversing to build the rest of the map.&lt;br /&gt;
		foundGoodID = goodID&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	goodsNameToGoodID[good[INDEX_GOOD_NAME]] = goodID&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return {recipeTable, recipeIDToWorkshopID, workshopTable, workshopNameToWorkshopID, goodsTable, goodsNameToGoodID}&lt;/div&gt;</summary>
		<author><name>76561198157077871</name></author>
	</entry>
</feed>