Module:WorkshopsData
From Against the Storm Official Wiki
Documentation for this module may be created at Module:WorkshopsData/doc
---
-- 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


