Module:ChestLoot: Difference between revisions

From JCraft Wiki
Jump to navigation Jump to search
Fandom Import>KasaneTetoLover
No edit summary
 
m 1 revision imported
 
(No difference)

Latest revision as of 00:39, 25 April 2026

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

local p = {}
local lootData = require('Module:ChestLoot/Data')

function p.main(frame)
    local args = frame:getParent().args
    local name = args[1] or ""
    
    local data = lootData[name]
    if not data then 
        return '<span class="error">Chest "' .. tostring(name) .. '" not found.</span>' 
    end
    
    local itemList = {}
    
    for _, pool in ipairs(data.pools or {}) do
        local r = pool.rolls or {1, 1}
        local rMin, rMax
        
        if type(r) == "table" then
            rMin = r.min or r[1] or 1
            rMax = r.max or r[2] or 1
        else
            rMin = r
            rMax = r
        end
        
        local avgRolls = (rMin + rMax) / 2
        local totalWeight = 0
        for _, entry in ipairs(pool.entries or {}) do
            totalWeight = totalWeight + (entry[2] or 1)
        end
        
        for _, entry in ipairs(pool.entries or {}) do
            local itemName = tostring(entry[1])
            local weight = entry[2] or 1
            local weightFraction = weight / totalWeight
            
            -- Quantity & Average Quantity Logic 
            local quantityStr = "1"
            local avgQuantity = 1
            if entry.count then
                if type(entry.count) == "table" then
                    local qMin = entry.count.min or entry.count[1] or 1
                    local qMax = entry.count.max or entry.count[2] or 1
                    quantityStr = qMin .. "-" .. qMax
                    avgQuantity = (qMin + qMax) / 2
                else
                    quantityStr = tostring(entry.count)
                    avgQuantity = tonumber(entry.count) or 1
                end
            end
            
            -- Statistical Calculations factoring in Quantity 
            local avgPerChest = weightFraction * avgRolls * avgQuantity
            local chance = (1 - (1 - weightFraction)^rMax) * 100
            local avgChestsToSearch = avgPerChest > 0 and (1 / avgPerChest) or 0
            
            table.insert(itemList, {
                name = itemName,
                chance = chance,
                avgPer = avgPerChest,
                avgSearch = avgChestsToSearch,
                quantity = quantityStr
            })
        end
    end
    
    -- Sorting: Chance (High to Low), then Natural Name Sort (Double digits first)
    table.sort(itemList, function(a, b)
        if math.abs(a.chance - b.chance) > 0.0001 then 
            return a.chance > b.chance
        else
            local aNum = tonumber(a.name:match("(%d+)"))
            local bNum = tonumber(b.name:match("(%d+)"))
            if aNum and bNum and aNum ~= bNum then
                return aNum > bNum 
            else
                return a.name > b.name 
            end
        end
    end)
    
    local html = mw.html.create('table')
        :addClass('wikitable sortable mw-collapsible mw-collapsed') 
        :css('border-collapse', 'collapse')
        :css('width', '100%')
        :css('border', '1px solid #444')
        :css('background-color', '#1e1e1e')
        :css('font-size', '0.9em')

    local cleanChestName = name:gsub("_", " "):gsub("^%l", string.upper)
    html:tag('tr')
        :tag('th')
            :attr('colspan', '5')
            :wikitext("Loot Table: " .. cleanChestName)
            :css('background-color', '#3d3d3d')
            :css('color', '#58d68d')
            :css('text-align', 'center')

    local headerRow = html:tag('tr'):css('background-color', '#2d2d2d'):css('border-bottom', '2px solid #444')
    headerRow:tag('th'):wikitext('Item'):css('padding', '0.6em'):css('text-align', 'left'):css('color', '#fff')
    headerRow:tag('th'):wikitext('Qty'):css('padding', '0.6em'):css('color', '#fff')
    headerRow:tag('th'):attr('data-sort-type', 'number'):wikitext('Chance'):css('padding', '0.6em'):css('color', '#fff')
    headerRow:tag('th'):attr('data-sort-type', 'number'):wikitext('Avg. Per Chest'):css('padding', '0.6em'):css('color', '#fff')
    headerRow:tag('th'):attr('data-sort-type', 'number'):wikitext('Avg. # Chests'):css('padding', '0.6em'):css('color', '#fff')
    
    for _, item in ipairs(itemList) do
        if item.name ~= "Air" then
            local cleanName = item.name:gsub("_", " ")
            
            -- Updated Whitelist to include Cinderella Mask 
            local linkedItems = { 
                ["Stone_Mask"] = true, 
                ["Stand_Arrow"] = true, 
                ["Stand_Arrowhead"] = true, 
                ["Requiem_Arrow"] = true,
                ["Cinderella_Mask"] = true 
            }
            
            local displayCell = linkedItems[item.name] and ('[[' .. item.name .. '|' .. cleanName .. ']]') or ('<span style="color:white !important;">' .. cleanName .. '</span>')

            local row = html:tag('tr'):css('border-bottom', '1px solid #333')
            row:tag('td'):wikitext(displayCell):css('padding', '0.4em 0.6em')
            row:tag('td'):wikitext(item.quantity):css('text-align', 'center'):css('color', '#bbb')
            row:tag('td'):wikitext(string.format("%.1f%%", item.chance)):css('text-align', 'center'):css('color', '#bbb')
            row:tag('td'):wikitext(string.format("%.3f", item.avgPer)):css('text-align', 'center'):css('color', '#bbb')
            row:tag('td'):wikitext(string.format("%.1f", item.avgSearch)):css('text-align', 'center'):css('color', '#bbb')
        end
    end
    
    return tostring(html)
end

return p