This module is invoked by the following templates:
- {{Companion Clothing/Camp Spirit/Page}}
- {{Companion Clothing/Camp Spirit/PageList}}
- {{Companion Clothing/Camp Spirit/Price}}
It uses these submodules:
- /Data - Individual companion hat information and pricing information based on rarity
local arguments = require("Module:Arguments")
-- Note: Comments are Lua Language Server Annotations
-- Annotations allow for type checking and autocomplete in VSCode and other IDEs with the appropriate extensions.
--- @type CompanionHatData
local data = mw.loadData("Module:Camp_Spirit/Companion/Hat/Data")
local p = {}
--- @param hat CompanionHat The companion hat data
--- @return (string | nil) The color to use as the main icon. nil for rare or common with one color
local function getColorToShow(hat)
if hat.rarity == "Rare" or (hat.rarity == "Common" and hat.colors == "One") then
return nil
end
local cts = hat.color_to_show or "Inky Purple"
return cts
end
local function formatHatData(name, frame)
local lang = mw.getContentLanguage()
local fromData = data.hats[name]
local hatData = {
name = name,
buy = lang:formatNum(data.prices.buy[string.lower(fromData.rarity)]) .. frame:expandTemplate{title = "Coin/Camp Spirit"},
sell = lang:formatNum(data.prices.sell[string.lower(fromData.rarity)]) .. frame:expandTemplate{title = "Coin/Camp Spirit"},
}
for k, v in pairs(fromData) do
-- Preprocess the description so it doesn't show nowiki/br tags
if k == "description" then
hatData[k] = frame:preprocess(v)
else
hatData[k] = v
end
end
hatData.color_to_show = getColorToShow(hatData)
-- Add icon file name without File: or .png to use with image template
if string.lower(fromData.rarity) == "rare" or (string.lower(fromData.rarity) == "common" and string.lower(fromData.colors) == "one") then
hatData.icon = string.lower(hatData.name .. " " .. hatData.rarity)
else
hatData.icon = string.lower(hatData.name .. " " .. hatData.rarity .. " " .. hatData.color_to_show)
end
-- Common hats with one color use the higher rare price
if string.lower(fromData.rarity) == "common" and string.lower(fromData.colors) == "one" then
hatData.buy = data.prices.buy.rare .. frame:expandTemplate{title = 'Coin/Camp Spirit'}
hatData.sell = data.prices.sell.rare .. frame:expandTemplate{title = 'Coin/Camp Spirit'}
end
return hatData
end
--- @class GetPriceArgs
--- @field type ("buy" | "sell" | nil) The type of price to return. Defaults to sell.
--- @field rarity (Rarity | nil) Rarity of the companion hat. Defaults to Common.
--- @class GetPriceFrame
--- @field args GetPriceArgs
--- Retrieves a companion hat price by rarity and price type
--- @param frame GetPriceFrame MediaWiki frame
--- @return number price Companion hat price or -1 if not found
function p.GetPrice(frame)
local args = arguments.getArgs(frame)
local priceType = string.lower(args["type"] or "sell")
local rarity = string.lower(args["rarity"] or "Common")
local rarities = {
["common"] = true,
["rare"] = true
}
local isValidRarity = rarities[rarity] ~= nil
if not isValidRarity then
error("Rarity does not match one of (Common|Rare)")
return -1
end
local priceTypes = {
["buy"] = true,
["sell"] = true
}
local isValidType = priceTypes[string.lower(priceType)] ~= nil
if not isValidType then
error("Type does not match one of (buy|sell)")
return -1
end
return data.prices[priceType][rarity]
end
--- @class GetHatsArgs
--- @field rarity (Rarity | nil) The rarity of the hats to return. Defaults to nil and returns all rarities.
--- @field season (Season | nil) The season of the hats to return. Defaults to nil and returns all seasons.
--- Retrieves a list of page names that match a rarity and/or season
--- @param frame table MediaWiki frame
--- @return string A comma-separated list of page names that match the filters
function p.GetPageList(frame)
local args = arguments.getArgs(frame)
--- @type (Rarity | nil)
local rarity = args.rarity or nil
--- @type (Season | nil)
local season = args.season or nil
local hatList = {}
if rarity ~= nil then
for k, v in pairs(data.hats) do
if v.rarity == rarity then
if season ~= nil then
if v.season == season then
table.insert(hatList, k .. " (Camp Spirit)")
end
else
table.insert(hatList, k .. " (Camp Spirit)")
end
end
end
elseif season ~= nil then
for k, v in pairs(data.hats) do
if v.season == season then
table.insert(hatList, k .. " (Camp Spirit)")
end
end
else
for k, _ in pairs(data.hats) do
table.insert(hatList, k .. " (Camp Spirit)")
end
end
table.sort(hatList)
return table.concat(hatList, ",")
end
--- @param frame table MediaWiki frame
function p.Infobox(frame)
local lang = mw.getContentLanguage()
local args = arguments.getArgs(frame)
local hatData = formatHatData(args["name"], frame)
return frame:expandTemplate { title = "Companion Clothing Infobox/Camp Spirit", args = hatData }
end
function p.Table(frame)
local tableBuilder = require("Module:TableBuilder")
local args = arguments.getArgs(frame)
local list = args["list"] or args[1]
if list == nil or #list == 0 then
error("Must provide a list of page names")
end
local rawCols = args["columns"] or "name"
local columns = {}
for col in string.gmatch(rawCols, '([^,]+)') do
table.insert(columns, col)
end
local hatList = {}
for hat in string.gmatch(list, '([^,]+)') do
table.insert(hatList, hat)
end
local tbl = tableBuilder.create({ ['class'] = 'wikitable sortable', ['style'] = 'width:100%;' })
local colHeaderMap = {
["icon"] = "Icon",
["name"] = "Hat",
["description"] = "Description",
["rarity"] = "Rarity",
["season"] = "Season",
["buy"] = "Buy",
["sell"] = "Sell Price"
}
local h = tbl:row()
for _, col in ipairs(columns) do
local header = colHeaderMap[col]
if not header then
error("Columns includes invalid column name: " .. col)
return
end
if col == "icon" then
h:th(colHeaderMap[col]):attr('class', 'unsortable'):attr('style', 'width:48px;padding:0;')
else
h:th(colHeaderMap[col])
end
end
local prefix = "Companion "
local suffix = " (Camp Spirit)"
local function formatPageLink(page)
return "[[" .. page .. "|" .. string.sub(page, #prefix, - #suffix) .. "]]"
end
local lang = mw.getContentLanguage()
for _, hat in ipairs(hatList) do
local hatData = formatHatData(string.sub(hat, 0, - (#suffix + 1)), frame)
if hatData ~= nil then
local r = tbl:row()
for _, col in ipairs(columns) do
local header = colHeaderMap[col]
if not header then
error("Columns includes invalid column name: " .. col)
return
end
if col == "name" or col == "page" then
r:td(formatPageLink(hat))
elseif col == "description" then
r:td(hatData.description)
elseif col == "rarity" then
r:td(hatData.rarity)
elseif col == "icon" then
local icon = mw.title.makeTitle('File', hatData.icon .. ".png")
local iconSize = 48
if icon.file.exists then
r:td(frame:expandTemplate{ title = "image", args = { hatData.icon, iconSize, link = hatData.name .. " (Camp Spirit)"} })
else
r:td(frame:expandTemplate{ title = "image", args = { "Unknown Item", iconSize, link = hatData.name .. " (Camp Spirit)"} })
end
elseif col == "season" then
if hatData.season == "All" then
r:td("Any Season")
else
r:td(frame:expandTemplate { title = "CSLink", args = { hatData.season or "All" } })
end
elseif col == "buy" then
r:td(hatData.buy)
elseif col == "sell" then
r:td(hatData.sell)
end
end
else
tbl:row():td(string.sub(hat, 0, -(#suffix + 1)))
end
end
return tbl:done() ..
'<sup style="font-style:italic;"><strong>Editor\'s Note:</strong> This table\'s content is automatically generated. The function that generates the table may be edited at [[Module:Camp Spirit/Companion/Hat]].</sup>'
end
function p.GetPage(frame)
local args = arguments.getArgs(frame)
local hatData = {
name = args["name"]
}
for k, v in pairs(data.hats[args["name"]]) do
hatData[k] = v
end
return frame:expandTemplate { title = "Companion Clothing Page/Camp Spirit/Content", args = hatData }
end
return p