Module:Resource infobox
From Beyond These Stars Official Wiki
Documentation for this module may be created at Module:Resource infobox/doc
--[[
Test in Scribunto console with:
=mw.dumpObject(p.render( {} ))
=p.render({ args = { page_name = "Iron" } })
=p.render({ args = { page_name = "Hot Coffee" } })
]]--
local p = {}
local Resource_Data_Module = require("Module:Resource_data")
local Building_Data_Module = require("Module:Building_data")
--#region html building helper functions
---@diagnostic disable-next-line: duplicate-doc-alias
---@alias HtmlNode table
local INFOBOX_CLASS = "bts-infobox-resource"
local HEADER_CLASS = INFOBOX_CLASS .. "-header"
local HEADER_ICON_CLASS = HEADER_CLASS .. "-icon"
local TITLE_CLASS = HEADER_CLASS .. "-title"
local SUBTITLE_CLASS = HEADER_CLASS .. "-subtitle"
local SUBHEADER_CLASS = INFOBOX_CLASS .. "-subheader"
local BENEFITS_CLASS = INFOBOX_CLASS .. "-benefits"
local BENEFITS_TABLE_CLASS = BENEFITS_CLASS .. "-table"
local PRODUCTION_CLASS = INFOBOX_CLASS .. "-production"
local PRODUCTION_TABLE_CLASS = PRODUCTION_CLASS .. "-table"
local LARGE_ICON_SIZE = "128px"
local SMALL_ICON_SIZE = "24px"
--- Renders wikitext for the resource's icon.
---@param resource Resource
---@return string wikitext
local function render_icon_markup(resource)
local icon_filename = resource.icon .. ".png"
local image_markup = "[[File:" .. icon_filename .. "|x" .. LARGE_ICON_SIZE .. "|" .. resource.name .. "|link=]]"
return image_markup
end
--- Adds the header of the infobox to the provided html node.
---@param div HtmlNode enclosing infobox div
---@param resource Resource
local function add_header(div, resource)
local section = div:tag("div"):addClass(HEADER_CLASS)
section:tag("div"):addClass(TITLE_CLASS):wikitext(resource.display_name)
section:tag("div"):addClass(HEADER_ICON_CLASS):wikitext(render_icon_markup(resource))
if resource.category and resource.category ~= "" then
section:tag("div"):addClass(SUBTITLE_CLASS):wikitext(resource.category .. " Resource")
end
end
--- Adds a subheader to the provided html node.
---@param div HtmlNode enclosing infobox div
---@param text string
local function add_subheader(div, text)
div:tag("div"):addClass(SUBHEADER_CLASS):wikitext(text)
end
--- Counts the benefits to peeps for the given resource.
---@param resource Resource
---@return number
local function count_benefits(resource)
local count = 0
if resource.peep_happiness_added and resource.peep_happiness_added ~= 0 then
count = count + 1
end
if resource.peep_energy_added and resource.peep_energy_added ~= 0 then
count = count + 1
end
if resource.peep_exhaustion_removed and resource.peep_exhaustion_removed ~= 0 then
count = count + 1
end
if resource.peep_temperature_effect and resource.peep_temperature_effect ~= "" then
count = count + 1
end
return count
end
--- Adds the benefits to peeps to the provided html node.
---@param div HtmlNode enclosing infobox div
---@param resource Resource
local function add_benefits_to_peeps(div, resource)
local section = div:tag("div"):addClass(BENEFITS_CLASS)
local count = count_benefits(resource)
if count > 0 then
local tbl = mw.html.create("table"):addClass(BENEFITS_TABLE_CLASS)
tbl:tag("tr")
:tag("th"):wikitext("Happiness"):done()
:tag("th"):wikitext("Energy"):done()
tbl:tag("tr")
:tag("td"):wikitext(resource.peep_happiness_added or 0):done()
:tag("td"):wikitext(resource.peep_energy_added or 0):done()
tbl:tag("tr")
:tag("th"):wikitext("Exhaustion"):done()
:tag("th"):wikitext("Temperature"):done()
tbl:tag("tr")
:tag("td"):wikitext(resource.peep_exhaustion_removed or 0):done()
:tag("td"):wikitext(resource.peep_temperature_effect):done()
section:node(tbl)
else
section:wikitext("None")
end
end
--- Renders the icon for a resource.
---@param resource Resource
---@return string wikitext
local function render_io_resource_icon(resource)
local icon_filename = resource.icon .. ".png"
local image_markup = "[[File:" .. icon_filename .. "|" .. SMALL_ICON_SIZE .. "|" .. resource.name .. "|link=]]"
return image_markup
end
--- Splits tasks by inputs and outputs.
---@param map_of_tasks table<string, BuildingTask[]>
---@param resource_id string the id of the resource to split tasks for
---@return table<string, BuildingTask[]> inputs
---@return table<string, BuildingTask[]> outputs
local function split_tasks_by_inputs_and_outputs(map_of_tasks, resource_id)
local inputs = {}
local outputs = {}
for building_name, tasks in pairs(map_of_tasks) do
for _, task in ipairs(tasks) do
for _, input in ipairs(task.inputs or {}) do
if input.resource == resource_id then
if not inputs[building_name] then
inputs[building_name] = {}
end
table.insert(inputs[building_name], task)
end
end
for _, output in ipairs(task.outputs or {}) do
if output.resource == resource_id then
if not outputs[building_name] then
outputs[building_name] = {}
end
table.insert(outputs[building_name], task)
end
end
end
end
return inputs, outputs
end
--- Concatenates the outputs of a task.
---@param task BuildingTask
---@return string wikitext
local function concatenate_outputs(task)
local outputs = ""
if not task.outputs or #task.outputs == 0 then return "" end
local count = 0
for _, output in ipairs(task.outputs) do
local name = Resource_Data_Module.get_name_by_id(output.resource)
if name and name ~= "" then
outputs = outputs .. (count > 0 and ", " or "") .. name
count = count + 1
end
end
return outputs
end
--- Concatenates the inputs of a task.
---@param task BuildingTask
---@return string wikitext
local function concatenate_inputs(task)
local inputs = ""
if not task.inputs or #task.inputs == 0 then return "" end
local count = 0
for _, input in ipairs(task.inputs) do
local name = Resource_Data_Module.get_name_by_id(input.resource)
if name and name ~= "" then
inputs = inputs .. (count > 0 and ", " or "") .. name
count = count + 1
end
end
return inputs
end
--- Adds the production input rows to the provided html node.
---@param tbl HtmlNode enclosing infobox div
---@param map_of_tasks_with_inputs table<string, BuildingTask[]>
---@param resource Resource
---@return number number of input rows added
local function add_production_input_rows(tbl, map_of_tasks_with_inputs, resource)
local count = 0
for building_name, tasks in pairs(map_of_tasks_with_inputs) do
for _, task in ipairs(tasks) do
local outputs = concatenate_outputs(task)
for _, input in ipairs(task.inputs) do
if input.resource == resource.name then
local building_link = "[[" .. building_name .. "]]"
local amount = input.value
local resource_icon = render_io_resource_icon(resource)
local resource_markup = amount .. "x " .. resource_icon
tbl:tag("tr")
:tag("td"):wikitext(building_link):done()
:tag("td"):wikitext(resource_markup):done()
:tag("td"):wikitext(outputs):done()
count = count + 1
end
end
end
end
return count
end
--- Adds the production output rows to the provided html node.
---@param tbl HtmlNode enclosing infobox div
---@param map_of_tasks_with_outputs table<string, BuildingTask[]>
---@param resource Resource
---@return number number of output rows added
local function add_production_output_rows(tbl, map_of_tasks_with_outputs, resource)
local count = 0
for building_name, tasks in pairs(map_of_tasks_with_outputs) do
for _, task in ipairs(tasks) do
local inputs = concatenate_inputs(task)
for _, output in ipairs(task.outputs) do
if output.resource == resource.name then
local building_link = "[[" .. building_name .. "]]"
local amount = output.value
local resource_icon = render_io_resource_icon(resource)
local resource_markup = amount .. "x " .. resource_icon
tbl:tag("tr")
:tag("td"):wikitext(building_link):done()
:tag("td"):wikitext(inputs):done()
:tag("td"):wikitext(resource_markup):done()
count = count + 1
end
end
end
end
return count
end
--- Adds the production to the provided html node.
---@param div HtmlNode enclosing infobox div
---@param resource Resource
local function add_production(div, resource)
local section = div:tag("div"):addClass(PRODUCTION_CLASS)
local building_map_of_tasks = Building_Data_Module.get_building_names_with_tasks_including_resource(resource.name)
local map_of_tasks_with_inputs, map_of_tasks_with_outputs = split_tasks_by_inputs_and_outputs(building_map_of_tasks, resource.name)
local tbl = mw.html.create("table"):addClass(PRODUCTION_TABLE_CLASS)
tbl:tag("tr")
:tag("th"):wikitext("Building"):done()
:tag("th"):wikitext("Input"):done()
:tag("th"):wikitext("Output"):done()
local input_count = 0
local output_count = 0
if next(map_of_tasks_with_inputs) ~= nil then
input_count = add_production_input_rows(tbl, map_of_tasks_with_inputs, resource)
end
if next(map_of_tasks_with_outputs) ~= nil then
output_count = add_production_output_rows(tbl, map_of_tasks_with_outputs, resource)
end
if input_count > 0 or output_count > 0 then
section:node(tbl)
else
section:wikitext("None")
end
end
--- Builds the infobox wikitext and html for the given resource.
---@param resource Resource
---@return string wikitext
local function build_infobox(resource)
---@type HtmlNode
local div = mw.html.create("div")
div:addClass(INFOBOX_CLASS)
add_header(div, resource)
add_subheader(div, "Benefits to Peeps")
add_benefits_to_peeps(div, resource)
add_subheader(div, "In production")
add_production(div, resource)
return tostring(div)
end
--- Appends the wiki category to the provided wikitext.
---@param wikitext string
---@param resource Resource
---@return string wikitext
local function append_wiki_category(wikitext, resource)
wikitext = wikitext .. "\n[[Category:Resources]]"
if resource.category and resource.category ~= "" then
wikitext = wikitext .. "\n[[Category:" .. resource.category .. " Resources]]"
end
return wikitext
end
--#endregion
--- `#invoke` entry point. Reads `page_name` from invoke args (not the parent
--- template); falls back to the current page title.
---@param frame table Scribunto frame from `#invoke`.
---@return string wikitext Infobox code or empty string if no resource exists.
function p.render(frame)
local args = frame.args or {}
---@type string
local name = args[1] or args.page_name or mw.title.getCurrentTitle().fullText
local resource = Resource_Data_Module.get_resource(name)
if not resource then return "" end
local wikitext = build_infobox(resource)
wikitext = append_wiki_category(wikitext, resource)
return wikitext
end
return p


