Module:Goodbox

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

local GoodsData = require("Module:GoodsData")

--region Private constants

-- Template parameters local ARG_GOOD_NAME = "name" local ARG_GOOD_PURPOSE = "purpose" local ARG_GOOD_SPECIES_PREF = "species_preference"

-- Infobox header labels local TITLE_ID = "ID" local TITLE_CATEGORY = "Storage Category" local TITLE_EATABLE = "Eatable" local TITLE_BURNABLE = "Burnable" local TITLE_BURN_TIME = "Fuel burn time" local TITLE_SELL_VALUE = "Value when sold" local TITLE_BUY_VALUE = "Price when bought"

local PATTERN_FORMAT_TWO_DECIMALS = "%1.2f" local PATTERN_CAPTURE_FIRST_LETTER_IN_WORD = "(%a)([%w]*)"

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"] = "2px", ["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" } -- Lookup table for storage category icons. local ICON_FILENAMES_CATEGORIES = { ["Building Materials"]	= "Icon_UI_CategoryBuilding.png", ["Consumable Items"]	= "Icon_UI_CategoryConsumable.png", ["Crafting Resources"]	= "Icon_UI_CategoryCrafting.png", ["Food"]				= "Icon UI CategoryFood.png", ["Fuel & Exploration"]	= "Icon_UI_CategoryFuel.png", ["Trade Goods"]			= "Icon_UI_CategoryTrade.png" }

--endregion

--region Private methods

--- --- Shortcut string to reformat numbers with two decimals. --- ---@param value number whole or with a fractional part ---@return string reformatted to force two decimal places local function toDecimal(value)

return string.format(PATTERN_FORMAT_TWO_DECIMALS, value) end

--- --- Capitalizes the first character of each word to "Make It Title Case." Also --- converts any underscores to spaces. --- --- @param title string to capitalize --- @return string capitalized with title case local function toTitleCase(title)

title = title:gsub("_", " ")

local newTitle = title:gsub(PATTERN_CAPTURE_FIRST_LETTER_IN_WORD, function(firstLetter, rest)		return firstLetter:upper .. rest:lower	end)

return newTitle 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 goodName string the name of the good the infobox is about ---@param purpose string the parameter provided to the template ---@param speciesPref string the parameter provided to the template ---@return table the Mediawiki html object into which we've been adding things local function makeInnerTable(wikiInfobox, goodName, purpose, speciesPref)

-- Grab the data we'll use to populate this. local goodID = GoodsData.getGoodID(goodName) local goodCategory = GoodsData.getGoodCategory(goodName) local goodIsEatable = GoodsData.isGoodEatable(goodName) local goodIsBurnable = GoodsData.isGoodBurnable(goodName) local goodBurnTime = GoodsData.getGoodBurnTime(goodName) local goodSellValue, goodBuyValue = GoodsData.getGoodValue(goodName)

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

-- Start with the things not provided by the data. if purpose and purpose ~= "" then innerTable:tag("tr") :tag("th"):wikitext(toTitleCase(ARG_GOOD_PURPOSE)):done :tag("td"):wikitext(purpose):done :done:newline end if speciesPref and speciesPref ~= "" then innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER) :tag("th"):wikitext(toTitleCase(ARG_GOOD_SPECIES_PREF)):done :tag("td"):wikitext(speciesPref):done :done:newline end

-- Storage category (this is the same as the subtitle for now) if goodCategory then local categoryIcon = "" innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER) :tag("th"):wikitext(TITLE_CATEGORY):done :tag("td"):wikitext(categoryIcon .. NBSP .. goodCategory):done :done:newline end -- Since false is a valid value, have to directly check if it's nil. if goodIsEatable ~= nil then innerTable:tag("tr") :tag("th"):wikitext(TITLE_EATABLE):done :tag("td"):wikitext(goodIsEatable and "Yes" or "No"):done :done:newline end if goodIsBurnable ~= nil then innerTable:tag("tr") :tag("th"):wikitext(TITLE_BURNABLE):done :tag("td"):wikitext(goodIsBurnable and "Yes" or "No"):done :done:newline end if goodIsBurnable and goodBurnTime then innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER) :tag("th"):wikitext(TITLE_BURN_TIME):done :tag("td"):wikitext(goodBurnTime):done :done:newline end -- Trade values. if goodSellValue then innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER) :tag("th"):wikitext(TITLE_SELL_VALUE):done :tag("td"):wikitext(toDecimal(goodSellValue)):done :done:newline end if goodBuyValue then innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER) :tag("th"):wikitext(TITLE_BUY_VALUE):done :tag("td"):wikitext(toDecimal(goodBuyValue)):done :done:newline end -- End with the ID. if goodID then innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER) :tag("th"):wikitext(TITLE_ID):done :tag("td"):wikitext("\'" .. goodID .. "\'"):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 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 Goodbox.infobox(frame)

-- Every good must have a name. local goodName = frame.args[ARG_GOOD_NAME] if not goodName or goodName == "" then return "You must specify the name of the good. See Template:Goodbox for examples." end

-- Use this method here to check to see whether the provided name is valid. if not GoodsData.getGoodID(goodName) then return "Goodbox can't find the specified good: " .. goodName .. "."	end

-- Additional template parameters, may or may not be present. local purpose = frame.args[ARG_GOOD_PURPOSE] local speciesPref = frame.args[ARG_GOOD_SPECIES_PREF]

-- Get the data. local goodDescription = GoodsData.getGoodDescription(goodName) local goodCategory = GoodsData.getGoodCategory(goodName) local goodIconFilename = GoodsData.getGoodIcon(goodName)

-- Make the top of the infobox that every item has... local wikiInfobox = mw.html.create("table"):css(CSS_INLINE_INFOBOX):newline -- with a title... wikiInfobox:tag("tr") :tag("th"):wikitext(goodName):done :done:newline -- and a subtitle, showing the category... if goodCategory then wikiInfobox:tag("tr") :tag("td"):wikitext(goodCategory):done :done:newline end -- and a large icon. if goodIconFilename then wikiInfobox:tag("tr") :tag("td"):wikitext(""):done :done:newline wikiInfobox:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER) :tag("td"):wikitext(goodName .. ", as seen in-game"):done :done:newline end

makeInnerTable(wikiInfobox, goodName, purpose, speciesPref)

-- Finish with the flavor text. if goodDescription then wikiInfobox:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER) :tag("td"):wikitext(goodDescription):done :done:newline end

return wikiInfobox end

--endregion

return Goodbox