Module:Infobox
Documentation for this module may be created at Module:Infobox/doc
local p = {}
-- Stat definitions: key -> { text, icon, isBonus }
local stats = {
-- Shared stats (isBonus only applies when explicitly requested)
hp = { text = 'HP', icon = 'Health.png', isBonus = true },
mp = { text = 'MP', icon = 'Mana.png', isBonus = true },
arm = { text = 'Armor', icon = 'Armor.png', isBonus = true },
def = { text = 'Defense', icon = 'Defense.png', isBonus = true },
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
local icons = {
type = { icon = 'Question_Mark.png', text = 'Type' },
}
local function formatBonus(value)
if not value or value == '' then
return nil
end
local num = tonumber(value)
if num and num > 0 then
return '+' .. value
end
return value
end
local function formatWeight(value)
if not value or value == '' then
return nil
end
return value .. ' oz'
end
local function makeIcon(frame, icon, tooltip)
local img = frame:preprocess('{{#spritescale:' .. icon .. '|stat}}')
return '<span title="' .. mw.text.encode(tooltip) .. '">' .. img .. '</span>'
end
function p.new(frame, applyBonuses)
local builder = {
root = mw.html.create('table'),
frame = frame,
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
local row = self.root:tag('tr')
local th = row:tag('th')
:css('text-align', 'right')
:css('width', '32px')
local iconData = icons[iconKey]
if iconData then
th:wikitext(makeIcon(self.frame, iconData.icon, label))
else
th:wikitext(label)
end
row:tag('td')
:css('text-align', 'left')
:wikitext(value)
return self
end
function p:addStat(key, value)
if not value or value == '' then
return self
end
local stat = stats[key]
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
th:wikitext(stat.text)
end
row:tag('td')
:css('text-align', 'left')
:wikitext(displayValue)
return self
end
function p:finish()
return tostring(self.root)
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
-- 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 box = p.new(frame, true) -- applyBonuses = true for items
:addClass('item-infobox')
local sprite = data.sprite or data.name
local spriteContent = frame:expandTemplate{
title = 'Sprite',
args = { sprite, '64', class = 'pageimage' }
}
box:addHeader(data.name or 'Unknown')
: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)
local categories = ''
if data.type then
categories = categories .. '[[Category:' .. data.type .. ']]'
end
return box:finish() .. categories
end
function p.monster(frame)
local args = frame:getParent().args
local box = p.new(frame, false) -- applyBonuses = false for monsters
:addClass('monster-infobox')
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 '' }
}
box:addHeader(args.name or 'Unknown')
:addImage(previewContent)
: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 box:finish() .. '[[Category:Monsters]]'
end
return p