Module:Infobox: Difference between revisions
Remove inline-block when float=none (via update-page on MediaWiki MCP Server) |
Use stat labels from ItemConfig (via update-page on MediaWiki MCP Server) |
||
| (5 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local ItemConfig = require('Module:ItemConfig') | |||
local | |||
local function makeIcon(frame, icon, tooltip) | local function makeIcon(frame, icon, tooltip) | ||
| Line 97: | Line 8: | ||
-- Format a stat line with positive/negative coloring | -- Format a stat line with positive/negative coloring | ||
local function formatStat( | local function formatStat(statKey, value) | ||
if not value or value == "" then | if not value or value == "" then | ||
return nil | return nil | ||
end | end | ||
local label = ItemConfig.getStatLabel(statKey) | |||
local numValue = tonumber(value) | local numValue = tonumber(value) | ||
if numValue then | if numValue then | ||
| Line 187: | Line 99: | ||
local function getItemData(name, rarity) | local function getItemData(name, rarity) | ||
local tables = 'Items' | local tables = 'Items' | ||
local fields = | local fields = ItemConfig.cargoFields.items | ||
local args = { | local args = { | ||
where = 'name="' .. name .. '"', | where = 'name="' .. name .. '"', | ||
| Line 209: | Line 121: | ||
local tables = 'Monsters' | local tables = 'Monsters' | ||
local fields = 'name,sprite,type,hp,xp,armor,defense,attack_speed,move_speed,respawn' | local fields = 'name,sprite,type,hp,xp,armor,defense,attack_speed,move_speed,respawn' | ||
local args = { | |||
where = 'name="' .. name .. '"', | |||
limit = 1 | |||
} | |||
local result = mw.ext.cargo.query(tables, fields, args) | |||
if result and result[1] then | |||
return result[1] | |||
end | |||
return nil | |||
end | |||
-- Query NPC data from Cargo | |||
local function getNPCData(name) | |||
local tables = 'NPCs' | |||
local fields = 'name,sprite,location,type,trainer' | |||
local args = { | local args = { | ||
where = 'name="' .. name .. '"', | where = 'name="' .. name .. '"', | ||
| Line 267: | Line 196: | ||
local itemRarity = string.lower(data.rarity or "common") | local itemRarity = string.lower(data.rarity or "common") | ||
local rarityColor = | local rarityColor = ItemConfig.getRarityColor(itemRarity) | ||
local rarityText = | local rarityText = ItemConfig.getRarityLabel(itemRarity) | ||
local html = {} | local html = {} | ||
| Line 294: | Line 223: | ||
end | end | ||
-- Stats | -- Stats (using config labels) | ||
if data.rng and data.rng ~= "" then | if data.rng and data.rng ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("rng", data.rng)) | ||
end | end | ||
if data.damage and data.damage ~= "" then | if data.damage and data.damage ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("damage", data.damage)) | ||
end | end | ||
if data.attack_speed and data.attack_speed ~= "" then | if data.attack_speed and data.attack_speed ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("attack_speed", data.attack_speed)) | ||
end | end | ||
if data.armor and data.armor ~= "" then | if data.armor and data.armor ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("armor", data.armor)) | ||
end | end | ||
if data.defense and data.defense ~= "" then | if data.defense and data.defense ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("defense", data.defense)) | ||
end | end | ||
if data.move_speed and data.move_speed ~= "" then | if data.move_speed and data.move_speed ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("move_speed", data.move_speed)) | ||
end | end | ||
if data.health and data.health ~= "" then | if data.health and data.health ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("health", data.health)) | ||
end | end | ||
if data.mana and data.mana ~= "" then | if data.mana and data.mana ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("mana", data.mana)) | ||
end | end | ||
if data.ability and data.ability ~= "" then | if data.ability and data.ability ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("ability", data.ability)) | ||
end | end | ||
if data.magic and data.magic ~= "" then | if data.magic and data.magic ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("magic", data.magic)) | ||
end | end | ||
if data.health_regen and data.health_regen ~= "" then | if data.health_regen and data.health_regen ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("health_regen", data.health_regen)) | ||
end | end | ||
if data.mana_regen and data.mana_regen ~= "" then | if data.mana_regen and data.mana_regen ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("mana_regen", data.mana_regen)) | ||
end | end | ||
if data.container and data.container ~= "" then | if data.container and data.container ~= "" then | ||
table.insert(html, formatStat(" | table.insert(html, formatStat("container", data.container)) | ||
end | end | ||
-- Size | -- Size (special format) | ||
if data.size and data.size ~= "" then | if data.size and data.size ~= "" then | ||
table.insert(html, string.format('<p>Size: %s/10</p>', data.size)) | table.insert(html, string.format('<p>Size: %s/10</p>', data.size)) | ||
end | end | ||
-- Weight | -- Weight (special format) | ||
if data.weight and data.weight ~= "" then | if data.weight and data.weight ~= "" then | ||
table.insert(html, string.format('<p>It weighs %s oz.</p>', data.weight)) | table.insert(html, string.format('<p>It weighs %s oz.</p>', data.weight)) | ||
| Line 362: | Line 291: | ||
if not previewMode then | if not previewMode then | ||
for _, t in ipairs(types) do | for _, t in ipairs(types) do | ||
categories = categories .. '[[Category:' .. pluralize(t) .. ']]' | categories = categories .. '[[Category:' .. ItemConfig.pluralize(t) .. ']]' | ||
end | end | ||
end | end | ||
| Line 401: | Line 330: | ||
local previewContent = frame:expandTemplate{ | local previewContent = frame:expandTemplate{ | ||
title = 'MonsterPreview', | title = 'MonsterPreview', | ||
args = { sprite, '128', mode = args.mode or 'auto', file = args.file or '' } | args = { sprite, '128', mode = args.mode or 'auto', file = args.file or '', class = 'pageimage' } | ||
} | } | ||
root:tag('tr') | root:tag('tr') | ||
| Line 409: | Line 338: | ||
:wikitext(previewContent) | :wikitext(previewContent) | ||
-- Stats | -- Stats using centralized config | ||
local function addStat(key, value) | local function addStat(key, value) | ||
if not value or value == '' then return end | if not value or value == '' then return end | ||
local | local icon = ItemConfig.getStatIcon(key) | ||
if not | local label = ItemConfig.getStatLabel(key) | ||
if not icon then return end | |||
local row = root:tag('tr') | local row = root:tag('tr') | ||
| Line 419: | Line 349: | ||
:css('text-align', 'right') | :css('text-align', 'right') | ||
:css('width', '32px') | :css('width', '32px') | ||
:wikitext(makeIcon(frame, | :wikitext(makeIcon(frame, icon, label)) | ||
row:tag('td') | row:tag('td') | ||
:css('text-align', 'left') | :css('text-align', 'left') | ||
| Line 434: | Line 364: | ||
-- Category is handled by MonsterEntry template | -- Category is handled by MonsterEntry template | ||
return tostring(root) | |||
end | |||
-- NPC infobox (queries from Cargo) | |||
function p.npc(frame) | |||
local args = frame:getParent().args | |||
local npcName = args.name or args[1] or mw.title.getCurrentTitle().text | |||
-- Query Cargo for NPC data | |||
local data = getNPCData(npcName) | |||
if not data then | |||
return '<span class="error">NPC not found: ' .. (npcName or 'nil') .. '</span>' | |||
end | |||
local root = mw.html.create('table') | |||
root:addClass('wikitable') | |||
:addClass('infobox') | |||
:addClass('npc-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(data.name or 'Unknown') | |||
-- Image | |||
local sprite = data.sprite or data.name | |||
local spriteContent = frame:expandTemplate{ | |||
title = 'Sprite', | |||
args = { sprite, '128', class = 'pageimage' } | |||
} | |||
root:tag('tr') | |||
:tag('td') | |||
:attr('colspan', 2) | |||
:css('text-align', 'center') | |||
:wikitext(spriteContent) | |||
-- Helper to add a row | |||
local function addRow(label, value) | |||
if not value or value == '' then return end | |||
local row = root:tag('tr') | |||
row:tag('th') | |||
:css('text-align', 'right') | |||
:wikitext(label) | |||
row:tag('td') | |||
:css('text-align', 'left') | |||
:wikitext(value) | |||
end | |||
-- Type | |||
addRow('Type', data.type) | |||
-- Trainer | |||
if data.trainer and data.trainer ~= '' then | |||
addRow('Trainer', data.trainer .. ' Trainer') | |||
end | |||
-- Location | |||
addRow('Location', data.location) | |||
-- Category is handled by NPCEntry template | |||
return tostring(root) | return tostring(root) | ||
end | end | ||
return p | return p | ||
Latest revision as of 20:58, 31 January 2026
Documentation for this module may be created at Module:Infobox/doc
local p = {}
local ItemConfig = require('Module:ItemConfig')
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(statKey, value)
if not value or value == "" then
return nil
end
local label = ItemConfig.getStatLabel(statKey)
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
-- Format description with bracketed text on separate lines and colored
local function formatDescription(desc)
if not desc or desc == "" then
return {}
end
local lines = {}
local remaining = desc
-- Pattern to find [bracketed text]
while remaining and remaining ~= "" do
local beforeBracket, bracketContent, afterBracket = remaining:match("^(.-)%[([^%]]+)%](.*)$")
if bracketContent then
-- Add any text before the bracket as jade-colored description
if beforeBracket and beforeBracket:match("%S") then
local trimmed = beforeBracket:match("^%s*(.-)%s*$")
if trimmed ~= "" then
table.insert(lines, string.format('<p class="color-jade">%s</p>', trimmed))
end
end
-- Add the bracketed text as columbia-colored (item-important)
table.insert(lines, string.format('<p class="color-columbia">[%s]</p>', bracketContent))
remaining = afterBracket
else
-- No more brackets, add remaining text as jade-colored
local trimmed = remaining:match("^%s*(.-)%s*$")
if trimmed ~= "" then
table.insert(lines, string.format('<p class="color-jade">%s</p>', trimmed))
end
remaining = nil
end
end
return lines
end
-- Split a comma-separated string into a table
local function splitTypes(typeStr)
if not typeStr or typeStr == "" then
return {}
end
local types = {}
for t in typeStr:gmatch("[^,]+") do
local trimmed = t:match("^%s*(.-)%s*$")
if trimmed and trimmed ~= "" then
table.insert(types, trimmed)
end
end
return types
end
-- Query item data from Cargo
local function getItemData(name, rarity)
local tables = 'Items'
local fields = ItemConfig.cargoFields.items
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
-- Query monster data from Cargo
local function getMonsterData(name)
local tables = 'Monsters'
local fields = 'name,sprite,type,hp,xp,armor,defense,attack_speed,move_speed,respawn'
local args = {
where = 'name="' .. name .. '"',
limit = 1
}
local result = mw.ext.cargo.query(tables, fields, args)
if result and result[1] then
return result[1]
end
return nil
end
-- Query NPC data from Cargo
local function getNPCData(name)
local tables = 'NPCs'
local fields = 'name,sprite,location,type,trainer'
local args = {
where = 'name="' .. name .. '"',
limit = 1
}
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] or mw.title.getCurrentTitle().text
local rarity = args.rarity
local float = args.float or "right"
local spriteSize = args.spriteSize or "64"
local previewMode = args.preview == "true" or args.preview == "1"
local data
-- If preview mode or direct data provided, use args instead of Cargo
if previewMode or args.damage or args.armor or args.type then
data = {
name = itemName,
sprite = args.sprite or itemName,
slot = args.slot,
type = args.type,
weight = args.weight,
rng = args.rng,
damage = args.damage,
health = args.health,
mana = args.mana,
ability = args.ability,
magic = args.magic,
armor = args.armor,
defense = args.defense,
move_speed = args.move_speed,
attack_speed = args.attack_speed,
size = args.size,
container = args.container,
health_regen = args.health_regen,
mana_regen = args.mana_regen,
description = args.description,
rarity = rarity or args.rarity or "common"
}
else
-- Query Cargo for item data
data = getItemData(itemName, rarity)
if not data then
return '<span class="error">Item not found: ' .. (itemName or 'nil') .. '</span>'
end
end
local itemRarity = string.lower(data.rarity or "common")
local rarityColor = ItemConfig.getRarityColor(itemRarity)
local rarityText = ItemConfig.getRarityLabel(itemRarity)
local html = {}
-- Container with tooltip-panel styling
if float == "none" then
table.insert(html, '<div class="tooltip-panel font-apogea-long infobox">')
else
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"))
end
-- 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 (with bracketed text handling)
local descLines = formatDescription(data.description)
for _, line in ipairs(descLines) do
table.insert(html, line)
end
-- Stats (using config labels)
if data.rng and data.rng ~= "" then
table.insert(html, formatStat("rng", data.rng))
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("attack_speed", data.attack_speed))
end
if data.armor and data.armor ~= "" then
table.insert(html, formatStat("armor", data.armor))
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("move_speed", data.move_speed))
end
if data.health and data.health ~= "" then
table.insert(html, formatStat("health", data.health))
end
if data.mana and data.mana ~= "" then
table.insert(html, formatStat("mana", 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("health_regen", data.health_regen))
end
if data.mana_regen and data.mana_regen ~= "" then
table.insert(html, formatStat("mana_regen", data.mana_regen))
end
if data.container and data.container ~= "" then
table.insert(html, formatStat("container", data.container))
end
-- Size (special format)
if data.size and data.size ~= "" then
table.insert(html, string.format('<p>Size: %s/10</p>', data.size))
end
-- Weight (special format)
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 display (show all types)
local types = splitTypes(data.type)
if #types > 0 then
table.insert(html, formatLine("[" .. table.concat(types, ", ") .. "]", "color-silver"))
end
table.insert(html, '</div>')
-- Categories (skip in preview mode)
local categories = ''
if not previewMode then
for _, t in ipairs(types) do
categories = categories .. '[[Category:' .. ItemConfig.pluralize(t) .. ']]'
end
end
return frame:preprocess(table.concat(html, '\n')) .. categories
end
-- Monster infobox (queries from Cargo)
function p.monster(frame)
local args = frame:getParent().args
local monsterName = args.name or args[1] or mw.title.getCurrentTitle().text
-- Query Cargo for monster data
local data = getMonsterData(monsterName)
if not data then
return '<span class="error">Monster not found: ' .. (monsterName or 'nil') .. '</span>'
end
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(data.name or 'Unknown')
-- Image
local sprite = data.sprite or data.name
local previewContent = frame:expandTemplate{
title = 'MonsterPreview',
args = { sprite, '128', mode = args.mode or 'auto', file = args.file or '', class = 'pageimage' }
}
root:tag('tr')
:tag('td')
:attr('colspan', 2)
:css('text-align', 'center')
:wikitext(previewContent)
-- Stats using centralized config
local function addStat(key, value)
if not value or value == '' then return end
local icon = ItemConfig.getStatIcon(key)
local label = ItemConfig.getStatLabel(key)
if not icon then return end
local row = root:tag('tr')
row:tag('th')
:css('text-align', 'right')
:css('width', '32px')
:wikitext(makeIcon(frame, icon, label))
row:tag('td')
:css('text-align', 'left')
:wikitext(value)
end
addStat('hp', data.hp)
addStat('xp', data.xp)
addStat('armor', data.armor)
addStat('defense', data.defense)
addStat('attack_speed', data.attack_speed)
addStat('move_speed', data.move_speed)
addStat('respawn', data.respawn)
-- Category is handled by MonsterEntry template
return tostring(root)
end
-- NPC infobox (queries from Cargo)
function p.npc(frame)
local args = frame:getParent().args
local npcName = args.name or args[1] or mw.title.getCurrentTitle().text
-- Query Cargo for NPC data
local data = getNPCData(npcName)
if not data then
return '<span class="error">NPC not found: ' .. (npcName or 'nil') .. '</span>'
end
local root = mw.html.create('table')
root:addClass('wikitable')
:addClass('infobox')
:addClass('npc-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(data.name or 'Unknown')
-- Image
local sprite = data.sprite or data.name
local spriteContent = frame:expandTemplate{
title = 'Sprite',
args = { sprite, '128', class = 'pageimage' }
}
root:tag('tr')
:tag('td')
:attr('colspan', 2)
:css('text-align', 'center')
:wikitext(spriteContent)
-- Helper to add a row
local function addRow(label, value)
if not value or value == '' then return end
local row = root:tag('tr')
row:tag('th')
:css('text-align', 'right')
:wikitext(label)
row:tag('td')
:css('text-align', 'left')
:wikitext(value)
end
-- Type
addRow('Type', data.type)
-- Trainer
if data.trainer and data.trainer ~= '' then
addRow('Trainer', data.trainer .. ' Trainer')
end
-- Location
addRow('Location', data.location)
-- Category is handled by NPCEntry template
return tostring(root)
end
return p