Module:Buildingbox

From Against the Storm Official Wiki
Revision as of 18:20, 24 December 2023 by Aeredor (talk | contribs) (fixing wrong italics. keeping single quotes)

Documentation for this module may be created at Module:Buildingbox/doc

---
--- Module to create an infobox for displaying on a building's wiki page.
---
--- Shows the facts from the data about the specified building in an easy-to-
--- read table, with a large icon, information, categories, and the flavor
--- text.
---
--- This should be invoked from Template:Buildingbox with the parameter of the
--- building whose infobox should be shown. See the template documentation for
--- more information about parameters and errors and to see examples.
---
--- @module Buildingbox
local Buildingbox = {}



local StyleUtils = require("Module:StyleUtils")

local Infobox = require("Module:Infobox")

local WorkshopsData = require("Module:WorkshopsData")
local InstitutionsData = require("Module:InstitutionsData")
local CampsData = require("Module:CampsData")
local FarmsData = require("Module:FarmsData")
local CollectorsData = require("Module:CollectorsData")



--region Private constants

local ARGS = {
	["name"] = "name",
	["purpose"] = "purpose",
	["species_preference"] = "species_preference",
	["specializations"] = "specializations",
}

--endregion



--region Private methods

---
--- Shortcut method to expand a template with parameters
---
---@param buildingName string the name of the building
---@return string html markup returned by the template
local function expandRecipeList(buildingName)

	return mw.getCurrentFrame():expandTemplate{ title="Recipe", args={
		building= buildingName, display="list"	} }
end



---
--- Shortcut method since the size methods return two values.
---
---@param buildingName string the name of the building to check
---@return number, number the X and Y sizes
local function distributeSizes(buildingName)

	local sizeX, sizeY = WorkshopsData.getWorkshopSize(buildingName)
	if sizeX and sizeY then return sizeX, sizeY end

	sizeX, sizeY = InstitutionsData.getInstitutionSize(buildingName)
	if sizeX and sizeY then return sizeX, sizeY end

	sizeX, sizeY = CampsData.getCampSize(buildingName)
	if sizeX and sizeY then return sizeX, sizeY end

	sizeX, sizeY = FarmsData.getFarmSize(buildingName)
	if sizeX and sizeY then return sizeX, sizeY end

	sizeX, sizeY = CollectorsData.getCollectorSize(buildingName)
	return sizeX, sizeY
end





---
--- Builds using the provided wikiInfobox a few header items.
---
---@param wikiInfobox table mw.html object into which we're building this
---@param buildingName string the name of the building the infobox is about
---@return table the Mediawiki html object into which we've been adding things
local function makeHeaderContent(wikiInfobox, buildingName)

	-- Grab the data we'll use to populate this.
	local description = WorkshopsData.getWorkshopDescription(buildingName)
				or InstitutionsData.getInstitutionDescription(buildingName)
				or CampsData.getCampDescription(buildingName)
				or FarmsData.getFarmDescription(buildingName)
				or CollectorsData.getCollectorDescription(buildingName)
	local iconFilename = WorkshopsData.getWorkshopIcon(buildingName)
				or InstitutionsData.getInstitutionIcon(buildingName)
				or CampsData.getCampIcon(buildingName)
				or FarmsData.getFarmIcon(buildingName)
				or CollectorsData.getCollectorIcon(buildingName)

	-- Start the header area
	local header = Infobox.startNewHeader(wikiInfobox)

	Infobox.makeTitle(header, buildingName)
	Infobox.makeFlavorText(header, description)
	Infobox.makeTitleIcon(header, iconFilename)

	return wikiInfobox
end



---
--- Builds using the provided wikiInfobox a subtable to lay out headers and
--- fields.
---
---@param wikiInfobox table mw.html object into which we're building this
---@param buildingName string the name of the good the infobox is about
---@param params table of template parameters
---@return table the Mediawiki html object into which we've been adding things
local function makeInnerContent(wikiInfobox, buildingName, params)

	-- Grab the data we'll use to populate this.
	local category = WorkshopsData.getWorkshopCategory(buildingName)
				or InstitutionsData.getInstitutionCategory(buildingName)
				or CampsData.getCampCategory(buildingName)
				or FarmsData.getFarmCategory(buildingName)
				or CollectorsData.getCollectorCategory(buildingName)
	local recipesTable = WorkshopsData.getAllWorkshopRecipes(buildingName)
				or InstitutionsData.getAllInstitutionRecipes(buildingName)
				or CampsData.getAllCampRecipes(buildingName)
				or FarmsData.getAllFarmRecipes(buildingName)
				or CollectorsData.getAllCollectorRecipes(buildingName)
	local isMovable = WorkshopsData.isWorkshopMovable(buildingName)
				or InstitutionsData.isInstitutionMovable(buildingName)
				or CampsData.isCampMovable(buildingName)
				or FarmsData.isFarmMovable(buildingName)
				or CollectorsData.isCollectorMovable(buildingName)
	local isEssential = WorkshopsData.isWorkshopInitiallyEssential(buildingName)
				or InstitutionsData.isInstitutionInitiallyEssential(buildingName)
				or CampsData.isCampInitiallyEssential(buildingName)
				or FarmsData.isFarmInitiallyEssential(buildingName)
				or CollectorsData.isCollectorInitiallyEssential(buildingName)
	local sizeX, sizeY = distributeSizes(buildingName)
	local range = CampsData.getCampArea(buildingName)
				-- Workshops and
				-- Institutions don't have a range/area
				or FarmsData.getFarmArea(buildingName)
				-- Collectors don't have a range
	local storageCap = WorkshopsData.getWorkshopStorage(buildingName)
				-- Institutions don't have storage
				or CampsData.getCampStorage(buildingName)
				or FarmsData.getFarmStorage(buildingName)
				or CollectorsData.getCollectorStorage(buildingName)
	local numWorkplaces = WorkshopsData.getWorkshopNumberOfWorkplaces(buildingName)
				or InstitutionsData.getInstitutionNumberOfWorkplaces(buildingName)
				or CampsData.getCampNumberOfWorkplaces(buildingName)
				or FarmsData.getFarmNumberOfWorkplaces(buildingName)
				or CollectorsData.getCollectorNumberOfWorkplaces(buildingName)
	local constructionTime = WorkshopsData.getWorkshopConstructionTime(buildingName)
				or InstitutionsData.getInstitutionConstructionTime(buildingName)
				or CampsData.getCampConstructionTime(buildingName)
				or FarmsData.getFarmConstructionTime(buildingName)
				or CollectorsData.getCollectorConstructionTime(buildingName)
	local constructionGoods = WorkshopsData.getAllWorkshopRequiredGoods(buildingName)
				or InstitutionsData.getAllInstitutionRequiredGoods(buildingName)
				or CampsData.getAllCampRequiredGoods(buildingName)
				or FarmsData.getAllFarmRequiredGoods(buildingName)
				or CollectorsData.getAllCollectorRequiredGoods(buildingName)
	local buildingID = WorkshopsData.getWorkshopID(buildingName)
				or InstitutionsData.getInstitutionID(buildingName)
				or CampsData.getCampID(buildingName)
				or FarmsData.getFarmID(buildingName)
				or CollectorsData.getCollectorID(buildingName)

	-- Start the inner table
	local innerTable = Infobox.startNewInnerTable(wikiInfobox)

	-- we'll reuse this to mark where separators are needed in the table
	local needsSeparator = false

	-- Start with the things from the parameters, if any
	for paramTitle, paramValue in pairs(params or {}) do
		if paramTitle ~= nil and paramValue ~= nil then
			Infobox.makeInnerRow(innerTable, paramValue, false,
					Infobox.toTitleCase(paramTitle), paramValue)
			-- Require a separator if there were any parameters.
			needsSeparator = true
		end
	end

	needsSeparator = Infobox.makeInnerRow(innerTable, category, needsSeparator,
			Infobox.TITLE_CATEGORY,
			Infobox.makeCategoryIcon(category, false) .. StyleUtils.NBSP .. category)
	needsSeparator = Infobox.makeInnerRow(innerTable, recipesTable and #recipesTable > 0,
			needsSeparator, Infobox.TITLE_RECIPES,
			expandRecipeList(buildingName))

	needsSeparator = true

	needsSeparator = Infobox.makeInnerRow(innerTable, isMovable, needsSeparator,
			Infobox.TITLE_MOVABLE, isMovable and "Yes" or "No")
	needsSeparator = Infobox.makeInnerRow(innerTable, isEssential, needsSeparator,
			Infobox.TITLE_ESSENTIAL, isEssential and "Yes" or "No")
	needsSeparator = Infobox.makeInnerRow(innerTable, sizeX and sizeY,
			needsSeparator, Infobox.TITLE_SIZE, sizeX .. " × " .. sizeY)
	needsSeparator = Infobox.makeInnerRow(innerTable, range, needsSeparator,
			Infobox.TITLE_RANGE, range)
	needsSeparator = Infobox.makeInnerRow(innerTable, storageCap, needsSeparator,
			Infobox.TITLE_STORAGE_CAPACITY, storageCap)

	needsSeparator = true

	needsSeparator = Infobox.makeInnerRow(innerTable, numWorkplaces, needsSeparator,
			Infobox.TITLE_WORKPLACES, numWorkplaces)

	needsSeparator = true

	needsSeparator = Infobox.makeInnerRow(innerTable, constructionTime,
			needsSeparator, Infobox.TITLE_CONSTRUCTION_TIME,
			constructionTime)
	needsSeparator = Infobox.makeInnerRow(innerTable, constructionGoods, needsSeparator,
			Infobox.TITLE_CONSTRUCTION_COST,
			Infobox.writeRequiredGoodsRows(constructionGoods) )

	needsSeparator = true

	needsSeparator = Infobox.makeInnerRow(innerTable, buildingID, needsSeparator,
			Infobox.TITLE_ID, "'" .. buildingID .. "'")

	-- Close the inner table, and return it with the passed context
	Infobox.endInnerTable(wikiInfobox, innerTable)

	return wikiInfobox
end

--endregion



--region Public methods

---
--- Creates an html and wiki markup to display the data in an infobox.
---
--- @param frame table from template's calling context
--- @return string of html and wiki markup
function Buildingbox.renderBuildingbox(frame)
	
	-- Every building must have a name.
	local buildingName = frame.args[ARGS.name]
	if not buildingName or buildingName == "" then
		return "You must specify the name of the building. See [[Template:Buildingbox]] for examples."
	end

	-- Use this method here to check to see whether the provided name is valid.
	if not ( WorkshopsData.getWorkshopID(buildingName)
			or InstitutionsData.getInstitutionID(buildingName)
			or CampsData.getCampID(buildingName)
			or FarmsData.getFarmID(buildingName)
			or CollectorsData.getCollectorID(buildingName) ) then
		return "Buildingbox can't find the specified building: " .. buildingName .. "."
	end

	-- Additional template parameters, may or may not be present.
	local purpose = frame.args[ARGS.purpose]
	local speciesPref = frame.args[ARGS.species_preference]
	local specializations = frame.args[ARGS.specializations]

	local wikiInfobox = Infobox.startNewInfobox()
	makeHeaderContent(wikiInfobox, buildingName)
	makeInnerContent(wikiInfobox, buildingName,
			{ [ARGS.purpose] = purpose, [ARGS.species_preference] = speciesPref,
			  [ARGS.specializations] = specializations })
	
	return wikiInfobox
end

--endregion

return Buildingbox