Jump to content

Module:Infobox: Difference between revisions

From Apogea Wiki
Dane (talk | contribs)
Update item() to query Cargo Items table (via update-page on MediaWiki MCP Server)
Dane (talk | contribs)
Switch item infobox to tooltip-panel styling (via update-page on MediaWiki MCP Server)
Line 1: Line 1:
local p = {}
local p = {}


-- Stat definitions: key -> { text, icon, isBonus }
-- Rarity color mapping
local stats = {
local rarityColors = {
    -- Shared stats (isBonus only applies when explicitly requested)
     common = "silver",
    hp = { text = 'HP', icon = 'Health.png', isBonus = true },
     uncommon = "mint",
    mp = { text = 'MP', icon = 'Mana.png', isBonus = true },
     rare = "sky",
    arm = { text = 'Armor', icon = 'Armor.png', isBonus = true },
     epic = "pink",
    def = { text = 'Defense', icon = 'Defense.png', isBonus = true },
     legendary = "gold"
    ms = { text = 'Move Speed', icon = 'Move_Speed.png', isBonus = true },
    as = { text = 'Attack Speed', icon = 'Attack_Speed.png', isBonus = true },
   
    -- Item-only stats
    wgt = { text = 'Weight', icon = 'Weight.png' },
    rng = { text = 'Range', icon = 'Range.png' },
     dmg = { text = 'Damage', icon = 'Damage.png' },
     eq = { text = 'Equip Size', icon = 'Weight.png' },
     ab = { text = 'Ability', icon = 'Ability.png', isBonus = true },
     mag = { text = 'Magic', icon = 'Magic.png', isBonus = true },
     hpregen = { text = 'HP Regen', icon = 'Health_Regen.png', isBonus = true },
    mpregen = { text = 'MP Regen', icon = 'Mana_Regen.png', isBonus = true },
    container = { text = 'Slots', icon = 'Container.png' },
   
    -- Monster-only stats
    xp = { text = 'Experience', icon = 'Experience.png' },
    respawn = { text = 'Respawn Time', icon = 'Respawn_Time.png' },
}
}


-- Other icons
-- Rarity display names
local icons = {
local rarityNames = {
     type = { icon = 'Question_Mark.png', text = 'Type' },
     common = "Common item.",
    uncommon = "Uncommon item.",
    rare = "Rare item.",
    epic = "Epic item.",
    legendary = "Legendary item."
}
}


local function formatBonus(value)
-- Stat definitions for monsters (keeping old table-based format)
     if not value or value == '' then
local monsterStats = {
        return nil
     hp = { text = 'HP', icon = 'Health.png' },
     end
     mp = { text = 'MP', icon = 'Mana.png' },
     local num = tonumber(value)
     arm = { text = 'Armor', icon = 'Armor.png' },
     if num and num > 0 then
     def = { text = 'Defense', icon = 'Defense.png' },
        return '+' .. value
     ms = { text = 'Move Speed', icon = 'Move_Speed.png' },
     end
     as = { text = 'Attack Speed', icon = 'Attack_Speed.png' },
     return value
     xp = { text = 'Experience', icon = 'Experience.png' },
end
     respawn = { text = 'Respawn Time', icon = 'Respawn_Time.png' },
 
}
local function formatWeight(value)
     if not value or value == '' then
        return nil
     end
    return value .. ' oz'
end


local function makeIcon(frame, icon, tooltip)
local function makeIcon(frame, icon, tooltip)
Line 55: Line 36:
end
end


function p.new(frame, applyBonuses)
-- Format a stat line with positive/negative coloring
    local builder = {
local function formatStat(label, value)
        root = mw.html.create('table'),
     if not value or value == "" then
        frame = frame,
         return nil
        applyBonuses = applyBonuses or false
    }
   
    builder.root
        :addClass('wikitable')
        :addClass('infobox')
        :css('float', 'right')
        :css('clear', 'right')
        :css('margin', '0 0 1em 1em')
        :css('width', '250px')
   
    setmetatable(builder, { __index = p })
    return builder
end
 
function p:addClass(class)
    self.root:addClass(class)
    return self
end
 
function p:addHeader(text)
    self.root:tag('tr')
        :tag('th')
            :attr('colspan', 2)
            :css('text-align', 'center')
            :wikitext(text)
    return self
end
 
function p:addImage(content)
    self.root:tag('tr')
        :tag('td')
            :attr('colspan', 2)
            :css('text-align', 'center')
            :wikitext(content)
    return self
end
 
function p:addRow(label, value, iconKey)
     if not value or value == '' then
         return self
     end
     end
      
      
     local row = self.root:tag('tr')
     local numValue = tonumber(value)
     local th = row:tag('th')
     if numValue then
        :css('text-align', 'right')
        local colorClass, prefix
         :css('width', '32px')
        if numValue >= 0 then
   
            colorClass = "color-conifer"
    local iconData = icons[iconKey]
            prefix = "+"
    if iconData then
         else
         th:wikitext(makeIcon(self.frame, iconData.icon, label))
            colorClass = "color-coral"
            prefix = ""
        end
         return string.format('<p>%s: <span class="%s">%s%s</span></p>', label, colorClass, prefix, value)
     else
     else
         th:wikitext(label)
         return string.format('<p>%s: %s</p>', label, value)
     end
     end
   
    row:tag('td')
        :css('text-align', 'left')
        :wikitext(value)
    return self
end
end


function p:addStat(key, value)
-- Format a plain text line
     if not value or value == '' then
local function formatLine(text, colorClass)
         return self
     if not text or text == "" then
         return nil
     end
     end
   
     if colorClass then
    local stat = stats[key]
         return string.format('<p class="%s">%s</p>', colorClass, text)
     if not stat then
         return self
    end
   
    local displayValue = value
    if self.applyBonuses and stat.isBonus then
        displayValue = formatBonus(value)
    end
   
    local row = self.root:tag('tr')
    local th = row:tag('th')
        :css('text-align', 'right')
        :css('width', '32px')
   
    if stat.icon then
        th:wikitext(makeIcon(self.frame, stat.icon, stat.text))
     else
     else
         th:wikitext(stat.text)
         return string.format('<p>%s</p>', text)
     end
     end
   
    row:tag('td')
        :css('text-align', 'left')
        :wikitext(displayValue)
    return self
end
function p:finish()
    return tostring(self.root)
end
end


Line 181: Line 95:
     local itemName = args.name or args[1]
     local itemName = args.name or args[1]
     local rarity = args.rarity
     local rarity = args.rarity
    local float = args.float or "right"
    local spriteSize = args.spriteSize or "64"
      
      
     -- Query Cargo for item data
     -- Query Cargo for item data
Line 189: Line 105:
     end
     end
      
      
     local box = p.new(frame, true) -- applyBonuses = true for items
     local itemRarity = string.lower(data.rarity or "common")
        :addClass('item-infobox')
    local rarityColor = rarityColors[itemRarity] or "silver"
    local rarityText = rarityNames[itemRarity] or ""
   
    local html = {}
      
      
    -- Container with tooltip-panel styling
    table.insert(html, string.format('<div class="tooltip-panel font-apogea-long infobox" style="float:%s; margin-%s:15px; margin-bottom:10px;">',
        float,
        float == "right" and "left" or "right"))
   
    -- Sprite
     local sprite = data.sprite or data.name
     local sprite = data.sprite or data.name
     local spriteContent = frame:expandTemplate{
     table.insert(html, string.format('{{Sprite|%s|%s|class=pageimage}}', sprite, spriteSize))
         title = 'Sprite',
   
         args = { sprite, '64', class = 'pageimage' }
    -- Item name with rarity color
     }
    table.insert(html, string.format('<p class="font-bitcell color-%s">%s</p>', rarityColor, data.name))
   
    -- Description
    if data.description and data.description ~= "" then
        table.insert(html, formatLine(data.description, "color-jade"))
    end
   
    -- Slot/Type line
    if data.slot and data.slot ~= "" then
        table.insert(html, formatLine("[" .. data.slot .. "]", "color-silver"))
    end
   
    -- Stats
    if data.rng and data.rng ~= "" then
        table.insert(html, formatStat("Range", data.rng))
    end
    if data.armor and data.armor ~= "" then
        table.insert(html, formatStat("Armor", data.armor))
    end
    if data.damage and data.damage ~= "" then
        table.insert(html, formatStat("Damage", data.damage))
    end
    if data.attack_speed and data.attack_speed ~= "" then
        table.insert(html, formatStat("Attackspeed", data.attack_speed))
    end
    if data.defense and data.defense ~= "" then
        table.insert(html, formatStat("Defense", data.defense))
    end
    if data.move_speed and data.move_speed ~= "" then
        table.insert(html, formatStat("Movespeed", data.move_speed))
    end
    if data.health and data.health ~= "" then
        table.insert(html, formatStat("HP", data.health))
    end
    if data.mana and data.mana ~= "" then
        table.insert(html, formatStat("MP", data.mana))
    end
    if data.ability and data.ability ~= "" then
         table.insert(html, formatStat("Ability", data.ability))
    end
    if data.magic and data.magic ~= "" then
        table.insert(html, formatStat("Magic", data.magic))
    end
    if data.health_regen and data.health_regen ~= "" then
        table.insert(html, formatStat("HP Regen", data.health_regen))
    end
    if data.mana_regen and data.mana_regen ~= "" then
         table.insert(html, formatStat("MP Regen", data.mana_regen))
    end
    if data.container and data.container ~= "" then
        table.insert(html, formatStat("Slots", data.container))
    end
   
    -- Size
    if data.size and data.size ~= "" then
        table.insert(html, string.format('<p>Size: %s</p>', data.size))
    end
   
    -- Weight
    if data.weight and data.weight ~= "" then
        table.insert(html, string.format('<p>It weighs %s oz.</p>', data.weight))
    end
   
    -- Rarity text (skip for common)
    if itemRarity ~= "common" and rarityText ~= "" then
        table.insert(html, formatLine(rarityText, "color-" .. rarityColor))
    end
   
    -- Type category
    if data.type and data.type ~= "" then
        table.insert(html, formatLine("[" .. data.type .. "]", "color-silver"))
     end
      
      
     box:addHeader(data.name or 'Unknown')
     table.insert(html, '</div>')
      :addImage(spriteContent)
      :addRow('Slot', data.slot)
      :addRow('Type', data.type and string.format('[[:Category:%s|%s]]', data.type, data.type), 'type')
      :addStat('wgt', formatWeight(data.weight))
      :addStat('rng', data.rng)
      :addStat('dmg', data.damage)
      :addStat('eq', data.size)
      :addStat('hp', data.health)
      :addStat('mp', data.mana)
      :addStat('ab', data.ability)
      :addStat('mag', data.magic)
      :addStat('arm', data.armor)
      :addStat('def', data.defense)
      :addStat('ms', data.move_speed)
      :addStat('as', data.attack_speed)
      :addStat('hpregen', data.health_regen)
      :addStat('mpregen', data.mana_regen)
      :addStat('container', data.container)
      
      
    -- Categories
     local categories = ''
     local categories = ''
     if data.type then
     if data.type then
Line 223: Line 202:
     end
     end
      
      
     return box:finish() .. categories
     return frame:preprocess(table.concat(html, '\n')) .. categories
end
end


-- Monster infobox (keeping table-based format for now)
function p.monster(frame)
function p.monster(frame)
     local args = frame:getParent().args
     local args = frame:getParent().args
      
      
     local box = p.new(frame, false) -- applyBonuses = false for monsters
     local root = mw.html.create('table')
    root:addClass('wikitable')
        :addClass('infobox')
         :addClass('monster-infobox')
         :addClass('monster-infobox')
        :css('float', 'right')
        :css('clear', 'right')
        :css('margin', '0 0 1em 1em')
        :css('width', '250px')
   
    -- Header
    root:tag('tr')
        :tag('th')
            :attr('colspan', 2)
            :css('text-align', 'center')
            :wikitext(args.name or 'Unknown')
      
      
    -- Image
     local sprite = args.sprite or args.name
     local sprite = args.sprite or args.name
     local previewContent = frame:expandTemplate{
     local previewContent = frame:expandTemplate{
Line 237: Line 231:
         args = { sprite, '128', mode = args.mode or 'auto', file = args.file or '' }
         args = { sprite, '128', mode = args.mode or 'auto', file = args.file or '' }
     }
     }
    root:tag('tr')
        :tag('td')
            :attr('colspan', 2)
            :css('text-align', 'center')
            :wikitext(previewContent)
   
    -- Stats
    local function addStat(key, value)
        if not value or value == '' then return end
        local stat = monsterStats[key]
        if not stat then return end
       
        local row = root:tag('tr')
        row:tag('th')
            :css('text-align', 'right')
            :css('width', '32px')
            :wikitext(makeIcon(frame, stat.icon, stat.text))
        row:tag('td')
            :css('text-align', 'left')
            :wikitext(value)
    end
      
      
     box:addHeader(args.name or 'Unknown')
     addStat('hp', args.hp)
      :addImage(previewContent)
    addStat('xp', args.xp)
      :addStat('hp', args.hp)
    addStat('arm', args.arm)
      :addStat('xp', args.xp)
    addStat('def', args.def)
      :addStat('arm', args.arm)
    addStat('as', args.as)
      :addStat('def', args.def)
    addStat('ms', args.ms)
      :addStat('as', args.as)
    addStat('respawn', args.respawn)
      :addStat('ms', args.ms)
      :addStat('respawn', args.respawn)
      
      
     return box:finish() .. '[[Category:Monsters]]'
     return tostring(root) .. '[[Category:Monsters]]'
end
end


return p
return p

Revision as of 00:41, 28 January 2026

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

local p = {}

-- Rarity color mapping
local rarityColors = {
    common = "silver",
    uncommon = "mint",
    rare = "sky",
    epic = "pink",
    legendary = "gold"
}

-- Rarity display names
local rarityNames = {
    common = "Common item.",
    uncommon = "Uncommon item.",
    rare = "Rare item.",
    epic = "Epic item.",
    legendary = "Legendary item."
}

-- Stat definitions for monsters (keeping old table-based format)
local monsterStats = {
    hp = { text = 'HP', icon = 'Health.png' },
    mp = { text = 'MP', icon = 'Mana.png' },
    arm = { text = 'Armor', icon = 'Armor.png' },
    def = { text = 'Defense', icon = 'Defense.png' },
    ms = { text = 'Move Speed', icon = 'Move_Speed.png' },
    as = { text = 'Attack Speed', icon = 'Attack_Speed.png' },
    xp = { text = 'Experience', icon = 'Experience.png' },
    respawn = { text = 'Respawn Time', icon = 'Respawn_Time.png' },
}

local function makeIcon(frame, icon, tooltip)
    local img = frame:preprocess('{{#spritescale:' .. icon .. '|stat}}')
    return '<span title="' .. mw.text.encode(tooltip) .. '">' .. img .. '</span>'
end

-- Format a stat line with positive/negative coloring
local function formatStat(label, value)
    if not value or value == "" then
        return nil
    end
    
    local numValue = tonumber(value)
    if numValue then
        local colorClass, prefix
        if numValue >= 0 then
            colorClass = "color-conifer"
            prefix = "+"
        else
            colorClass = "color-coral"
            prefix = ""
        end
        return string.format('<p>%s: <span class="%s">%s%s</span></p>', label, colorClass, prefix, value)
    else
        return string.format('<p>%s: %s</p>', label, value)
    end
end

-- Format a plain text line
local function formatLine(text, colorClass)
    if not text or text == "" then
        return nil
    end
    if colorClass then
        return string.format('<p class="%s">%s</p>', colorClass, text)
    else
        return string.format('<p>%s</p>', text)
    end
end

-- Query item data from Cargo
local function getItemData(name, rarity)
    local tables = 'Items'
    local fields = 'name,sprite,slot,type,weight,rng,damage,health,mana,ability,magic,armor,defense,move_speed,attack_speed,size,container,health_regen,mana_regen,description,rarity'
    local args = {
        where = 'name="' .. name .. '"',
        limit = 1
    }
    
    if rarity and rarity ~= '' then
        args.where = args.where .. ' AND rarity="' .. rarity .. '"'
    end
    
    local result = mw.ext.cargo.query(tables, fields, args)
    
    if result and result[1] then
        return result[1]
    end
    return nil
end

function p.item(frame)
    local args = frame:getParent().args
    local itemName = args.name or args[1]
    local rarity = args.rarity
    local float = args.float or "right"
    local spriteSize = args.spriteSize or "64"
    
    -- Query Cargo for item data
    local data = getItemData(itemName, rarity)
    
    if not data then
        return '<span class="error">Item not found: ' .. (itemName or 'nil') .. '</span>'
    end
    
    local itemRarity = string.lower(data.rarity or "common")
    local rarityColor = rarityColors[itemRarity] or "silver"
    local rarityText = rarityNames[itemRarity] or ""
    
    local html = {}
    
    -- Container with tooltip-panel styling
    table.insert(html, string.format('<div class="tooltip-panel font-apogea-long infobox" style="float:%s; margin-%s:15px; margin-bottom:10px;">', 
        float, 
        float == "right" and "left" or "right"))
    
    -- Sprite
    local sprite = data.sprite or data.name
    table.insert(html, string.format('{{Sprite|%s|%s|class=pageimage}}', sprite, spriteSize))
    
    -- Item name with rarity color
    table.insert(html, string.format('<p class="font-bitcell color-%s">%s</p>', rarityColor, data.name))
    
    -- Description
    if data.description and data.description ~= "" then
        table.insert(html, formatLine(data.description, "color-jade"))
    end
    
    -- Slot/Type line
    if data.slot and data.slot ~= "" then
        table.insert(html, formatLine("[" .. data.slot .. "]", "color-silver"))
    end
    
    -- Stats
    if data.rng and data.rng ~= "" then
        table.insert(html, formatStat("Range", data.rng))
    end
    if data.armor and data.armor ~= "" then
        table.insert(html, formatStat("Armor", data.armor))
    end
    if data.damage and data.damage ~= "" then
        table.insert(html, formatStat("Damage", data.damage))
    end
    if data.attack_speed and data.attack_speed ~= "" then
        table.insert(html, formatStat("Attackspeed", data.attack_speed))
    end
    if data.defense and data.defense ~= "" then
        table.insert(html, formatStat("Defense", data.defense))
    end
    if data.move_speed and data.move_speed ~= "" then
        table.insert(html, formatStat("Movespeed", data.move_speed))
    end
    if data.health and data.health ~= "" then
        table.insert(html, formatStat("HP", data.health))
    end
    if data.mana and data.mana ~= "" then
        table.insert(html, formatStat("MP", data.mana))
    end
    if data.ability and data.ability ~= "" then
        table.insert(html, formatStat("Ability", data.ability))
    end
    if data.magic and data.magic ~= "" then
        table.insert(html, formatStat("Magic", data.magic))
    end
    if data.health_regen and data.health_regen ~= "" then
        table.insert(html, formatStat("HP Regen", data.health_regen))
    end
    if data.mana_regen and data.mana_regen ~= "" then
        table.insert(html, formatStat("MP Regen", data.mana_regen))
    end
    if data.container and data.container ~= "" then
        table.insert(html, formatStat("Slots", data.container))
    end
    
    -- Size
    if data.size and data.size ~= "" then
        table.insert(html, string.format('<p>Size: %s</p>', data.size))
    end
    
    -- Weight
    if data.weight and data.weight ~= "" then
        table.insert(html, string.format('<p>It weighs %s oz.</p>', data.weight))
    end
    
    -- Rarity text (skip for common)
    if itemRarity ~= "common" and rarityText ~= "" then
        table.insert(html, formatLine(rarityText, "color-" .. rarityColor))
    end
    
    -- Type category
    if data.type and data.type ~= "" then
        table.insert(html, formatLine("[" .. data.type .. "]", "color-silver"))
    end
    
    table.insert(html, '</div>')
    
    -- Categories
    local categories = ''
    if data.type then
        categories = categories .. '[[Category:' .. data.type .. ']]'
    end
    
    return frame:preprocess(table.concat(html, '\n')) .. categories
end

-- Monster infobox (keeping table-based format for now)
function p.monster(frame)
    local args = frame:getParent().args
    
    local root = mw.html.create('table')
    root:addClass('wikitable')
        :addClass('infobox')
        :addClass('monster-infobox')
        :css('float', 'right')
        :css('clear', 'right')
        :css('margin', '0 0 1em 1em')
        :css('width', '250px')
    
    -- Header
    root:tag('tr')
        :tag('th')
            :attr('colspan', 2)
            :css('text-align', 'center')
            :wikitext(args.name or 'Unknown')
    
    -- Image
    local sprite = args.sprite or args.name
    local previewContent = frame:expandTemplate{
        title = 'MonsterPreview',
        args = { sprite, '128', mode = args.mode or 'auto', file = args.file or '' }
    }
    root:tag('tr')
        :tag('td')
            :attr('colspan', 2)
            :css('text-align', 'center')
            :wikitext(previewContent)
    
    -- Stats
    local function addStat(key, value)
        if not value or value == '' then return end
        local stat = monsterStats[key]
        if not stat then return end
        
        local row = root:tag('tr')
        row:tag('th')
            :css('text-align', 'right')
            :css('width', '32px')
            :wikitext(makeIcon(frame, stat.icon, stat.text))
        row:tag('td')
            :css('text-align', 'left')
            :wikitext(value)
    end
    
    addStat('hp', args.hp)
    addStat('xp', args.xp)
    addStat('arm', args.arm)
    addStat('def', args.def)
    addStat('as', args.as)
    addStat('ms', args.ms)
    addStat('respawn', args.respawn)
    
    return tostring(root) .. '[[Category:Monsters]]'
end

return p