Module:Shopbox: Difference between revisions

From Against the Storm Official Wiki
(Updated to use new WorkshopsData. No longer stores external data but uses new getter methods. Improved documentation.)
m (changed category icon maker)
 
(6 intermediate revisions by the same user not shown)
Line 15: Line 15:




local Infobox = require("Module:Infobox")
local WorkshopsData = require("Module:WorkshopsData")
local WorkshopsData = require("Module:WorkshopsData")
local ResourceLink = require("Module:ResourceLink")
local StyleUtils = require("Module:StyleUtils")




Line 22: Line 23:
--region Private constants
--region Private constants


-- External templates
local ARGS = {
local TEMPLATE_RL_ICON = "med"
["name"] = "name",
 
-- Template parameters
local ARG_WORKSHOP_NAME = "name"
 
-- Infobox header labels
local TITLE_ID = "ID"
local TITLE_CATEGORY = "Toolbar Category"
local TITLE_SIZE = "Building Size"
local TITLE_MOVABLE = "Movable"
local TITLE_ESSENTIAL = "Initially Essential"
local TITLE_STORAGE_CAPACITY = "Storage Capacity"
local TITLE_CONSTRUCTION_TIME = "Construction Time"
local TITLE_CONSTRUCTION_COST = "Construction Cost"
local TITLE_WORKPLACES = "Workplaces"
local TITLE_RECIPES = "Recipes"
 
-- Subheading for all the buildings from this template.
local BUILDING_CATEGORY = "Production Building"
 
local INDEX_REQ_STACK_SIZE = "stackSize"
local INDEX_REQ_GOOD_ID = "goodID"
 
local BOLD = "'''"
local NBSP = " "
local WIKIMARKUP_MED_ICON_ALT = "|32px|alt="
 
local CSS_INLINE_INFOBOX = {
["float"] = "right",
["clear"] = "right",
["width"] = "256px",
["border"] = "1px solid #a2a9b1",
["border-spacing"] = "3px",
["border-collapse"] = "collapse",
["margin"] = "0.5em 0 0.5em 1em"
}
local CSS_INLINE_INFOBOX_INNER_TABLE = {
["border-collapse"] = "collapse"
}
local CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER = {
["border-bottom"] = "1px solid #a2a9b1"
}
local CSS_INLINE_INFOBOX_TR_TOP_DIVIDER = {
["border-top"] = "1px solid #a2a9b1"
}
 
-- Only two valid construction toolbar categories for buildings from this
-- template.
local ICON_FILENAMES_CATEGORIES = {
["Food Production"] = "Construct Food Production.png",
["Industry"] = "Construct Industry.png"
}
}


Line 83: Line 34:


---
---
--- A shortcut method that redirects to ResourceLink to build links to goods
--- Shortcut method to expand a template with parameters
--- with their IDs from the tables of required goods.
---
---
---@param goodID string the ID of the good to link to
---@param workshopName string the name of the workshop
---@return string wikimarkup representing an icon and link
---@return string html markup returned by the template
local function resourceLink(goodID)
local function expandRecipeList(workshopName)


return ResourceLink.resourceLinkWithID(goodID, TEMPLATE_RL_ICON)
return mw.getCurrentFrame():expandTemplate{ title="Recipe", args={
building=workshopName, display="list" } }
end
end


Line 96: Line 47:


---
---
--- Lays out an inner, no-styling table to display construction goods with
--- Builds using the provided wikiInfobox a few header items.
--- their stack sizes.
---
---
--- @param requiredGoods table of required goods, with stack sizes and IDs
---@param wikiInfobox table mw.html object into which we're building this
--- @return string wikimarkup for a table of required goods to insert in other markup
---@param workshopName string the name of the building the infobox is about
local function writeRequiredGoodsRows(requiredGoods)
---@return table the Mediawiki html object into which we've been adding things
local function makeHeaderContent(wikiInfobox, workshopName)


if not requiredGoods or #requiredGoods == 0 then
-- Grab the data we'll use to populate this.
error("Cannot write content with provided table of required goods.")
local workshopDescription = WorkshopsData.getWorkshopDescription(workshopName)
end
local workshopIconFilename = WorkshopsData.getWorkshopIcon(workshopName)


local requiredGoodsRows =  mw.html.create("table")
-- Start the header area
requiredGoodsRows:newline()
local header = Infobox.startNewHeader(wikiInfobox)
 
for _, requiredGroup in ipairs(requiredGoods) do
 
local stackSize = requiredGroup[INDEX_REQ_STACK_SIZE]
local goodID = requiredGroup[INDEX_REQ_GOOD_ID]
 
requiredGoodsRows:tag("tr")
:tag("td"):wikitext(BOLD .. stackSize .. BOLD):done()
:tag("td"):wikitext(resourceLink(goodID)):done()
:done():newline()
end
 
return requiredGoodsRows
end
 
 
 
---
--- Lays out the provided recipe IDs in a small list.
---
---@param recipes table of recipe IDs
---@return string wiki markup of a list of those IDs
local function writeRecipesRows(recipes)
 
if not recipes or #recipes == 0 then
error("Cannot write content with provided table of recipes.")
end
 
local recipeRows = mw.html.create("ul")
recipeRows:newline()
 
for _, recipeID in ipairs(recipes) do
-- Temporarily, just write the ID of the recipe.
recipeRows:tag("li"):wikitext(recipeID):done():newline()
end


recipeRows:done()
Infobox.makeTitle(header, workshopName)
Infobox.makeFlavorText(header, workshopDescription)
Infobox.makeTitleIcon(header, workshopIconFilename)


return recipeRows
return wikiInfobox
end
end


Line 159: Line 77:
---@param workshopName string the name of the good the infobox is about
---@param workshopName string the name of the good the infobox is about
---@return table the Mediawiki html object into which we've been adding things
---@return table the Mediawiki html object into which we've been adding things
local function makeInnerTable(wikiInfobox, workshopName)
local function makeInnerContent(wikiInfobox, workshopName)


-- Grab the data we'll use to populate this.
-- Grab the data we'll use to populate this.
local workshopID = WorkshopsData.getWorkshopID(workshopName)
local workshopCategory = WorkshopsData.getWorkshopCategory(workshopName)
local workshopCategory = WorkshopsData.getWorkshopCategory(workshopName)
local workshopSizeX, workshopSizeY = WorkshopsData.getWorkshopSize(workshopName)
local workshopRecipesTable = WorkshopsData.getAllWorkshopRecipes(workshopName)
local workshopIsMovable = WorkshopsData.isWorkshopMovable(workshopName)
local workshopIsMovable = WorkshopsData.isWorkshopMovable(workshopName)
local workshopIsEssential = WorkshopsData.isWorkshopInitiallyEssential(workshopName)
local workshopIsEssential = WorkshopsData.isWorkshopInitiallyEssential(workshopName)
local workshopSizeX, workshopSizeY = WorkshopsData.getWorkshopSize(workshopName)
local workshopStorageCap = WorkshopsData.getWorkshopStorage(workshopName)
local workshopStorageCap = WorkshopsData.getWorkshopStorage(workshopName)
local workshopWorkplaces = WorkshopsData.getWorkshopNumberOfWorkplaces(workshopName)
local workshopConstructionTime = WorkshopsData.getWorkshopConstructionTime(workshopName)
local workshopConstructionTime = WorkshopsData.getWorkshopConstructionTime(workshopName)
local workshopRequiredGoods = WorkshopsData.getWorkshopRequiredGoods(workshopName)
local workshopRequiredGoods = WorkshopsData.getAllWorkshopRequiredGoods(workshopName)
local workshopRecipesTable = WorkshopsData.getWorkshopRecipes(workshopName)
local workshopID = WorkshopsData.getWorkshopID(workshopName)
local workshopWorkplacesTable = WorkshopsData.getWorkshopWorkplaces(workshopName)


-- Only need to count these, just do it right away.
-- Start the inner table
local workshopWorkplaces
local innerTable = Infobox.startNewInnerTable(wikiInfobox)
if not workshopWorkplacesTable then
workshopWorkplaces = #workshopWorkplacesTable
else
workshopWorkplaces = nil
end


-- Start the inner table
-- we'll reuse this to mark where separators are needed in the table
local innerTable = wikiInfobox:tag("tr"):tag("td"):newline():tag("table"):css(CSS_INLINE_INFOBOX_INNER_TABLE)
local needsSeparator = false
innerTable:newline()


-- Additional parameters would go here.
-- Additional parameters would go here.


-- Construction toolbar category.
needsSeparator = Infobox.makeInnerRow(innerTable, workshopCategory, needsSeparator,
if workshopCategory then
Infobox.TITLE_CATEGORY,
local categoryIconFilename = ICON_FILENAMES_CATEGORIES[workshopCategory]
Infobox.makeCategoryIcon(workshopCategory, false) .. StyleUtils.NBSP .. workshopCategory)
if categoryIconFilename ~= nil then
needsSeparator = Infobox.makeInnerRow(innerTable, workshopRecipesTable and #workshopRecipesTable > 0,
local categoryIconPart = "[[File:" .. categoryIconFilename .. WIKIMARKUP_MED_ICON_ALT .. workshopCategory .. "]]"
needsSeparator, Infobox.TITLE_RECIPES,
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER)
expandRecipeList(workshopName))
:tag("th"):wikitext(TITLE_CATEGORY):done()
 
:tag("td"):wikitext(categoryIconPart .. NBSP .. workshopCategory):done()
needsSeparator = true
:done():newline()
 
end
needsSeparator = Infobox.makeInnerRow(innerTable, workshopIsMovable, needsSeparator,
end
Infobox.TITLE_MOVABLE, workshopIsMovable and "Yes" or "No")
-- Expand recipes into a small table
needsSeparator = Infobox.makeInnerRow(innerTable, workshopIsEssential, needsSeparator,
if workshopRecipesTable and #workshopRecipesTable > 0 then
Infobox.TITLE_ESSENTIAL, workshopIsEssential and "Yes" or "No")
local recipesRows = tostring( writeRecipesRows(workshopRecipesTable) )
needsSeparator = Infobox.makeInnerRow(innerTable, workshopSizeX and workshopSizeY,
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER)
needsSeparator, Infobox.TITLE_SIZE, workshopSizeX .. " × " .. workshopSizeY)
:tag("th"):wikitext(TITLE_RECIPES):done()
needsSeparator = Infobox.makeInnerRow(innerTable, workshopStorageCap, needsSeparator,
:newline()
Infobox.TITLE_STORAGE_CAPACITY, workshopStorageCap)
:tag("td"):wikitext(recipesRows):done()
needsSeparator = Infobox.makeInnerRow(innerTable, workshopWorkplaces, needsSeparator,
:done():newline()
Infobox.TITLE_WORKPLACES, workshopWorkplaces)
end
 
-- Since false is a valid value, have to directly check if it's nil.
needsSeparator = true
if workshopIsMovable ~= nil then
 
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER)
needsSeparator = Infobox.makeInnerRow(innerTable, workshopConstructionTime,
:tag("th"):wikitext(TITLE_MOVABLE):done()
needsSeparator, Infobox.TITLE_CONSTRUCTION_TIME,
:tag("td"):wikitext( workshopIsMovable and "Yes" or "No" ):done()
workshopConstructionTime)
:done():newline()
needsSeparator = Infobox.makeInnerRow(innerTable, workshopRequiredGoods, needsSeparator,
end
Infobox.TITLE_CONSTRUCTION_COST,
if workshopIsEssential ~= nil then
Infobox.writeRequiredGoodsRows(workshopRequiredGoods) )
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER)
 
:tag("th"):wikitext(TITLE_ESSENTIAL):done()
needsSeparator = true
:tag("td"):wikitext( workshopIsEssential and "Yes" or "No" ):done()
 
:done():newline()
needsSeparator = Infobox.makeInnerRow(innerTable, workshopID, needsSeparator,
end
Infobox.TITLE_ID, StyleUtils.ITALIC .. workshopID .. StyleUtils.ITALIC)
-- Combine sizes into one line
 
if workshopSizeX ~= nil and workshopSizeY ~= nil then
-- Close the inner table, and return it with the passed context
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER)
Infobox.endInnerTable(wikiInfobox, innerTable)
:tag("th"):wikitext(TITLE_SIZE):done()
:tag("td"):wikitext(workshopSizeX .. " × " .. workshopSizeY):done()
:done():newline()
end
if workshopStorageCap then
innerTable:tag("tr")
:tag("th"):wikitext(TITLE_STORAGE_CAPACITY):done()
:tag("td"):wikitext(workshopStorageCap):done()
:done():newline()
end
if workshopWorkplaces then
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER)
:tag("th"):wikitext(TITLE_WORKPLACES):done()
:tag("td"):wikitext(workshopWorkplaces):done()
:done():newline()
end
if workshopConstructionTime then
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER)
:tag("th"):wikitext(TITLE_CONSTRUCTION_TIME):done()
:tag("td"):wikitext(workshopConstructionTime):done()
:done():newline()
end
-- Need to build a separate table to display building materials
if workshopRequiredGoods then
local requiredGoodsRows = tostring( writeRequiredGoodsRows(workshopRequiredGoods) )
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER)
:tag("th"):wikitext(TITLE_CONSTRUCTION_COST):done()
:newline()
:tag("td"):newline():wikitext(requiredGoodsRows):newline():done()
:done():newline()
end
if workshopID then
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER)
:tag("th"):wikitext(TITLE_ID):done()
:tag("td"):wikitext(workshopID):done()
:done():newline()
end


-- Close the table.
return wikiInfobox
innerTable:done():newline()
-- Close the table cell and row the inner table is in.
wikiInfobox:done():done():newline()
end
end


--endregion
--endregion
Line 275: Line 146:


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


-- Use this method here to check to see whether the provided name is valid.
-- Use this method here to check to see whether the provided name is valid.
if not WorkshopsData.getAllDataForWorkshop(workshopName) then
if not WorkshopsData.getWorkshopID(workshopName) then
return "Shopbox can't find the specified workshop: " .. workshopName .. "."
return "Shopbox can't find the specified building: " .. workshopName .. "."
end
end


-- Additional template parameters would go here.
-- Additional template parameters would go here.


-- Get the data to display.
local wikiInfobox = Infobox.startNewInfobox()
local workshopDescription = WorkshopsData.getWorkshopDescription(workshopName)
makeHeaderContent(wikiInfobox, workshopName)
local workshopIconFilename = WorkshopsData.getWorkshopIcon(workshopName)
makeInnerContent(wikiInfobox, workshopName)
 
-- Make the top of the infobox that every workshop has...
local wikiInfobox = mw.html.create("table"):css(CSS_INLINE_INFOBOX):newline()
-- with a title...
wikiInfobox:tag("tr")
:tag("th"):wikitext(workshopName):done()
:done():newline()
-- and a subtitle, showing the functional category...
wikiInfobox:tag("tr")
:tag("td"):wikitext(BUILDING_CATEGORY):done()
:done():newline()
-- and a large icon.
if workshopIconFilename then
wikiInfobox:tag("tr")
:tag("td"):wikitext("[[File:" .. workshopIconFilename .. "]]"):done()
:done():newline()
wikiInfobox:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER)
:tag("td"):wikitext(workshopName .. ", as seen in-game"):done()
:done():newline()
end
makeInnerTable(wikiInfobox, workshopName)
 
-- Finish with the flavor text.
if workshopDescription then
wikiInfobox:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER)
:tag("td"):wikitext(workshopDescription):done()
:done():newline()
end
return wikiInfobox
return wikiInfobox

Latest revision as of 05:46, 24 December 2023

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

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



local Infobox = require("Module:Infobox")
local WorkshopsData = require("Module:WorkshopsData")
local StyleUtils = require("Module:StyleUtils")



--region Private constants

local ARGS = {
	["name"] = "name",
}

--endregion



--region Private methods

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

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



---
--- Builds using the provided wikiInfobox a few header items.
---
---@param wikiInfobox table mw.html object into which we're building this
---@param workshopName 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, workshopName)

	-- Grab the data we'll use to populate this.
	local workshopDescription = WorkshopsData.getWorkshopDescription(workshopName)
	local workshopIconFilename = WorkshopsData.getWorkshopIcon(workshopName)

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

	Infobox.makeTitle(header, workshopName)
	Infobox.makeFlavorText(header, workshopDescription)
	Infobox.makeTitleIcon(header, workshopIconFilename)

	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 workshopName string the name of the good the infobox is about
---@return table the Mediawiki html object into which we've been adding things
local function makeInnerContent(wikiInfobox, workshopName)

	-- Grab the data we'll use to populate this.
	local workshopCategory = WorkshopsData.getWorkshopCategory(workshopName)
	local workshopRecipesTable = WorkshopsData.getAllWorkshopRecipes(workshopName)
	local workshopIsMovable = WorkshopsData.isWorkshopMovable(workshopName)
	local workshopIsEssential = WorkshopsData.isWorkshopInitiallyEssential(workshopName)
	local workshopSizeX, workshopSizeY = WorkshopsData.getWorkshopSize(workshopName)
	local workshopStorageCap = WorkshopsData.getWorkshopStorage(workshopName)
	local workshopWorkplaces = WorkshopsData.getWorkshopNumberOfWorkplaces(workshopName)
	local workshopConstructionTime = WorkshopsData.getWorkshopConstructionTime(workshopName)
	local workshopRequiredGoods = WorkshopsData.getAllWorkshopRequiredGoods(workshopName)
	local workshopID = WorkshopsData.getWorkshopID(workshopName)

	-- 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

	-- Additional parameters would go here.

	needsSeparator = Infobox.makeInnerRow(innerTable, workshopCategory, needsSeparator,
			Infobox.TITLE_CATEGORY,
			Infobox.makeCategoryIcon(workshopCategory, false) .. StyleUtils.NBSP .. workshopCategory)
	needsSeparator = Infobox.makeInnerRow(innerTable, workshopRecipesTable and #workshopRecipesTable > 0,
			needsSeparator, Infobox.TITLE_RECIPES,
			expandRecipeList(workshopName))

	needsSeparator = true

	needsSeparator = Infobox.makeInnerRow(innerTable, workshopIsMovable, needsSeparator,
			Infobox.TITLE_MOVABLE, workshopIsMovable and "Yes" or "No")
	needsSeparator = Infobox.makeInnerRow(innerTable, workshopIsEssential, needsSeparator,
			Infobox.TITLE_ESSENTIAL, workshopIsEssential and "Yes" or "No")
	needsSeparator = Infobox.makeInnerRow(innerTable, workshopSizeX and workshopSizeY,
			needsSeparator, Infobox.TITLE_SIZE, workshopSizeX .. " × " .. workshopSizeY)
	needsSeparator = Infobox.makeInnerRow(innerTable, workshopStorageCap, needsSeparator,
			Infobox.TITLE_STORAGE_CAPACITY, workshopStorageCap)
	needsSeparator = Infobox.makeInnerRow(innerTable, workshopWorkplaces, needsSeparator,
			Infobox.TITLE_WORKPLACES, workshopWorkplaces)

	needsSeparator = true

	needsSeparator = Infobox.makeInnerRow(innerTable, workshopConstructionTime,
			needsSeparator, Infobox.TITLE_CONSTRUCTION_TIME,
			workshopConstructionTime)
	needsSeparator = Infobox.makeInnerRow(innerTable, workshopRequiredGoods, needsSeparator,
			Infobox.TITLE_CONSTRUCTION_COST,
			Infobox.writeRequiredGoodsRows(workshopRequiredGoods) )

	needsSeparator = true

	needsSeparator = Infobox.makeInnerRow(innerTable, workshopID, needsSeparator,
			Infobox.TITLE_ID, StyleUtils.ITALIC .. workshopID .. StyleUtils.ITALIC)

	-- 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 Shopbox.renderShopbox(frame)
	
	-- Every workshop must have a name.
	local workshopName = frame.args[ARGS.name]
	if not workshopName or workshopName == "" then
		return "You must specify the name of the building. See [[Template:Shopbox]] for examples."
	end

	-- Use this method here to check to see whether the provided name is valid.
	if not WorkshopsData.getWorkshopID(workshopName) then
		return "Shopbox can't find the specified building: " .. workshopName .. "."
	end

	-- Additional template parameters would go here.

	local wikiInfobox = Infobox.startNewInfobox()
	makeHeaderContent(wikiInfobox, workshopName)
	makeInnerContent(wikiInfobox, workshopName)
	
	return wikiInfobox
end

--endregion

return Shopbox