This module implements Template:LootTable.
local p = {}
-- Background colours of pool blocks in template
local poolColours = {
"#EEEEEE",
"#FEEFCD",
"#E8F3D8",
"#EAE9E1",
"#F9E6FF",
"#F6FFCC",
"#E6FFEE",
"#FFE6E6",
"#E6FCFF",
"#F2F2F2"
}
-- Default table titles by loot table type for easy lookup
local tableTypeTitles = {
advancement_entity = "Rewards",
advancement_reward = "Rewards",
command = "Rewards",
barter = "Barter results",
block = "Block drops",
chest = "Chest loot",
empty = "No loot",
entity = "Entity loot",
fishing = "Fishing loot",
generic = "Unique drops",
gift = "Gifts",
selector = "Unique drops"
}
-- Parse loot entries from text to in-memory data.
local function parseLootEntries(args)
local pools = {} -- Container for nested tables which represent each pool
local poolWeights = {} -- Container for each pool's loot entry weights for calculation
-- Default values for optional additional columns
pools.hasNotes = false;
pools.hasLooting = false;
-- Loop over pools to parse data, caps at 10 pools to prevent malicious wiki editing
for poolIndex = 1, 10 do
local poolData = args["pool" .. poolIndex]
-- End pool parsing when reaching non-existent pool
if not poolData then
break
else
local pool = {}
poolWeights[poolIndex] = 0
-- Prep base pool data and variables
pool.items = {}
pool.poolNumber = poolIndex
pool.rolls = args["rolls" .. poolIndex] or "1"
pool.notes = args["notes" .. poolIndex]
-- Append newline indicator to poolData so the following loop can identify lines properly
poolData = poolData .. "\n"
-- Loop over pool data line by line, delineating by newline markers
for line in string.match(poolData, "[^\r\n]+[\r\n]") do
local entry = {}
-- Split entry lines into data groups of approximate format key:value
for key, value in string.match(line, "([%a]+)%s*:%s*(.-)%s*[;\r\n]") do
if value ~= "" then
entry[key:lower()] = value
end
end
-- Ensure a weight value is present for calculation purposes in numeric format
-- Update table-wide variables based on current entry
entry.weight = tonumber(entry.weight or 1) or 1
poolWeights[poolIndex] = poolWeights[poolIndex] + entry.weight
pools.hasLooting = pools.hasLooting or entry.looting ~= nil
pools.hasNotes = pools.hasNotes or entry.notes ~= nil
table.insert(pool.items, entry)
end
table.insert(pools, pool)
end
end
return pools, poolWeights
end
local function generateLootLines(pools, poolWeights, columnCount)
local output = {}
-- Loop over pools in pool collection for individual formatting
for _, pool in ipairs(pools) do
local backgroundColour = poolColours[poolIndex] or ""
if backgroundColour ~= "" then
backgroundColour = "background-color:" .. backgroundColour
end
-- Loop over entries in current pool for individual formatting
for _, entry in ipairs(pool.items) do
-- Prep base variables for entry
local itemLink = "Nothing"
local quantity = entry.quantity or "-"
local looting = ""
local notes = ""
local chance = "100%"
-- Skip entry entries
if entry.item ~= nil and string.lower(entry.item) ~= "nothing" then
local image = entry.image or (entry.item .. ".png")
local imageLink = ""
-- Process image link with formatting
if image:lower() ~= "none" then
imageLink = "[[File:" .. image .. "|" .. (entry.imagesize or "32px") .. "|link=" .. entry.item
end
-- Compile item link with processed image link
itemLink = imageLink .. "[[" .. entry.item .. "]]"
end
-- Format looting column value if applicable
if entry.looting then
looting = " || +" .. entry.looting .. " per level"
elseif pools.hasLooting then
looting = " || -"
end
-- Format chance column value if applicable, calculated by entry's weight over the total pool weight
if entry.weight and poolWeights[pools.poolNumber] then
chance = string.format("%.1f", (entry.weight / poolWeights[pools.poolNumber]) * 100) .. "%"
end
-- Add notes if applicable or empty column value if required
if entry.notes then
notes = " || style=\"text-align:left;\" | " .. entry.notes
elseif pools.hasNotes then
notes = " || "
end
-- Insert formatting data for entry
table.insert(output, "| " .. itemLink .. " || " .. quantity .. looting .. " || " .. chance .. notes)
end
local poolDescription = "| colspan = " .. columnCount .. " | " -- Begin bottom row text
-- Add background colour to pool if applicable
if backgroundColour ~= "" then
table.insert(output, "|- style=\"" .. backgroundColour .. "\"")
else
table.insert(output, "|-")
end
-- Begin adding pool roll count to description
poolDescription = poolDescription .. "The above pool is rolled "
if pool.rolls == "1" then
poolDescription = poolDescription .. "1 time."
else
poolDescription = poolDescription .. pool.rolls .. " times."
end
-- Add notes if present in pool data
if pool.notes then
poolDescription = poolDescription .. "<br/>" .. pool.notes
end
table.insert(output, poolDescription)
end
return table.concat(output, "\n")
end
function p.lootTable(frame)
-- Prep base data for final printout
local data = frame
local columnCount = 3
local linesOut = {} -- Container for per-line text for output
local pools, poolWeights = parseLootEntries(data)
local title = ""
local columnHeader = "|-\n! Item !! Quantity !! " -- Start column header line with base columns
-- Set default value to table type titles. This acts as a safety if we somehow have an invalid table type
setmetatable(tableTypeTitles, {__index = function() return "Unique drops" end})
-- Process arguments from template block on page
if frame == mw.getCurrentFrame() then
data = require("Module:ProcessArgs").merge(true)
else
frame = mw.getCurrentFrame()
end
-- Set table title based on specified title in template or default for loot table type
title = data.title or tableTypeTitles[data.type]
-- Add looting column if required
if pools.hasLooting then
columnHeader = columnHeader .. frame:expandTemplate{title = "tooltip", args = {"Looting", "The amount of extra items obtainable with the Looting enchantment."}} .. " !! "
columnCount = columnCount + 1
end
-- Insert chance column
columnHeader = columnHeader .. "Chance"
-- Add notes column if required
if pools.hasNotes then
columnHeader = columnHeader .. " !! Notes "
columnCount = columnCount + 1
end
-- Compile final output
table.insert(linesOut, "{| class = \"wikitable\"\n|-")
table.insert(linesOut, "! colspan = " .. columnCount .. " | " .. title)
table.insert(linesOut, generateLootLines(pools, poolWeights, columnCount))
table.insert(linesOut, "|}")
return table.concat(linesOut, "\n")
end
return p