Module:GladeResourcesController: Difference between revisions
From Against the Storm Official Wiki
Adding caption generation; adding comments |
Anteprefix (talk | contribs) Remove unneeded suppressTrees from render view functions |
||
| (21 intermediate revisions by 2 users not shown) | |||
| Line 8: | Line 8: | ||
local GladeResourcesData = require("Module:GladeResourcesData") | local GladeResourcesData = require("Module:GladeResourcesData") | ||
local GoodsData = require("Module:GoodsData") | local GoodsData = require("Module:GoodsData") | ||
local BiomesData = require("Module:BiomesData") | |||
local BuildingDataProxy = require("Module:BuildingDataProxy") | |||
local DataModelsWithGladeResourcesRecipes = { | local DataModelsWithGladeResourcesRecipes = { | ||
require("Module:MinesData"), | require("Module:MinesData"), | ||
require("Module:CampsData"), | require("Module:CampsData"), | ||
require("Module:FishingData"), | require("Module:FishingData"), | ||
require("Module:GatheringData"), | require("Module:GatheringData"), | ||
| Line 37: | Line 38: | ||
local VIEW_ARG_DEPOSIT = "deposit" | local VIEW_ARG_DEPOSIT = "deposit" | ||
local VIEW_ARG_BUILDING = "building" | |||
local VIEW_ARG_PRODUCT = "primary" | local VIEW_ARG_PRODUCT = "primary" | ||
local VIEW_ARG_BONUS_1 = "bonus1" | local VIEW_ARG_BONUS_1 = "bonus1" | ||
| Line 43: | Line 46: | ||
local VIEW_ARG_BONUS_4 = "bonus4" | local VIEW_ARG_BONUS_4 = "bonus4" | ||
local VIEW_ARG_SKIP_BIOMES = "skip_biomes" | |||
local SKIP_FLAG = "skip" | |||
local VIEW_ARG_BIOME_PREFIX = "biome" | |||
local VIEW_ARG_FORCE_DEFAULT = "default" | |||
--endregion | --endregion | ||
| Line 49: | Line 58: | ||
--region Localization string constants | --region Localization string constants | ||
local ERROR_MESSAGE_PRODUCT_AND_BONUS_BUT_NOT_MATCH = "When | local ERROR_MESSAGE_PRODUCT_AND_BONUS_BUT_NOT_MATCH = "When searching for a good as both a main and bonus resource, the parameters must match" | ||
local ERROR_MESSAGE_NO_PARAMETERS_GIVEN = "You must specify the name of a product, a bonus resource, or a building—and as it's spelled in the game" | |||
--endregion | --endregion | ||
| Line 58: | Line 68: | ||
local frame | local frame | ||
local biomesIDs | |||
--endregion | --endregion | ||
| Line 66: | Line 78: | ||
---@private | ---@private | ||
-----Goes through the provided list of deposits and finds the maximum number of bonuses, so that the view can be standardized. | ---Sorts given the function provided. | ||
--- | |||
---@param arrayToSort table | |||
---@param comparisonFunction function | |||
---@return table the sorted array | |||
local function sortArrayWith(arrayToSort, comparisonFunction) | |||
table.sort(arrayToSort, function(a, b) | |||
return comparisonFunction(a) < comparisonFunction(b) | |||
end) | |||
return arrayToSort | |||
end | |||
---@private | |||
---Uses the specified building ID to go through applicable data models, assembling a list of possible deposits, filtered by the grade of the building. | |||
--- | |||
---@param buildingID string a building's ID | |||
---@return table array of deposit records retrieved from GladeResourcesData | |||
local function assembleDepositsFromBuilding(buildingID, suppressTrees) | |||
local depositsList = {} | |||
local isWoodcutter = buildingID == "Woodcutters Camp" | |||
if isWoodcutter then | |||
local newList = GladeResourcesData.getAllDepositsWhereDepositIsTree() | |||
for _, deposit in ipairs(newList) do | |||
table.insert(depositsList, deposit) | |||
end | |||
else | |||
--This isn't as expensive as it looks, because typically only one data model will return something. However, we don't know which it will be in advance. | |||
for _, dataModel in ipairs(DataModelsWithGladeResourcesRecipes) do | |||
local recipeDataArray = dataModel:getIDsAndRecipesWhereBuildingID(buildingID) | |||
if #recipeDataArray > 0 then | |||
local products = {} | |||
for _, recipeData in ipairs(recipeDataArray) do | |||
local id = dataModel:getRecipeProductID(recipeData) | |||
products[id] = dataModel:getRecipeGrade(recipeData) | |||
end | |||
for id, grade in pairs(products) do | |||
local newList = GladeResourcesData.getAllDepositsWherePrimaryResourceAndGrade(id, grade, suppressTrees) | |||
for _, deposit in ipairs(newList) do | |||
table.insert(depositsList, deposit) | |||
end | |||
end | |||
end | |||
end | |||
end | |||
return depositsList | |||
end | |||
---@private | |||
---Looks up the building ID from the building data models for the one that can exploit the given deposit. | |||
--- | |||
---@param deposit table record from GladeResourcesData | |||
---@return string, string building display name, icon filename | |||
local function getBuildingForDeposit(deposit) | |||
local productID = GladeResourcesData.getDepositPrimaryProduct(deposit) | |||
local isTree = GladeResourcesData.isDepositTree(deposit) | |||
--This isn't as expensive as it looks, because typically only one data model will return something. However, we don't know which it will be in advance. | |||
for _, dataModel in ipairs(DataModelsWithGladeResourcesRecipes) do | |||
local recipeDataArray = dataModel:getIDsAndRecipesWhereProductID(productID) | |||
if #recipeDataArray > 0 then | |||
for i = 1, #recipeDataArray do | |||
local id = dataModel:getRecipeBuildingID(recipeDataArray[i]) | |||
if (isTree or dataModel:getName(id) ~= "Woodcutters' Camp") then | |||
local name = dataModel:getName(id) | |||
local icon = dataModel:getIcon(id) | |||
return name, icon | |||
end | |||
end | |||
end | |||
end | |||
return "" | |||
end | |||
---@private | |||
---Checks whether the provided list of deposits can be harvested by a single building. If so, returns that building's name and icon (for use in a building link). Otherwise, returns nil. | |||
--- | |||
---@param depositsList table array of deposit records retrieved from GladeResourcesData | |||
---@return string, string building name and icon, if there is only one, nil if none or more than one | |||
local function checkOnlyOneBuildingForAllDeposits(depositsList) | |||
local buildings = {} | |||
for _, deposit in ipairs(depositsList) do | |||
local name, icon = getBuildingForDeposit(deposit) | |||
buildings[name] = icon | |||
end | |||
local firstBuildingName, firstBuildingIcon = next(buildings) | |||
if firstBuildingName and not next(buildings, firstBuildingName) then | |||
return firstBuildingName, firstBuildingIcon | |||
else | |||
return nil | |||
end | |||
end | |||
---@private | |||
---Goes through the provided list of deposits and finds the maximum number of bonuses, so that the view can be standardized. | |||
--- | --- | ||
---@param depositsList table array of deposit records retrieved from GladeResourcesData | ---@param depositsList table array of deposit records retrieved from GladeResourcesData | ||
| Line 79: | Line 200: | ||
end | end | ||
return maxFound | return maxFound | ||
end | |||
---@private | |||
---Tallies up the categories and concatenates them. Also makes them plural if there are more than one of a particular category. | |||
--- | |||
---@param depositsList table | |||
---@return string the categories among the deposits | |||
local function writeCaptionForDeposits(depositsList) | |||
local categories = {} | |||
for _, deposit in ipairs(depositsList) do | |||
local category = GladeResourcesData.getDepositCategory(deposit) | |||
if not categories[category] then | |||
categories[category] = 1 | |||
else | |||
categories[category] = categories[category] + 1 | |||
end | |||
end | |||
local caption = "" | |||
for category, categoryCount in pairs(categories) do | |||
if categoryCount > 1 then | |||
category = category .. "s" | |||
end | |||
if caption == "" then | |||
caption = category | |||
else | |||
caption = caption .. " & " .. category | |||
end | |||
end | |||
return caption | |||
end | |||
---@private | |||
---Tallies up the descriptions. If there's exactly one, it returns that description, otherwise it returns blank since they can't be combined (and to save space). | |||
--- | |||
---@param depositsList table | |||
---@return string the one or shared description in the list, or "" if they are varied | |||
local function writeDescriptionForDeposits(depositsList) | |||
--Heuristic: If there are more then 2, then there's no way all the descriptions match. | |||
if #depositsList > 2 then | |||
return "" | |||
end | |||
local descriptions = {} | |||
for _, deposit in ipairs(depositsList) do | |||
local desc = GladeResourcesData.getDepositDescription(deposit) | |||
descriptions[desc] = true | |||
end | |||
--Use exactly one description unless there are more, in which case return empty. | |||
local firstDescription = next(descriptions) | |||
if firstDescription and not next(descriptions, firstDescription) then | |||
return firstDescription | |||
else | |||
return "" | |||
end | |||
end | |||
local function writeBiomePartialLink(biomeID) | |||
local icon = BiomesData.getIcon(biomeID) .. ".png" | |||
local pageName = BiomesData.getName(biomeID) | |||
return "File:" .. icon .. "|" .. pageName | |||
end | end | ||
| Line 88: | Line 280: | ||
---@param depositsList table list of deposits from GladeResourcesData | ---@param depositsList table list of deposits from GladeResourcesData | ||
---@param maxBonuses number slots for bonus resources | ---@param maxBonuses number slots for bonus resources | ||
---@param | ---@param title string title for the whole panel | ||
---@param buildingID string an ID for a building specified, if any | |||
---@param skipFlagForBiomes string flag for skipping biomes columns | |||
---@param displayOverride string override code, if any | ---@param displayOverride string override code, if any | ||
---@return string wiki markup | ---@return string wiki markup | ||
local function renderViewStart(depositsList, maxBonuses, | local function renderViewStart(depositsList, maxBonuses, title, buildingID, skipFlagForBiomes, displayOverride) | ||
displayOverride = displayOverride --TODO write the other view modes | displayOverride = displayOverride --TODO write the other view modes | ||
local skipBuildingColumn = "" | |||
if buildingID then | |||
skipBuildingColumn = "skip" | |||
else | |||
local buildingName = checkOnlyOneBuildingForAllDeposits(depositsList) | |||
if buildingName then | |||
skipBuildingColumn = "skip" | |||
end | |||
end | |||
local caption = writeCaptionForDeposits(depositsList) | |||
local numDeposits = #depositsList | local numDeposits = #depositsList | ||
--Special case where we swap the title out for the name of the one deposit and show the description | |||
local description = "" | |||
if numDeposits == 1 and not displayOverride == VIEW_ARG_FORCE_DEFAULT then | |||
title = GladeResourcesData.getDepositName(depositsList[1]) | |||
description = writeDescriptionForDeposits(depositsList) | |||
end | |||
local viewArgs = { | |||
[VIEW_ARG_HEAD] = title, | |||
[VIEW_ARG_DESC] = description, | |||
[VIEW_ARG_CAPTION] = caption, | |||
[VIEW_ARG_NUM_DEPOSITS] = numDeposits, | |||
[VIEW_ARG_MAX_BONUSES] = maxBonuses, | |||
[VIEW_ARG_BUILDING] = skipBuildingColumn, | |||
[VIEW_ARG_SKIP_BIOMES] = skipFlagForBiomes, | |||
} | |||
if skipFlagForBiomes ~= SKIP_FLAG then | |||
for i, biomeID in ipairs(biomesIDs) do | |||
local biomeArg = VIEW_ARG_BIOME_PREFIX .. i | |||
viewArgs[biomeArg] = writeBiomePartialLink(biomeID) | |||
end | |||
end | |||
local wikiMarkup = frame:expandTemplate{ | local wikiMarkup = frame:expandTemplate{ | ||
title = VIEW_TEMPLATE_START, | title = VIEW_TEMPLATE_START, | ||
args = | args = viewArgs, | ||
} | } | ||
| Line 129: | Line 353: | ||
local wikiMarkup = "" | local wikiMarkup = "" | ||
if amount > 1 then | if amount > 1 then | ||
wikiMarkup = wikiMarkup .. "''" .. amount .. "'' " | wikiMarkup = wikiMarkup .. "'''" .. amount .. "''' " | ||
end | end | ||
| Line 175: | Line 399: | ||
title = VIEW_RESOURCE_LINK, | title = VIEW_RESOURCE_LINK, | ||
args = { | args = { | ||
["name"] = productName, | |||
["iconfilename"] = iconFilename, | |||
["iconsize"] = "medium", | ["iconsize"] = "medium", | ||
["display"] = "notext", | ["display"] = "notext", | ||
} | } | ||
} | } | ||
wikiMarkup = wikiMarkup .. "'''" .. chance*100 .. "%'''" | wikiMarkup = wikiMarkup .. "<br>'''" .. chance*100 .. "%'''" | ||
return wikiMarkup | return wikiMarkup | ||
end | end | ||
---@private | |||
---Looks up the building that can get the specified deposit for the view. | |||
--- | |||
---@param deposit table from GladeResourceData | |||
---@param displayOverride string override code, if any | |||
---@return string wiki markup | |||
local function renderBuilding(deposit, displayOverride) | |||
displayOverride = displayOverride --TODO write the other display modes | |||
local buildingName, buildingIcon = getBuildingForDeposit(deposit) | |||
local wikiMarkup = frame:expandTemplate{ | |||
title = VIEW_BUILDING_LINK, | |||
args = { | |||
["name"] = buildingName, | |||
["iconfilename"] = buildingIcon, | |||
["iconsize"] = "large", | |||
["display"] = "notext" | |||
} | |||
} | |||
return wikiMarkup | |||
end | |||
---@private | ---@private | ||
-----Makes a row for one deposit. | ---Used when a building is specified or there's just one row. | ||
--- | |||
---@param buildingID string | |||
---@return string wiki markup | |||
local function renderBottomBuildingLink(buildingID, buildingName, buildingIcon) | |||
if buildingID then | |||
buildingName = BuildingDataProxy.getName(buildingID) | |||
buildingIcon = BuildingDataProxy.getIcon(buildingID) | |||
end | |||
local wikiMarkup = frame:expandTemplate{ | |||
title = VIEW_BUILDING_LINK, | |||
args = { | |||
["name"] = buildingName, | |||
["iconfilename"] = buildingIcon, | |||
["iconsize"] = "huge" | |||
} | |||
} | |||
return wikiMarkup | |||
end | |||
---@private | |||
---Makes a row for one deposit. If the buildingID is given, skips showing it, because it means it's factored out of the rows. | |||
--- | --- | ||
---@param deposit table from GladeResourceData | ---@param deposit table from GladeResourceData | ||
---@param numDeposits number total number of deposits | |||
---@param maxBonuses number slots for bonus resources | ---@param maxBonuses number slots for bonus resources | ||
---@param buildingID string a specified buildingID, if any | |||
---@param isSkippingBiomes string flag for skipping biomes columns | |||
---@param displayOverride string override code, if any | ---@param displayOverride string override code, if any | ||
---@return string wiki markup | ---@return string wiki markup | ||
local function renderViewOneRow(deposit, maxBonuses, displayOverride) | local function renderViewOneRow(deposit, numDeposits, maxBonuses, buildingID, isSkippingBiomes, displayOverride) | ||
displayOverride = displayOverride --TODO write the other display modes | displayOverride = displayOverride --TODO write the other display modes | ||
--Special case where we take out the name and building icon when there's just one deposit or it's all harvestable by one building. | |||
local depositName = "" | |||
if numDeposits > 1 then | |||
depositName = GladeResourcesData.getDepositName(deposit) | |||
end | |||
local buildingLink = "" | |||
if not buildingID then | |||
buildingLink = renderBuilding(deposit, displayOverride) | |||
end | |||
local viewArgs = { | local viewArgs = { | ||
[VIEW_ARG_DEPOSIT] = | [VIEW_ARG_DEPOSIT] = depositName, | ||
[VIEW_ARG_BUILDING] = buildingLink, | |||
[VIEW_ARG_CHARGES] = GladeResourcesData.getDepositCharges(deposit), | [VIEW_ARG_CHARGES] = GladeResourcesData.getDepositCharges(deposit), | ||
[VIEW_ARG_PRODUCT] = renderProduct(deposit, displayOverride), | [VIEW_ARG_PRODUCT] = renderProduct(deposit, displayOverride), | ||
| Line 209: | Line 498: | ||
[VIEW_ARG_BONUS_3] = renderBonus(deposit, 3, displayOverride), | [VIEW_ARG_BONUS_3] = renderBonus(deposit, 3, displayOverride), | ||
[VIEW_ARG_BONUS_4] = renderBonus(deposit, 4, displayOverride), | [VIEW_ARG_BONUS_4] = renderBonus(deposit, 4, displayOverride), | ||
[VIEW_ARG_SKIP_BIOMES] = isSkippingBiomes, | |||
} | } | ||
local depositID = GladeResourcesData.getDepositID(deposit) | |||
if isSkippingBiomes ~= SKIP_FLAG then | |||
for i, biomeID in ipairs(biomesIDs) do | |||
local biomeArg = VIEW_ARG_BIOME_PREFIX .. i | |||
local isInBiome = BiomesData.isNodeOfAnyTypeInBiome(depositID, biomeID) | |||
local biomePartialLink = writeBiomePartialLink(biomeID) | |||
viewArgs[biomeArg] = isInBiome and biomePartialLink or "" | |||
end | |||
end | |||
return frame:expandTemplate{ | return frame:expandTemplate{ | ||
| Line 224: | Line 524: | ||
---@param depositsList table list of deposits from GladeResourcesData | ---@param depositsList table list of deposits from GladeResourcesData | ||
---@param maxBonuses number slots for bonus resources | ---@param maxBonuses number slots for bonus resources | ||
---@param buildingID string an ID for a building specified, if any | |||
---@param skipFlagForBiomes string flag for skipping biomes columns | |||
---@param displayOverride string override code, if any | ---@param displayOverride string override code, if any | ||
---@return string wiki markup | ---@return string wiki markup | ||
local function renderViewAllRows(depositsList, maxBonuses, displayOverride) | local function renderViewAllRows(depositsList, maxBonuses, buildingID, skipFlagForBiomes, displayOverride) | ||
local numDeposits = #depositsList | |||
-- Factor out a single building from the rows. | |||
if not buildingID then | |||
local buildingName = checkOnlyOneBuildingForAllDeposits(depositsList) | |||
if buildingName then | |||
buildingID = BuildingDataProxy.getID(buildingName) | |||
end | |||
end | |||
local wikiMarkup = "" | local wikiMarkup = "" | ||
for _, deposit in ipairs(depositsList) do | for _, deposit in ipairs(depositsList) do | ||
wikiMarkup = wikiMarkup .. "\n" | wikiMarkup = wikiMarkup .. "\n" | ||
wikiMarkup = wikiMarkup .. renderViewOneRow(deposit, maxBonuses, displayOverride) | wikiMarkup = wikiMarkup .. renderViewOneRow(deposit, numDeposits, maxBonuses, buildingID, skipFlagForBiomes, displayOverride) | ||
end | end | ||
| Line 242: | Line 554: | ||
---Closes out the view, based on the display override or lack thereof. Returns whatever else needs to be appended to do so. | ---Closes out the view, based on the display override or lack thereof. Returns whatever else needs to be appended to do so. | ||
--- | --- | ||
---@param depositsList table list of deposits from GladeResourcesData | |||
---@param buildingID string an ID for a building specified, if any | |||
---@param displayOverride string override code, if any | ---@param displayOverride string override code, if any | ||
---@return string wiki markup | ---@return string wiki markup | ||
local function renderViewEnd(displayOverride) | local function renderViewEnd(depositsList, buildingID, displayOverride) | ||
displayOverride = displayOverride --TODO write the other display modes | displayOverride = displayOverride --TODO write the other display modes | ||
local | local numDeposits = #depositsList | ||
local | local buildingLink = "" | ||
if numDeposits > 0 then | |||
if buildingID then | |||
buildingLink = renderBottomBuildingLink(buildingID) | |||
if | |||
else | else | ||
local buildingName, buildingIcon = checkOnlyOneBuildingForAllDeposits(depositsList) | |||
if buildingName and buildingIcon then | |||
buildingLink = renderBottomBuildingLink(nil, buildingName, buildingIcon) | |||
end | |||
end | end | ||
end | end | ||
local | local wikiMarkup = "" | ||
wikiMarkup = wikiMarkup .. frame:expandTemplate{ | |||
title = VIEW_TEMPLATE_END, | |||
args = { | |||
["numdeposits"] = numDeposits, | |||
["building"] = buildingLink, | |||
}, | |||
} | |||
return wikiMarkup | |||
return | |||
end | end | ||
| Line 296: | Line 601: | ||
frame = mwFrame | frame = mwFrame | ||
local | local productName = frame.args.product --TODO these are currently IDs, they need to be names | ||
local | local bonusName = frame.args.bonus | ||
local | local buildingName = frame.args.building | ||
local skipFlagForBiomes = frame.args[VIEW_ARG_SKIP_BIOMES] | |||
local displayOverride = frame.args.display | local displayOverride = frame.args.display | ||
local suppressTrees = true | |||
--Unset blanks back to nil | biomesIDs = sortArrayWith(BiomesData.getAllBiomeIDs(), BiomesData.getName) | ||
if | |||
--Unset blanks back to nil or get their names from their data model | |||
local productID | |||
if productName and productName ~= "" then | |||
productID = GoodsData.getGoodID(productName) | |||
end | end | ||
local bonusID | |||
if bonusName and bonusName ~= "" then | |||
bonusID = GoodsData.getGoodID(bonusName) | |||
if | |||
end | end | ||
local buildingID = BuildingDataProxy.getID(buildingName) | |||
--Find out whether Trees should be excluded | |||
if (not buildingName) or buildingName == "" or buildingName == "Woodcutters' Camp" then | |||
suppressTrees = false | |||
end | |||
local depositsList = {} | local depositsList = {} | ||
if | local title = "" | ||
if | if productID and bonusID then | ||
if productID ~= bonusID then | |||
error(ERROR_MESSAGE_PRODUCT_AND_BONUS_BUT_NOT_MATCH) | |||
else | else | ||
depositsList = GladeResourcesData. | depositsList = sortArrayWith(GladeResourcesData.getAllDepositsWherePrimaryOrBonusResource(productID, suppressTrees), GladeResourcesData.getDepositName) | ||
end | end | ||
elseif | title = #depositsList .. " Deposits for " .. productName .. " or as a bonus." | ||
depositsList = GladeResourcesData.getAllDepositsWherePrimaryResource( | |||
elseif | elseif productID then | ||
depositsList = GladeResourcesData.getAllDepositsWhereBonusResource( | depositsList = sortArrayWith(GladeResourcesData.getAllDepositsWherePrimaryResource(productID, suppressTrees), GladeResourcesData.getDepositName) | ||
title = #depositsList .. " Deposits for " .. productName .. "." | |||
elseif bonusID then | |||
depositsList = sortArrayWith(GladeResourcesData.getAllDepositsWhereBonusResource(bonusID, suppressTrees), GladeResourcesData.getDepositName) | |||
title = #depositsList .. " Deposits where " .. bonusName .. " is a bonus." | |||
elseif buildingID then | |||
depositsList = sortArrayWith(assembleDepositsFromBuilding(buildingID, suppressTrees), GladeResourcesData.getDepositName) | |||
title = #depositsList .. " Deposits exploited by the " .. buildingName .. "." | |||
else | |||
error(ERROR_MESSAGE_NO_PARAMETERS_GIVEN) | |||
end | end | ||
local maxBonuses = countMaxBonusesInList(depositsList) | local maxBonuses = countMaxBonusesInList(depositsList) | ||
local wikiMarkup = "" | local wikiMarkup = "" | ||
wikiMarkup = wikiMarkup .. renderViewStart(depositsList, maxBonuses, | wikiMarkup = wikiMarkup .. renderViewStart(depositsList, maxBonuses, title, buildingID, skipFlagForBiomes, displayOverride) | ||
wikiMarkup = wikiMarkup .. renderViewAllRows(depositsList, maxBonuses, displayOverride) | wikiMarkup = wikiMarkup .. renderViewAllRows(depositsList, maxBonuses, buildingID, skipFlagForBiomes, displayOverride) | ||
wikiMarkup = wikiMarkup .. renderViewEnd(displayOverride) | wikiMarkup = wikiMarkup .. renderViewEnd(depositsList, buildingID, displayOverride) | ||
return wikiMarkup | return wikiMarkup | ||
Latest revision as of 02:12, 9 August 2025
Documentation for this module may be created at Module:GladeResourcesController/doc
---@class GladeResourcesController
local GladeResourcesController = {}
--region Dependencies
local GladeResourcesData = require("Module:GladeResourcesData")
local GoodsData = require("Module:GoodsData")
local BiomesData = require("Module:BiomesData")
local BuildingDataProxy = require("Module:BuildingDataProxy")
local DataModelsWithGladeResourcesRecipes = {
require("Module:MinesData"),
require("Module:CampsData"),
require("Module:FishingData"),
require("Module:GatheringData"),
}
local VIEW_TEMPLATE_START = "Deposit/view"
local VIEW_TEMPLATE_ROW = "Deposit/view/row"
local VIEW_TEMPLATE_END = "Deposit/view/end"
local VIEW_BUILDING_LINK = "Building_link/view"
local VIEW_RESOURCE_LINK = "Resource_link/view"
--endregion
--region Private constants
local VIEW_ARG_HEAD = "heading"
local VIEW_ARG_DESC = "description"
local VIEW_ARG_CAPTION = "caption"
local VIEW_ARG_CHARGES = "charges"
local VIEW_ARG_NUM_DEPOSITS = "numdeposits"
local VIEW_ARG_MAX_BONUSES = "maxbonuses"
local VIEW_ARG_DEPOSIT = "deposit"
local VIEW_ARG_BUILDING = "building"
local VIEW_ARG_PRODUCT = "primary"
local VIEW_ARG_BONUS_1 = "bonus1"
local VIEW_ARG_BONUS_2 = "bonus2"
local VIEW_ARG_BONUS_3 = "bonus3"
local VIEW_ARG_BONUS_4 = "bonus4"
local VIEW_ARG_SKIP_BIOMES = "skip_biomes"
local SKIP_FLAG = "skip"
local VIEW_ARG_BIOME_PREFIX = "biome"
local VIEW_ARG_FORCE_DEFAULT = "default"
--endregion
--region Localization string constants
local ERROR_MESSAGE_PRODUCT_AND_BONUS_BUT_NOT_MATCH = "When searching for a good as both a main and bonus resource, the parameters must match"
local ERROR_MESSAGE_NO_PARAMETERS_GIVEN = "You must specify the name of a product, a bonus resource, or a building—and as it's spelled in the game"
--endregion
--region Private member variables
local frame
local biomesIDs
--endregion
--region Private methods
---@private
---Sorts given the function provided.
---
---@param arrayToSort table
---@param comparisonFunction function
---@return table the sorted array
local function sortArrayWith(arrayToSort, comparisonFunction)
table.sort(arrayToSort, function(a, b)
return comparisonFunction(a) < comparisonFunction(b)
end)
return arrayToSort
end
---@private
---Uses the specified building ID to go through applicable data models, assembling a list of possible deposits, filtered by the grade of the building.
---
---@param buildingID string a building's ID
---@return table array of deposit records retrieved from GladeResourcesData
local function assembleDepositsFromBuilding(buildingID, suppressTrees)
local depositsList = {}
local isWoodcutter = buildingID == "Woodcutters Camp"
if isWoodcutter then
local newList = GladeResourcesData.getAllDepositsWhereDepositIsTree()
for _, deposit in ipairs(newList) do
table.insert(depositsList, deposit)
end
else
--This isn't as expensive as it looks, because typically only one data model will return something. However, we don't know which it will be in advance.
for _, dataModel in ipairs(DataModelsWithGladeResourcesRecipes) do
local recipeDataArray = dataModel:getIDsAndRecipesWhereBuildingID(buildingID)
if #recipeDataArray > 0 then
local products = {}
for _, recipeData in ipairs(recipeDataArray) do
local id = dataModel:getRecipeProductID(recipeData)
products[id] = dataModel:getRecipeGrade(recipeData)
end
for id, grade in pairs(products) do
local newList = GladeResourcesData.getAllDepositsWherePrimaryResourceAndGrade(id, grade, suppressTrees)
for _, deposit in ipairs(newList) do
table.insert(depositsList, deposit)
end
end
end
end
end
return depositsList
end
---@private
---Looks up the building ID from the building data models for the one that can exploit the given deposit.
---
---@param deposit table record from GladeResourcesData
---@return string, string building display name, icon filename
local function getBuildingForDeposit(deposit)
local productID = GladeResourcesData.getDepositPrimaryProduct(deposit)
local isTree = GladeResourcesData.isDepositTree(deposit)
--This isn't as expensive as it looks, because typically only one data model will return something. However, we don't know which it will be in advance.
for _, dataModel in ipairs(DataModelsWithGladeResourcesRecipes) do
local recipeDataArray = dataModel:getIDsAndRecipesWhereProductID(productID)
if #recipeDataArray > 0 then
for i = 1, #recipeDataArray do
local id = dataModel:getRecipeBuildingID(recipeDataArray[i])
if (isTree or dataModel:getName(id) ~= "Woodcutters' Camp") then
local name = dataModel:getName(id)
local icon = dataModel:getIcon(id)
return name, icon
end
end
end
end
return ""
end
---@private
---Checks whether the provided list of deposits can be harvested by a single building. If so, returns that building's name and icon (for use in a building link). Otherwise, returns nil.
---
---@param depositsList table array of deposit records retrieved from GladeResourcesData
---@return string, string building name and icon, if there is only one, nil if none or more than one
local function checkOnlyOneBuildingForAllDeposits(depositsList)
local buildings = {}
for _, deposit in ipairs(depositsList) do
local name, icon = getBuildingForDeposit(deposit)
buildings[name] = icon
end
local firstBuildingName, firstBuildingIcon = next(buildings)
if firstBuildingName and not next(buildings, firstBuildingName) then
return firstBuildingName, firstBuildingIcon
else
return nil
end
end
---@private
---Goes through the provided list of deposits and finds the maximum number of bonuses, so that the view can be standardized.
---
---@param depositsList table array of deposit records retrieved from GladeResourcesData
---@return number maximum bonuses across all in the list
local function countMaxBonusesInList(depositsList)
local maxFound = 0
for _, deposit in ipairs(depositsList) do
local numBonuses = GladeResourcesData.getDepositNumBonusResources(deposit)
if numBonuses > maxFound then
maxFound = numBonuses
end
end
return maxFound
end
---@private
---Tallies up the categories and concatenates them. Also makes them plural if there are more than one of a particular category.
---
---@param depositsList table
---@return string the categories among the deposits
local function writeCaptionForDeposits(depositsList)
local categories = {}
for _, deposit in ipairs(depositsList) do
local category = GladeResourcesData.getDepositCategory(deposit)
if not categories[category] then
categories[category] = 1
else
categories[category] = categories[category] + 1
end
end
local caption = ""
for category, categoryCount in pairs(categories) do
if categoryCount > 1 then
category = category .. "s"
end
if caption == "" then
caption = category
else
caption = caption .. " & " .. category
end
end
return caption
end
---@private
---Tallies up the descriptions. If there's exactly one, it returns that description, otherwise it returns blank since they can't be combined (and to save space).
---
---@param depositsList table
---@return string the one or shared description in the list, or "" if they are varied
local function writeDescriptionForDeposits(depositsList)
--Heuristic: If there are more then 2, then there's no way all the descriptions match.
if #depositsList > 2 then
return ""
end
local descriptions = {}
for _, deposit in ipairs(depositsList) do
local desc = GladeResourcesData.getDepositDescription(deposit)
descriptions[desc] = true
end
--Use exactly one description unless there are more, in which case return empty.
local firstDescription = next(descriptions)
if firstDescription and not next(descriptions, firstDescription) then
return firstDescription
else
return ""
end
end
local function writeBiomePartialLink(biomeID)
local icon = BiomesData.getIcon(biomeID) .. ".png"
local pageName = BiomesData.getName(biomeID)
return "File:" .. icon .. "|" .. pageName
end
---@private
---Sets up the view, based on the display override or lack thereof. Returns whatever else needs to be appended to do so.
---
---@param depositsList table list of deposits from GladeResourcesData
---@param maxBonuses number slots for bonus resources
---@param title string title for the whole panel
---@param buildingID string an ID for a building specified, if any
---@param skipFlagForBiomes string flag for skipping biomes columns
---@param displayOverride string override code, if any
---@return string wiki markup
local function renderViewStart(depositsList, maxBonuses, title, buildingID, skipFlagForBiomes, displayOverride)
displayOverride = displayOverride --TODO write the other view modes
local skipBuildingColumn = ""
if buildingID then
skipBuildingColumn = "skip"
else
local buildingName = checkOnlyOneBuildingForAllDeposits(depositsList)
if buildingName then
skipBuildingColumn = "skip"
end
end
local caption = writeCaptionForDeposits(depositsList)
local numDeposits = #depositsList
--Special case where we swap the title out for the name of the one deposit and show the description
local description = ""
if numDeposits == 1 and not displayOverride == VIEW_ARG_FORCE_DEFAULT then
title = GladeResourcesData.getDepositName(depositsList[1])
description = writeDescriptionForDeposits(depositsList)
end
local viewArgs = {
[VIEW_ARG_HEAD] = title,
[VIEW_ARG_DESC] = description,
[VIEW_ARG_CAPTION] = caption,
[VIEW_ARG_NUM_DEPOSITS] = numDeposits,
[VIEW_ARG_MAX_BONUSES] = maxBonuses,
[VIEW_ARG_BUILDING] = skipBuildingColumn,
[VIEW_ARG_SKIP_BIOMES] = skipFlagForBiomes,
}
if skipFlagForBiomes ~= SKIP_FLAG then
for i, biomeID in ipairs(biomesIDs) do
local biomeArg = VIEW_ARG_BIOME_PREFIX .. i
viewArgs[biomeArg] = writeBiomePartialLink(biomeID)
end
end
local wikiMarkup = frame:expandTemplate{
title = VIEW_TEMPLATE_START,
args = viewArgs,
}
return wikiMarkup
end
---@private
-----Converts the data about the product in the specified deposit for the view.
---
---@param deposit table from GladeResourceData
---@param displayOverride string override code, if any
---@return string wiki markup
local function renderProduct(deposit, displayOverride)
displayOverride = displayOverride --TODO write the other display modes
local productID, amount = GladeResourcesData.getDepositPrimaryProduct(deposit)
local iconFilename = GoodsData.getIcon(productID)
local productName = GoodsData.getName(productID)
local wikiMarkup = ""
if amount > 1 then
wikiMarkup = wikiMarkup .. "'''" .. amount .. "''' "
end
wikiMarkup = wikiMarkup .. frame:expandTemplate{
title = VIEW_RESOURCE_LINK,
args = {
["iconsize"] = "medium",
["iconfilename"] = iconFilename,
["name"] = productName,
["display"] = "notext",
}
}
return wikiMarkup
end
---@private
-----Converts the data about the specified bonus in the specified deposit for the view.
---
---@param deposit table from GladeResourceData
---@param index number which bonus from deposit to get
---@param displayOverride string override code, if any
---@return string wiki markup
local function renderBonus(deposit, index, displayOverride)
displayOverride = displayOverride --TODO write the other display modes
local productID, amount, chance = GladeResourcesData.getDepositBonusResourceAt(deposit, index)
if not productID then
return ""
end
local iconFilename = GoodsData.getIcon(productID)
local productName = GoodsData.getName(productID)
local wikiMarkup = ""
if amount and amount > 1 then
wikiMarkup = wikiMarkup .. "'''" .. amount .. "''' "
end
wikiMarkup = wikiMarkup .. frame:expandTemplate{
title = VIEW_RESOURCE_LINK,
args = {
["name"] = productName,
["iconfilename"] = iconFilename,
["iconsize"] = "medium",
["display"] = "notext",
}
}
wikiMarkup = wikiMarkup .. "<br>'''" .. chance*100 .. "%'''"
return wikiMarkup
end
---@private
---Looks up the building that can get the specified deposit for the view.
---
---@param deposit table from GladeResourceData
---@param displayOverride string override code, if any
---@return string wiki markup
local function renderBuilding(deposit, displayOverride)
displayOverride = displayOverride --TODO write the other display modes
local buildingName, buildingIcon = getBuildingForDeposit(deposit)
local wikiMarkup = frame:expandTemplate{
title = VIEW_BUILDING_LINK,
args = {
["name"] = buildingName,
["iconfilename"] = buildingIcon,
["iconsize"] = "large",
["display"] = "notext"
}
}
return wikiMarkup
end
---@private
---Used when a building is specified or there's just one row.
---
---@param buildingID string
---@return string wiki markup
local function renderBottomBuildingLink(buildingID, buildingName, buildingIcon)
if buildingID then
buildingName = BuildingDataProxy.getName(buildingID)
buildingIcon = BuildingDataProxy.getIcon(buildingID)
end
local wikiMarkup = frame:expandTemplate{
title = VIEW_BUILDING_LINK,
args = {
["name"] = buildingName,
["iconfilename"] = buildingIcon,
["iconsize"] = "huge"
}
}
return wikiMarkup
end
---@private
---Makes a row for one deposit. If the buildingID is given, skips showing it, because it means it's factored out of the rows.
---
---@param deposit table from GladeResourceData
---@param numDeposits number total number of deposits
---@param maxBonuses number slots for bonus resources
---@param buildingID string a specified buildingID, if any
---@param isSkippingBiomes string flag for skipping biomes columns
---@param displayOverride string override code, if any
---@return string wiki markup
local function renderViewOneRow(deposit, numDeposits, maxBonuses, buildingID, isSkippingBiomes, displayOverride)
displayOverride = displayOverride --TODO write the other display modes
--Special case where we take out the name and building icon when there's just one deposit or it's all harvestable by one building.
local depositName = ""
if numDeposits > 1 then
depositName = GladeResourcesData.getDepositName(deposit)
end
local buildingLink = ""
if not buildingID then
buildingLink = renderBuilding(deposit, displayOverride)
end
local viewArgs = {
[VIEW_ARG_DEPOSIT] = depositName,
[VIEW_ARG_BUILDING] = buildingLink,
[VIEW_ARG_CHARGES] = GladeResourcesData.getDepositCharges(deposit),
[VIEW_ARG_PRODUCT] = renderProduct(deposit, displayOverride),
[VIEW_ARG_MAX_BONUSES] = maxBonuses,
[VIEW_ARG_BONUS_1] = renderBonus(deposit, 1, displayOverride),
[VIEW_ARG_BONUS_2] = renderBonus(deposit, 2, displayOverride),
[VIEW_ARG_BONUS_3] = renderBonus(deposit, 3, displayOverride),
[VIEW_ARG_BONUS_4] = renderBonus(deposit, 4, displayOverride),
[VIEW_ARG_SKIP_BIOMES] = isSkippingBiomes,
}
local depositID = GladeResourcesData.getDepositID(deposit)
if isSkippingBiomes ~= SKIP_FLAG then
for i, biomeID in ipairs(biomesIDs) do
local biomeArg = VIEW_ARG_BIOME_PREFIX .. i
local isInBiome = BiomesData.isNodeOfAnyTypeInBiome(depositID, biomeID)
local biomePartialLink = writeBiomePartialLink(biomeID)
viewArgs[biomeArg] = isInBiome and biomePartialLink or ""
end
end
return frame:expandTemplate{
title = VIEW_TEMPLATE_ROW,
args = viewArgs,
}
end
---@private
---Goes through the list of deposits and makes rows for each.
---
---@param depositsList table list of deposits from GladeResourcesData
---@param maxBonuses number slots for bonus resources
---@param buildingID string an ID for a building specified, if any
---@param skipFlagForBiomes string flag for skipping biomes columns
---@param displayOverride string override code, if any
---@return string wiki markup
local function renderViewAllRows(depositsList, maxBonuses, buildingID, skipFlagForBiomes, displayOverride)
local numDeposits = #depositsList
-- Factor out a single building from the rows.
if not buildingID then
local buildingName = checkOnlyOneBuildingForAllDeposits(depositsList)
if buildingName then
buildingID = BuildingDataProxy.getID(buildingName)
end
end
local wikiMarkup = ""
for _, deposit in ipairs(depositsList) do
wikiMarkup = wikiMarkup .. "\n"
wikiMarkup = wikiMarkup .. renderViewOneRow(deposit, numDeposits, maxBonuses, buildingID, skipFlagForBiomes, displayOverride)
end
return wikiMarkup
end
---@private
---Closes out the view, based on the display override or lack thereof. Returns whatever else needs to be appended to do so.
---
---@param depositsList table list of deposits from GladeResourcesData
---@param buildingID string an ID for a building specified, if any
---@param displayOverride string override code, if any
---@return string wiki markup
local function renderViewEnd(depositsList, buildingID, displayOverride)
displayOverride = displayOverride --TODO write the other display modes
local numDeposits = #depositsList
local buildingLink = ""
if numDeposits > 0 then
if buildingID then
buildingLink = renderBottomBuildingLink(buildingID)
else
local buildingName, buildingIcon = checkOnlyOneBuildingForAllDeposits(depositsList)
if buildingName and buildingIcon then
buildingLink = renderBottomBuildingLink(nil, buildingName, buildingIcon)
end
end
end
local wikiMarkup = ""
wikiMarkup = wikiMarkup .. frame:expandTemplate{
title = VIEW_TEMPLATE_END,
args = {
["numdeposits"] = numDeposits,
["building"] = buildingLink,
},
}
return wikiMarkup
end
--endregion
--region Public methods
---Called from Template:Deposit. Returns markup text for display by using external view templates.
---
---@param mwFrame table the Mediawiki calling context for the template
---@return string wiki markup
function GladeResourcesController.main(mwFrame)
frame = mwFrame
local productName = frame.args.product --TODO these are currently IDs, they need to be names
local bonusName = frame.args.bonus
local buildingName = frame.args.building
local skipFlagForBiomes = frame.args[VIEW_ARG_SKIP_BIOMES]
local displayOverride = frame.args.display
local suppressTrees = true
biomesIDs = sortArrayWith(BiomesData.getAllBiomeIDs(), BiomesData.getName)
--Unset blanks back to nil or get their names from their data model
local productID
if productName and productName ~= "" then
productID = GoodsData.getGoodID(productName)
end
local bonusID
if bonusName and bonusName ~= "" then
bonusID = GoodsData.getGoodID(bonusName)
end
local buildingID = BuildingDataProxy.getID(buildingName)
--Find out whether Trees should be excluded
if (not buildingName) or buildingName == "" or buildingName == "Woodcutters' Camp" then
suppressTrees = false
end
local depositsList = {}
local title = ""
if productID and bonusID then
if productID ~= bonusID then
error(ERROR_MESSAGE_PRODUCT_AND_BONUS_BUT_NOT_MATCH)
else
depositsList = sortArrayWith(GladeResourcesData.getAllDepositsWherePrimaryOrBonusResource(productID, suppressTrees), GladeResourcesData.getDepositName)
end
title = #depositsList .. " Deposits for " .. productName .. " or as a bonus."
elseif productID then
depositsList = sortArrayWith(GladeResourcesData.getAllDepositsWherePrimaryResource(productID, suppressTrees), GladeResourcesData.getDepositName)
title = #depositsList .. " Deposits for " .. productName .. "."
elseif bonusID then
depositsList = sortArrayWith(GladeResourcesData.getAllDepositsWhereBonusResource(bonusID, suppressTrees), GladeResourcesData.getDepositName)
title = #depositsList .. " Deposits where " .. bonusName .. " is a bonus."
elseif buildingID then
depositsList = sortArrayWith(assembleDepositsFromBuilding(buildingID, suppressTrees), GladeResourcesData.getDepositName)
title = #depositsList .. " Deposits exploited by the " .. buildingName .. "."
else
error(ERROR_MESSAGE_NO_PARAMETERS_GIVEN)
end
local maxBonuses = countMaxBonusesInList(depositsList)
local wikiMarkup = ""
wikiMarkup = wikiMarkup .. renderViewStart(depositsList, maxBonuses, title, buildingID, skipFlagForBiomes, displayOverride)
wikiMarkup = wikiMarkup .. renderViewAllRows(depositsList, maxBonuses, buildingID, skipFlagForBiomes, displayOverride)
wikiMarkup = wikiMarkup .. renderViewEnd(depositsList, buildingID, displayOverride)
return wikiMarkup
end
--endregion
return GladeResourcesController


