Module:Resource infobox: Difference between revisions

From Beyond These Stars Official Wiki
looks up input and output resource names instead of codenames
adds generic category too
 
(One intermediate revision by the same user not shown)
Line 2: Line 2:
Test in Scribunto console with:
Test in Scribunto console with:
=mw.dumpObject(p.render( {} ))
=mw.dumpObject(p.render( {} ))
=p.render({ args = { page_name = "Iron" } })
=p.render({ args = { page_name = "Hot Coffee" } })
=p.render({ args = { page_name = "Hot Coffee" } })
]]--
]]--
Line 32: Line 33:


local LARGE_ICON_SIZE = "128px"
local LARGE_ICON_SIZE = "128px"
local SMALL_ICON_SIZE = "32px"
local SMALL_ICON_SIZE = "24px"




Line 41: Line 42:
local function render_icon_markup(resource)
local function render_icon_markup(resource)
   local icon_filename = resource.icon .. ".png"
   local icon_filename = resource.icon .. ".png"
   local image_markup = "[[File:" .. icon_filename .. "|" .. LARGE_ICON_SIZE .. "|" .. resource.name .. "|link=]]"
   local image_markup = "[[File:" .. icon_filename .. "|x" .. LARGE_ICON_SIZE .. "|" .. resource.name .. "|link=]]"
   return image_markup
   return image_markup
end
end
Line 163: Line 164:
   local count = 0
   local count = 0
   for _, output in ipairs(task.outputs) do
   for _, output in ipairs(task.outputs) do
     outputs = outputs .. (count > 0 and ", " or "") .. Resource_Data_Module.get_name_by_id(output.resource)
     local name = Resource_Data_Module.get_name_by_id(output.resource)
    count = count + 1
    if name and name ~= "" then
      outputs = outputs .. (count > 0 and ", " or "") .. name
      count = count + 1
    end
   end
   end
   return outputs
   return outputs
Line 177: Line 181:
   local count = 0
   local count = 0
   for _, input in ipairs(task.inputs) do
   for _, input in ipairs(task.inputs) do
     inputs = inputs .. (count > 0 and ", " or "") .. Resource_Data_Module.get_name_by_id(input.resource)
     local name = Resource_Data_Module.get_name_by_id(input.resource)
    count = count + 1
    if name and name ~= "" then
      inputs = inputs .. (count > 0 and ", " or "") .. name
      count = count + 1
    end
   end
   end
   return inputs
   return inputs
Line 290: Line 297:
---@return string wikitext
---@return string wikitext
local function append_wiki_category(wikitext, resource)
local function append_wiki_category(wikitext, resource)
   if not resource.category or resource.category == "" then return wikitext end
  wikitext = wikitext .. "\n[[Category:Resources]]"
  return wikitext .. "\n[[Category:" .. resource.category .. " Resources]]"
   if resource.category and resource.category ~= "" then
    wikitext = wikitext .. "\n[[Category:" .. resource.category .. " Resources]]"
  end
  return wikitext
end
end



Latest revision as of 00:08, 11 October 2026

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