|
|
(One intermediate revision by the same user not shown) |
Line 1: |
Line 1: |
| --- @module WorkshopsData | | ---@module WorkshopsData.lua |
| local WorkshopsData = {}
| |
| | |
| | |
| | |
| --region Dependencies
| |
| | |
| local DATA_TEMPLATE_NAME = "Template:Workshops_csv"
| |
| | |
| local CsvUtils = require("Module:CsvUtils")
| |
| | |
| -- Some dependencies are loaded lazily
| |
| local GoodsData
| |
| | |
| --endregion
| |
| | |
| | |
| | |
| --region Private member variables
| |
| | |
| --- Main data table, like this: table[ID] = table containing data for that ID
| |
| local workshopsTable
| |
| | |
| --- Supporting table, list of names table[i] = name.
| |
| local workshopsNames
| |
| | |
| --- Lookup map. Built once and reused on all subsequent calls within this
| |
| --- session, like this: table[displayName] = workshopID
| |
| local mapNamesToIDs
| |
| | |
| --- Lookup map. Built once and reused on all subsequent calls within this
| |
| --- session, like this: table[recipeID] = { workshopName1, workshopName2, ... }
| |
| local mapRecipeIDsToWorkshopNames
| |
| | |
| --endregion
| |
| | |
| | |
| | |
| --region Private constants
| |
| | |
| local INDEX_ID = "id"
| |
| local INDEX_NAME = "displayName"
| |
| local INDEX_DESCRIPTION = "description"
| |
| local INDEX_CATEGORY = "category"
| |
| local INDEX_SIZE_X = "sizeX"
| |
| local INDEX_SIZE_Y = "sizeY"
| |
| local INDEX_CITY_SCORE = "cityScore"
| |
| local INDEX_MOVABLE = "movable"
| |
| local INDEX_ESSENTIAL = "initiallyEssential"
| |
| local INDEX_STORAGE_CAP = "storage"
| |
| local INDEX_CONSTRUCTION_TIME = "constructionTime"
| |
| local INDEX_REQUIRED_GOODS = "requiredGoods"
| |
| local INDEX_WORKPLACES = "workplaces"
| |
| local INDEX_RECIPES = "recipes"
| |
| | |
| local INDEX_CONSTRUCTION_GOODS_STACK_SIZE = "stackSize"
| |
| local INDEX_CONSTRUCTION_GOODS_GOOD_ID = "goodID"
| |
| | |
| local PATTERN_SPLIT_STACK_AND_ID = "(%d+)%s([%[%]%s%a]+)"
| |
| | |
| --endregion
| |
| | |
| | |
| | |
| --region Private methods
| |
| | |
| --- | | --- |
| --- Creates a new subtable containing the construction goods required for the | | ---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. |
| --- specified workshop. | |
| --- | | --- |
| --- @param originalWorkshop table workshop data record from which to make subtable | | ---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. |
| --- @param workshopsHeaderLookup table header lookup built from the CSV data
| |
| --- @return table subtable with the required construction goods
| |
| local function makeRequiredGoodsSubtable(originalWorkshop, workshopsHeaderLookup)
| |
| | |
| -- A constant we'll need only within this function.
| |
| local REQ_GOOD_HEADER_BASE_STRING = "requiredGood"
| |
|
| |
|
| -- Copy the originals directly into a subtable.
| |
| local requiredIndex1 = workshopsHeaderLookup[REQ_GOOD_HEADER_BASE_STRING .. "1"]
| |
| local requiredIndex2 = workshopsHeaderLookup[REQ_GOOD_HEADER_BASE_STRING .. "2"]
| |
| local requiredIndex3 = workshopsHeaderLookup[REQ_GOOD_HEADER_BASE_STRING .. "3"]
| |
|
| |
|
| local number1, id1 = originalWorkshop[requiredIndex1]:match(PATTERN_SPLIT_STACK_AND_ID)
| |
| local number2, id2 = originalWorkshop[requiredIndex2]:match(PATTERN_SPLIT_STACK_AND_ID)
| |
| local number3, id3 = originalWorkshop[requiredIndex3]:match(PATTERN_SPLIT_STACK_AND_ID)
| |
|
| |
|
| -- don't add subtables that would just contain nils
| | --Create instance |
| local requiredGoods = {
| | local BaseDataModel = require("Module:BaseDataModel") |
| number1 and id1 and { [INDEX_CONSTRUCTION_GOODS_STACK_SIZE] = tonumber(number1), [INDEX_CONSTRUCTION_GOODS_GOOD_ID] = id1 } or nil,
| | local DATA_FILE = "Module:WorkshopsData/Workshops.json" |
| number2 and id2 and { [INDEX_CONSTRUCTION_GOODS_STACK_SIZE] = tonumber(number2), [INDEX_CONSTRUCTION_GOODS_GOOD_ID] = id2 } or nil,
| |
| number3 and id3 and { [INDEX_CONSTRUCTION_GOODS_STACK_SIZE] = tonumber(number3), [INDEX_CONSTRUCTION_GOODS_GOOD_ID] = id3 } or nil
| |
| }
| |
|
| |
|
| return requiredGoods
| | ---@type BaseDataModel |
| end
| | local workshopsDataModel = BaseDataModel.new(DATA_FILE) |
|
| |
|
|
| |
|
|
| |
|
| --- | | --Begin instance overrides |
| --- Creates a new subtable containing the workplaces available in the specified
| | for _, building in pairs(workshopsDataModel.dataTable) do |
| --- workshop.
| | building[workshopsDataModel.schema.CATEGORY2] = "Production Building" |
| ---
| | building[workshopsDataModel.schema.IS_PROVIDING_SERVICES] = false |
| --- @param originalWorkshop table workshop data record from which to make subtable
| |
| --- @param workshopsHeaderLookup table header lookup built from the CSV data
| |
| --- @return table subtable with the workplaces
| |
| local function makeWorkplacesSubtable(originalWorkshop, workshopsHeaderLookup)
| |
| | |
| -- A constant we'll need only within this function.
| |
| local WORKPLACE_HEADER_BASE_STRING = "workplace"
| |
| | |
| -- Copy the originals directly into a subtable.
| |
| local workplaceIndex1 = workshopsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "1"]
| |
| local workplaceIndex2 = workshopsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "2"]
| |
| local workplaceIndex3 = workshopsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "3"]
| |
| local workplaceIndex4 = workshopsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "4"]
| |
| | |
| local workplace1 = originalWorkshop[workplaceIndex1]
| |
| local workplace2 = originalWorkshop[workplaceIndex2]
| |
| local workplace3 = originalWorkshop[workplaceIndex3]
| |
| local workplace4 = originalWorkshop[workplaceIndex4]
| |
| | |
| -- if it's not an empty string, then save that to the table, otherwise nil
| |
| local workplaces = {
| |
| (workplace1 ~= "" and workplace1) or nil,
| |
| (workplace2 ~= "" and workplace2) or nil,
| |
| (workplace3 ~= "" and workplace3) or nil,
| |
| (workplace4 ~= "" and workplace4) or nil
| |
| }
| |
| | |
| return workplaces
| |
| end | | end |
|
| |
|
|
| |
|
|
| |
|
| --- | | --/** Function definitions follow. **/ |
| --- Creates a new subtable containing the recipes available in the specified | | --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. |
| --- workshop.
| | --region Public building interface |
| ---
| | --no overrides! |
| --- @param workshopName string the display name of the workshop
| | --endregion |
| --- @param originalWorkshop table workshop data record from which to make subtable
| |
| --- @param workshopsHeaderLookup table header lookup built from the CSV data
| |
| --- @return table subtable with the recipe IDs
| |
| local function makeRecipesSubtable(workshopName, originalWorkshop, workshopsHeaderLookup)
| |
| | |
| -- A constant we'll need only within this function.
| |
| local LOOKUP_RECIPE_BASE_STRING = "recipe"
| |
| | |
| -- Copy the originals directly into a subtable.
| |
| local recipeIndex1 = workshopsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. "1"]
| |
| local recipeIndex2 = workshopsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. "2"]
| |
| local recipeIndex3 = workshopsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. "3"]
| |
| local recipeIndex4 = workshopsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. "4"]
| |
| | |
| local recipe1 = originalWorkshop[recipeIndex1]
| |
| local recipe2 = originalWorkshop[recipeIndex2]
| |
| local recipe3 = originalWorkshop[recipeIndex3]
| |
| local recipe4 = originalWorkshop[recipeIndex4]
| |
| | |
| local recipes = {
| |
| (recipe1 ~= "" and recipe1) or nil,
| |
| (recipe2 ~= "" and recipe2) or nil,
| |
| (recipe3 ~= "" and recipe3) or nil,
| |
| (recipe4 ~= "" and recipe4) or nil
| |
| }
| |
| | |
| if recipe1 and recipe1 ~= "" then
| |
| if not mapRecipeIDsToWorkshopNames[recipe1] then
| |
| mapRecipeIDsToWorkshopNames[recipe1] = {}
| |
| end
| |
| table.insert(mapRecipeIDsToWorkshopNames[recipe1], workshopName)
| |
| end
| |
| if recipe2 and recipe2 ~= "" then
| |
| if not mapRecipeIDsToWorkshopNames[recipe2] then
| |
| mapRecipeIDsToWorkshopNames[recipe2] = {}
| |
| end
| |
| table.insert(mapRecipeIDsToWorkshopNames[recipe2], workshopName)
| |
| end
| |
| if recipe3 and recipe3 ~= "" then
| |
| if not mapRecipeIDsToWorkshopNames[recipe3] then
| |
| mapRecipeIDsToWorkshopNames[recipe3] = {}
| |
| end
| |
| table.insert(mapRecipeIDsToWorkshopNames[recipe3], workshopName)
| |
| end
| |
| if recipe4 and recipe4 ~= "" then
| |
| if not mapRecipeIDsToWorkshopNames[recipe4] then
| |
| mapRecipeIDsToWorkshopNames[recipe4] = {}
| |
| end
| |
| table.insert(mapRecipeIDsToWorkshopNames[recipe4], workshopName)
| |
| end
| |
| | |
| return recipes
| |
| end
| |
| | |
| | |
| | |
| ---
| |
| --- Transforms the originalWorkshopTable returned from CSV processing to be
| |
| --- more conducive to member functions looking up data. Converts text strings
| |
| --- into subtables. Converts header row into field keys on every record and
| |
| --- stores records by id rather than arbitrary integer.
| |
| ---
| |
| --- @param originalWorkshopsTable table of CSV-based data, with header row, data rows
| |
| --- @param workshopsHeaderLookup table lookup table of headers to get indexes
| |
| --- @return table better structured with IDs as keys
| |
| local function restructureWorkshopsTable(originalWorkshopsTable, workshopsHeaderLookup)
| |
| | |
| -- A few constants we'll need only within this function.
| |
| local DATA_ROWS = 2
| |
| local INDEX_ORIGINAL_ID = 1
| |
| local INDEX_ORIGINAL_NAME = 2
| |
| local INDEX_ORIGINAL_DESCRIPTION = 3
| |
| local INDEX_ORIGINAL_CATEGORY = 4
| |
| local INDEX_ORIGINAL_SIZE_X = 5
| |
| local INDEX_ORIGINAL_SIZE_Y = 6
| |
| -- Required goods are indexes 7, 8, 9
| |
| local INDEX_ORIGINAL_CONSTRUCTION_TIME = 10
| |
| local INDEX_ORIGINAL_CITY_SCORE = 11
| |
| local INDEX_ORIGINAL_MOVABLE = 12
| |
| local INDEX_ORIGINAL_ESSENTIAL = 13
| |
| local INDEX_ORIGINAL_STORAGE_CAP = 14
| |
| | |
| mapNamesToIDs = {}
| |
| workshopsNames = {}
| |
| mapRecipeIDsToWorkshopNames = {}
| |
| | |
| local newWorkshopTable = {}
| |
| for _, originalWorkshop in ipairs (originalWorkshopsTable[DATA_ROWS]) do
| |
| | |
| -- Copy over the content, mapping unhelpful indexes into headers keys.
| |
| local newWorkshop = {}
| |
| newWorkshop[INDEX_ID] = originalWorkshop[INDEX_ORIGINAL_ID]
| |
| newWorkshop[INDEX_NAME] = originalWorkshop[INDEX_ORIGINAL_NAME]
| |
| newWorkshop[INDEX_DESCRIPTION] = originalWorkshop[INDEX_ORIGINAL_DESCRIPTION]
| |
| newWorkshop[INDEX_CATEGORY] = originalWorkshop[INDEX_ORIGINAL_CATEGORY]
| |
| newWorkshop[INDEX_SIZE_X] = tonumber(originalWorkshop[INDEX_ORIGINAL_SIZE_X])
| |
| newWorkshop[INDEX_SIZE_Y] = tonumber(originalWorkshop[INDEX_ORIGINAL_SIZE_Y])
| |
| newWorkshop[INDEX_CITY_SCORE] = tonumber(originalWorkshop[INDEX_ORIGINAL_CITY_SCORE])
| |
| newWorkshop[INDEX_MOVABLE] = originalWorkshop[INDEX_ORIGINAL_MOVABLE] == "TRUE"
| |
| newWorkshop[INDEX_ESSENTIAL] = originalWorkshop[INDEX_ORIGINAL_ESSENTIAL] == "TRUE"
| |
| newWorkshop[INDEX_STORAGE_CAP] = tonumber(originalWorkshop[INDEX_ORIGINAL_STORAGE_CAP])
| |
| newWorkshop[INDEX_CONSTRUCTION_TIME] = tonumber(originalWorkshop[INDEX_ORIGINAL_CONSTRUCTION_TIME])
| |
| | |
| newWorkshop[INDEX_REQUIRED_GOODS] = makeRequiredGoodsSubtable(originalWorkshop, workshopsHeaderLookup)
| |
| newWorkshop[INDEX_WORKPLACES] = makeWorkplacesSubtable(originalWorkshop, workshopsHeaderLookup)
| |
| newWorkshop[INDEX_RECIPES] = makeRecipesSubtable(newWorkshop[INDEX_NAME], originalWorkshop, workshopsHeaderLookup)
| |
| | |
| newWorkshopTable[ newWorkshop[INDEX_ID] ] = newWorkshop
| |
| | |
| table.insert(workshopsNames, newWorkshop[INDEX_NAME])
| |
| | |
| -- Also populate the map for looking up IDs with display names
| |
| mapNamesToIDs[newWorkshop[INDEX_NAME]] = newWorkshop[INDEX_ID]
| |
| end
| |
| | |
| return newWorkshopTable
| |
| end
| |
| | |
| | |
| | |
| local function load()
| |
| | |
| if not workshopsTable then
| |
| | |
| -- Utility module retrieves the data as basic, flat lua tables.
| |
| local originalWorkshopsTable, workshopsHeaderLookup = CsvUtils.extractTables(DATA_TEMPLATE_NAME)
| |
| | |
| -- Now restructure to be more conducive.
| |
| workshopsTable = restructureWorkshopsTable(originalWorkshopsTable, workshopsHeaderLookup)
| |
| end
| |
| end
| |
|
| |
|
| | --region Public building recipe query interface |
| | --no overrides! |
| --endregion | | --endregion |
|
| |
|
| | | --region Public recipe data retrieval interface |
| | | --no overrides! |
| --region Public methods | |
| | |
| --- DEPRECATED --- DO NOT USE ---
| |
| ---@deprecated
| |
| function WorkshopsData.getAllWorkshopRecipes(displayName)
| |
| | |
| if not displayName or displayName == "" then
| |
| error("Parameter is nil or empty for display name.")
| |
| end
| |
| | |
| load()
| |
| | |
| local id = mapNamesToIDs[displayName]
| |
| if not id then
| |
| return nil
| |
| end
| |
| | |
| local workshop = workshopsTable[id]
| |
| if not workshop then
| |
| return nil
| |
| end
| |
| | |
| return workshop[INDEX_RECIPES]
| |
| end
| |
| | |
| | |
| | |
| --- DEPRECATED --- DO NOT USE --- | |
| ---@deprecated
| |
| function WorkshopsData.getWorkshopIcon(displayName)
| |
| | |
| if not displayName or displayName == "" then
| |
| error("Parameter is nil or empty for display name.")
| |
| end
| |
| | |
| load()
| |
| | |
| local id = mapNamesToIDs[displayName]
| |
| if not id then
| |
| return nil
| |
| end
| |
| | |
| -- the base string of the icon is the ID. It has to be not nil to
| |
| -- concatenate
| |
| return id .. "_icon.png"
| |
| end
| |
| | |
| | |
| | |
| --- DEPRECATED --- DO NOT USE ---
| |
| ---@deprecated
| |
| function WorkshopsData.getWorkshopNamesWithRecipeID(recipeID)
| |
| | |
| -- At runtime, this should never be nil or empty.
| |
| if not recipeID or recipeID == "" then
| |
| error("Parameter is nil or empty for product ID.")
| |
| end
| |
| | |
| load()
| |
| | |
| return mapRecipeIDsToWorkshopNames[recipeID]
| |
| end
| |
| | |
| --endregion | | --endregion |
| | --/** End Function definitions. Procedure resumes. **/ |
|
| |
|
|
| |
|
|
| |
|
| --region Public Building interface
| | return workshopsDataModel |
| | |
| -- getID(displayName)
| |
| -- getCategory(id)
| |
| -- getCityScore(id)
| |
| -- getConstructionCosts(id) -- returns { [goodName] = stack size }
| |
| -- getConstructionTime(id)
| |
| -- getDescription(id)
| |
| -- getIcon(id)
| |
| -- isMovable(id)
| |
| -- getName(id)
| |
| -- getNumberOfWorkplaces(id)
| |
| -- getSize(id) -- returns string "X x Y"
| |
| -- getStorage(id)
| |
| | |
| function WorkshopsData.getID(displayName)
| |
| load()
| |
| return mapNamesToIDs[displayName]
| |
| end
| |
| | |
| function WorkshopsData.getCategory(id)
| |
| load()
| |
| return workshopsTable[id] ~= nil and workshopsTable[id][INDEX_CATEGORY]
| |
| end
| |
| | |
| function WorkshopsData.getCityScore(id)
| |
| load()
| |
| return workshopsTable[id] ~= nil and workshopsTable[id][INDEX_CITY_SCORE]
| |
| end
| |
| | |
| function WorkshopsData.getConstructionCosts(id)
| |
| | |
| load()
| |
| GoodsData = require("Module:GoodsData")
| |
| | |
| workshop = workshopsTable[id]
| |
| if not workshop then
| |
| return nil
| |
| end
| |
| | |
| local constructionCosts = {}
| |
| for _, stacks in ipairs(workshop[INDEX_REQUIRED_GOODS]) do
| |
| local goodName = GoodsData.getGoodNameByID(stacks[INDEX_CONSTRUCTION_GOODS_GOOD_ID])
| |
| constructionCosts[goodName] = stacks[INDEX_CONSTRUCTION_GOODS_STACK_SIZE]
| |
| end
| |
| | |
| return constructionCosts
| |
| end
| |
| | |
| function WorkshopsData.getConstructionTime(id)
| |
| load()
| |
| return workshopsTable[id] ~= nil and workshopsTable[id][INDEX_CONSTRUCTION_TIME]
| |
| end
| |
| | |
| function WorkshopsData.getDescription(id)
| |
| load()
| |
| return workshopsTable[id] ~= nil and workshopsTable[id][INDEX_DESCRIPTION]
| |
| end
| |
| | |
| function WorkshopsData.getIcon(id)
| |
| load()
| |
| return workshopsTable[id] ~= nil and id .. "_icon.png"
| |
| end
| |
| | |
| function WorkshopsData.isMovable(id)
| |
| load()
| |
| return workshopsTable[id] ~= nil and workshopsTable[id][INDEX_MOVABLE]
| |
| end
| |
| | |
| function WorkshopsData.getName(id)
| |
| load()
| |
| return workshopsTable[id] ~= nil and workshopsTable[id][INDEX_NAME]
| |
| end
| |
| | |
| function WorkshopsData.getNumberOfWorkplaces(id)
| |
| load()
| |
| return workshopsTable[id] ~= nil and #workshopsTable[id][INDEX_WORKPLACES]
| |
| end
| |
| | |
| function WorkshopsData.getSize(id)
| |
| load()
| |
| | |
| workshop = workshopsTable[id]
| |
| if not workshop then
| |
| return nil
| |
| end
| |
| | |
| return workshop[INDEX_SIZE_X] .. " × " .. workshop[INDEX_SIZE_Y]
| |
| end
| |
| | |
| function WorkshopsData.getStorage(id)
| |
| load()
| |
| return workshopsTable[id] ~= nil and workshopsTable[id][INDEX_STORAGE_CAP]
| |
| end
| |
| | |
| --endregion
| |
| | |
| return WorkshopsData
| |