Module:GoodsData: Difference between revisions
(Now data table is indexed with keys instead of just integers, should be easier to use now. Refactored code; added getter methods; reordered methods, improved documentation and commenting) |
(rounding sell and buy values to 2 decimal places) |
||
(18 intermediate revisions by 2 users not shown) | |||
Line 12: | Line 12: | ||
--- preferable to call the getter methods with the name of the good rather than | --- preferable to call the getter methods with the name of the good rather than | ||
--- retrieving the entire record for the good, so that your code stays | --- retrieving the entire record for the good, so that your code stays | ||
--- protected from any variations in this module. | --- protected from any variations in this module. These getter methods are all | ||
--- called with the plain-language name of the good, as spelled in the game. | --- called with the plain-language name of the good, as spelled in the game. | ||
--- | --- | ||
Line 22: | Line 22: | ||
--- * amberSellValue, amberBuyValue = GoodsData.getGoodValue(goodName) | --- * amberSellValue, amberBuyValue = GoodsData.getGoodValue(goodName) | ||
--- * iconFilename = GoodsData.getGoodIcon(goodName) | --- * iconFilename = GoodsData.getGoodIcon(goodName) | ||
--- | |||
--- And these getter methods are all called with the good's ID. You will have | |||
--- an ID instead of a display name when dealing with other game data like | |||
--- recipes, workshops, etc. | |||
--- * name = GoodsData.getGoodNameByID(goodID) | |||
--- * iconFilename = GoodsData.getGoodIconByID(goodID) | |||
--- | --- | ||
--- As a last resort, or if you need to transform the data structure, you can | --- As a last resort, or if you need to transform the data structure, you can | ||
--- call the method getAllDataForGood(displayName). This returns a whole record | --- call the method getAllDataForGood(displayName) or | ||
--- | --- getAllDataForGoodByID(goodID). This returns a whole record from the data | ||
--- table corresponding to the requested display name. | |||
--- | --- | ||
--- The data table for goods has the following structure: | --- The data table for goods has the following structure: | ||
Line 62: | Line 69: | ||
--region Private member variables | --region Private member variables | ||
--- Main data table, like this: table[ID] = table containing data for that ID | --- Main data table, like this: table[ID] = table containing data for that ID. | ||
--- This needs to be indexed by ID because IDs are guaranteed to be unique. | |||
local goodsTable | local goodsTable | ||
--- Lookup map. Built once and reused on all subsequent calls within this | --- Lookup map. Built once and reused on all subsequent calls within this | ||
--- session, like this: table[displayName] = goodID | --- session, like this: table[displayName] = goodID | ||
local | local mapNamesToIDs | ||
--endregion | --endregion | ||
Line 77: | Line 85: | ||
local DATA_TEMPLATE_NAME = "Template:Goods_csv" | local DATA_TEMPLATE_NAME = "Template:Goods_csv" | ||
local | local VALUE_DIVISOR = 12 | ||
local INDEX_ID = "id" | |||
local INDEX_NAME = "displayName" | local INDEX_NAME = "displayName" | ||
local INDEX_DESCRIPTION = "description" | local INDEX_DESCRIPTION = "description" | ||
Line 87: | Line 93: | ||
local INDEX_EATABLE = "eatable" | local INDEX_EATABLE = "eatable" | ||
local INDEX_BURNABLE = "canBeBurned" | local INDEX_BURNABLE = "canBeBurned" | ||
local | local INDEX_BURN_TIME = "burningTime" | ||
local INDEX_SELL_VALUE = "tradingSellValue" | local INDEX_SELL_VALUE = "tradingSellValue" | ||
local INDEX_BUY_VALUE = "tradingBuyValue" | local INDEX_BUY_VALUE = "tradingBuyValue" | ||
local INDEX_ICON_FILENAME = "iconName" | local INDEX_ICON_FILENAME = "iconName" | ||
local PATTERN_TUTORIAL = "tutorial" | |||
--endregion | --endregion | ||
Line 105: | Line 113: | ||
--- @param originalGoodsTable table of CSV-based data, with header row, data rows | --- @param originalGoodsTable table of CSV-based data, with header row, data rows | ||
--- @return table with new structure with IDs as keys | --- @return table with new structure with IDs as keys | ||
function restructureGoodsTable(originalGoodsTable) | local function restructureGoodsTable(originalGoodsTable) | ||
-- 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_EATABLE = 5 | |||
local INDEX_ORIGINAL_BURNABLE = 6 | |||
local INDEX_ORIGINAL_BURN_TIME = 7 | |||
local INDEX_ORIGINAL_SELL_VALUE = 8 | |||
local INDEX_ORIGINAL_BUY_VALUE = 9 | |||
local INDEX_ORIGINAL_ICON_FILENAME = 10 | |||
mapNamesToIDs = {} | |||
local newGoodsTable = {} | local newGoodsTable = {} | ||
for _, | for _, originalGood in ipairs(originalGoodsTable[DATA_ROWS]) do | ||
-- Copy over the content, mapping unhelpful indexes into headers keys. | -- Skip over any rows where the ID contains the tutorial term. | ||
if not string.find(originalGood[INDEX_ORIGINAL_ID], PATTERN_TUTORIAL) then | |||
-- Copy over the content, mapping unhelpful indexes into headers keys. | |||
local newGood = {} | |||
newGood[INDEX_ID] = originalGood[INDEX_ORIGINAL_ID] | |||
newGood[INDEX_NAME] = originalGood[INDEX_ORIGINAL_NAME] | |||
newGood[INDEX_DESCRIPTION] = originalGood[INDEX_ORIGINAL_DESCRIPTION] | |||
newGood[INDEX_CATEGORY] = originalGood[INDEX_ORIGINAL_CATEGORY] | |||
newGood[INDEX_EATABLE] = originalGood[INDEX_ORIGINAL_EATABLE] == "True" | |||
newGood[INDEX_BURNABLE] = originalGood[INDEX_ORIGINAL_BURNABLE] == "True" | |||
if newGood[INDEX_BURNABLE] then | |||
newGood[INDEX_BURN_TIME] = tonumber(originalGood[INDEX_ORIGINAL_BURN_TIME]) | |||
else | |||
newGood[INDEX_BURN_TIME] = 0 | |||
end | |||
newGood[INDEX_SELL_VALUE] = tonumber(originalGood[INDEX_ORIGINAL_SELL_VALUE]) / VALUE_DIVISOR | |||
newGood[INDEX_BUY_VALUE] = tonumber(originalGood[INDEX_ORIGINAL_BUY_VALUE]) / VALUE_DIVISOR | |||
newGood[INDEX_ICON_FILENAME] = originalGood[INDEX_ORIGINAL_ICON_FILENAME] .. ".png" | |||
newGood[ | -- Also populate the map for looking up IDs with display names | ||
mapNamesToIDs[newGood[INDEX_NAME]] = newGood[INDEX_ID] | |||
newGoodsTable[newGood[INDEX_ID]] = newGood | |||
end | end | ||
end | end | ||
Line 135: | Line 169: | ||
--- method is automatically called by all public member functions if the main | --- method is automatically called by all public member functions if the main | ||
--- data table has not yet been populated in the current session. | --- data table has not yet been populated in the current session. | ||
function loadData() | local function loadData() | ||
-- Utility module retrieves the data as basic, flat lua tables. We don't | -- Utility module retrieves the data as basic, flat lua tables. We don't | ||
Line 143: | Line 177: | ||
-- Now restructure to be more conducive for data about goods. | -- Now restructure to be more conducive for data about goods. | ||
goodsTable = restructureGoodsTable(originalGoodsTable) | goodsTable = restructureGoodsTable(originalGoodsTable) | ||
end | |||
local function load() | |||
if not goodsTable then | |||
loadData() | |||
end | |||
end | end | ||
Line 153: | Line 194: | ||
--- | --- | ||
--- Returns nil if the good with the specified name is not found. | --- Returns nil if the good with the specified name is not found. | ||
--- | --- | ||
--- @param displayName string plain-language name of the good to find | --- @param displayName string plain-language name of the good to find | ||
--- @return string ID of the good found, or nil if not found | --- @return string ID of the good found, or nil if not found | ||
function findGoodIDByName(displayName) | local function findGoodIDByName(displayName) | ||
-- At runtime, this should never be nil or empty, so throw an error. | -- At runtime, this should never be nil or empty, so throw an error. | ||
Line 170: | Line 208: | ||
end | end | ||
return mapNamesToIDs[displayName] | |||
end | |||
--endregion | |||
--region Public methods | |||
--- | |||
--- Retrieve the whole table of data for the specified good. 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 | |||
end | --- specified good cannot be found. | ||
--- | |||
--- @param goodID string the ID of the good | |||
--- @return table containing the data for the specified good with key-value pairs, or nil if not found | |||
function GoodsData.getAllDataForGoodByID(goodID) | |||
-- At runtime, this should never be nil or empty. | |||
if not goodID or goodID == "" then | |||
error("Parameter is nil or empty for the good's ID.") | |||
end | |||
if not goodsTable then | |||
loadData() | |||
end | end | ||
return | return goodsTable[goodID] | ||
end | end | ||
--- | --- | ||
Line 212: | Line 255: | ||
-- At runtime, this should never be nil or empty. | -- At runtime, this should never be nil or empty. | ||
if not displayName or displayName == "" then | if not displayName or displayName == "" then | ||
error("Parameter is nil or empty for the good's name | error("Parameter is nil or empty for the good's name.") | ||
end | end | ||
Line 225: | Line 268: | ||
return goodsTable[goodID] | return goodsTable[goodID] | ||
end | |||
--- | |||
--- Retrieves the ID for the good specified by its plain language display name. | |||
--- | |||
--- Returns nil if the good named was not found. | |||
--- | |||
---@param displayName string the plain language name of the good | |||
---@return string the good's ID | |||
function GoodsData.getGoodID(displayName) | |||
local good = GoodsData.getAllDataForGood(displayName) | |||
if not good then | |||
return nil | |||
end | |||
return good[INDEX_ID] | |||
end | end | ||
Line 235: | Line 298: | ||
--- Returns nil if the good named was not found. | --- Returns nil if the good named was not found. | ||
--- | --- | ||
---@param displayName string | ---@param displayName string the plain language name of the good | ||
---@return string the in-game description of the specified good | ---@return string the in-game description of the specified good | ||
function GoodsData.getGoodDescription(displayName) | function GoodsData.getGoodDescription(displayName) | ||
Line 256: | Line 319: | ||
--- Returns nil if the good named was not found. | --- Returns nil if the good named was not found. | ||
--- | --- | ||
---@param displayName string | ---@param displayName string the plain language name of the good | ||
---@return string the | ---@return string the category | ||
function GoodsData.getGoodCategory(displayName) | function GoodsData.getGoodCategory(displayName) | ||
Line 277: | Line 340: | ||
--- Returns nil if the good named was not found. | --- Returns nil if the good named was not found. | ||
--- | --- | ||
---@param displayName string | ---@param displayName string the plain language name of the good | ||
---@return boolean true if the good counts as food | ---@return boolean true if the good counts as food | ||
function GoodsData.isGoodEatable(displayName) | function GoodsData.isGoodEatable(displayName) | ||
Line 298: | Line 361: | ||
--- Returns nil if the good named was not found. | --- Returns nil if the good named was not found. | ||
--- | --- | ||
---@param displayName string | ---@param displayName string the plain language name of the good | ||
---@return boolean true if the good counts as fuel | ---@return boolean true if the good counts as fuel | ||
function GoodsData.isGoodBurnable(displayName) | function GoodsData.isGoodBurnable(displayName) | ||
Line 319: | Line 382: | ||
--- Returns nil if the good named was not found. | --- Returns nil if the good named was not found. | ||
--- | --- | ||
---@param displayName string | ---@param displayName string the plain language name of the good | ||
---@return number of seconds the good burns as fuel | ---@return number of seconds the good burns as fuel | ||
function GoodsData.getGoodBurnTime(displayName) | function GoodsData.getGoodBurnTime(displayName) | ||
Line 329: | Line 392: | ||
end | end | ||
return good[ | return good[INDEX_BURN_TIME] | ||
end | end | ||
Line 340: | Line 403: | ||
--- Returns nil if the good named was not found. | --- Returns nil if the good named was not found. | ||
--- | --- | ||
---@param displayName string | ---@param displayName string the plain language name of the good | ||
---@return number of amber the good sells for | ---@return number of amber the good sells for | ||
---@return number of amber required to buy the good | ---@return number of amber required to buy the good | ||
Line 362: | Line 425: | ||
--- Returns nil if the good named was not found. | --- Returns nil if the good named was not found. | ||
--- | --- | ||
---@param displayName string | ---@param displayName string the the plain language name of the good | ||
---@return string the filename of the icon for the specified good | ---@return string the filename of the icon for the specified good | ||
function GoodsData.getGoodIcon(displayName) | function GoodsData.getGoodIcon(displayName) | ||
Line 374: | Line 437: | ||
return good[INDEX_ICON_FILENAME] | return good[INDEX_ICON_FILENAME] | ||
end | end | ||
--- | |||
--- Retrieves the plain-language display name for the good specified by its ID. | |||
--- | |||
--- Returns nil if the good named was not found. | |||
--- | |||
---@param goodID string the ID of the good | |||
---@return string the plain language name of the good | |||
function GoodsData.getGoodNameByID(goodID) | |||
-- Rather than getting it directly from goodsTable here, get it via this | |||
-- other method that has additional error checking. | |||
local good = GoodsData.getAllDataForGoodByID(goodID) | |||
if not good then | |||
return nil | |||
end | |||
return good[INDEX_NAME] | |||
end | |||
--- | |||
--- Retrieves the icon filename for the good specified by its ID. | |||
--- | |||
--- Returns nil if the good named was not found. | |||
--- | |||
---@param goodID string the ID of the good | |||
---@return string the filename of the icon for the specified good | |||
function GoodsData.getGoodIconByID(goodID) | |||
-- Rather than getting it directly from goodsTable here, get it via this | |||
-- other method that has additional error checking. | |||
local good = GoodsData.getAllDataForGoodByID(goodID) | |||
if not good then | |||
return nil | |||
end | |||
return good[INDEX_ICON_FILENAME] | |||
end | |||
--Goods interface | |||
-- getName | |||
-- getCategory | |||
-- getDescription | |||
-- getIcon | |||
-- getBurnTime | |||
-- getSellValue | |||
-- getSellValueAfterPrestigePenalty | |||
-- getBuyValue | |||
function GoodsData.getName(id) | |||
load() | |||
return goodsTable[id] ~= nil and goodsTable[id][INDEX_NAME] | |||
end | |||
function GoodsData.getCategory(id) | |||
load() | |||
return goodsTable[id] ~= nil and goodsTable[id][INDEX_CATEGORY] | |||
end | |||
function GoodsData.getDescription(id) | |||
load() | |||
return goodsTable[id] ~= nil and goodsTable[id][INDEX_DESCRIPTION] | |||
end | |||
function GoodsData.getIcon(id) | |||
load() | |||
return goodsTable[id] ~= nil and goodsTable[id][INDEX_ICON_FILENAME] | |||
end | |||
function GoodsData.getBurnTime(id) | |||
load() | |||
return goodsTable[id] ~= nil and goodsTable[id][INDEX_BURN_TIME] | |||
end | |||
function GoodsData.getSellValue(id) | |||
load() | |||
local value = goodsTable[id][INDEX_SELL_VALUE] | |||
return goodsTable[id] ~= nil and tonumber(string.format("%.2f", value)) | |||
end | |||
function GoodsData.getSellValueAfterPrestigePenalty(id) | |||
load() | |||
local value = goodsTable[id][INDEX_SELL_VALUE] / 2 | |||
return goodsTable[id] ~= nil and tonumber(string.format("%.2f", value)) | |||
end | |||
function GoodsData.getBuyValue(id) | |||
load() | |||
local value = goodsTable[id][INDEX_BUY_VALUE] | |||
return goodsTable[id] ~= nil and tonumber(string.format("%.2f", value)) | |||
end | |||
--endregion | --endregion | ||
return GoodsData | return GoodsData |
Latest revision as of 14:31, 12 October 2024
Overview
Module for compiling goods (or resources as some call them) information from wiki data sources. Restructures the flat data tables that are produced from CsvUtils to make them more conducive to Lua methods that need to display the information.
Usage
The standard way of using this module is a call like the following:
iconFilename = GoodsData.getGoodIcon(goodName)
This will return a string corresponding to the filename of the good, including the .png extension. It is preferable to call the getter methods with the name of the good rather than retrieving the entire record for the good, so that your code stays protected from any variations in this module. The getter methods are all called with the plain-language name of the good, as spelled in the game.
longDescription = GoodsData.getGoodDescription(goodName) inventoryCategory = GoodsData.getGoodCategory(goodName) isEatable = GoodsData.isGoodEatable(goodName) isBurnable = GoodsData.isGoodBurnable(goodName) burnSeconds = GoodsData.getGoodBurnTime(goodName) amberSellValue, amberBuyValue = GoodsData.getGoodValue(goodName) iconFilename = GoodsData.getGoodIcon(goodName)
As a last resort, or if you need to transform the data structure, you can
call the method getAllDataForGood(displayName)
. This returns a whole record
from the data table corresponding to the requested display name.
The data table for goods has the following structure:
goodsTable = { ["good1_ID"] = { ["id"] = "good1_ID", ["displayName"] = "Plain Language Name", ["description"] = "A long string with some HTML entities too.", ["category"] = "Inventory category", ["eatable"] = true or false if food ["canBeBurned"] = true or false if fuel and sacrifice ["burningTime"] = 99, number of seconds ["tradingSellValue"] = 99.99, in amber ["tradingBuyValue"] = 99.99, in amber ["iconName"] = "Icon_Resource_filename.png" including PNG extension }, ["good2_ID"] = { ... }, ["good3_ID"] = { ... }, ... }
--- --- Module for compiling goods (or resources as some call them) information --- from wiki data sources. Restructures the flat data tables that are produced --- from CsvUtils to make them more conducive to Lua methods that need to --- display the information. --- --- The standard way of using this module is a call like the following: --- --- iconFilename = GoodsData.getGoodIcon(goodName) --- --- This will return a string corresponding to the filename of the good. It is --- preferable to call the getter methods with the name of the good rather than --- retrieving the entire record for the good, so that your code stays --- protected from any variations in this module. These getter methods are all --- called with the plain-language name of the good, as spelled in the game. --- --- * longDescription = GoodsData.getGoodDescription(goodName) --- * inventoryCategory = GoodsData.getGoodCategory(goodName) --- * isEatable = GoodsData.isGoodEatable(goodName) --- * isBurnable = GoodsData.isGoodBurnable(goodName) --- * burnSeconds = GoodsData.getGoodBurnTime(goodName) --- * amberSellValue, amberBuyValue = GoodsData.getGoodValue(goodName) --- * iconFilename = GoodsData.getGoodIcon(goodName) --- --- And these getter methods are all called with the good's ID. You will have --- an ID instead of a display name when dealing with other game data like --- recipes, workshops, etc. --- * name = GoodsData.getGoodNameByID(goodID) --- * iconFilename = GoodsData.getGoodIconByID(goodID) --- --- As a last resort, or if you need to transform the data structure, you can --- call the method getAllDataForGood(displayName) or --- getAllDataForGoodByID(goodID). This returns a whole record from the data --- table corresponding to the requested display name. --- --- The data table for goods has the following structure: --- --- goodsTable = { --- ["good1_ID"] = { --- ["id"] = "good1_ID", --- ["displayName"] = "Plain Language Name", --- ["description"] = "A long string with some HTML entities too.", --- ["category"] = "Inventory category", --- ["eatable"] = true or false if food --- ["canBeBurned"] = true or false if fuel and sacrifice --- ["burningTime"] = 99, number of seconds --- ["tradingSellValue"] = 99.99, in amber --- ["tradingBuyValue"] = 99.99, in amber --- ["iconName"] = "Icon_Resource_filename.png" including PNG extension --- }, --- ["good2_ID"] = { --- ... --- }, --- ["good3_ID"] = { --- ... --- }, --- ... --- } --- --- @module GoodsData local GoodsData = {} local CsvUtils = require("Module:CsvUtils") --region Private member variables --- Main data table, like this: table[ID] = table containing data for that ID. --- This needs to be indexed by ID because IDs are guaranteed to be unique. local goodsTable --- Lookup map. Built once and reused on all subsequent calls within this --- session, like this: table[displayName] = goodID local mapNamesToIDs --endregion --region Private constants local DATA_TEMPLATE_NAME = "Template:Goods_csv" local VALUE_DIVISOR = 12 local INDEX_ID = "id" local INDEX_NAME = "displayName" local INDEX_DESCRIPTION = "description" local INDEX_CATEGORY = "category" local INDEX_EATABLE = "eatable" local INDEX_BURNABLE = "canBeBurned" local INDEX_BURN_TIME = "burningTime" local INDEX_SELL_VALUE = "tradingSellValue" local INDEX_BUY_VALUE = "tradingBuyValue" local INDEX_ICON_FILENAME = "iconName" local PATTERN_TUTORIAL = "tutorial" --endregion --region Private methods --- --- Since the goods information is already flat and well structured, all this has --- to do is swap out the integer keys for the good IDs and only return the data --- rows, without the header row. --- --- @param originalGoodsTable table of CSV-based data, with header row, data rows --- @return table with new structure with IDs as keys local function restructureGoodsTable(originalGoodsTable) -- 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_EATABLE = 5 local INDEX_ORIGINAL_BURNABLE = 6 local INDEX_ORIGINAL_BURN_TIME = 7 local INDEX_ORIGINAL_SELL_VALUE = 8 local INDEX_ORIGINAL_BUY_VALUE = 9 local INDEX_ORIGINAL_ICON_FILENAME = 10 mapNamesToIDs = {} local newGoodsTable = {} for _, originalGood in ipairs(originalGoodsTable[DATA_ROWS]) do -- Skip over any rows where the ID contains the tutorial term. if not string.find(originalGood[INDEX_ORIGINAL_ID], PATTERN_TUTORIAL) then -- Copy over the content, mapping unhelpful indexes into headers keys. local newGood = {} newGood[INDEX_ID] = originalGood[INDEX_ORIGINAL_ID] newGood[INDEX_NAME] = originalGood[INDEX_ORIGINAL_NAME] newGood[INDEX_DESCRIPTION] = originalGood[INDEX_ORIGINAL_DESCRIPTION] newGood[INDEX_CATEGORY] = originalGood[INDEX_ORIGINAL_CATEGORY] newGood[INDEX_EATABLE] = originalGood[INDEX_ORIGINAL_EATABLE] == "True" newGood[INDEX_BURNABLE] = originalGood[INDEX_ORIGINAL_BURNABLE] == "True" if newGood[INDEX_BURNABLE] then newGood[INDEX_BURN_TIME] = tonumber(originalGood[INDEX_ORIGINAL_BURN_TIME]) else newGood[INDEX_BURN_TIME] = 0 end newGood[INDEX_SELL_VALUE] = tonumber(originalGood[INDEX_ORIGINAL_SELL_VALUE]) / VALUE_DIVISOR newGood[INDEX_BUY_VALUE] = tonumber(originalGood[INDEX_ORIGINAL_BUY_VALUE]) / VALUE_DIVISOR newGood[INDEX_ICON_FILENAME] = originalGood[INDEX_ORIGINAL_ICON_FILENAME] .. ".png" -- Also populate the map for looking up IDs with display names mapNamesToIDs[newGood[INDEX_NAME]] = newGood[INDEX_ID] newGoodsTable[newGood[INDEX_ID]] = newGood end end return newGoodsTable 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. We don't -- need to use the header lookup table that's returned with the data table. local originalGoodsTable, _ = CsvUtils.extractTables(DATA_TEMPLATE_NAME) -- Now restructure to be more conducive for data about goods. goodsTable = restructureGoodsTable(originalGoodsTable) end local function load() if not goodsTable then loadData() end end --- --- Uses the display name, which people are more familiar with, to find the --- encoded ID of the good. Useful for retrieving good data that is indexed by --- ID. --- --- Returns nil if the good with the specified name is not found. --- --- @param displayName string plain-language name of the good to find --- @return string ID of the good found, or nil if not found local function findGoodIDByName(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 the good's name: " .. displayName .. ".") end if not goodsTable then loadData() end return mapNamesToIDs[displayName] end --endregion --region Public methods --- --- Retrieve the whole table of data for the specified good. 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 good cannot be found. --- --- @param goodID string the ID of the good --- @return table containing the data for the specified good with key-value pairs, or nil if not found function GoodsData.getAllDataForGoodByID(goodID) -- At runtime, this should never be nil or empty. if not goodID or goodID == "" then error("Parameter is nil or empty for the good's ID.") end if not goodsTable then loadData() end return goodsTable[goodID] end --- --- Retrieve the whole table of data for the specified good. 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 good cannot be found. --- --- @param displayName string plain language name of the good --- @return table containing the data for the specified good with key-value pairs, or nil if not found function GoodsData.getAllDataForGood(displayName) -- At runtime, this should never be nil or empty. if not displayName or displayName == "" then error("Parameter is nil or empty for the good's name.") end if not goodsTable then loadData() end local goodID = findGoodIDByName(displayName) if not goodID then return nil end return goodsTable[goodID] end --- --- Retrieves the ID for the good specified by its plain language display name. --- --- Returns nil if the good named was not found. --- ---@param displayName string the plain language name of the good ---@return string the good's ID function GoodsData.getGoodID(displayName) local good = GoodsData.getAllDataForGood(displayName) if not good then return nil end return good[INDEX_ID] end --- --- Retrieves the description for the good specified by its plain language --- display name. --- --- Returns nil if the good named was not found. --- ---@param displayName string the plain language name of the good ---@return string the in-game description of the specified good function GoodsData.getGoodDescription(displayName) local good = GoodsData.getAllDataForGood(displayName) if not good then return nil end return good[INDEX_DESCRIPTION] end --- --- Retrieves the inventory category for the good specified by its plain --- language display name. --- --- Returns nil if the good named was not found. --- ---@param displayName string the plain language name of the good ---@return string the category function GoodsData.getGoodCategory(displayName) local good = GoodsData.getAllDataForGood(displayName) if not good then return nil end return good[INDEX_CATEGORY] end --- --- Retrieves whether the good is eatable, specified by its plain language --- display name. --- --- Returns nil if the good named was not found. --- ---@param displayName string the plain language name of the good ---@return boolean true if the good counts as food function GoodsData.isGoodEatable(displayName) local good = GoodsData.getAllDataForGood(displayName) if not good then return nil end return good[INDEX_EATABLE] end --- --- Retrieves whether the good is burnable, specified by its plain language --- display name. --- --- Returns nil if the good named was not found. --- ---@param displayName string the plain language name of the good ---@return boolean true if the good counts as fuel function GoodsData.isGoodBurnable(displayName) local good = GoodsData.getAllDataForGood(displayName) if not good then return nil end return good[INDEX_BURNABLE] end --- --- Retrieves the burn time for the good specified by its plain language --- display name. --- --- Returns nil if the good named was not found. --- ---@param displayName string the plain language name of the good ---@return number of seconds the good burns as fuel function GoodsData.getGoodBurnTime(displayName) local good = GoodsData.getAllDataForGood(displayName) if not good then return nil end return good[INDEX_BURN_TIME] end --- --- Retrieves the trading value for the good specified by its plain language --- display name. --- --- Returns nil if the good named was not found. --- ---@param displayName string the plain language name of the good ---@return number of amber the good sells for ---@return number of amber required to buy the good function GoodsData.getGoodValue(displayName) local good = GoodsData.getAllDataForGood(displayName) if not good then return nil end return good[INDEX_SELL_VALUE], good[INDEX_BUY_VALUE] end --- --- Retrieves the icon filename for the good specified by its plain language --- display name. --- --- Returns nil if the good named was not found. --- ---@param displayName string the the plain language name of the good ---@return string the filename of the icon for the specified good function GoodsData.getGoodIcon(displayName) local good = GoodsData.getAllDataForGood(displayName) if not good then return nil end return good[INDEX_ICON_FILENAME] end --- --- Retrieves the plain-language display name for the good specified by its ID. --- --- Returns nil if the good named was not found. --- ---@param goodID string the ID of the good ---@return string the plain language name of the good function GoodsData.getGoodNameByID(goodID) -- Rather than getting it directly from goodsTable here, get it via this -- other method that has additional error checking. local good = GoodsData.getAllDataForGoodByID(goodID) if not good then return nil end return good[INDEX_NAME] end --- --- Retrieves the icon filename for the good specified by its ID. --- --- Returns nil if the good named was not found. --- ---@param goodID string the ID of the good ---@return string the filename of the icon for the specified good function GoodsData.getGoodIconByID(goodID) -- Rather than getting it directly from goodsTable here, get it via this -- other method that has additional error checking. local good = GoodsData.getAllDataForGoodByID(goodID) if not good then return nil end return good[INDEX_ICON_FILENAME] end --Goods interface -- getName -- getCategory -- getDescription -- getIcon -- getBurnTime -- getSellValue -- getSellValueAfterPrestigePenalty -- getBuyValue function GoodsData.getName(id) load() return goodsTable[id] ~= nil and goodsTable[id][INDEX_NAME] end function GoodsData.getCategory(id) load() return goodsTable[id] ~= nil and goodsTable[id][INDEX_CATEGORY] end function GoodsData.getDescription(id) load() return goodsTable[id] ~= nil and goodsTable[id][INDEX_DESCRIPTION] end function GoodsData.getIcon(id) load() return goodsTable[id] ~= nil and goodsTable[id][INDEX_ICON_FILENAME] end function GoodsData.getBurnTime(id) load() return goodsTable[id] ~= nil and goodsTable[id][INDEX_BURN_TIME] end function GoodsData.getSellValue(id) load() local value = goodsTable[id][INDEX_SELL_VALUE] return goodsTable[id] ~= nil and tonumber(string.format("%.2f", value)) end function GoodsData.getSellValueAfterPrestigePenalty(id) load() local value = goodsTable[id][INDEX_SELL_VALUE] / 2 return goodsTable[id] ~= nil and tonumber(string.format("%.2f", value)) end function GoodsData.getBuyValue(id) load() local value = goodsTable[id][INDEX_BUY_VALUE] return goodsTable[id] ~= nil and tonumber(string.format("%.2f", value)) end --endregion return GoodsData