Module:Goodbox

From Against the Storm Official Wiki
Revision as of 03:00, 12 November 2023 by Aeredor (talk | contribs) (added margin around infobox)

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

---
-- Module to create infobox for displaying on a good's wiki page.
--
-- @module Good
local Goodbox = {}

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

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

local INDEX_GOOD_ID = 1
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 TITLE_CATEGORY = "Inventory Category"
local TITLE_TYPE = "ID Type"
local TITLE_EATABLE = "Is eatable?"
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 = "^%[(.-)%]"
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 NBSP = "&nbsp;"

local WIKI_MED_ICON_MARKUP = "|32px|alt="

local categoryIcons = {
	["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"
}

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



---
-- Member variable: Good
-- 
-- 
local good



---
-- 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 or 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 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"):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
		local catIcon = "[[File:" .. categoryIcons[goodCategory] .. WIKI_MED_ICON_MARKUP .. goodCategory .. "]]"
		innerTable:tag("tr"):tag("th"):wikitext(TITLE_CATEGORY):done()
			:tag("td"):wikitext(catIcon .. NBSP .. 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
end



---
-- Extracts the beginning of the ID into the type of good. For example, when 
-- ID = [Vessel] Pottery, the type is Vessel.
--
-- @param goodID the ID of the good from the data
-- @return the type of good
function extractType(goodID)
	
	local typecode = goodID:match(PATTERN_CAPTURE_BEGINNING_WITHIN_BRACKETS)
	
	if not typecode then
		typecode = goodID:match(PATTERN_CAPTURE_BEGINNING_AFTER_UNDERSCORE)
	end
	
	if not typecode then
		typecode = goodID:match(PATTERN_CAPTURE_FIRST_WORD)
	end
	
	return typecode
end



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



---
-- Capitalizes the first character of each word.
--
-- @param title the title to capitalize
-- @return the title once capitalized
function toTitleCase(title)
	
	local newTitle = title:gsub("(%a)([%w_']*)", function(first, rest)
			return first:upper() .. rest:lower()
		end)
	
	newTitle, _ = newTitle:gsub("_", " ")
	
	return newTitle
end



return Goodbox