Jump to content

Module:ItemCategoryTable

From Apogea Wiki
Revision as of 03:12, 28 January 2026 by Dane (talk | contribs) (Add Slots column for Containers category (via update-page on MediaWiki MCP Server))

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

local p = {}

-- Parent categories and their child types
local parentCategories = {
    ["Accessories"] = {"Ring", "Necklace"},
    ["Weapons"] = {"Sword", "Large Sword", "Dagger", "Knife", "Axe", "Large Axe", "Bow", "Staff", "Orb"},
    ["Shields"] = {"Small Shield", "Large Shield"},
    ["Armor"] = {"Heavy Chest", "Heavy Legs", "Heavy Helmet", "Heavy Boots", "Light Chest", "Light Legs", "Light Helmet", "Light Boots", "Light Mask", "Light Neck"},
    ["Heavy Armor"] = {"Heavy Chest", "Heavy Legs", "Heavy Helmet", "Heavy Boots"},
    ["Light Armor"] = {"Light Chest", "Light Legs", "Light Helmet", "Light Boots", "Light Mask", "Light Neck"},
    ["Food"] = {"Cooked Food", "Edible Food", "Raw Food", "Special Food"},
    ["Consumables"] = {"Potions", "Drinks", "Cooked Food", "Edible Food", "Raw Food", "Special Food"},
    ["Materials"] = {"Book Products", "Cloth Products", "Cooking Items", "Desert Products", "Forge Products", "Grave Products", "Holy Products", "Monster Products", "North Products", "Plains Products", "Swamp Products", "Flowers"},
    ["Regional Products"] = {"Desert Products", "North Products", "Plains Products", "Swamp Products"},
    ["Ammunition"] = {"Arrows", "Conjured Arrows"},
    ["Equipment"] = {"Ring", "Necklace", "Gloves", "Sword", "Large Sword", "Dagger", "Knife", "Axe", "Large Axe", "Bow", "Staff", "Orb", "Small Shield", "Large Shield", "Heavy Chest", "Heavy Legs", "Heavy Helmet", "Heavy Boots", "Light Chest", "Light Legs", "Light Helmet", "Light Boots", "Light Mask", "Light Neck", "Container", "Tools"},
}

-- Query items by type from Cargo
local function getItemsByType(itemType)
    local tables = 'Items'
    local fields = 'name,sprite,type,weight,damage,armor,defense,health,mana,ability,magic,rng,move_speed,attack_speed,health_regen,mana_regen,container,size,rarity'
    local args = {
        where = 'type LIKE "%' .. itemType .. '%"',
        orderBy = 'name',
        limit = 500
    }
    
    return mw.ext.cargo.query(tables, fields, args)
end

-- Query items by multiple types
local function getItemsByTypes(types)
    local tables = 'Items'
    local fields = 'name,sprite,type,weight,damage,armor,defense,health,mana,ability,magic,rng,move_speed,attack_speed,health_regen,mana_regen,container,size,rarity'
    
    -- Build OR conditions for each type
    local conditions = {}
    for _, t in ipairs(types) do
        table.insert(conditions, 'type LIKE "%' .. t .. '%"')
    end
    
    local args = {
        where = table.concat(conditions, ' OR '),
        orderBy = 'name',
        limit = 500
    }
    
    return mw.ext.cargo.query(tables, fields, args)
end

-- Get the singular type name from a plural category name
local function singularize(plural)
    local mapping = {
        ["Rings"] = "Ring",
        ["Necklaces"] = "Necklace",
        ["Staves"] = "Staff",
        ["Knives"] = "Knife",
        ["Axes"] = "Axe",
        ["Large Axes"] = "Large Axe",
        ["Swords"] = "Sword",
        ["Large Swords"] = "Large Sword",
        ["Regular Swords"] = "Regular Sword",
        ["Daggers"] = "Dagger",
        ["Bows"] = "Bow",
        ["Orbs"] = "Orb",
        ["Small Shields"] = "Small Shield",
        ["Large Shields"] = "Large Shield",
        ["Gloves"] = "Gloves",
        ["Containers"] = "Container",
        ["Tools"] = "Tools",
        ["Heavy Helmets"] = "Heavy Helmet",
        ["Light Helmets"] = "Light Helmet",
        ["Light Masks"] = "Light Mask",
        ["Heavy Boots"] = "Heavy Boots",
        ["Light Boots"] = "Light Boots",
        ["Heavy Legs"] = "Heavy Legs",
        ["Light Legs"] = "Light Legs",
        ["Heavy Chest Armor"] = "Heavy Chest",
        ["Light Chest Armor"] = "Light Chest",
        ["Light Neck Armor"] = "Light Neck",
        ["Potions"] = "Potions",
        ["Drinks"] = "Drinks",
        ["Arrows"] = "Arrows",
        ["Conjured Arrows"] = "Conjured Arrows",
        ["Books"] = "Book",
        ["Cooked Food"] = "Cooked Food",
        ["Edible Food"] = "Edible Food",
        ["Raw Food"] = "Raw Food",
        ["Special Food"] = "Special Food",
        ["Light Sources"] = "Light Sources",
        ["Flowers"] = "Flowers",
        ["Currency"] = "Currency",
        ["Book Products"] = "Book Products",
        ["Cloth Products"] = "Cloth Products",
        ["Cooking Items"] = "Cooking Items",
        ["Desert Products"] = "Desert Products",
        ["Forge Products"] = "Forge Products",
        ["Grave Products"] = "Grave Products",
        ["Holy Products"] = "Holy Products",
        ["Monster Products"] = "Monster Products",
        ["North Products"] = "North Products",
        ["Plains Products"] = "Plains Products",
        ["Swamp Products"] = "Swamp Products",
    }
    return mapping[plural] or plural:gsub("s$", "")
end

-- Get the plural/category name from a type
local function pluralize(singular)
    local mapping = {
        ["Ring"] = "Rings",
        ["Necklace"] = "Necklaces",
        ["Staff"] = "Staves",
        ["Knife"] = "Knives",
        ["Axe"] = "Axes",
        ["Large Axe"] = "Large Axes",
        ["Sword"] = "Swords",
        ["Large Sword"] = "Large Swords",
        ["Dagger"] = "Daggers",
        ["Bow"] = "Bows",
        ["Orb"] = "Orbs",
        ["Small Shield"] = "Small Shields",
        ["Large Shield"] = "Large Shields",
        ["Gloves"] = "Gloves",
        ["Container"] = "Containers",
        ["Tools"] = "Tools",
        ["Heavy Helmet"] = "Heavy Helmets",
        ["Light Helmet"] = "Light Helmets",
        ["Light Mask"] = "Light Masks",
        ["Heavy Boots"] = "Heavy Boots",
        ["Light Boots"] = "Light Boots",
        ["Heavy Legs"] = "Heavy Legs",
        ["Light Legs"] = "Light Legs",
        ["Heavy Chest"] = "Heavy Chest Armor",
        ["Light Chest"] = "Light Chest Armor",
        ["Light Neck"] = "Light Neck Armor",
        ["Arrows"] = "Arrows",
        ["Conjured Arrows"] = "Conjured Arrows",
        ["Potions"] = "Potions",
        ["Drinks"] = "Drinks",
        ["Cooked Food"] = "Cooked Food",
        ["Edible Food"] = "Edible Food",
        ["Raw Food"] = "Raw Food",
        ["Special Food"] = "Special Food",
        ["Book Products"] = "Book Products",
        ["Cloth Products"] = "Cloth Products",
        ["Cooking Items"] = "Cooking Items",
        ["Desert Products"] = "Desert Products",
        ["Forge Products"] = "Forge Products",
        ["Grave Products"] = "Grave Products",
        ["Holy Products"] = "Holy Products",
        ["Monster Products"] = "Monster Products",
        ["North Products"] = "North Products",
        ["Plains Products"] = "Plains Products",
        ["Swamp Products"] = "Swamp Products",
        ["Flowers"] = "Flowers",
        ["Book"] = "Books",
        ["Light Sources"] = "Light Sources",
        ["Currency"] = "Currency",
    }
    return mapping[singular] or singular
end

-- Get numeric value from stat (0 if empty)
local function statNum(value)
    if value and value ~= "" then
        return tonumber(value) or 0
    end
    return 0
end

-- Format stat value (return 0 if empty)
local function stat(value)
    if value and value ~= "" then
        return value
    end
    return "0"
end

-- Calculate total stat power for an item
local function calcPower(item)
    return statNum(item.damage) + statNum(item.armor) + statNum(item.defense) +
           statNum(item.health) + statNum(item.mana) + statNum(item.ability) +
           statNum(item.magic) + statNum(item.rng) + statNum(item.move_speed) +
           statNum(item.attack_speed)
end

function p.render(frame)
    local args = frame:getParent().args
    local categoryName = args[1] or args.category or mw.title.getCurrentTitle().text:gsub("^Category:", "")
    
    -- Check if this is a parent category
    local isParent = parentCategories[categoryName] ~= nil
    local isContainers = (categoryName == "Containers")
    local items
    
    if isParent then
        items = getItemsByTypes(parentCategories[categoryName])
    else
        local itemType = singularize(categoryName)
        items = getItemsByType(itemType)
    end
    
    if not items or #items == 0 then
        return '<p class="mw-empty">No items found.</p>'
    end
    
    -- Calculate power for each item and sort
    for _, item in ipairs(items) do
        item._power = calcPower(item)
    end
    
    -- Sort by slots for containers, otherwise by power
    if isContainers then
        table.sort(items, function(a, b) return statNum(a.size) > statNum(b.size) end)
    else
        table.sort(items, function(a, b) return a._power > b._power end)
    end
    
    -- Build sortable table
    local tbl = mw.html.create('table')
    tbl:addClass('wikitable')
       :addClass('sortable')
       :css('width', '100%')
    
    -- Header row
    local header = tbl:tag('tr')
    header:tag('th')
        :css('width', '64px')
        :addClass('unsortable')
        :wikitext('')
    header:tag('th'):wikitext('Item')
    if isParent then
        header:tag('th'):wikitext('Type')
    end
    if isContainers then
        header:tag('th'):attr('title', 'Container Slots'):wikitext('Slots')
    end
    header:tag('th'):attr('title', 'Weight'):wikitext('WGT')
    header:tag('th'):attr('title', 'Damage'):wikitext('DMG')
    header:tag('th'):attr('title', 'Armor'):wikitext('ARM')
    header:tag('th'):attr('title', 'Defense'):wikitext('DEF')
    header:tag('th'):attr('title', 'Health'):wikitext('HP')
    header:tag('th'):attr('title', 'Mana'):wikitext('MP')
    header:tag('th'):attr('title', 'Ability'):wikitext('ABL')
    header:tag('th'):attr('title', 'Magic'):wikitext('MAG')
    header:tag('th'):attr('title', 'Range'):wikitext('RNG')
    header:tag('th'):attr('title', 'Move Speed'):wikitext('MS')
    header:tag('th'):attr('title', 'Attack Speed'):wikitext('AS')
    header:tag('th'):attr('title', 'Total Stats'):wikitext('Total')
    
    -- Data rows
    for _, item in ipairs(items) do
        local row = tbl:tag('tr')
        
        -- Icon column
        local iconCell = row:tag('td')
            :css('width', '64px')
            :css('text-align', 'center')
        local sprite = item.sprite or item.name
        iconCell:wikitext(frame:preprocess('{{Sprite|' .. sprite .. '|x2}}'))
        
        -- Item name column
        row:tag('td'):wikitext('[[' .. item.name .. ']]')
        
        -- Type column (for parent categories)
        if isParent then
            local typeCategory = pluralize(item.type or "")
            row:tag('td'):wikitext('[[:Category:' .. typeCategory .. '|' .. (item.type or "") .. ']]')
        end
        
        -- Slots column (for containers)
        if isContainers then
            row:tag('td'):css('text-align', 'right'):wikitext(stat(item.size))
        end
        
        -- Stats
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.weight))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.damage))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.armor))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.defense))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.health))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.mana))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.ability))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.magic))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.rng))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.move_speed))
        row:tag('td'):css('text-align', 'right'):wikitext(stat(item.attack_speed))
        row:tag('td'):css('text-align', 'right'):wikitext(item._power)
    end
    
    return tostring(tbl)
end

return p