Jump to content

Module:ItemSources: Difference between revisions

From Apogea Wiki
Jayarrowz (talk | contribs)
No edit summary
Dane (talk | contribs)
Remove == Sources == header from module output (keep in page source) (via update-page on MediaWiki MCP Server)
Tag: Manual revert
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
-- Module:ItemSources
local p = {}
-- Displays item drop sources from NPCs in a table format
 
-- Usage: {{#invoke:ItemSources|list|source1=NPC Name,Quantity,Rarity}}
-- Drop rarity sort order (ascending)
local rarityOrder = {
    common = 1,
    semirare = 2,
    rare = 3,
    veryrare = 4,
    ultrarare = 5
}
 
-- Format quantity display
local function formatQuantity(min, max)
    if not min or min == '' then
        return '?'
    end
    if not max or max == '' or min == max then
        return tostring(min)
    end
    return min .. '-' .. max
end
 
-- Get rarity sort value
local function getRarityValue(rarity)
    if not rarity then return 99 end
    return rarityOrder[string.lower(rarity)] or 99
end
 
-- Get quantity sort value (max if present, otherwise min)
local function getQuantitySortValue(min, max)
    if max and max ~= '' then
        return tonumber(max) or 0
    end
    return tonumber(min) or 0
end


local p = {}
-- Get cost sort value
local function getCostSortValue(cost)
    if not cost or cost == '' then
        return 999999
    end
    return tonumber(cost) or 999999
end


-- Helper to get args from either direct invoke or template
-- Build the drops table
local function getArgs(frame)
local function buildDropsTable(frame, drops)
     local args = {}
     if #drops == 0 then
   
         return ''
    local parent = frame:getParent()
    if parent and parent.args then
         for k, v in pairs(parent.args) do
            args[k] = v
        end
     end
     end
      
      
     if frame.args then
     -- Sort by rarity ascending, then quantity ascending
         for k, v in pairs(frame.args) do
    table.sort(drops, function(a, b)
             args[k] = v
        local rarityA = getRarityValue(a.rarity)
         local rarityB = getRarityValue(b.rarity)
        if rarityA ~= rarityB then
             return rarityA < rarityB
         end
         end
     end
        return getQuantitySortValue(a.min, a.max) < getQuantitySortValue(b.min, b.max)
     end)
      
      
     return args
     local tbl = mw.html.create('table')
end
        :addClass('wikitable')
 
        :addClass('sortable')
-- Display a list of item sources
function p.list(frame)
    local args = getArgs(frame)
      
      
     -- Parse all sources
     -- Header row
     local sources = {}
     local headerRow = tbl:tag('tr')
    headerRow:tag('th'):addClass('unsortable'):css('min-width', '64px'):wikitext('')
    headerRow:tag('th'):wikitext('Source')
    headerRow:tag('th'):wikitext('Quantity')
    headerRow:tag('th'):wikitext('Rarity')
      
      
     local i = 1
     for _, src in ipairs(drops) do
    while args["source" .. i] or args["s" .. i] do
        local quantity = formatQuantity(src.min, src.max)
         local sourceStr = args["source" .. i] or args["s" .. i]
        local rarityValue = getRarityValue(src.rarity)
         local quantityValue = getQuantitySortValue(src.min, src.max)
          
          
         -- Parse: "NPC Name,Quantity,Rarity" or "NPC Name,Quantity" or just "NPC Name"
        local row = tbl:tag('tr')
         local parts = {}
       
         for part in sourceStr:gmatch("[^,]+") do
         -- Preview cell (use MonsterPreview for monsters)
             table.insert(parts, part:match("^%s*(.-)%s*$")) -- trim
         local previewWikitext = frame:preprocess(string.format('{{MonsterPreview|%s|64}}', src.source))
        end
         row:tag('td')
             :css('text-align', 'center')
            :wikitext(previewWikitext)
          
          
         local npcName = parts[1] or "Unknown"
         -- Source cell
         local quantity = parts[2] or "1"
         row:tag('td')
        local rarity = parts[3] or ""
            :wikitext(string.format('[[%s]]', src.source))
          
          
         table.insert(sources, {
         -- Quantity cell with sort value
             npc = npcName,
        row:tag('td')
             quantity = quantity,
             :attr('data-sort-value', quantityValue)
            rarity = rarity
             :wikitext(quantity)
        })
          
          
         i = i + 1
         -- Rarity cell with sort value
        row:tag('td')
            :attr('data-sort-value', rarityValue)
            :wikitext(src.rarity or '')
     end
     end
      
      
     -- Check if any source has rarity
     return '=== Drops ===\n' .. tostring(tbl)
    local hasRarity = false
end
    for _, source in ipairs(sources) do
 
        if source.rarity ~= "" then
-- Build the shops table
            hasRarity = true
local function buildShopsTable(frame, shops)
            break
    if #shops == 0 then
         end
         return ''
     end
     end
      
      
     -- Build HTML
     -- Sort by cost ascending
    local html = {}
     table.sort(shops, function(a, b)
   
        return getCostSortValue(a.cost) < getCostSortValue(b.cost)
     table.insert(html, '<div class="item-sources">')
    end)
      
      
     -- Table
     local tbl = mw.html.create('table')
    table.insert(html, '<table class="wikitable sortable item-sources-table">')
        :addClass('wikitable')
        :addClass('sortable')
      
      
     -- Header row
     -- Header row
     table.insert(html, '<tr>')
     local headerRow = tbl:tag('tr')
     table.insert(html, '<th>Source</th>')
     headerRow:tag('th'):addClass('unsortable'):css('min-width', '64px'):wikitext('')
     table.insert(html, '<th>Quantity</th>')
     headerRow:tag('th'):wikitext('Shop')
     if hasRarity then
     headerRow:tag('th'):wikitext('Cost')
        table.insert(html, '<th>Rarity</th>')
     headerRow:tag('th'):wikitext('Currency')
     end
    table.insert(html, '</tr>')
      
      
    -- Render each source
     for _, src in ipairs(shops) do
     for _, source in ipairs(sources) do
         local costValue = getCostSortValue(src.cost)
         table.insert(html, '<tr>')
          
          
         -- Source name cell
         local row = tbl:tag('tr')
        table.insert(html, string.format(
            '<td class="item-sources-cell-name">[[%s]]</td>',
            source.npc
        ))
          
          
         -- Quantity cell
         -- Preview cell (use Sprite for NPC)
         table.insert(html, string.format(
         local previewWikitext = frame:preprocess(string.format('{{Sprite|%s|64}}', src.source))
            '<td class="item-sources-cell-quantity">%s</td>',
         row:tag('td')
            source.quantity
            :css('text-align', 'center')
         ))
            :wikitext(previewWikitext)
          
          
         -- Rarity cell (only if any source has rarity)
         -- Source cell
         if hasRarity then
        row:tag('td')
             table.insert(html, string.format(
            :wikitext(string.format('[[%s]]', src.source))
                '<td class="item-sources-cell-rarity">%s</td>',
       
                source.rarity
         -- Cost cell with sort value
             ))
        row:tag('td')
             :attr('data-sort-value', costValue)
            :wikitext(src.cost or '?')
       
        -- Currency cell
        row:tag('td')
            :wikitext(src.currency or '')
    end
   
    return '=== Shops ===\n' .. tostring(tbl)
end
 
-- Main function to display item sources
function p.display(frame)
    local args = frame:getParent().args
    local item = args.item or args[1] or mw.title.getCurrentTitle().text
   
    -- Query ItemSource for all sources (include cost and currency for shops)
    local sources = mw.ext.cargo.query('ItemSource', 'source,source_type,rarity,min,max,cost,currency', {
        where = 'item="' .. item .. '"'
    })
   
    if not sources or #sources == 0 then
        return ''
    end
   
    -- Separate into drops and shops
    local drops = {}
    local shops = {}
   
    for _, src in ipairs(sources) do
        if src.source_type == 'shop' then
             table.insert(shops, src)
        else
            -- Default to drop for Monster or any other type
            table.insert(drops, src)
         end
         end
       
        table.insert(html, '</tr>')
     end
     end
      
      
     table.insert(html, '</table>')
     -- Build output
    table.insert(html, '</div>')
    local output = {}
   
    local dropsOutput = buildDropsTable(frame, drops)
    if dropsOutput ~= '' then
        table.insert(output, dropsOutput)
    end
   
    local shopsOutput = buildShopsTable(frame, shops)
    if shopsOutput ~= '' then
        table.insert(output, shopsOutput)
    end
      
      
     return frame:preprocess(table.concat(html, '\n'))
     return table.concat(output, '\n\n')
end
end


return p
return p

Latest revision as of 20:19, 30 January 2026

Module:ItemSources

[edit source]

This module displays item drop sources from NPCs in a table format.

Basic Usage

[edit source]
{{#invoke:ItemSources|list
|source1=NPC Name,Quantity,Rarity
|source2=NPC Name,Quantity,Rarity
}}

Source Format

[edit source]

Each source uses the format:

NPC Name,Quantity,Rarity
  • NPC Name - Required. The name of the NPC (automatically linked)
  • Quantity - Optional. Amount dropped (default: 1). Can be a range like "2-4"
  • Rarity - Optional. Drop rate like "1/50", "Rare", or "Always"

Parameters

[edit source]
Parameter Required Description
source1, source2, etc. Yes Source entries in "NPC,Quantity,Rarity" format
s1, s2, etc. No Shorthand for source1, source2, etc.

Examples

[edit source]

Basic Drop Table

[edit source]
{{#invoke:ItemSources|list
|source1=Goblin,1,1/50
|source2=Orc Warrior,2-4,1/100
|source3=Dragon,5,1/500
}}

Without Rarity

[edit source]

If no sources have rarity specified, the Rarity column is automatically hidden:

{{#invoke:ItemSources|list
|source1=Goblin,1
|source2=Orc Warrior,3
|source3=Chest,1
}}

Mixed Rarity

[edit source]

Some sources can have rarity while others don't:

{{#invoke:ItemSources|list
|source1=Cave Troll,1
|source2=Tomb Worker,1
|source3=Bear,1,Semi Rare
|source4=Bandit,1,Rare
}}

Using Shorthand

[edit source]
{{#invoke:ItemSources|list
|s1=Goblin,1,1/50
|s2=Orc,2,1/100
}}

Guaranteed Drops

[edit source]
{{#invoke:ItemSources|list
|source1=Quest Reward,1,Always
|source2=Boss,1,100%
|source3=Chest,1-3,Always
}}

Table Columns

[edit source]
Column Description
Source Linked name of the NPC
Quantity Amount dropped (can be a range)
Rarity Drop rate (only shown if any source has rarity)
  • The Rarity column only appears if at least one source has a rarity value
  • NPC names are automatically linked using [[NPC Name]]
  • Quantity can be a single number or a range (e.g., "1-5", "2-4")

local p = {}

-- Drop rarity sort order (ascending)
local rarityOrder = {
    common = 1,
    semirare = 2,
    rare = 3,
    veryrare = 4,
    ultrarare = 5
}

-- Format quantity display
local function formatQuantity(min, max)
    if not min or min == '' then
        return '?'
    end
    if not max or max == '' or min == max then
        return tostring(min)
    end
    return min .. '-' .. max
end

-- Get rarity sort value
local function getRarityValue(rarity)
    if not rarity then return 99 end
    return rarityOrder[string.lower(rarity)] or 99
end

-- Get quantity sort value (max if present, otherwise min)
local function getQuantitySortValue(min, max)
    if max and max ~= '' then
        return tonumber(max) or 0
    end
    return tonumber(min) or 0
end

-- Get cost sort value
local function getCostSortValue(cost)
    if not cost or cost == '' then
        return 999999
    end
    return tonumber(cost) or 999999
end

-- Build the drops table
local function buildDropsTable(frame, drops)
    if #drops == 0 then
        return ''
    end
    
    -- Sort by rarity ascending, then quantity ascending
    table.sort(drops, function(a, b)
        local rarityA = getRarityValue(a.rarity)
        local rarityB = getRarityValue(b.rarity)
        if rarityA ~= rarityB then
            return rarityA < rarityB
        end
        return getQuantitySortValue(a.min, a.max) < getQuantitySortValue(b.min, b.max)
    end)
    
    local tbl = mw.html.create('table')
        :addClass('wikitable')
        :addClass('sortable')
    
    -- Header row
    local headerRow = tbl:tag('tr')
    headerRow:tag('th'):addClass('unsortable'):css('min-width', '64px'):wikitext('')
    headerRow:tag('th'):wikitext('Source')
    headerRow:tag('th'):wikitext('Quantity')
    headerRow:tag('th'):wikitext('Rarity')
    
    for _, src in ipairs(drops) do
        local quantity = formatQuantity(src.min, src.max)
        local rarityValue = getRarityValue(src.rarity)
        local quantityValue = getQuantitySortValue(src.min, src.max)
        
        local row = tbl:tag('tr')
        
        -- Preview cell (use MonsterPreview for monsters)
        local previewWikitext = frame:preprocess(string.format('{{MonsterPreview|%s|64}}', src.source))
        row:tag('td')
            :css('text-align', 'center')
            :wikitext(previewWikitext)
        
        -- Source cell
        row:tag('td')
            :wikitext(string.format('[[%s]]', src.source))
        
        -- Quantity cell with sort value
        row:tag('td')
            :attr('data-sort-value', quantityValue)
            :wikitext(quantity)
        
        -- Rarity cell with sort value
        row:tag('td')
            :attr('data-sort-value', rarityValue)
            :wikitext(src.rarity or '')
    end
    
    return '=== Drops ===\n' .. tostring(tbl)
end

-- Build the shops table
local function buildShopsTable(frame, shops)
    if #shops == 0 then
        return ''
    end
    
    -- Sort by cost ascending
    table.sort(shops, function(a, b)
        return getCostSortValue(a.cost) < getCostSortValue(b.cost)
    end)
    
    local tbl = mw.html.create('table')
        :addClass('wikitable')
        :addClass('sortable')
    
    -- Header row
    local headerRow = tbl:tag('tr')
    headerRow:tag('th'):addClass('unsortable'):css('min-width', '64px'):wikitext('')
    headerRow:tag('th'):wikitext('Shop')
    headerRow:tag('th'):wikitext('Cost')
    headerRow:tag('th'):wikitext('Currency')
    
    for _, src in ipairs(shops) do
        local costValue = getCostSortValue(src.cost)
        
        local row = tbl:tag('tr')
        
        -- Preview cell (use Sprite for NPC)
        local previewWikitext = frame:preprocess(string.format('{{Sprite|%s|64}}', src.source))
        row:tag('td')
            :css('text-align', 'center')
            :wikitext(previewWikitext)
        
        -- Source cell
        row:tag('td')
            :wikitext(string.format('[[%s]]', src.source))
        
        -- Cost cell with sort value
        row:tag('td')
            :attr('data-sort-value', costValue)
            :wikitext(src.cost or '?')
        
        -- Currency cell
        row:tag('td')
            :wikitext(src.currency or '')
    end
    
    return '=== Shops ===\n' .. tostring(tbl)
end

-- Main function to display item sources
function p.display(frame)
    local args = frame:getParent().args
    local item = args.item or args[1] or mw.title.getCurrentTitle().text
    
    -- Query ItemSource for all sources (include cost and currency for shops)
    local sources = mw.ext.cargo.query('ItemSource', 'source,source_type,rarity,min,max,cost,currency', {
        where = 'item="' .. item .. '"'
    })
    
    if not sources or #sources == 0 then
        return ''
    end
    
    -- Separate into drops and shops
    local drops = {}
    local shops = {}
    
    for _, src in ipairs(sources) do
        if src.source_type == 'shop' then
            table.insert(shops, src)
        else
            -- Default to drop for Monster or any other type
            table.insert(drops, src)
        end
    end
    
    -- Build output
    local output = {}
    
    local dropsOutput = buildDropsTable(frame, drops)
    if dropsOutput ~= '' then
        table.insert(output, dropsOutput)
    end
    
    local shopsOutput = buildShopsTable(frame, shops)
    if shopsOutput ~= '' then
        table.insert(output, shopsOutput)
    end
    
    return table.concat(output, '\n\n')
end

return p