Module:CampsData: Difference between revisions
From Against the Storm Official Wiki
Added two new methods to support getting names from the database |
Updated with common method names (like a building interface) |
||
| Line 107: | Line 107: | ||
--region Dependencies | |||
local CsvUtils = require("Module:CsvUtils") | local CsvUtils = require("Module:CsvUtils") | ||
-- Some dependencies are loaded lazily | |||
local GoodsData | |||
--endregion | |||
| Line 181: | Line 188: | ||
local function makeRequiredGoodsSubtable(originalCamp, campsHeaderLookup) | local function makeRequiredGoodsSubtable(originalCamp, campsHeaderLookup) | ||
-- 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 = campsHeaderLookup[REQ_GOOD_HEADER_BASE_STRING .. "1"] | |||
local requiredIndex2 = campsHeaderLookup[REQ_GOOD_HEADER_BASE_STRING .. "2"] | |||
local requiredIndex3 = campsHeaderLookup[REQ_GOOD_HEADER_BASE_STRING .. "3"] | |||
local number1, id1 = originalCamp[requiredIndex1]:match(PATTERN_SPLIT_STACK_AND_ID) | |||
local number2, id2 = originalCamp[requiredIndex2]:match(PATTERN_SPLIT_STACK_AND_ID) | |||
local number3, id3 = originalCamp[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 | end | ||
| Line 214: | Line 221: | ||
local function makeWorkplacesSubtable(originalCamp, campsHeaderLookup) | local function makeWorkplacesSubtable(originalCamp, campsHeaderLookup) | ||
-- A constant we'll need only within this function. | |||
local WORKPLACE_HEADER_BASE_STRING = "workplace" | |||
-- Copy the originals directly into a subtable. | |||
local workplaceIndex1 = campsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "1"] | |||
local workplaceIndex2 = campsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "2"] | |||
local workplaceIndex3 = campsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "3"] | |||
local workplaceIndex4 = campsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "4"] | |||
local workplace1 = originalCamp[workplaceIndex1] | |||
local workplace2 = originalCamp[workplaceIndex2] | |||
local workplace3 = originalCamp[workplaceIndex3] | |||
local workplace4 = originalCamp[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 | ||
| Line 251: | Line 258: | ||
local function makeRecipesSubtable(campName, originalCamp, campsHeaderLookup) | local function makeRecipesSubtable(campName, originalCamp, campsHeaderLookup) | ||
-- A constant we'll need only within this function. | |||
local MAX_RECIPES = 3 | |||
local LOOKUP_RECIPE_BASE_STRING = "recipe" | |||
local LOOKUP_GOOD_BASE_STRING = "SeekedDeposits" | |||
local LOOKUP_GRADE_BASE_STRING = "Grade" | |||
local LOOKUP_GATHERING_TIME_BASE_STRING = "GatheringTime" | |||
if not mapRecipeGoodIDsToCampNames then | |||
mapRecipeGoodIDsToCampNames = {} | |||
end | |||
-- Copy the originals directly into a subtable. | |||
local recipes = {} | |||
for i = 1, MAX_RECIPES do | |||
-- A subtable for this recipe | |||
newRecipe = {} | |||
local originalGoodIndex = campsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. i | |||
.. LOOKUP_GOOD_BASE_STRING] | |||
local originalGradeIndex = campsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. i | |||
.. LOOKUP_GRADE_BASE_STRING] | |||
local originalGatheringTimeIndex = campsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. i | |||
.. LOOKUP_GATHERING_TIME_BASE_STRING] | |||
local originalGoodID = originalCamp[originalGoodIndex] | |||
-- Skip blank recipes. | |||
if originalGoodID and originalGoodID ~= "" then | |||
newRecipe[INDEX_RECIPE_GOOD_ID] = originalGoodID | |||
newRecipe[INDEX_RECIPE_GRADE] = tonumber(originalCamp[originalGradeIndex]:match(PATTERN_CAPTURE_END_NUMBER)) | |||
newRecipe[INDEX_RECIPE_GATHERING_TIME] = tonumber(originalCamp[originalGatheringTimeIndex]) | |||
table.insert(recipes,newRecipe) | |||
if not mapRecipeGoodIDsToCampNames[originalGoodID] then | |||
mapRecipeGoodIDsToCampNames[originalGoodID] = {} | |||
end | |||
table.insert(mapRecipeGoodIDsToCampNames[originalGoodID], campName) | |||
end | |||
end | |||
return recipes | |||
end | end | ||
| Line 308: | Line 315: | ||
local function restructureGathererHuts(originalCampsTable, campsHeaderLookup) | local function restructureGathererHuts(originalCampsTable, campsHeaderLookup) | ||
-- 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_AREA = 14 | |||
local INDEX_ORIGINAL_STORAGE = 15 | |||
mapNamesToIDs = {} | |||
campsNames = {} | |||
local newCampsTable = {} | |||
for _, originalCamp in ipairs(originalCampsTable[DATA_ROWS]) do | |||
-- Copy over the content, mapping unhelpful indexes into headers keys. | |||
local newCamp = {} | |||
newCamp[INDEX_ID] = originalCamp[INDEX_ORIGINAL_ID] | |||
newCamp[INDEX_NAME] = originalCamp[INDEX_ORIGINAL_NAME] | |||
newCamp[INDEX_DESCRIPTION] = originalCamp[INDEX_ORIGINAL_DESCRIPTION] | |||
newCamp[INDEX_CATEGORY] = originalCamp[INDEX_ORIGINAL_CATEGORY] | |||
newCamp[INDEX_SIZE_X] = tonumber(originalCamp[INDEX_ORIGINAL_SIZE_X]) | |||
newCamp[INDEX_SIZE_Y] = tonumber(originalCamp[INDEX_ORIGINAL_SIZE_Y]) | |||
newCamp[INDEX_CITY_SCORE] = tonumber(originalCamp[INDEX_ORIGINAL_CITY_SCORE]) | |||
newCamp[INDEX_MOVABLE] = originalCamp[INDEX_ORIGINAL_MOVABLE] == "True" | |||
newCamp[INDEX_INITIALLY_ESSENTIAL] = originalCamp[INDEX_ORIGINAL_ESSENTIAL] == "True" | |||
newCamp[INDEX_AREA] = tonumber(originalCamp[INDEX_ORIGINAL_AREA]) | |||
newCamp[INDEX_STORAGE] = tonumber(originalCamp[INDEX_ORIGINAL_STORAGE]) | |||
newCamp[INDEX_CONSTRUCTION_TIME] = tonumber(originalCamp[INDEX_ORIGINAL_CONSTRUCTION_TIME]) | |||
newCamp[INDEX_REQUIRED_GOODS] = makeRequiredGoodsSubtable(originalCamp, campsHeaderLookup) | |||
newCamp[INDEX_WORKPLACES] = makeWorkplacesSubtable(originalCamp, campsHeaderLookup) | |||
newCamp[INDEX_RECIPES] = makeRecipesSubtable(newCamp[INDEX_NAME], originalCamp, campsHeaderLookup) | |||
newCampsTable[ newCamp[INDEX_ID] ] = newCamp | |||
table.insert(campsNames, newCamp[INDEX_NAME]) | |||
-- Also populate the map for looking up IDs with display names | |||
mapNamesToIDs[ newCamp[INDEX_NAME] ] = newCamp[INDEX_ID] | |||
end | |||
return newCampsTable | |||
end | end | ||
| Line 371: | Line 378: | ||
local function addWoodcuttersCampRow(originalCampsTable, campsHeaderLookup) | local function addWoodcuttersCampRow(originalCampsTable, campsHeaderLookup) | ||
-- 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_AREA = 14 | |||
local INDEX_ORIGINAL_STORAGE = 15 | |||
-- The woodcutters' camp is at index 1 in the data rows. | |||
local originalCamp = originalCampsTable[DATA_ROWS][1] | |||
local newCamp = {} | |||
newCamp[INDEX_ID] = originalCamp[INDEX_ORIGINAL_ID] | |||
newCamp[INDEX_NAME] = originalCamp[INDEX_ORIGINAL_NAME] | |||
newCamp[INDEX_DESCRIPTION] = originalCamp[INDEX_ORIGINAL_DESCRIPTION] | |||
newCamp[INDEX_CATEGORY] = originalCamp[INDEX_ORIGINAL_CATEGORY] | |||
newCamp[INDEX_SIZE_X] = tonumber(originalCamp[INDEX_ORIGINAL_SIZE_X]) | |||
newCamp[INDEX_SIZE_Y] = tonumber(originalCamp[INDEX_ORIGINAL_SIZE_Y]) | |||
newCamp[INDEX_CONSTRUCTION_TIME] = tonumber(originalCamp[INDEX_ORIGINAL_CONSTRUCTION_TIME]) | |||
newCamp[INDEX_CITY_SCORE] = tonumber(originalCamp[INDEX_ORIGINAL_CITY_SCORE]) | |||
newCamp[INDEX_MOVABLE] = originalCamp[INDEX_ORIGINAL_MOVABLE] | |||
newCamp[INDEX_INITIALLY_ESSENTIAL] = originalCamp[INDEX_ORIGINAL_ESSENTIAL] | |||
newCamp[INDEX_AREA] = tonumber(originalCamp[INDEX_ORIGINAL_AREA]) | |||
newCamp[INDEX_STORAGE] = tonumber(originalCamp[INDEX_ORIGINAL_STORAGE]) | |||
newCamp[INDEX_REQUIRED_GOODS] = makeRequiredGoodsSubtable(originalCamp, campsHeaderLookup) | |||
newCamp[INDEX_WORKPLACES] = makeWorkplacesSubtable(originalCamp, campsHeaderLookup) | |||
-- Create a subtable of one recipe. This part of the record does not exist | |||
-- in the data and needs to be fabricated to match the other camps. | |||
local oneRecipe = {} | |||
local recipe = {} | |||
recipe[INDEX_RECIPE_GOOD_ID] = WOODCUTTER_ID_WOOD | |||
recipe[INDEX_RECIPE_GRADE] = WOODCUTTER_GRADE | |||
recipe[INDEX_RECIPE_GATHERING_TIME] = WOODCUTTER_GATHERING_TIME | |||
table.insert(oneRecipe, recipe) | |||
newCamp[INDEX_RECIPES] = oneRecipe | |||
campsTable[newCamp[INDEX_ID]] = newCamp | |||
mapNamesToIDs[newCamp[INDEX_NAME]] = newCamp[INDEX_ID] | |||
-- This is the only camp that harvests wood. | |||
mapRecipeGoodIDsToCampNames[WOODCUTTER_ID_WOOD] = {} | |||
table.insert(mapRecipeGoodIDsToCampNames[WOODCUTTER_ID_WOOD], newCamp[INDEX_NAME]) | |||
end | end | ||
| Line 435: | Line 442: | ||
local function loadData() | local function loadData() | ||
-- Utility module retrieves the data as basic, flat lua tables. | |||
local originalGathererHutsTable, gathererHutsHeaderLookup = CsvUtils.extractTables(GATHERER_HUTS_DATA_TEMPLATE_NAME) | |||
-- Now restructure to be more conducive. | |||
campsTable = restructureGathererHuts(originalGathererHutsTable, gathererHutsHeaderLookup) | |||
-- Now append the woodcutters' camp and fake recipe records for its | |||
local originalCampsTable, campsHeaderLookup = CsvUtils.extractTables(CAMPS_DATA_TEMPLATE_NAME) | |||
-- Now restructure and append a row for the camp, since there is only one record right now. | |||
addWoodcuttersCampRow(originalCampsTable, campsHeaderLookup) | |||
end | |||
local function load() | |||
if not campsTable then | |||
loadData() | |||
end | |||
end | end | ||
| Line 461: | Line 476: | ||
local function findCampIDByName(displayName) | local function findCampIDByName(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 camp's name: " .. displayName .. ".") | |||
end | |||
if not campsTable then | |||
loadData() | |||
end | |||
return mapNamesToIDs[displayName] | |||
end | end | ||
| Line 489: | Line 504: | ||
function CampsData.getAllDataForCampByID(campID) | function CampsData.getAllDataForCampByID(campID) | ||
-- At runtime, this should never be nil or empty. | |||
if not campID or campID == "" then | |||
error("Parameter is nil or empty for the camp's ID.") | |||
end | |||
if not campsTable then | |||
loadData() | |||
end | |||
return campsTable[campID] | |||
end | end | ||
| Line 513: | Line 528: | ||
function CampsData.getAllDataForCamp(displayName) | function CampsData.getAllDataForCamp(displayName) | ||
-- At runtime, this should never be nil or empty. | |||
if not displayName or displayName == "" then | |||
error("Parameter is nil or empty for the camp's name.") | |||
end | |||
if not campsTable then | |||
loadData() | |||
end | |||
local campID = findCampIDByName(displayName) | |||
if not campID then | |||
return nil | |||
end | |||
return campsTable[campID] | |||
end | end | ||
| Line 542: | Line 557: | ||
function CampsData.getCampID(displayName) | function CampsData.getCampID(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_ID] | |||
end | end | ||
| Line 563: | Line 578: | ||
function CampsData.getCampDescription(displayName) | function CampsData.getCampDescription(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_DESCRIPTION] | |||
end | end | ||
| Line 584: | Line 599: | ||
function CampsData.getCampCategory(displayName) | function CampsData.getCampCategory(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_CATEGORY] | |||
end | end | ||
| Line 606: | Line 621: | ||
function CampsData.getCampSize(displayName) | function CampsData.getCampSize(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_SIZE_X], camp[INDEX_SIZE_Y] | |||
end | end | ||
| Line 633: | Line 648: | ||
function CampsData.getAllCampRequiredGoods(displayName) | function CampsData.getAllCampRequiredGoods(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_REQUIRED_GOODS] | |||
end | end | ||
| Line 656: | Line 671: | ||
function CampsData.getCampRequiredGood(displayName, requirementIndex) | function CampsData.getCampRequiredGood(displayName, requirementIndex) | ||
local requiredGoods = CampsData.getAllCampRequiredGoods(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 | end | ||
| Line 682: | Line 697: | ||
function CampsData.getCampConstructionTime(displayName) | function CampsData.getCampConstructionTime(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_CONSTRUCTION_TIME] | |||
end | end | ||
| Line 703: | Line 718: | ||
function CampsData.getCampCityScore(displayName) | function CampsData.getCampCityScore(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_CITY_SCORE] | |||
end | end | ||
| Line 724: | Line 739: | ||
function CampsData.isCampMovable(displayName) | function CampsData.isCampMovable(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_MOVABLE] | |||
end | end | ||
| Line 745: | Line 760: | ||
function CampsData.isCampInitiallyEssential(displayName) | function CampsData.isCampInitiallyEssential(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_INITIALLY_ESSENTIAL] | |||
end | end | ||
| Line 766: | Line 781: | ||
function CampsData.getCampArea(displayName) | function CampsData.getCampArea(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_AREA] | |||
end | end | ||
| Line 787: | Line 802: | ||
function CampsData.getCampStorage(displayName) | function CampsData.getCampStorage(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_STORAGE] | |||
end | end | ||
| Line 808: | Line 823: | ||
function CampsData.getAllCampWorkplaces(displayName) | function CampsData.getAllCampWorkplaces(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_WORKPLACES] | |||
end | end | ||
| Line 829: | Line 844: | ||
function CampsData.getCampNumberOfWorkplaces(displayName) | function CampsData.getCampNumberOfWorkplaces(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return #camp[INDEX_WORKPLACES] | |||
end | end | ||
| Line 857: | Line 872: | ||
function CampsData.getAllCampRecipes(displayName) | function CampsData.getAllCampRecipes(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_RECIPES] | |||
end | end | ||
| Line 878: | Line 893: | ||
function CampsData.getCampNumberOfRecipes(displayName) | function CampsData.getCampNumberOfRecipes(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return 0 | |||
end | |||
local recipes = camp[INDEX_RECIPES] | |||
if not recipes then | |||
return 0 | |||
end | |||
return #recipes | |||
end | end | ||
| Line 905: | Line 920: | ||
function CampsData.getCampRecipeProduct(displayName, recipeIndex) | function CampsData.getCampRecipeProduct(displayName, recipeIndex) | ||
local recipes = CampsData.getAllCampRecipes(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] | |||
end | end | ||
| Line 934: | Line 949: | ||
function CampsData.getCampRecipeStats(displayName, recipeIndex) | function CampsData.getCampRecipeStats(displayName, recipeIndex) | ||
local recipes = CampsData.getAllCampRecipes(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_GATHERING_TIME] | |||
end | end | ||
| Line 960: | Line 975: | ||
function CampsData.getCampIcon(displayName) | function CampsData.getCampIcon(displayName) | ||
local camp = CampsData.getAllDataForCamp(displayName) | |||
if not camp then | |||
return nil | |||
end | |||
-- the base string of the icon is the ID. It has to be not nil to | |||
-- concatenate | |||
if camp[INDEX_ID] then | |||
return camp[INDEX_ID] .. "_icon.png" | |||
else | |||
return nil | |||
end | |||
end | end | ||
| Line 987: | Line 1,002: | ||
function CampsData.getCampNameByID(campID) | function CampsData.getCampNameByID(campID) | ||
local camp = CampsData.getAllDataForCampByID(campID) | |||
if not camp then | |||
return nil | |||
end | |||
return camp[INDEX_NAME] | |||
end | end | ||
| Line 1,007: | Line 1,022: | ||
function CampsData.getCampIconByID(campID) | function CampsData.getCampIconByID(campID) | ||
local camp = CampsData.getAllDataForCampByID(campID) | |||
if not camp then | |||
return nil | |||
end | |||
-- the base string of the icon is the ID. It has to be not nil to | |||
-- concatenate | |||
if camp[INDEX_ID] then | |||
return camp[INDEX_ID] .. "_icon.png" | |||
else | |||
return nil | |||
end | |||
end | end | ||
| Line 1,032: | Line 1,047: | ||
function CampsData.getCampNamesWithRecipeProductID(productID) | function CampsData.getCampNamesWithRecipeProductID(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 campsTable then | |||
loadData() | |||
end | |||
return mapRecipeGoodIDsToCampNames[productID] | |||
end | end | ||
| Line 1,053: | Line 1,068: | ||
function CampsData.getCampNameFromDatabase(index) | function CampsData.getCampNameFromDatabase(index) | ||
if not index then | |||
return nil | |||
end | |||
if not campsTable then | |||
loadData() | |||
end | |||
return campsNames[index] | |||
end | end | ||
| Line 1,073: | Line 1,088: | ||
function CampsData.getNumberOfCampsInDatabase() | function CampsData.getNumberOfCampsInDatabase() | ||
if not campsTable then | |||
loadData() | |||
end | |||
return #campsNames | |||
end | |||
--endregion | |||
--region Public Building interface | |||
-- getCategory | |||
-- getCityScore | |||
-- getConstructionCosts (as [goodName] = stack size) | |||
-- getConstructionTime | |||
-- getDescription | |||
-- getIcon | |||
-- getMovable | |||
-- getName | |||
-- getNumberOfWorkplaces | |||
-- getSize (as "X x Y") | |||
-- getStorage | |||
function CampsData.getCategory(id) | |||
load() | |||
return campsTable[id] ~= nil and campsTable[id][INDEX_CATEGORY] | |||
end | |||
function CampsData.getCityScore(id) | |||
load() | |||
return campsTable[id] ~= nil and campsTable[id][INDEX_CITY_SCORE] | |||
end | |||
function CampsData.getConstructionCosts(id) | |||
load() | |||
GoodsData = require("Module:GoodsData") | |||
camp = campsTable[id] | |||
if not camp then | |||
return false | |||
end | |||
local constructionCosts = {} | |||
for _, stacks in ipairs(camp[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 CampsData.getConstructionTime(id) | |||
load() | |||
return campsTable[id] ~= nil and campsTable[id][INDEX_CONSTRUCTION_TIME] | |||
end | |||
function CampsData.getDescription(id) | |||
load() | |||
return campsTable[id] ~= nil and campsTable[id][INDEX_DESCRIPTION] | |||
end | |||
function CampsData.getIcon(id) | |||
load() | |||
return campsTable[id] ~= nil and id .. "_icon.png" | |||
end | |||
function CampsData.isMovable(id) | |||
load() | |||
return campsTable[id] ~= nil and campsTable[id][INDEX_MOVABLE] | |||
end | |||
function CampsData.getName(id) | |||
load() | |||
return campsTable[id] ~= nil and campsTable[id][INDEX_NAME] | |||
end | |||
function CampsData.getNumberOfWorkplaces(id) | |||
load() | |||
return campsTable[id] ~= nil and #campsTable[id][INDEX_WORKPLACES] | |||
end | |||
function CampsData.getSize(id) | |||
load() | |||
camp = campsTable[id] | |||
if not camp then | |||
return false | |||
end | |||
return camp[INDEX_SIZE_X] .. " × " .. camp[INDEX_SIZE_Y] | |||
end | |||
function CampsData.getStorage(id) | |||
load() | |||
return campsTable[id] ~= nil and campsTable[id][INDEX_STORAGE] | |||
end | end | ||
Revision as of 01:50, 9 October 2024
Documentation for this module may be created at Module:CampsData/doc
---
--- Module for compiling camps 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:
---
--- area = CampsData.getCampArea(campName)
---
--- This will return the working radius of the camp. It is preferable to
--- call the getter methods with the name of the camp rather than
--- retrieving the entire data record for the camp. This way your code
--- stays protected from variations in this module. These getter methods are
--- called with the plain-language display name of the camp, as spelled
--- in the game, including punctuation.
---
--- * longDescription = CampsData.getCampDescription(campName)
--- * constructionCategory = CampsData.getCampCategory(campName)
--- * sizeX, sizeY = CampsData.getCampSize(campName)
--- * requiredGoodID, stackSize = CampsData.getCampRequiredGood(campName, requirementIndex)
--- * timeSeconds = CampsData.getCampConstructionTime(campName)
--- * cityScore = CampsData.getCampCityScore(campName)
--- * isMovable = CampsData.isCampMovable(campName)
--- * isInitiallyEssential = CampsData.isCampInitiallyEssential(campName)
--- * radius = CampsData.getCampArea(campName)
--- * storageCapacity = CampsData.getCampStorage(campName)
--- * workplaces = CampsData.getCampNumberOfWorkplaces(campName)
--- * goodID = CampsData.getCampRecipeProduct(campName, recipeIndex)
--- * gradeStars, gatheringSeconds = CampsData.getCampRecipeStats(campName, recipeIndex)
--- * iconFilename = CampsData.getCampIcon(campName)
---
--- And the following getter methods are all called with the camp's ID.
--- You will have an ID instead of a display name when dealing with other data
--- like recipes, species, etc.
---
--- * name = CampsData.getCampNameByID(campID)
--- * iconFilename = CampsData.getCampIconByID(campID)
---
--- You can retrieve all camps that produce a certain good (with any grade of
--- efficiency) with the following getter:
---
--- campNamesTable = CampsData.getCampNamesWithRecipeProductID(productID)
---
--- There are methods to retrieve the lists of required goods, workplaces, and
--- recipes, but it is advised to instead use the getter methods
--- getCampRequiredGood, getCampNumberOfWorkplaces, and
--- getCampRecipe with an index desired, which is good for loops. If
--- you must get the tables, there are three "getAll" methods:
---
--- * requiredGoodsTable = CampsData.getAllCampRequiredGoods(campName)
--- * workplacesTable = CampsData.getAllCampWorkplaces(campName)
--- * recipesTable = CampsData.getAllCampRecipes(campName)
---
--- As a last resort, or if you need to transform the data structure, you can
--- call the method getAllDataForCamp(campName) or
--- getAllDataForCampByID(campID). These return a whole record
--- from the data table corresponding to the required display name or ID.
---
--- The data table for camps has the following structure:
---
--- campsTable = {
--- ["camp1_ID"] = {
--- ["id"] = "camp1_ID",
--- ["displayName"] = "Plain Language Name",
--- ["description"] = "A long string with some HTML entities too.",
--- ["category"] = "Construction toolbar category",
--- ["sizeX"] = 9, size in tiles
--- ["sizeY"] = 9, size in tiles
--- ["requiredGoods"] = {
--- [1] = { ["stackSize"] = 99, ["goodID"] = "good1_ID" },
--- [2] = { ["stackSize"] = 99, ["goodID"] = "good2_ID" },
--- [3] = { ... } or missing if fewer
--- },
--- ["constructionTime"] = 99, number of seconds
--- ["cityScore"] = 99, points?
--- ["movable"] = true or false, if it can be moved at any cost
--- ["initiallyEssential"] = true or false, if a new-game-starting blueprint
--- ["area"] = 99, tile radius
--- ["storage"] = 99, capacity
--- ["workplaces"] = {
--- [1] = "Any",
--- [2] = "Any",
--- [3] = "Any",
--- [4] = ... representing the number of workplaces, or missing if fewer
--- },
--- ["recipes"] = {
--- [1] = {
--- "goodID" = "good1_ID",
--- "grade" = 9, number of stars,
--- "gatheringTime" = 99, seconds,
--- }
--- [2] = { ... }
--- [3] = ... or missing if fewer
--- }
--- },
--- ["camp2_ID"] = {
--- ...
--- },
--- ["camp3_ID"] = {
--- ...
--- },
--- ...
--- }
---
--- @module CampsData
local CampsData = {}
--region Dependencies
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 campsTable
--- Supporting table, list of names table[i] = name.
local campsNames
--- Lookup map. Built once and reused on subsequent calls within this session,
--- like this: table[display name] = campID
local mapNamesToIDs
--- Lookup map. Built once and reused on subsequent calls within this session,
--- like this: table[goodID] = { campName1, campName2, ... }
local mapRecipeGoodIDsToCampNames
--endregion
--region Private constants
local GATHERER_HUTS_DATA_TEMPLATE_NAME = "Template:GathererHuts_csv"
local CAMPS_DATA_TEMPLATE_NAME = "Template:Camps_csv"
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_AREA = "area"
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_GRADE = "grade"
local INDEX_RECIPE_GATHERING_TIME = "gatheringTime"
local PATTERN_SPLIT_STACK_AND_ID = "(%d+)%s([%[%]%s%a]+)"
local PATTERN_CAPTURE_END_NUMBER = "Grade(%d)"
local WOODCUTTER_ID_WOOD = "[Mat Raw] Wood"
local WOODCUTTER_GRADE = 1
local WOODCUTTER_GATHERING_TIME = 2
--endregion
--region Private methods
---
--- Creates a new subtable containing the construction goods required for the
--- specified camp.
---
--- @param originalCamp table camp data record from which to make subtable
--- @param campsHeaderLookup table header lookup built from the CSV data
--- @return table subtable with the required construction goods
local function makeRequiredGoodsSubtable(originalCamp, campsHeaderLookup)
-- 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 = campsHeaderLookup[REQ_GOOD_HEADER_BASE_STRING .. "1"]
local requiredIndex2 = campsHeaderLookup[REQ_GOOD_HEADER_BASE_STRING .. "2"]
local requiredIndex3 = campsHeaderLookup[REQ_GOOD_HEADER_BASE_STRING .. "3"]
local number1, id1 = originalCamp[requiredIndex1]:match(PATTERN_SPLIT_STACK_AND_ID)
local number2, id2 = originalCamp[requiredIndex2]:match(PATTERN_SPLIT_STACK_AND_ID)
local number3, id3 = originalCamp[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
--- camp.
---
--- @param originalCamp table camp data record from which to make subtable
--- @param campsHeaderLookup table header lookup built from the CSV data
--- @return table subtable with the workplaces
local function makeWorkplacesSubtable(originalCamp, campsHeaderLookup)
-- A constant we'll need only within this function.
local WORKPLACE_HEADER_BASE_STRING = "workplace"
-- Copy the originals directly into a subtable.
local workplaceIndex1 = campsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "1"]
local workplaceIndex2 = campsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "2"]
local workplaceIndex3 = campsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "3"]
local workplaceIndex4 = campsHeaderLookup[WORKPLACE_HEADER_BASE_STRING .. "4"]
local workplace1 = originalCamp[workplaceIndex1]
local workplace2 = originalCamp[workplaceIndex2]
local workplace3 = originalCamp[workplaceIndex3]
local workplace4 = originalCamp[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
--- camp.
---
--- @param campName string the display name of the camp
--- @param originalCamp table camp data record from which to make subtable
--- @param campsHeaderLookup table header lookup built from the CSV data
--- @return table subtable with the recipe IDs
local function makeRecipesSubtable(campName, originalCamp, campsHeaderLookup)
-- A constant we'll need only within this function.
local MAX_RECIPES = 3
local LOOKUP_RECIPE_BASE_STRING = "recipe"
local LOOKUP_GOOD_BASE_STRING = "SeekedDeposits"
local LOOKUP_GRADE_BASE_STRING = "Grade"
local LOOKUP_GATHERING_TIME_BASE_STRING = "GatheringTime"
if not mapRecipeGoodIDsToCampNames then
mapRecipeGoodIDsToCampNames = {}
end
-- Copy the originals directly into a subtable.
local recipes = {}
for i = 1, MAX_RECIPES do
-- A subtable for this recipe
newRecipe = {}
local originalGoodIndex = campsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. i
.. LOOKUP_GOOD_BASE_STRING]
local originalGradeIndex = campsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. i
.. LOOKUP_GRADE_BASE_STRING]
local originalGatheringTimeIndex = campsHeaderLookup[LOOKUP_RECIPE_BASE_STRING .. i
.. LOOKUP_GATHERING_TIME_BASE_STRING]
local originalGoodID = originalCamp[originalGoodIndex]
-- Skip blank recipes.
if originalGoodID and originalGoodID ~= "" then
newRecipe[INDEX_RECIPE_GOOD_ID] = originalGoodID
newRecipe[INDEX_RECIPE_GRADE] = tonumber(originalCamp[originalGradeIndex]:match(PATTERN_CAPTURE_END_NUMBER))
newRecipe[INDEX_RECIPE_GATHERING_TIME] = tonumber(originalCamp[originalGatheringTimeIndex])
table.insert(recipes,newRecipe)
if not mapRecipeGoodIDsToCampNames[originalGoodID] then
mapRecipeGoodIDsToCampNames[originalGoodID] = {}
end
table.insert(mapRecipeGoodIDsToCampNames[originalGoodID], campName)
end
end
return recipes
end
---
--- Transforms the originalCampsTable 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 originalCampsTable table of CSV-based data, with header row, data rows
--- @param campsHeaderLookup table lookup table of headers to get indexes
--- @return table better structured with IDs as keys
local function restructureGathererHuts(originalCampsTable, campsHeaderLookup)
-- 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_AREA = 14
local INDEX_ORIGINAL_STORAGE = 15
mapNamesToIDs = {}
campsNames = {}
local newCampsTable = {}
for _, originalCamp in ipairs(originalCampsTable[DATA_ROWS]) do
-- Copy over the content, mapping unhelpful indexes into headers keys.
local newCamp = {}
newCamp[INDEX_ID] = originalCamp[INDEX_ORIGINAL_ID]
newCamp[INDEX_NAME] = originalCamp[INDEX_ORIGINAL_NAME]
newCamp[INDEX_DESCRIPTION] = originalCamp[INDEX_ORIGINAL_DESCRIPTION]
newCamp[INDEX_CATEGORY] = originalCamp[INDEX_ORIGINAL_CATEGORY]
newCamp[INDEX_SIZE_X] = tonumber(originalCamp[INDEX_ORIGINAL_SIZE_X])
newCamp[INDEX_SIZE_Y] = tonumber(originalCamp[INDEX_ORIGINAL_SIZE_Y])
newCamp[INDEX_CITY_SCORE] = tonumber(originalCamp[INDEX_ORIGINAL_CITY_SCORE])
newCamp[INDEX_MOVABLE] = originalCamp[INDEX_ORIGINAL_MOVABLE] == "True"
newCamp[INDEX_INITIALLY_ESSENTIAL] = originalCamp[INDEX_ORIGINAL_ESSENTIAL] == "True"
newCamp[INDEX_AREA] = tonumber(originalCamp[INDEX_ORIGINAL_AREA])
newCamp[INDEX_STORAGE] = tonumber(originalCamp[INDEX_ORIGINAL_STORAGE])
newCamp[INDEX_CONSTRUCTION_TIME] = tonumber(originalCamp[INDEX_ORIGINAL_CONSTRUCTION_TIME])
newCamp[INDEX_REQUIRED_GOODS] = makeRequiredGoodsSubtable(originalCamp, campsHeaderLookup)
newCamp[INDEX_WORKPLACES] = makeWorkplacesSubtable(originalCamp, campsHeaderLookup)
newCamp[INDEX_RECIPES] = makeRecipesSubtable(newCamp[INDEX_NAME], originalCamp, campsHeaderLookup)
newCampsTable[ newCamp[INDEX_ID] ] = newCamp
table.insert(campsNames, newCamp[INDEX_NAME])
-- Also populate the map for looking up IDs with display names
mapNamesToIDs[ newCamp[INDEX_NAME] ] = newCamp[INDEX_ID]
end
return newCampsTable
end
---
--- Creates a row for the only record in this table, the woodcutters' camp, in
--- a way that matches the other gathering camps or huts.
---
---@param originalCampsTable table the one-record table
---@param campsHeaderLookup table lookup table of headers to get indexes
---@return table one record to add to campsTable
local function addWoodcuttersCampRow(originalCampsTable, campsHeaderLookup)
-- 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_AREA = 14
local INDEX_ORIGINAL_STORAGE = 15
-- The woodcutters' camp is at index 1 in the data rows.
local originalCamp = originalCampsTable[DATA_ROWS][1]
local newCamp = {}
newCamp[INDEX_ID] = originalCamp[INDEX_ORIGINAL_ID]
newCamp[INDEX_NAME] = originalCamp[INDEX_ORIGINAL_NAME]
newCamp[INDEX_DESCRIPTION] = originalCamp[INDEX_ORIGINAL_DESCRIPTION]
newCamp[INDEX_CATEGORY] = originalCamp[INDEX_ORIGINAL_CATEGORY]
newCamp[INDEX_SIZE_X] = tonumber(originalCamp[INDEX_ORIGINAL_SIZE_X])
newCamp[INDEX_SIZE_Y] = tonumber(originalCamp[INDEX_ORIGINAL_SIZE_Y])
newCamp[INDEX_CONSTRUCTION_TIME] = tonumber(originalCamp[INDEX_ORIGINAL_CONSTRUCTION_TIME])
newCamp[INDEX_CITY_SCORE] = tonumber(originalCamp[INDEX_ORIGINAL_CITY_SCORE])
newCamp[INDEX_MOVABLE] = originalCamp[INDEX_ORIGINAL_MOVABLE]
newCamp[INDEX_INITIALLY_ESSENTIAL] = originalCamp[INDEX_ORIGINAL_ESSENTIAL]
newCamp[INDEX_AREA] = tonumber(originalCamp[INDEX_ORIGINAL_AREA])
newCamp[INDEX_STORAGE] = tonumber(originalCamp[INDEX_ORIGINAL_STORAGE])
newCamp[INDEX_REQUIRED_GOODS] = makeRequiredGoodsSubtable(originalCamp, campsHeaderLookup)
newCamp[INDEX_WORKPLACES] = makeWorkplacesSubtable(originalCamp, campsHeaderLookup)
-- Create a subtable of one recipe. This part of the record does not exist
-- in the data and needs to be fabricated to match the other camps.
local oneRecipe = {}
local recipe = {}
recipe[INDEX_RECIPE_GOOD_ID] = WOODCUTTER_ID_WOOD
recipe[INDEX_RECIPE_GRADE] = WOODCUTTER_GRADE
recipe[INDEX_RECIPE_GATHERING_TIME] = WOODCUTTER_GATHERING_TIME
table.insert(oneRecipe, recipe)
newCamp[INDEX_RECIPES] = oneRecipe
campsTable[newCamp[INDEX_ID]] = newCamp
mapNamesToIDs[newCamp[INDEX_NAME]] = newCamp[INDEX_ID]
-- This is the only camp that harvests wood.
mapRecipeGoodIDsToCampNames[WOODCUTTER_ID_WOOD] = {}
table.insert(mapRecipeGoodIDsToCampNames[WOODCUTTER_ID_WOOD], newCamp[INDEX_NAME])
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 originalGathererHutsTable, gathererHutsHeaderLookup = CsvUtils.extractTables(GATHERER_HUTS_DATA_TEMPLATE_NAME)
-- Now restructure to be more conducive.
campsTable = restructureGathererHuts(originalGathererHutsTable, gathererHutsHeaderLookup)
-- Now append the woodcutters' camp and fake recipe records for its
local originalCampsTable, campsHeaderLookup = CsvUtils.extractTables(CAMPS_DATA_TEMPLATE_NAME)
-- Now restructure and append a row for the camp, since there is only one record right now.
addWoodcuttersCampRow(originalCampsTable, campsHeaderLookup)
end
local function load()
if not campsTable then
loadData()
end
end
---
--- Uses the display name, which people are more familiar with, to find the
--- encoded ID of the camp. Useful for retrieving the data that is
--- indexed by ID.
---
--- Returns nil if the camp with the specified name is not found.
---
--- @param displayName string plain-language name of the camp to find
--- @return string ID of the camp found, or nil if not found
local function findCampIDByName(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 camp's name: " .. displayName .. ".")
end
if not campsTable then
loadData()
end
return mapNamesToIDs[displayName]
end
--endregion
--region Public methods
--- Retrieve the whole table of data for the specified camp. 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 camp cannot be found.
---
--- @param campID string ID of the camp
--- @return table containing the data with key-value pairs, or nil if not found
function CampsData.getAllDataForCampByID(campID)
-- At runtime, this should never be nil or empty.
if not campID or campID == "" then
error("Parameter is nil or empty for the camp's ID.")
end
if not campsTable then
loadData()
end
return campsTable[campID]
end
--- Retrieve the whole table of data for the specified camp. 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 camp cannot be found.
---
--- @param displayName string plain language name of the camp
--- @return table containing the data with key-value pairs, or nil if not found
function CampsData.getAllDataForCamp(displayName)
-- At runtime, this should never be nil or empty.
if not displayName or displayName == "" then
error("Parameter is nil or empty for the camp's name.")
end
if not campsTable then
loadData()
end
local campID = findCampIDByName(displayName)
if not campID then
return nil
end
return campsTable[campID]
end
---
--- Retrieves the ID for the camp specified by its plain language
--- display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return string the ID of the specified camp
function CampsData.getCampID(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_ID]
end
---
--- Retrieves the description for the camp specified by its plain
--- language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return string the in-game description of the specified camp
function CampsData.getCampDescription(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_DESCRIPTION]
end
---
--- Retrieves the construction toolbar category for the camp specified
--- by its plain language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return string the category of the specified camp
function CampsData.getCampCategory(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_CATEGORY]
end
---
--- Retrieves the 2x2 size for the camp specified by its plain language
--- display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return number the X-size of the camp
---@return number the Y-size of the camp
function CampsData.getCampSize(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_SIZE_X], camp[INDEX_SIZE_Y]
end
---
--- Retrieves the goods required for construction for the camp 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 camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return table of required goods
function CampsData.getAllCampRequiredGoods(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_REQUIRED_GOODS]
end
---
--- Retrieves the specified required construction good for the camp
--- specified by its plain language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@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 CampsData.getCampRequiredGood(displayName, requirementIndex)
local requiredGoods = CampsData.getAllCampRequiredGoods(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 camp specified by its plain
--- language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return number of seconds it takes to construct the camp
function CampsData.getCampConstructionTime(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_CONSTRUCTION_TIME]
end
---
--- Retrieves the city score awarded for the camp specified by its plain
--- language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return number of points for city score from having the camp
function CampsData.getCampCityScore(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_CITY_SCORE]
end
---
--- Retrieves whether the camp specified by its plain language display
--- name can be moved, at any cost.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return boolean of whether the camp can be moved
function CampsData.isCampMovable(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_MOVABLE]
end
---
--- Retrieves whether the camp specified by its plain language display
--- name has an essential starting blueprint for a new game profile.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return boolean of whether the camp's blueprint is essential
function CampsData.isCampInitiallyEssential(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_INITIALLY_ESSENTIAL]
end
---
--- Retrieves the gathering area for the camp specified by its plain
--- language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return number of tiles of gathering radius
function CampsData.getCampArea(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_AREA]
end
---
--- Retrieves the storage capacity of the camp specified by its plain
--- language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return number of storage capacity at the camp
function CampsData.getCampStorage(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_STORAGE]
end
---
--- Retrieves the table of workplaces for the camp specified by its
--- plain language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return table of workplaces
function CampsData.getAllCampWorkplaces(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_WORKPLACES]
end
---
--- Retrieves the number of workplaces for the camp specified by its
--- plain language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return number of workplaces
function CampsData.getCampNumberOfWorkplaces(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return #camp[INDEX_WORKPLACES]
end
---
--- Retrieves the table of recipes for the camp 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 camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return table of recipe IDs
function CampsData.getAllCampRecipes(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
return camp[INDEX_RECIPES]
end
---
--- Retrieves the number of recipes for the camp specified by its
--- plain language display name, in a table that looks like this:
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return number of recipes at the camp
function CampsData.getCampNumberOfRecipes(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return 0
end
local recipes = camp[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 camp specified by its plain language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@param recipeIndex number the index of the recipe ID
---@return string the ID of the good produced by the specified recipe
function CampsData.getCampRecipeProduct(displayName, recipeIndex)
local recipes = CampsData.getAllCampRecipes(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]
end
---
--- Retrieves the other stats for specified recipe at the camp specified by
--- its plain language display name: the efficiency grade and the gathering
--- time.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@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 CampsData.getCampRecipeStats(displayName, recipeIndex)
local recipes = CampsData.getAllCampRecipes(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_GATHERING_TIME]
end
---
--- Retrieves the icon filename for the camp specified by its plain
--- language display name.
---
--- Returns nil if the camp named was not found.
---
---@param displayName string the plain language name of the camp
---@return string the camp's icon filename, including the extension
function CampsData.getCampIcon(displayName)
local camp = CampsData.getAllDataForCamp(displayName)
if not camp then
return nil
end
-- the base string of the icon is the ID. It has to be not nil to
-- concatenate
if camp[INDEX_ID] then
return camp[INDEX_ID] .. "_icon.png"
else
return nil
end
end
---
--- Retrieves the plain language display name for the camp specified by
--- its ID.
---
--- Returns nil if the camp named was not found.
---
---@param campID string the ID of the camp
---@return string the camp's name as seen in-game
function CampsData.getCampNameByID(campID)
local camp = CampsData.getAllDataForCampByID(campID)
if not camp then
return nil
end
return camp[INDEX_NAME]
end
---
--- Retrieves the icon filename for the the camp specified by its ID.
---
--- Returns nil if the camp named was not found.
---
---@param campID string the ID of the camp
---@return string the camp's icon filename, including the extension
function CampsData.getCampIconByID(campID)
local camp = CampsData.getAllDataForCampByID(campID)
if not camp then
return nil
end
-- the base string of the icon is the ID. It has to be not nil to
-- concatenate
if camp[INDEX_ID] then
return camp[INDEX_ID] .. "_icon.png"
else
return nil
end
end
---
--- Retrieve all display names of camps that have a recipe that produces the
--- specified product ID.
---
---@param productID string the ID of the good to produce
---@return table of camp names that produce the specified good
function CampsData.getCampNamesWithRecipeProductID(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 campsTable then
loadData()
end
return mapRecipeGoodIDsToCampNames[productID]
end
---
--- Retrieves the name of the camp at the specified index.
---
---@param index number index
---@return string name of the building at the specified index
function CampsData.getCampNameFromDatabase(index)
if not index then
return nil
end
if not campsTable then
loadData()
end
return campsNames[index]
end
---
--- Returns the number of buildings that can be retrieved from this
--- module's database.
---
---@return number of records
function CampsData.getNumberOfCampsInDatabase()
if not campsTable then
loadData()
end
return #campsNames
end
--endregion
--region Public Building interface
-- getCategory
-- getCityScore
-- getConstructionCosts (as [goodName] = stack size)
-- getConstructionTime
-- getDescription
-- getIcon
-- getMovable
-- getName
-- getNumberOfWorkplaces
-- getSize (as "X x Y")
-- getStorage
function CampsData.getCategory(id)
load()
return campsTable[id] ~= nil and campsTable[id][INDEX_CATEGORY]
end
function CampsData.getCityScore(id)
load()
return campsTable[id] ~= nil and campsTable[id][INDEX_CITY_SCORE]
end
function CampsData.getConstructionCosts(id)
load()
GoodsData = require("Module:GoodsData")
camp = campsTable[id]
if not camp then
return false
end
local constructionCosts = {}
for _, stacks in ipairs(camp[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 CampsData.getConstructionTime(id)
load()
return campsTable[id] ~= nil and campsTable[id][INDEX_CONSTRUCTION_TIME]
end
function CampsData.getDescription(id)
load()
return campsTable[id] ~= nil and campsTable[id][INDEX_DESCRIPTION]
end
function CampsData.getIcon(id)
load()
return campsTable[id] ~= nil and id .. "_icon.png"
end
function CampsData.isMovable(id)
load()
return campsTable[id] ~= nil and campsTable[id][INDEX_MOVABLE]
end
function CampsData.getName(id)
load()
return campsTable[id] ~= nil and campsTable[id][INDEX_NAME]
end
function CampsData.getNumberOfWorkplaces(id)
load()
return campsTable[id] ~= nil and #campsTable[id][INDEX_WORKPLACES]
end
function CampsData.getSize(id)
load()
camp = campsTable[id]
if not camp then
return false
end
return camp[INDEX_SIZE_X] .. " × " .. camp[INDEX_SIZE_Y]
end
function CampsData.getStorage(id)
load()
return campsTable[id] ~= nil and campsTable[id][INDEX_STORAGE]
end
--endregion
return CampsData


