Module:CollectorsData
From Against the Storm Official Wiki
Documentation for this module may be created at Module:CollectorsData/doc
--- @module CollectorsData local CollectorsData = {} --region Dependencies local DATA_TEMPLATE_NAME = "Template:Collectors_csv" local CsvUtils = require("Module:CsvUtils") -- Some dependencies are loaded lazily local GoodsData --endregion --region Private member variables --- Main data tables, like this: table[ID] = table containing data for that ID local collectorsTable --- Supporting table, list of names table[i] = name. local collectorsNames --- Lookup map. Built once and reused on subsequent calls within this session, --- like this: table[display name] = id local mapNamesToIDs --- Lookup map. Built once and reused on subsequent calls within this session, --- like this: table[goodID] = { name1, name2, ... } local mapRecipeGoodIDsToCollectorNames --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_CONSTRUCTION_TIME = "constructionTime" local INDEX_CITY_SCORE = "cityScore" local INDEX_MOVABLE = "movable" local INDEX_INITIALLY_ESSENTIAL = "initiallyEssential" local INDEX_STORAGE = "storage" local INDEX_REQUIRED_GOODS = "requiredGoods" -- table local INDEX_WORKPLACES = "workplaces" -- table local INDEX_RECIPES = "recipes" -- table local INDEX_CONSTRUCTION_GOODS_STACK_SIZE = "stackSize" local INDEX_CONSTRUCTION_GOODS_GOOD_ID = "goodID" local INDEX_RECIPE_GOOD_ID = "goodID" local INDEX_RECIPE_STACK_SIZE = "stackSize" local INDEX_RECIPE_GRADE = "grade" local INDEX_RECIPE_PRODUCTION_TIME = "productionTime" local PATTERN_SPLIT_STACK_AND_ID = "(%d+)%s([%[%]%s%a]+)" local PATTERN_CAPTURE_END_NUMBER = "(%d)$" --endregion --region Private methods --- --- Creates a new subtable containing the construction goods required for the --- specified building. --- --- @param originalBuilding table data record from which to make subtable --- @param headerLookup table header lookup built from the CSV data --- @return table subtable with the required construction goods local function makeRequiredGoodsSubtable(originalBuilding, headerLookup) -- 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 = headerLookup[REQ_GOOD_HEADER_BASE_STRING .. "1"] local requiredIndex2 = headerLookup[REQ_GOOD_HEADER_BASE_STRING .. "2"] local requiredIndex3 = headerLookup[REQ_GOOD_HEADER_BASE_STRING .. "3"] local number1, id1 = originalBuilding[requiredIndex1]:match(PATTERN_SPLIT_STACK_AND_ID) local number2, id2 = originalBuilding[requiredIndex2]:match(PATTERN_SPLIT_STACK_AND_ID) local number3, id3 = originalBuilding[requiredIndex3]:match(PATTERN_SPLIT_STACK_AND_ID) -- don't add subtables that would just contain nils local requiredGoods = { number1 and id1 and { [INDEX_CONSTRUCTION_GOODS_STACK_SIZE] = tonumber(number1), [INDEX_CONSTRUCTION_GOODS_GOOD_ID] = id1 } or nil, 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 end --- --- Creates a new subtable containing the workplaces available in the specified --- building. --- --- @param originalBuilding table data record from which to make subtable --- @param headerLookup table header lookup built from the CSV data --- @return table subtable with the workplaces local function makeWorkplacesSubtable(originalBuilding, headerLookup) -- A constant we'll need only within this function. local WORKPLACE_HEADER_BASE_STRING = "workplace" -- Copy the originals directly into a subtable. local workplaceIndex1 = headerLookup[WORKPLACE_HEADER_BASE_STRING .. "1"] local workplaceIndex2 = headerLookup[WORKPLACE_HEADER_BASE_STRING .. "2"] local workplaceIndex3 = headerLookup[WORKPLACE_HEADER_BASE_STRING .. "3"] local workplaceIndex4 = headerLookup[WORKPLACE_HEADER_BASE_STRING .. "4"] local workplace1 = originalBuilding[workplaceIndex1] local workplace2 = originalBuilding[workplaceIndex2] local workplace3 = originalBuilding[workplaceIndex3] local workplace4 = originalBuilding[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 --- --- Creates a new subtable containing the recipes available in the specified --- building. --- --- @param buildingName string the display name of the building --- @param originalBuilding table data record from which to make subtable --- @param headerLookup table header lookup built from the CSV data --- @return table subtable with the recipe IDs local function makeRecipesSubtable(buildingName, originalBuilding, headerLookup) -- A constant we'll need only within this function. local MAX_RECIPES = 3 local LOOKUP_RECIPE_BASE_STRING = "recipe" local LOOKUP_GOOD_SUFFIX_STRING = "Good" local LOOKUP_GRADE_SUFFIX_STRING = "Grade" local LOOKUP_TIME_SUFFIX_STRING = "ProductionTime" if not mapRecipeGoodIDsToCollectorNames then mapRecipeGoodIDsToCollectorNames = {} end -- Copy the originals directly into a subtable. local recipes = {} for i = 1, MAX_RECIPES do -- A subtable for this recipe newRecipe = {} local originalGoodIndex = headerLookup[LOOKUP_RECIPE_BASE_STRING .. i .. LOOKUP_GOOD_SUFFIX_STRING] local originalGradeIndex = headerLookup[LOOKUP_RECIPE_BASE_STRING .. i .. LOOKUP_GRADE_SUFFIX_STRING] local originalTimeIndex = headerLookup[LOOKUP_RECIPE_BASE_STRING .. i .. LOOKUP_TIME_SUFFIX_STRING] local originalStackSize, originalGoodID = originalBuilding[originalGoodIndex]:match(PATTERN_SPLIT_STACK_AND_ID) -- Skip blank recipes. if originalGoodID and originalGoodID ~= "" then newRecipe[INDEX_RECIPE_GOOD_ID] = originalGoodID newRecipe[INDEX_RECIPE_STACK_SIZE] = tonumber(originalStackSize) newRecipe[INDEX_RECIPE_GRADE] = tonumber(originalBuilding[originalGradeIndex]:match(PATTERN_CAPTURE_END_NUMBER)) newRecipe[INDEX_RECIPE_PRODUCTION_TIME] = tonumber(originalBuilding[originalTimeIndex]) table.insert(recipes,newRecipe) if not mapRecipeGoodIDsToCollectorNames[originalGoodID] then mapRecipeGoodIDsToCollectorNames[originalGoodID] = {} end table.insert(mapRecipeGoodIDsToCollectorNames[originalGoodID], buildingName) end end return recipes end --- --- Transforms the originalCollectorsTable 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 originalCollectorsTable table of CSV-based data, with header row, data rows --- @param headerLookup table lookup table of headers to get indexes --- @return table better structured with IDs as keys local function restructureCollectors(originalCollectorsTable, headerLookup) -- A few constants we need only in 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 = 14 mapNamesToIDs = {} collectorsNames = {} local newCollectorsTable = {} for _, originalCollector in ipairs(originalCollectorsTable[DATA_ROWS]) do -- Copy over the content, mapping unhelpful indexes into headers keys. local newCollector = {} newCollector[INDEX_ID] = originalCollector[INDEX_ORIGINAL_ID] newCollector[INDEX_NAME] = originalCollector[INDEX_ORIGINAL_NAME] newCollector[INDEX_DESCRIPTION] = originalCollector[INDEX_ORIGINAL_DESCRIPTION] newCollector[INDEX_CATEGORY] = originalCollector[INDEX_ORIGINAL_CATEGORY] newCollector[INDEX_SIZE_X] = tonumber(originalCollector[INDEX_ORIGINAL_SIZE_X]) newCollector[INDEX_SIZE_Y] = tonumber(originalCollector[INDEX_ORIGINAL_SIZE_Y]) newCollector[INDEX_CITY_SCORE] = tonumber(originalCollector[INDEX_ORIGINAL_CITY_SCORE]) newCollector[INDEX_MOVABLE] = originalCollector[INDEX_ORIGINAL_MOVABLE] == "True" newCollector[INDEX_INITIALLY_ESSENTIAL] = originalCollector[INDEX_ORIGINAL_ESSENTIAL] == "True" newCollector[INDEX_STORAGE] = tonumber(originalCollector[INDEX_ORIGINAL_STORAGE]) newCollector[INDEX_CONSTRUCTION_TIME] = tonumber(originalCollector[INDEX_ORIGINAL_CONSTRUCTION_TIME]) newCollector[INDEX_REQUIRED_GOODS] = makeRequiredGoodsSubtable(originalCollector, headerLookup) newCollector[INDEX_WORKPLACES] = makeWorkplacesSubtable(originalCollector, headerLookup) newCollector[INDEX_RECIPES] = makeRecipesSubtable(newCollector[INDEX_NAME], originalCollector, headerLookup) newCollectorsTable[ newCollector[INDEX_ID] ] = newCollector table.insert(collectorsNames, newCollector[INDEX_NAME]) -- Also populate the map for looking up IDs with display names mapNamesToIDs[ newCollector[INDEX_NAME] ] = newCollector[INDEX_ID] end return newCollectorsTable end --- --- Data loader function that uses the utility module and restructures the data --- to be easier to access for invoking methods and later method calls. This --- method is automatically called by all public member functions if the main --- data table has not yet been populated in the current session. local function loadData() -- Utility module retrieves the data as basic, flat lua tables. local originalCollectorsTable, headerLookup = CsvUtils.extractTables(DATA_TEMPLATE_NAME) -- Now restructure to be more conducive. collectorsTable = restructureCollectors(originalCollectorsTable, headerLookup) end local function load() if not collectorsTable then loadData() end end --- --- Uses the display name, which people are more familiar with, to find the --- encoded ID of the building. Useful for retrieving the data that is --- indexed by ID. --- --- Returns nil if the building with the specified name is not found. --- --- @param displayName string plain-language name of the building to find --- @return string ID of the building found, or nil if not found local function findIDByName(displayName) -- At runtime, this should never be nil or empty, so throw an error. if not displayName or displayName == "" then error("Parameter is nil or empty for name: " .. displayName .. ".") end if not collectorsTable then loadData() end return mapNamesToIDs[displayName] end --endregion --region Public methods --- Retrieve the whole table of data for the specified collector. Instead of --- this, you should probably be calling the individual getter methods. --- --- Throws an error if called with nil or empty string. Returns nil if the --- specified collector cannot be found. --- --- @param id string ID of the collector --- @return table containing the data with key-value pairs, or nil if not found function CollectorsData.getAllDataForCollectorByID(id) -- At runtime, this should never be nil or empty. if not id or id == "" then error("Parameter is nil or empty for the id.") end if not collectorsTable then loadData() end return collectorsTable[id] end --- Retrieve the whole table of data for the specified collector. Instead of --- this, you should probably be calling the individual getter methods. --- --- Throws an error if called with nil or empty string. Returns nil if the --- specified collector cannot be found. --- --- @param displayName string plain language name of the collector --- @return table containing the data with key-value pairs, or nil if not found function CollectorsData.getAllDataForCollector(displayName) -- At runtime, this should never be nil or empty. if not displayName or displayName == "" then error("Parameter is nil or empty for the name.") end if not collectorsTable then loadData() end local id = findIDByName(displayName) if not id then return nil end return collectorsTable[id] end --- --- Retrieves the ID for the collector specified by its plain language --- display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return string the ID of the specified collector function CollectorsData.getCollectorID(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_ID] end --- --- Retrieves the description for the collector specified by its plain --- language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return string the in-game description of the specified collector function CollectorsData.getCollectorDescription(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_DESCRIPTION] end --- --- Retrieves the construction toolbar category for the collector specified --- by its plain language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return string the category of the specified collector function CollectorsData.getCollectorCategory(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_CATEGORY] end --- --- Retrieves the 2x2 size for the collector specified by its plain language --- display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return number the X-size of the collector ---@return number the Y-size of the collector function CollectorsData.getCollectorSize(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_SIZE_X], collector[INDEX_SIZE_Y] end --- --- Retrieves the goods required for construction for the collector specified --- by its plain language display name, in a table that looks like this: --- --- ["requiredGoods"] = { --- [1] = { ["stackSize"] = 99, ["goodID"] = "good1_ID" }, --- [2] = { ["stackSize"] = 99, ["goodID"] = "good2_ID" }, --- [3] = { ... } or missing if fewer --- } --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return table of required goods function CollectorsData.getAllCollectorRequiredGoods(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_REQUIRED_GOODS] end --- --- Retrieves the specified required construction good for the collector --- specified by its plain language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@param requirementIndex number which construction good to retrieve ---@return string the ID of the good that is required, or nil if none ---@return number the stack size of that good, or nil if none function CollectorsData.getCollectorRequiredGood(displayName, requirementIndex) local requiredGoods = CollectorsData.getAllCollectorRequiredGoods(displayName) if not requiredGoods then return nil end local requirement = requiredGoods[requirementIndex] if not requirement then return nil end return requirement[INDEX_CONSTRUCTION_GOODS_GOOD_ID], requirement[INDEX_CONSTRUCTION_GOODS_STACK_SIZE] end --- --- Retrieves the construction time for the collector specified by its plain --- language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return number of seconds it takes to construct the collector function CollectorsData.getCollectorConstructionTime(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_CONSTRUCTION_TIME] end --- --- Retrieves the city score awarded for the collector specified by its plain --- language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return number of points for city score from having the collector function CollectorsData.getCollectorCityScore(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_CITY_SCORE] end --- --- Retrieves whether the collector specified by its plain language display --- name can be moved, at any cost. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return boolean of whether the collector can be moved function CollectorsData.isCollectorMovable(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_MOVABLE] end --- --- Retrieves whether the collector specified by its plain language display --- name has an essential starting blueprint for a new game profile. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return boolean of whether the collector's blueprint is essential function CollectorsData.isCollectorInitiallyEssential(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_INITIALLY_ESSENTIAL] end --- --- Retrieves the storage capacity of the collector specified by its plain --- language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return number of storage capacity at the collector function CollectorsData.getCollectorStorage(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_STORAGE] end --- --- Retrieves the table of workplaces for the collector specified by its --- plain language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return table of workplaces function CollectorsData.getAllCollectorWorkplaces(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_WORKPLACES] end --- --- Retrieves the number of workplaces for the collector specified by its --- plain language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return number of workplaces function CollectorsData.getCollectorNumberOfWorkplaces(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return #collector[INDEX_WORKPLACES] end --- --- Retrieves the table of recipes for the collector specified by its --- plain language display name, in a table that looks like this: --- --- ["recipes"] = { --- [1] = "recipe1_ID", --- [2] = "recipe2_ID", --- [3] = "recipe3_ID", --- [4] = ... or missing if fewer --- } --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return table of recipe IDs function CollectorsData.getAllCollectorRecipes(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end return collector[INDEX_RECIPES] end --- --- Retrieves the number of recipes for the collector specified by its --- plain language display name, in a table that looks like this: --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return number of recipes at the collector function CollectorsData.getCollectorNumberOfRecipes(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return 0 end local recipes = collector[INDEX_RECIPES] if not recipes then return 0 end return #recipes end --- --- Retrieves the product's ID and the stack size produced by the specified --- recipe at the collector specified by its plain language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@param recipeIndex number the index of the recipe ID ---@return string the ID of the good produced by the specified recipe function CollectorsData.getCollectorRecipeProduct(displayName, recipeIndex) local recipes = CollectorsData.getAllCollectorRecipes(displayName) if not recipes then return nil end local recipe = recipes[recipeIndex] if not recipe then return nil end return recipe[INDEX_RECIPE_GOOD_ID], recipe[INDEX_RECIPE_STACK_SIZE] end --- --- Retrieves the other stats for specified recipe at the collector specified by --- its plain language display name: the efficiency grade and the gathering --- time. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@param recipeIndex number the index of the recipe ID ---@return number of stars, the grade of the specified recipe ---@return number of seconds for gathering function CollectorsData.getCollectorRecipeStats(displayName, recipeIndex) local recipes = CollectorsData.getAllCollectorRecipes(displayName) if not recipes then return nil end local recipe = recipes[recipeIndex] if not recipe then return nil end return recipe[INDEX_RECIPE_GRADE], recipe[INDEX_RECIPE_PRODUCTION_TIME] end --- --- Retrieves the icon filename for the collector specified by its plain --- language display name. --- --- Returns nil if the collector named was not found. --- ---@param displayName string the plain language name of the collector ---@return string the collector's icon filename, including the extension function CollectorsData.getCollectorIcon(displayName) local collector = CollectorsData.getAllDataForCollector(displayName) if not collector then return nil end -- the base string of the icon is the ID. It has to be not nil to -- concatenate if collector[INDEX_ID] then return collector[INDEX_ID] .. "_icon.png" else return nil end end --- --- Retrieves the plain language display name for the collector specified by --- its ID. --- --- Returns nil if the collector named was not found. --- ---@param id string the ID of the collector ---@return string the collector's name as seen in-game function CollectorsData.getCollectorNameByID(id) local collector = CollectorsData.getAllDataForCollectorByID(id) if not collector then return nil end return collector[INDEX_NAME] end --- --- Retrieves the icon filename for the the collector specified by its ID. --- --- Returns nil if the collector named was not found. --- ---@param id string the ID of the collector ---@return string the collector's icon filename, including the extension function CollectorsData.getCollectorIconByID(id) local collector = CollectorsData.getAllDataForCollectorByID(id) if not collector then return nil end -- the base string of the icon is the ID. It has to be not nil to -- concatenate if collector[INDEX_ID] then return collector[INDEX_ID] .. "_icon.png" else return nil end end --- --- Retrieve all display names of collectors that have a recipe that produces the --- specified product ID. --- ---@param productID string the ID of the good to produce ---@return table of collector names that produce the specified good function CollectorsData.getCollectorNamesWithRecipeProductID(productID) -- At runtime, this should never be nil or empty. if not productID or productID == "" then error("Parameter is nil or empty for product ID.") end if not collectorsTable then loadData() end return mapRecipeGoodIDsToCollectorNames[productID] end --- --- Retrieves the name of the collector at the specified index. --- ---@param index number index ---@return string name of the building at the specified index function CollectorsData.getCollectorNameFromDatabase(index) if not index then return nil end if not collectorsTable then loadData() end return collectorsNames[index] end --- --- Returns the number of buildings that can be retrieved from this --- module's database. --- ---@return number of records function CollectorsData.getNumberOfCollectorsInDatabase() if not collectorsTable then loadData() end return #collectorsNames end --endregion --region Public Building interface -- getID(displayName) -- getCategory -- getCityScore -- getConstructionCosts (as [goodName] = stack size) -- getConstructionTime -- getDescription -- getIcon -- isMovable -- getName -- getNumberOfWorkplaces -- getSize (as "X x Y") -- getStorage function CollectorsData.getID(displayName) load() return mapNamesToIDs[displayName] end function CollectorsData.getCategory(id) load() return collectorsTable[id] ~= nil and collectorsTable[id][INDEX_CATEGORY] end function CollectorsData.getCityScore(id) load() return collectorsTable[id] ~= nil and collectorsTable[id][INDEX_CITY_SCORE] end function CollectorsData.getConstructionCosts(id) load() GoodsData = require("Module:GoodsData") collector = collectorsTable[id] if not collector then return false end local constructionCosts = {} for _, stacks in ipairs(collector[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 CollectorsData.getConstructionTime(id) load() return collectorsTable[id] ~= nil and collectorsTable[id][INDEX_CONSTRUCTION_TIME] end function CollectorsData.getDescription(id) load() return collectorsTable[id] ~= nil and collectorsTable[id][INDEX_DESCRIPTION] end function CollectorsData.getIcon(id) load() return collectorsTable[id] ~= nil and id .. "_icon.png" end function CollectorsData.isMovable(id) load() return collectorsTable[id] ~= nil and collectorsTable[id][INDEX_MOVABLE] end function CollectorsData.getName(id) load() return collectorsTable[id] ~= nil and collectorsTable[id][INDEX_NAME] end function CollectorsData.getNumberOfWorkplaces(id) load() return collectorsTable[id] ~= nil and #collectorsTable[id][INDEX_WORKPLACES] end function CollectorsData.getSize(id) load() collector = collectorsTable[id] if not collector then return false end return collector[INDEX_SIZE_X] .. " × " .. collector[INDEX_SIZE_Y] end function CollectorsData.getStorage(id) load() return collectorsTable[id] ~= nil and collectorsTable[id][INDEX_STORAGE] end --endregion return CollectorsData