Module:Goodbox: Difference between revisions

From Against the Storm Official Wiki
m (A couple of small cleanups)
(Updated to use utility module Infobox)
Line 14: Line 14:




local Infobox = require("Module:Infobox")
local GoodsData = require("Module:GoodsData")
local GoodsData = require("Module:GoodsData")


Line 20: Line 21:
--region  Private constants
--region  Private constants


-- Template parameters
local ARG_NAME = "name"
local ARG_GOOD_NAME = "name"
local ARG_PURPOSE = "purpose"
local ARG_GOOD_PURPOSE = "purpose"
local ARG_SPECIES_PREFERENCE = "species_preference"
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 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
--endregion
Line 73: Line 32:


--region Private methods
--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


---
---
Line 125: Line 53:


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


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


-- Storage category (this is the same as the subtitle for now)
-- Storage category (this is the same as the subtitle for now)
if goodCategory then
if goodCategory then
local categoryIcon = "[[File:" .. ICON_FILENAMES_CATEGORIES[goodCategory] .. WIKIMARKUP_MED_ICON_ALT .. goodCategory .. "]]"
 
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER)
local categoryIcon = "[[File:" .. Infobox.ICON_FILENAMES_CATEGORIES[goodCategory] .. "|" .. Infobox.ICONSIZE_MED .. "|alt=" .. goodCategory .. "]]"
:tag("th"):wikitext(TITLE_CATEGORY):done()
 
:tag("td"):wikitext(categoryIcon .. NBSP .. goodCategory):done()
Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_TOP,
:done():newline()
Infobox.TITLE_CATEGORY, categoryIcon .. NBSP .. goodCategory)
end
end
-- Since false is a valid value, have to directly check if it's nil.
-- Since false is a valid value, have to directly check if it's nil.
if goodIsEatable ~= nil then
if goodIsEatable ~= nil then
innerTable:tag("tr")
 
:tag("th"):wikitext(TITLE_EATABLE):done()
Infobox.buildStandardRow(innerTable, nil,
:tag("td"):wikitext(goodIsEatable and "Yes" or "No"):done()
Infobox.TITLE_EATABLE, goodIsEatable and "Yes" or "No")
:done():newline()
end
end
if goodIsBurnable ~= nil then
if goodIsBurnable ~= nil then
innerTable:tag("tr")
 
:tag("th"):wikitext(TITLE_BURNABLE):done()
Infobox.buildStandardRow(innerTable, nil,
:tag("td"):wikitext(goodIsBurnable and "Yes" or "No"):done()
Infobox.TITLE_BURNABLE, goodIsBurnable and "Yes" or "No")
:done():newline()
end
end
if goodIsBurnable and goodBurnTime then
if goodIsBurnable and goodBurnTime then
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER)
 
:tag("th"):wikitext(TITLE_BURN_TIME):done()
Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_BOT,
:tag("td"):wikitext(goodBurnTime):done()
Infobox.TITLE_BURN_TIME, goodBurnTime)
:done():newline()
end
end
-- Trade values.
-- Trade values.
if goodSellValue then
if goodSellValue then
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER)
 
:tag("th"):wikitext(TITLE_SELL_VALUE):done()
Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_TOP,
:tag("td"):wikitext(toDecimal(goodSellValue)):done()
Infobox.TITLE_SELL_VALUE, Infobox.toTwoDecimalPlaces(goodSellValue))
:done():newline()
end
end
if goodBuyValue then
if goodBuyValue then
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER)
 
:tag("th"):wikitext(TITLE_BUY_VALUE):done()
Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_BOT,
:tag("td"):wikitext(toDecimal(goodBuyValue)):done()
Infobox.TITLE_BUY_VALUE, Infobox.toTwoDecimalPlaces(goodBuyValue))
:done():newline()
end
end
-- End with the ID.
-- End with the ID.
if goodID then
if goodID then
innerTable:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER)
 
:tag("th"):wikitext(TITLE_ID):done()
Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_TOP,
:tag("td"):wikitext("\'" .. goodID .. "\'"):done()
Infobox.TITLE_ID, "\'" .. goodID .. "\'")
:done():newline()
end
end


Line 207: Line 127:
--- @param frame table from template's calling context
--- @param frame table from template's calling context
--- @return string of html and wiki markup
--- @return string of html and wiki markup
function Goodbox.infobox(frame)
function Goodbox.renderGoodbox(frame)


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


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


-- Get the data.
-- Get the data.
Line 230: Line 150:


-- Make the top of the infobox that every item has...
-- Make the top of the infobox that every item has...
local wikiInfobox = mw.html.create("table"):css(CSS_INLINE_INFOBOX):newline()
local wikiInfobox = mw.html.create("table"):css(Infobox.CSS_MAIN):newline()
-- with a title...
-- with a title...
wikiInfobox:tag("tr")
wikiInfobox:tag("tr")
Line 246: Line 166:
:tag("td"):wikitext("[[File:" .. goodIconFilename .. "]]"):done()
:tag("td"):wikitext("[[File:" .. goodIconFilename .. "]]"):done()
:done():newline()
:done():newline()
wikiInfobox:tag("tr"):css(CSS_INLINE_INFOBOX_TR_BOTTOM_DIVIDER)
wikiInfobox:tag("tr"):css(Infobox.CSS_TR_BORDER_BOT)
:tag("td"):wikitext(goodName .. ", as seen in-game"):done()
:tag("td"):wikitext(goodName .. ", as seen in-game"):done()
:done():newline()
:done():newline()
Line 255: Line 175:
-- Finish with the flavor text.
-- Finish with the flavor text.
if goodDescription then
if goodDescription then
wikiInfobox:tag("tr"):css(CSS_INLINE_INFOBOX_TR_TOP_DIVIDER)
wikiInfobox:tag("tr"):css(Infobox.CSS_TR_BORDER_TOP)
:tag("td"):wikitext(goodDescription):done()
:tag("td"):wikitext(goodDescription):done()
:done():newline()
:done():newline()

Revision as of 00:59, 28 November 2023

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

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



--region  Private constants

local ARG_NAME = "name"
local ARG_PURPOSE = "purpose"
local ARG_SPECIES_PREFERENCE = "species_preference"

local NBSP = " "

--endregion



--region Private methods

---
--- 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(Infobox.CSS_INNER_TABLE)
	innerTable:newline()

	-- Start with the things not provided by the data.
	if purpose and purpose ~= "" then

		Infobox.buildStandardRow(innerTable, nil,
				Infobox.toTitleCase(ARG_PURPOSE), purpose)
	end
	if speciesPref and speciesPref ~= "" then

		Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_BOT,
				Infobox.toTitleCase(ARG_SPECIES_PREFERENCE), speciesPref)
	end

	-- Storage category (this is the same as the subtitle for now)
	if goodCategory then

		local categoryIcon = "[[File:" .. Infobox.ICON_FILENAMES_CATEGORIES[goodCategory] .. "|" .. Infobox.ICONSIZE_MED .. "|alt=" .. goodCategory .. "]]"

		Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_TOP,
				Infobox.TITLE_CATEGORY, categoryIcon .. NBSP .. goodCategory)
	end
	-- Since false is a valid value, have to directly check if it's nil.
	if goodIsEatable ~= nil then

		Infobox.buildStandardRow(innerTable, nil,
				Infobox.TITLE_EATABLE, goodIsEatable and "Yes" or "No")
	end
	if goodIsBurnable ~= nil then

		Infobox.buildStandardRow(innerTable, nil,
				Infobox.TITLE_BURNABLE, goodIsBurnable and "Yes" or "No")
	end
	if goodIsBurnable and goodBurnTime then

		Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_BOT,
				Infobox.TITLE_BURN_TIME, goodBurnTime)
	end
	-- Trade values.
	if goodSellValue then

		Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_TOP,
				Infobox.TITLE_SELL_VALUE, Infobox.toTwoDecimalPlaces(goodSellValue))
	end
	if goodBuyValue then

		Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_BOT,
				Infobox.TITLE_BUY_VALUE, Infobox.toTwoDecimalPlaces(goodBuyValue))
	end
	-- End with the ID.
	if goodID then

		Infobox.buildStandardRow(innerTable, Infobox.CSS_TR_BORDER_TOP,
				Infobox.TITLE_ID, "\'" .. goodID .. "\'")
	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.renderGoodbox(frame)

	-- Every good must have a name.
	local goodName = frame.args[ARG_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_PURPOSE]
	local speciesPref = frame.args[ARG_SPECIES_PREFERENCE]

	-- 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(Infobox.CSS_MAIN):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("[[File:" .. goodIconFilename .. "]]"):done()
			:done():newline()
		wikiInfobox:tag("tr"):css(Infobox.CSS_TR_BORDER_BOT)
				: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(Infobox.CSS_TR_BORDER_TOP)
				:tag("td"):wikitext(goodDescription):done()
			:done():newline()
	end

	return wikiInfobox
end

--endregion

return Goodbox