Module:WorkshopsData

--- -- Module for compiling goods (or resources as some call them) information from -- wiki data sources. -- -- @module WorkshopsData local WorkshopsData = {}

--- -- Dependencies --- local CsvUtils = require("Module:CsvUtils")

--- -- Constants for this module --- local WORKSHOPS_DATA_TEMPLATE_NAME = "Template:Workshops_csv"

local INDEX_WORKSHOP_ID = 1 local INDEX_WORKSHOP_NAME = 2 local INDEX_WORKSHOP_DESCRIPTION = 3 local INDEX_WORKSHOP_CATEGORY = 4 local INDEX_WORKSHOP_SIZE_X = 5 local INDEX_WORKSHOP_SIZE_Y = 6 local INDEX_WORKSHOP_CITY_SCORE = 7 local INDEX_WORKSHOP_MOVABLE = 8 local INDEX_WORKSHOP_INITIALLY_ESSENTIAL = 9 local INDEX_WORKSHOP_STORAGE = 10 local INDEX_WORKSHOP_CONSTRUCTION_TIME = 11 local INDEX_WORKSHOP_REQUIRED_GOODS = 12 local INDEX_WORKSHOP_WORKPLACES = 13 local INDEX_WORKSHOP_RECIPES = 14

local HEADER_ROW = 1 local DATA_ROWS = 2

local PATTERN_SPLIT_STACK_AND_ID = "(%d+)%s([%[%]%s%a]+)"

--- -- Private member variables ---

-- Main data tables. Populated from CSV data and organized better for Lua.

-- like this: table[workshopID] = table containing workshops data local workshopsTable

-- Lookup map. Built once and reused on subsequent calls -- like this: table[display name] = workshopID local workshopNameToWorkshopID

--- -- Data loader function. Calls the data templates, restructures the data to be -- useful for getter methods, and makes a merge table. -- -- This method is called the first time any of the actual template methods are -- invoked and they see that the data tables are nil. This method populates -- them and reorganizes them for easier use (and easier code). function loadData -- Use the CSV utility module to load the data templates we need for -- resources. local originalWorkshopsTable, workshopsHeaderLookup = CsvUtils.luaTableFromCSV(CsvUtils.extractCSV(WORKSHOPS_DATA_TEMPLATE_NAME)) -- Now restructure the table so subtables can be passed to member functions -- for cleaner code. workshopsTable = restructureWorkshopTable(originalWorkshopsTable, workshopsHeaderLookup) end

--- -- Retrieve all data for the specified workshop. Returned items look like this: -- workshop { -- 		id --		display name --		description --		category --		size x --		size y --		city score --		movable --		initially essential --		storage --		construction time --		required goods (just their IDs) { --			#1 { stack size, id } --			#2 { stack size, id } --			#3 { stack size, id } --		} --		workplaces { --			workplace #1 --			workplace #2 --			workplace #3 --			workplace #4 --		} --		recipes (just their IDs) { --			recipe #1 --			recipe #2 --			recipe #3 --			recipe #4 --		} -- } -- -- @param workshopName plain language name of the workshop -- @return a table containing the data for the specified workshop function WorkshopsData.getAllDataForWorkshop(workshopName) if not workshopsTable then loadData end local targetWorkshopID = findWorkshopIDByName(workshopName) if not targetWorkshopID then error("No building found. Please check spelling and any punctuation like an apostrophe: " .. workshopName) end return workshopsTable[targetWorkshopID] end

--- -- Transforms the oldWorkshopsTable returned from CSV processing to be more -- conducive to member functions looking up data. Essentially, we convert the -- text strings into tables with the same base name and an index. -- -- @param oldRecipeTable the CSV-based table, with a header row then data rows -- @param recipeHeaderLookup the lookup table built from the CSV data -- @return a new table for use in looking up recipe data function restructureWorkshopTable(oldWorkshopTable, workshopsHeaderLookup) -- New table structure is only data rows, no header row needed. Therefore, -- the new table is one degree flatter, like this: -- oldWorkshopTable[2][1] contains the same data as newWorkshopTable[1] -- (but organized by workshopID instead of by index and with subtables) local newWorkshopTable = {} oldWorkshopTable = oldWorkshopTable[DATA_ROWS] -- A few constants we need only in this function. local INDEX_OLD_WORKSHOP_ID = 1 local INDEX_OLD_WORKSHOP_NAME = 2 local INDEX_OLD_WORKSHOP_DESCRIPTION = 3 local INDEX_OLD_WORKSHOP_CATEGORY = 4 local INDEX_OLD_WORKSHOP_SIZE_X = 5 local INDEX_OLD_WORKSHOP_SIZE_Y = 6 local INDEX_OLD_WORKSHOP_CONSTRUCTION_TIME = 10 local INDEX_OLD_WORKSHOP_CITY_SCORE = 11 local INDEX_OLD_WORKSHOP_MOVABLE = 12 local INDEX_OLD_WORKSHOP_INITIALLY_ESSENTIAL = 13 local INDEX_OLD_WORKSHOP_STORAGE = 14 for i, oldWorkshop in ipairs(oldWorkshopTable) do		local newWorkshop = {} -- Copy over the flat information from the old recipe. local newWorkshopID = oldWorkshop[INDEX_OLD_WORKSHOP_ID] newWorkshop[INDEX_WORKSHOP_ID] = newWorkshopID newWorkshop[INDEX_WORKSHOP_NAME] = oldWorkshop[INDEX_OLD_WORKSHOP_NAME] newWorkshop[INDEX_WORKSHOP_DESCRIPTION] = oldWorkshop[INDEX_OLD_WORKSHOP_DESCRIPTION] newWorkshop[INDEX_WORKSHOP_CATEGORY] = oldWorkshop[INDEX_OLD_WORKSHOP_CATEGORY] newWorkshop[INDEX_WORKSHOP_SIZE_X] = oldWorkshop[INDEX_OLD_WORKSHOP_SIZE_X] newWorkshop[INDEX_WORKSHOP_SIZE_Y] = oldWorkshop[INDEX_OLD_WORKSHOP_SIZE_Y] newWorkshop[INDEX_WORKSHOP_CITY_SCORE] = oldWorkshop[INDEX_OLD_WORKSHOP_CITY_SCORE] newWorkshop[INDEX_WORKSHOP_MOVABLE] = oldWorkshop[INDEX_OLD_WORKSHOP_MOVABLE] newWorkshop[INDEX_WORKSHOP_INITIALLY_ESSENTIAL] = oldWorkshop[INDEX_OLD_WORKSHOP_INITIALLY_ESSENTIAL] newWorkshop[INDEX_WORKSHOP_STORAGE] = oldWorkshop[INDEX_OLD_WORKSHOP_STORAGE] newWorkshop[INDEX_WORKSHOP_CONSTRUCTION_TIME] = oldWorkshop[INDEX_OLD_WORKSHOP_CONSTRUCTION_TIME] newWorkshop[INDEX_WORKSHOP_REQUIRED_GOODS] = makeRequiredGoodsSubtable(oldWorkshop, workshopsHeaderLookup) newWorkshop[INDEX_WORKSHOP_WORKPLACES] = makeWorkplacesSubtable(oldWorkshop, workshopsHeaderLookup) newWorkshop[INDEX_WORKSHOP_RECIPES] = makeRecipesSubtable(oldWorkshop, workshopsHeaderLookup) newWorkshopTable[newWorkshopID] = newWorkshop end return newWorkshopTable end

--- -- Loops through the old workshop, extracting req'd goods and putting them -- into a new subtable. Uses the lookup table from the CSV extraction to -- keep the data in the same order. -- -- @param oldWorkshop the workshop from which to extract req'd goods information -- @param workshopsHeaderLookup the lookup table built from the CSV data -- @return a subtable with the req'd goods information from oldWorkshop function makeRequiredGoodsSubtable(oldWorkshop, workshopsHeaderLookup) -- A few constants we'll need only within this function. local REQ_GOOD_MAX = 3 local LOOKUP_REQ_GOOD_BASE_STRING = "requiredGood" -- A subtable to return local requiredGoods = {} for i = 1,REQ_GOOD_MAX do local oldIndex = workshopsHeaderLookup[LOOKUP_REQ_GOOD_BASE_STRING .. i]		local newGroup = {} -- Split the digit part into the req'd good stack size and the rest -- of the text into the req'd good's id. newGroup[1], newGroup[2] = oldWorkshop[oldIndex]:match(PATTERN_SPLIT_STACK_AND_ID) table.insert(requiredGoods, newGroup) end return requiredGoods end

--- -- Loops through the old workshop, extracting workplaces and putting them -- into a new subtable. Uses the lookup table from the CSV extraction to -- keep the data in the same order. -- -- @param oldWorkshop the workshop from which to extract workplaces information -- @param workshopsHeaderLookup the lookup table built from the CSV data -- @return a subtable with the workplaces information from oldWorkshop function makeWorkplacesSubtable(oldWorkshop, workshopsHeaderLookup) -- A few constants we'll need only within this function. local WORKPLACE_MAX = 4 local LOOKUP_WORKPLACE_BASE_STRING = "workplace" -- A subtable to return local workplaces = {} for i = 1,WORKPLACE_MAX do local oldIndex = workshopsHeaderLookup[LOOKUP_WORKPLACE_BASE_STRING .. i]		workplaces[i] = oldWorkshop[oldIndex] end return workplaces end

--- -- Loops through the old workshop, extracting recipes and putting them -- into a new subtable. Uses the lookup table from the CSV extraction to -- keep the data in the same order. -- -- @param oldWorkshop the workshop from which to extract recipes -- @param workshopsHeaderLookup the lookup table built from the CSV data -- @return a subtable with the recipes from oldWorkshop function makeRecipesSubtable(oldWorkshop, workshopsHeaderLookup) -- A few constants we'll need only within this function. local RECIPE_MAX = 4 local LOOKUP_RECIPE_BASE_STRING = "recipe" -- A subtable to return local recipes = {} for i=1,RECIPE_MAX do local oldIndex = workshopsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. i]		recipes[i] = oldWorkshop[oldIndex] end return recipes end

--- -- Look up so workshops can be found by their common ID, rather than their -- display name, which people are more familiar with. -- -- Uses the display name provided to look up the associated ID for the workshop. -- Builds a lookup table the first time it's called so it only has to happen -- once. -- -- @param displayName the plain-language name of the workshop to find -- @return the ID of the workshop found, or nil if not found function findWorkshopIDByName(displayName) if not workshopsTable then loadData end local foundWorkshopID = nil -- Decide whether we need to traverse the big table. If this isn't the first -- time this method is called, we won't have to build the table again, we -- can just look it up. if not workshopNameToWorkshopID then workshopNameToWorkshopID = {} for workshopID, workshop in pairs(workshopsTable) do			if not foundWorkshopID and workshop[INDEX_WORKSHOP_NAME] == displayName then -- Found it, but keep traversing to build the rest of the map. foundWorkshopID = workshopID end workshopNameToWorkshopID[workshop[INDEX_WORKSHOP_NAME]] = workshopID end else -- From the lookup table. foundWorkshopID = workshopNameToWorkshopID[displayName] end return foundWorkshopID end

--- -- Retrieves the name and icon filename for a workshop. -- -- @param workshopID the ID of the workshop to look up -- @return display name, icon filename function WorkshopsData.getWorkshopNameAndIcon(workshopID) if not workshopsTable then loadData end local workshop = workshopsTable[workshopID] if not workshop then error("ID for workshop not found to look up name and icon: " .. workshopID) end return workshop[INDEX_WORKSHOP_NAME], workshop[INDEX_WORKSHOP_NAME] .. "_icon" end

return WorkshopsData