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 (Now also returns an error if the name is empty)
Line 70: Line 70:
local name = frame.args[ARG_GOOD_NAME]
local name = frame.args[ARG_GOOD_NAME]
if not name then
if not name or name == "" then
error("You must specify the name of the good in the Goodbox template.")
error("You must specify the name of the good in the Goodbox template.")
end
end

Revision as of 21:36, 7 November 2023

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 CSS_INFOBOX_INLINE_STYLE_TABLE = { 
	["float"] = "right", 
	["clear"] = "right", 
	["width"] = "256px", 
	["border"] = "1px solid #a2a9b1", 
	["border-spacing"] = "2px"
}

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