Jump to content

Module:Item/Components/Infobox

From Creopedia

This documentation is transcluded from Module:Item/Components/Infobox/doc.

Output an infobox for Module:Item using Module:InfoboxLua.


require( 'strict' )

local infoboxLua = require( 'Module:InfoboxLua' )
local effect = require( 'Module:Effect' )
local fixJsonArray = require( 'Module:InfoboxLua/Util' ).fixJsonArray
local getThumbnail = require( 'Module:Item' ).getThumbnail

-- Icons are 28px pixel art, which reads far too small against a 320px infobox.
-- Render at 3x -- an integer multiple, so every source pixel maps to a clean 3x3
-- block -- and tag the image so the browser upscales with nearest-neighbour
-- instead of smoothing the artwork into mush.
local ICON_SOURCE_SIZE = 28
local ICON_SCALE = 3

local p = {}

--- @param rarityId number
--- @return string|nil
local function getRarityHtml( rarityId )
	local rarityTable = mw.loadJsonData( 'Module:GameData/EvoCreo2/RarityTable.json' )
	local rarity = rarityTable[rarityId]

	if not rarity or not rarity.name then
		return nil
	end

	return require( 'Module:Rarity' )._main( rarity.nameId )
end

--- @param type table
--- @return string|nil
local function getItemTypeHtml( type )
	if not type or not type.name then
		return nil
	end

	return require( 'Module:BadgeLua' ).render( {
		text = type.name
	} )
end

--- @param element table
--- @return string|nil
local function getElementHtml( element )
	if not element or not element.name then
		return nil
	end

	return require( 'Module:Element' )._main( element.name )
end

--- @param money string|number
--- @return string|nil
local function getMoneyHtml( money )
	if not money then
		return nil
	end

	return require( 'Module:Money' )._main( money )
end

--- @param evocreo2Data table
--- @param args table
--- @return SectionComponentData|nil
local function getEvoCreo2Section( evocreo2Data, args )
	if not evocreo2Data then
		return nil
	end

	local section = {
		label = 'EvoCreo 2',
		columns = 2,
		items = {
			{
				label = 'Type',
				content = getItemTypeHtml( evocreo2Data.type )
			},
			{
				label = 'Rarity',
				content = getRarityHtml( evocreo2Data.rarityId )
			},
			{
				label = 'Cost',
				content = getMoneyHtml( args.evocreo2_cost or evocreo2Data.cost )
			},
			{
				label = 'Cooldown',
				content = type( evocreo2Data.cooldown ) == 'number' and string.format( '%d s', evocreo2Data.cooldown ) or
				nil
			},
		},
	}

	for _, card in ipairs( effect.getInfoboxCards( evocreo2Data.itemEffectMaps, 'item' ) ) do
		table.insert( section.items, card )
	end

	return section
end

--- @param evocreoData table
--- @param args table
--- @return SectionComponentData|nil
local function getEvoCreoSection( evocreoData, args )
	if not evocreoData then
		return nil
	end

	return {
		label = 'EvoCreo',
		columns = 2,
		items = {
			{
				label = 'Type',
				content = getItemTypeHtml( { name = evocreoData.type } )
			},
			{
				label = 'Element',
				content = getElementHtml( { name = evocreoData.element } )
			},
			{
				label = 'Cost',
				content = getMoneyHtml( args.evocreo_cost or evocreoData.cost )
			},
			{
				label = 'Boon',
				content = table.concat( fixJsonArray( evocreoData.boon ), ', ' )
			}
		}
	}
end

--- The game sections, in order, with no gaps.
---
--- These must be appended rather than written as a two element literal. An item
--- that never appeared in EvoCreo 2 makes the first entry nil, which leaves a
--- hole at index 1, and ipairs stops at a hole -- so the EvoCreo section that
--- follows it was silently dropped and the infobox rendered empty.
---
--- @param data table
--- @param args table
--- @return table
local function getSections( data, args )
	local sections = {}

	for _, section in ipairs( {
		{ getEvoCreo2Section, data.evocreo2 },
		{ getEvoCreoSection, data.evocreo }
	} ) do
		local built = section[1]( section[2], args )

		if built then
			table.insert( sections, built )
		end
	end

	return sections
end

--- The file that illustrates the item.
---
--- EvoCreo 2 artwork is the default. An item that only ever appeared in EvoCreo
--- has none, and asking for it renders a broken file link, so those fall back
--- to the EvoCreo icon.
---
--- @param data table
--- @param args table
--- @return string
local function getImageSrc( data, args )
	if args.image then
		return args.image
	end

	if not data.evocreo2 and data.evocreo then
		return getThumbnail( data.name, 'evocreo' )
	end

	return getThumbnail( data.name )
end

--- Build the infobox data needed from the raw data
---
--- @param context table
--- @return table
local function getInfoboxData( context )
	local data = context.data
	local args = context.args or {}

	return {
		title = data.name,
		image = {
			src = getImageSrc( data, args ),
			size = ICON_SOURCE_SIZE * ICON_SCALE,
			class = 'cp-image-pixelated',
		},
		sections = {
			{
				sections = getSections( data, args )
			}
		}
	}
end

--- @param context ComponentContext
--- @return string
function p.render( context )
	return mw.getCurrentFrame():extensionTag {
		name = 'templatestyles', args = { src = 'Module:Item/Components/Infobox/styles.css' }
	} .. infoboxLua.render( getInfoboxData( context ) )
end

return p