Module:Shopbox

--- --- 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 WorkshopsData = require("Module:WorkshopsData") local ResourceLink = require("Module:ResourceLink")

--region Private constants

-- External templates local TEMPLATE_RL_ICON = "med"

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

--endregion

--region Private methods

--- --- A shortcut method that redirects to ResourceLink to build links to goods --- with their IDs from the tables of required goods. --- ---@param goodID string the ID of the good to link to ---@return string wikimarkup representing an icon and link local function resourceLink(goodID)

return ResourceLink.resourceLinkWithID(goodID, TEMPLATE_RL_ICON) end

--- --- Lays out an inner, no-styling table to display construction goods with --- their stack sizes. --- --- @param requiredGoods table of required goods, with stack sizes and IDs --- @return string wikimarkup for a table of required goods to insert in other markup local function writeRequiredGoodsRows(requiredGoods)

if not requiredGoods or #requiredGoods == 0 then error("Cannot write content with provided table of required goods.") end

local requiredGoodsRows = mw.html.create("table") requiredGoodsRows:newline

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

return recipeRows 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 makeInnerTable(wikiInfobox, workshopName)

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

-- Only need to count these, just do it right away. local workshopWorkplaces if not workshopWorkplacesTable then workshopWorkplaces = #workshopWorkplacesTable else workshopWorkplaces = nil end

-- Start the inner table local innerTable = wikiInfobox:tag("tr"):tag("td"):newline:tag("table"):css(CSS_INLINE_INFOBOX_INNER_TABLE) innerTable:newline

-- Additional parameters would go here.

-- Construction toolbar category. if workshopCategory then local categoryIconFilename = ICON_FILENAMES_CATEGORIES[workshopCategory] if categoryIconFilename ~= nil then local categoryIconPart = "" innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER) :tag("th"):wikitext(TITLE_CATEGORY):done :tag("td"):wikitext(categoryIconPart .. NBSP .. workshopCategory):done :done:newline end end -- Expand recipes into a small table if workshopRecipesTable and #workshopRecipesTable > 0 then local recipesRows = tostring( writeRecipesRows(workshopRecipesTable) ) innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER) :tag("th"):wikitext(TITLE_RECIPES):done :newline :tag("td"):wikitext(recipesRows):done :done:newline end -- Since false is a valid value, have to directly check if it's nil. if workshopIsMovable ~= nil then innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER) :tag("th"):wikitext(TITLE_MOVABLE):done :tag("td"):wikitext( workshopIsMovable and "Yes" or "No" ):done :done:newline end if workshopIsEssential ~= nil then innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER) :tag("th"):wikitext(TITLE_ESSENTIAL):done :tag("td"):wikitext( workshopIsEssential and "Yes" or "No" ):done :done:newline end -- Combine sizes into one line if workshopSizeX ~= nil and workshopSizeY ~= nil then innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER) :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. innerTable:done:newline -- Close the table cell and row the inner table is in. wikiInfobox:done:done:newline end

--endregion

--region Public methods

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

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

-- Additional template parameters would go here.

-- Get the data to display. local workshopDescription = WorkshopsData.getWorkshopDescription(workshopName) local workshopIconFilename = WorkshopsData.getWorkshopIcon(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(""):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 end

--endregion

return Shopbox