Advent of Ascension Wiki

This wiki is currently being updated to 1.18.2+ versions of the mod. If you are struggling to find information regarding 1.16.5 AoA, or are curious as to why 1.18.2+ versions are being released incomplete, please check out this page.

READ MORE

Advent of Ascension Wiki
Advertisement

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
Advertisement