Module:Goodbox: Difference between revisions

From Against the Storm Official Wiki
(No longer referencing mw title since it's the title of this module not where it's being invoked from.)
m (fixing wrong italics. keeping single quotes)
 
(23 intermediate revisions by the same user not shown)
Line 1: Line 1:
---
---
-- Module to create infobox for displaying on a good's wiki page.
--- Module to create an infobox for displaying on a good's wiki page.
--
---
-- @module Good
--- 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 Goodbox = {}


---
 
-- Dependencies
 
---
local Infobox = require("Module:Infobox")
local GoodsData = require("Module:GoodsData")
local GoodsData = require("Module:GoodsData")
local StyleUtils = require("Module:StyleUtils")


---
-- Constants
---
local ARG_GOOD_NAME = "name"
local ARG_GOOD_PURPOSE = "purpose"
local ARG_GOOD_SPECIES_PREF = "species_preference"


local INDEX_GOOD_ID = 1
--region  Private constants
local INDEX_GOOD_NAME = 2
local INDEX_GOOD_DESCRIPTION = 3
local INDEX_GOOD_CATEGORY = 4
local INDEX_GOOD_EATABLE = 5
local INDEX_GOOD_CAN_BE_BURNED = 6
local INDEX_GOOD_BURNING_TIME = 7
local INDEX_GOOD_TRADING_SELL_VALUE = 8
local INDEX_GOOD_TRADING_BUY_VALUE = 9
local INDEX_GOOD_ICON_FILENAME = 10


local TITLE_ID = "ID"
local ARGS = {
local TITLE_CATEGORY = "Inventory Category"
["name"] = "name",
local TITLE_TYPE = "ID Type"
["purpose"] = "purpose",
local TITLE_EATABLE = "Is eatable?"
["species_preference"] = "species_preference",
local TITLE_BURNABLE = "Is burnable?"
}
local TITLE_BURN_TIME = "Fuel burn time"
local TITLE_SELL_VALUE = "Value when sold"
local TITLE_BUY_VALUE = "Price when bought"


local PATTERN_CAPTURE_BEGINNING_WITHIN_BRACKETS = "^%[(.-)%]"
--endregion
local PATTERN_CAPTURE_BEGINNING_AFTER_UNDERSCORE = "^_(.-)%s"
local PATTERN_CAPTURE_FIRST_WORD = "^(%w-)%s"
local PATTERN_FORMAT_TWO_DECIMALS = "%1.2f"


local BR = "<br />"


local CSS_INFOBOX_INLINE_STYLE_TABLE = {
["float"] = "right",
["clear"] = "right",
["width"] = "256px",
["border"] = "1px solid #a2a9b1",
["border-spacing"] = "2px"
}


--region Private methods
---
--- Builds using the provided wikiInfobox a few header items.
---
---
-- Member variable: Good
---@param wikiInfobox table mw.html object into which we're building this
--  
---@param goodName string the name of the good the infobox is about
--  
---@return table the Mediawiki html object into which we've been adding things
local good
local function makeHeaderContent(wikiInfobox, goodName)
 
-- Grab the data we'll use to populate this.
local goodDescription = GoodsData.getGoodDescription(goodName)
local goodIconFilename = GoodsData.getGoodIcon(goodName)


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


Infobox.makeTitle(header, goodName)
Infobox.makeFlavorText(header, goodDescription)
Infobox.makeTitleIcon(header, goodIconFilename)


---
-- 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 Goodbox.infobox(frame)
-- Every good must have a name.
local name = frame.args[ARG_GOOD_NAME]
if not name then
error("You must specify the name of the good in the Goodbox template.")
end
-- Every Good should have a purpose.
local purpose = frame.args[ARG_GOOD_PURPOSE]
-- Specific parameters, may or may not be present.
local speciesPref = frame.args[ARG_GOOD_SPECIES_PREF]
-- Retrieve the actual data for the good.
good = GoodsData.getAllDataForGood(name)
if not good then
return "No good found for infobox."
end
local goodID = good[INDEX_GOOD_ID]
local goodName = good[INDEX_GOOD_NAME]
local goodDescription = good[INDEX_GOOD_DESCRIPTION]
local goodCategory = good[INDEX_GOOD_CATEGORY]
local goodIsEatable = good[INDEX_GOOD_EATABLE]
local goodIsBurnable = good[INDEX_GOOD_CAN_BE_BURNED]
local goodBurnTime = good[INDEX_GOOD_BURNING_TIME]
local goodSellValue = good[INDEX_GOOD_TRADING_SELL_VALUE]
local goodBuyValue = good[INDEX_GOOD_TRADING_BUY_VALUE]
local goodIconFilename = good[INDEX_GOOD_ICON_FILENAME]
local goodType = extractType(goodID)
-- Make the top of the infobox that every item has.
wikiInfobox = mw.html.create("table"):css( CSS_INFOBOX_INLINE_STYLE_TABLE )
-- Title of infobox.
if name then
wikiInfobox:tag("tr"):tag("td"):wikitext(name):done():done():newline()
end
-- Subtitle for category.
if goodCategory then
wikiInfobox:tag("tr"):tag("td"):wikitext(goodCategory):done():done():newline()
end
-- Large icon of infobox.
if goodIconFilename then
wikiInfobox:tag("tr"):tag("td"):wikitext("[[File:" .. goodIconFilename .. ".png]]"):done():done():newline()
wikiInfobox:tag("tr"):tag("td"):wikitext(name .. " icon as seen in-game"):done():done():newline()
end
-- Data fields of the infobox with labels and values
local innerTable = wikiInfobox:tag("tr"):tag("td"):tag("table")
innerTable:newline()
if purpose then
innerTable:tag("tr"):tag("th"):wikitext(toTitleCase(ARG_GOOD_PURPOSE)):done()
:tag("td"):wikitext(purpose):done():done():newline()
end
if speciesPref then
innerTable:tag("tr"):tag("th"):wikitext(toTitleCase(ARG_GOOD_SPECIES_PREF)):done()
:tag("td"):wikitext(speciesPref):done():done():newline()
end
-- Data provided by the CSV
if goodCategory then
innerTable:tag("tr"):tag("th"):wikitext(TITLE_CATEGORY):done()
:tag("td"):wikitext(goodCategory):done():done():newline()
end
-- Eatable is superfluous when the category is food.
--if goodIsEatable then
-- innerTable:tag("tr"):tag("th"):wikitext(TITLE_EATABLE):done()
-- :tag("td"):wikitext(goodIsEatable):done():done():newline()
--end
-- Burnable is superfluous but we can use it to determine whether to show
-- how long the fuel burns.
-- if goodIsBurnable then
-- innerTable:tag("tr"):tag("th"):wikitext(TITLE_BURNABLE):done()
-- :tag("td"):wikitext(goodIsBurnable):done():done():newline()
-- end
if goodIsBurnable == "True" and goodBurnTime then
innerTable:tag("tr"):tag("th"):wikitext(TITLE_BURN_TIME):done()
:tag("td"):wikitext(goodBurnTime):done():done():newline()
end
if goodSellValue then
innerTable:tag("tr"):tag("th"):wikitext(TITLE_SELL_VALUE):done()
:tag("td"):wikitext(toDecimal(goodSellValue)):done():done():newline()
end
if goodBuyValue then
innerTable:tag("tr"):tag("th"):wikitext(TITLE_BUY_VALUE):done()
:tag("td"):wikitext(toDecimal(goodBuyValue)):done():done():newline()
end
if goodID then
innerTable:tag("tr"):tag("th"):wikitext(TITLE_ID):done()
:tag("td"):wikitext("\"" .. goodID .. "\""):done():done():newline()
end
innerTable:done()
wikiInfobox:done():done():newline()
if goodDescription then
wikiInfobox:tag("tr"):tag("td"):wikitext(goodDescription):done():done():newline()
end
return wikiInfobox
return wikiInfobox
end
end
Line 175: Line 59:


---
---
-- Extracts the beginning of the ID into the type of good. For example, when
--- Builds using the provided wikiInfobox a subtable to lay out headers and
-- ID = [Vessel] Pottery, the type is Vessel.
--- fields.
--
---
-- @param goodID the ID of the good from the data
---@param wikiInfobox table mw.html object into which we're building this
-- @return the type of good
---@param goodName string the name of the good the infobox is about
function extractType(goodID)
---@param params table of strings, the parameter provided to the template
---@return table the Mediawiki html object into which we've been adding things
local typecode = goodID:match(PATTERN_CAPTURE_BEGINNING_WITHIN_BRACKETS)
local function makeInnerContent(wikiInfobox, goodName, params)
 
if not typecode then
-- Grab the data we'll use to populate this.
typecode = goodID:match(PATTERN_CAPTURE_BEGINNING_AFTER_UNDERSCORE)
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)
local goodID = GoodsData.getGoodID(goodName)
 
-- 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
end
if not typecode then
typecode = goodID:match(PATTERN_CAPTURE_FIRST_WORD)
end
return typecode
end


needsSeparator = Infobox.makeInnerRow(innerTable, goodCategory, needsSeparator,
Infobox.TITLE_CATEGORY,
Infobox.makeCategoryIcon(goodCategory, true) .. StyleUtils.NBSP .. goodCategory)
needsSeparator = Infobox.makeInnerRow(innerTable, goodIsEatable, needsSeparator,
Infobox.TITLE_EATABLE, goodIsEatable and "Yes" or "No")
needsSeparator = Infobox.makeInnerRow(innerTable, goodIsBurnable, needsSeparator,
Infobox.TITLE_BURNABLE, goodIsBurnable and "Yes" or "No")
needsSeparator = Infobox.makeInnerRow(innerTable, goodIsBurnable and goodBurnTime,
needsSeparator, Infobox.TITLE_BURN_TIME, goodBurnTime)
needsSeparator = true
needsSeparator = Infobox.makeInnerRow(innerTable, goodSellValue, needsSeparator,
Infobox.TITLE_SELL_VALUE, Infobox.toTwoDecimalPlaces(goodSellValue) .. StyleUtils.NBSP .. StyleUtils.AMBER())
needsSeparator = Infobox.makeInnerRow(innerTable, goodBuyValue, needsSeparator,
Infobox.TITLE_BUY_VALUE, Infobox.toTwoDecimalPlaces(goodBuyValue) .. StyleUtils.NBSP .. StyleUtils.AMBER())
needsSeparator = true
needsSeparator = Infobox.makeInnerRow(innerTable, goodID, needsSeparator,
Infobox.TITLE_ID, "'" .. goodID .. "'")


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


function toDecimal(value)
return wikiInfobox
return string.format(PATTERN_FORMAT_TWO_DECIMALS, value)
end
end


--endregion




--region Public methods
---
--- Creates an html and wiki markup to display the data in an infobox.
---
---
-- Capitalizes the first character of each word.
--- @param frame table from template's calling context
--
--- @return string of html and wiki markup
-- @param title the title to capitalize
function Goodbox.renderGoodbox(frame)
-- @return the title once capitalized
 
function toTitleCase(title)
-- Every good must have a name.
local goodName = frame.args[ARGS.name]
local newTitle = title:gsub("(%a)([%w_']*)", function(first, rest)
if not goodName or goodName == "" then
return first:upper() .. rest:lower()
return "You must specify the name of the good. See [[Template:Goodbox]] for examples."
end)
end
 
newTitle, _ = newTitle:gsub("_", " ")
-- Use this method here to check to see whether the provided name is valid.
if not GoodsData.getGoodID(goodName) then
return newTitle
return "Goodbox can't find the specified good: " .. goodName .. "."
end
 
-- Additional template parameters, may or may not be present.
local purpose = frame.args[ARGS.purpose]
local speciesPref = frame.args[ARGS.species_preference]
 
local wikiInfobox = Infobox.startNewInfobox()
makeHeaderContent(wikiInfobox, goodName)
makeInnerContent(wikiInfobox, goodName,
{ [ARGS.purpose] = purpose, [ARGS.species_preference] = speciesPref })
 
return wikiInfobox
end
end


 
--endregion


return Goodbox
return Goodbox

Latest revision as of 18:19, 24 December 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")
local StyleUtils = require("Module:StyleUtils")



--region  Private constants

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

--endregion



--region Private methods

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

	-- Grab the data we'll use to populate this.
	local goodDescription = GoodsData.getGoodDescription(goodName)
	local goodIconFilename = GoodsData.getGoodIcon(goodName)

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

	Infobox.makeTitle(header, goodName)
	Infobox.makeFlavorText(header, goodDescription)
	Infobox.makeTitleIcon(header, goodIconFilename)

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

	-- Grab the data we'll use to populate this.
	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)
	local goodID = GoodsData.getGoodID(goodName)

	-- 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, goodCategory, needsSeparator,
			Infobox.TITLE_CATEGORY,
			Infobox.makeCategoryIcon(goodCategory, true) .. StyleUtils.NBSP .. goodCategory)
	needsSeparator = Infobox.makeInnerRow(innerTable, goodIsEatable, needsSeparator,
			Infobox.TITLE_EATABLE, goodIsEatable and "Yes" or "No")
	needsSeparator = Infobox.makeInnerRow(innerTable, goodIsBurnable, needsSeparator,
			Infobox.TITLE_BURNABLE, goodIsBurnable and "Yes" or "No")
	needsSeparator = Infobox.makeInnerRow(innerTable, goodIsBurnable and goodBurnTime,
			needsSeparator, Infobox.TITLE_BURN_TIME, goodBurnTime)

	needsSeparator = true

	needsSeparator = Infobox.makeInnerRow(innerTable, goodSellValue, needsSeparator,
			Infobox.TITLE_SELL_VALUE, Infobox.toTwoDecimalPlaces(goodSellValue) .. StyleUtils.NBSP .. StyleUtils.AMBER())
	needsSeparator = Infobox.makeInnerRow(innerTable, goodBuyValue, needsSeparator,
			Infobox.TITLE_BUY_VALUE, Infobox.toTwoDecimalPlaces(goodBuyValue) .. StyleUtils.NBSP .. StyleUtils.AMBER())

	needsSeparator = true

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

	-- 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 Goodbox.renderGoodbox(frame)

	-- Every good must have a name.
	local goodName = frame.args[ARGS.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[ARGS.purpose]
	local speciesPref = frame.args[ARGS.species_preference]

	local wikiInfobox = Infobox.startNewInfobox()
	makeHeaderContent(wikiInfobox, goodName)
	makeInnerContent(wikiInfobox, goodName,
			{ [ARGS.purpose] = purpose, [ARGS.species_preference] = speciesPref })

	return wikiInfobox
end

--endregion

return Goodbox