Module:WorkshopsData: Difference between revisions

From Against the Storm Official Wiki
(Created for lighter weight referencing of building information.)
 
(Now an instance override of BaseDataModel; functional change)
 
(28 intermediate revisions by the same user not shown)
Line 1: Line 1:
---@module WorkshopsData.lua
---
---
-- Module for compiling goods (or resources as some call them) information from
---This module does not define an _actual_ derived class, but it creates an instance of one via prototyping patterns. Understand this file as a big procedure, top-to-bottom, rather than a class definition.
-- 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:
---Initializes a BaseDataModel with the data file associated with this module. Makes necessary modifications to the basic data, including schema and method overrides, to permit the exceptions associated with data in this model.
-- 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[targetGoodID]
end






---
--Create instance
-- Transforms the oldWorkshopsTable returned from CSV processing to be more
local BaseDataModel = require("Module:BaseDataModel")
-- conducive to member functions looking up data. Essentially, we convert the
local DATA_FILE = "Module:WorkshopsData/Workshops.json"
-- 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


---@type BaseDataModel
local workshopsDataModel = BaseDataModel.new(DATA_FILE)




---
-- 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


 
--Begin instance overrides
 
for _, building in pairs(workshopsDataModel.dataTable) do
---
    building[workshopsDataModel.schema.CATEGORY2] = "Production Building"
-- Loops through the old workshop, extracting workplaces and putting them
    building[workshopsDataModel.schema.IS_PROVIDING_SERVICES] = false
-- 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
end






---
--/** Function definitions follow. **/
-- Loops through the old workshop, extracting recipes and putting them
--Collapse the regions in the IDE to see the procedure pick up with the assignments of these functions to override the associated member methods of BaseDataModel.
-- into a new subtable. Uses the lookup table from the CSV extraction to
--region Public building interface
-- keep the data in the same order.
--no overrides!
--
--endregion
-- @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 workshopTable 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(workshopTable) 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


--region Public building recipe query interface
--no overrides!
--endregion


 
--region Public recipe data retrieval interface
---
--no overrides!
-- Retrieves the name and icon filename for a workshop.
--endregion
--
--/** End Function definitions. Procedure resumes. **/
-- @param workshopID the ID of the workshop to look up
-- @return display name, icon filename
function WorkshopsData.getWorkshopNameAndIcon(workshopID)
if not workshopTable then
loadData()
end
local workshop = workshopTable[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
return workshopsDataModel

Latest revision as of 03:41, 8 November 2024

Documentation for this module may be created at Module:WorkshopsData/doc

---@module WorkshopsData.lua
---
---This module does not define an _actual_ derived class, but it creates an instance of one via prototyping patterns. Understand this file as a big procedure, top-to-bottom, rather than a class definition.
---
---Initializes a BaseDataModel with the data file associated with this module. Makes necessary modifications to the basic data, including schema and method overrides, to permit the exceptions associated with data in this model.



--Create instance
local BaseDataModel = require("Module:BaseDataModel")
local DATA_FILE = "Module:WorkshopsData/Workshops.json"

---@type BaseDataModel
local workshopsDataModel = BaseDataModel.new(DATA_FILE)



--Begin instance overrides
for _, building in pairs(workshopsDataModel.dataTable) do
    building[workshopsDataModel.schema.CATEGORY2] = "Production Building"
    building[workshopsDataModel.schema.IS_PROVIDING_SERVICES] = false
end



--/** Function definitions follow. **/
--Collapse the regions in the IDE to see the procedure pick up with the assignments of these functions to override the associated member methods of BaseDataModel.
--region Public building interface
--no overrides!
--endregion

--region Public building recipe query interface
--no overrides!
--endregion

--region Public recipe data retrieval interface
--no overrides!
--endregion
--/** End Function definitions. Procedure resumes. **/



return workshopsDataModel