Jump to content

Module:ItemCategoryTable

From Apogea Wiki

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

local p = {}
local ItemConfig = require('Module:ItemConfig')

-- Query items by type from Cargo (type is a List field, requires HOLDS)
local function getItemsByType(itemType)
    local tables = 'Items'
    local fields = ItemConfig.cargoFields.itemsTable
    local args = {
        where = 'type HOLDS "' .. 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 = ItemConfig.cargoFields.itemsTable

    -- Build OR conditions for each type (using HOLDS for List field)
    local conditions = {}
    for _, t in ipairs(types) do
        table.insert(conditions, 'type HOLDS "' .. t .. '"')
    end

    local args = {
        where = table.concat(conditions, ' OR '),
        orderBy = 'name',
        limit = 500
    }

    return mw.ext.cargo.query(tables, fields, args)
end

-- Query all items
local function getAllItems()
    local tables = 'Items'
    local fields = ItemConfig.cargoFields.itemsTable
    local args = {
        orderBy = 'name',
        limit = 500
    }

    return mw.ext.cargo.query(tables, fields, args)
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

-- Sort column mapping
local sortColumns = {
    name = function(item) return item.name or item._pageName or "" end,
    type = function(item) return item.type or "" end,
    slots = function(item) return statNum(item.container) end,
    container = function(item) return statNum(item.container) end,
    weight = function(item) return statNum(item.weight) end,
    damage = function(item) return statNum(item.damage) end,
    armor = function(item) return statNum(item.armor) end,
    defense = function(item) return statNum(item.defense) end,
    health = function(item) return statNum(item.health) end,
    mana = function(item) return statNum(item.mana) end,
    ability = function(item) return statNum(item.ability) end,
    magic = function(item) return statNum(item.magic) end,
    rng = function(item) return statNum(item.rng) end,
    move_speed = function(item) return statNum(item.move_speed) end,
    attack_speed = function(item) return statNum(item.attack_speed) end,
    power = function(item) return item._power end,
    total = function(item) return item._power end
}

function p.render(frame)
    local args = frame.args
    local categoryName = args[1] or args.category or mw.title.getCurrentTitle().text:gsub("^Category:", "")
    local sortBy = args.sort or args.sortby
    local sortDir = args.dir or args.sortdir or "desc"

    -- Check if this is a parent category or all items
    local isAllItems = (categoryName == "Items")
    local isParent = ItemConfig.isParentCategory(categoryName) or isAllItems
    local isContainers = (categoryName == "Containers")
    local items

    if isAllItems then
        items = getAllItems()
    elseif ItemConfig.isParentCategory(categoryName) then
        items = getItemsByTypes(ItemConfig.getChildTypes(categoryName))
    else
        local itemType = ItemConfig.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
    for _, item in ipairs(items) do
        item._power = calcPower(item)
    end

    -- Determine sort column
    local sortFunc = nil
    if sortBy and sortColumns[sortBy] then
        sortFunc = sortColumns[sortBy]
    elseif isContainers then
        sortFunc = sortColumns.slots
    else
        sortFunc = sortColumns.power
    end

    -- Sort items
    local ascending = (sortDir == "asc")
    table.sort(items, function(a, b)
        local valA = sortFunc(a)
        local valB = sortFunc(b)
        if ascending then
            return valA < valB
        else
            return valA > valB
        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 or "Unknown"
        if sprite and sprite ~= "" then
            iconCell:wikitext(frame:preprocess('{{Sprite|' .. sprite .. '|x2}}'))
        end

        -- Item name column
        local itemName = item.name or "Unknown"
        row:tag('td'):wikitext('[[' .. itemName .. ']]')

        -- Type column (for parent categories)
        if isParent then
            local typeCategory = ItemConfig.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.container))
        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