Jump to content

Module:Creo/Components/Sprites

From Creopedia

This documentation is transcluded from Module:Creo/Components/Sprites/doc.

Output sprite tables for a Creo.

Implements Template:Creo/Sprites.


require( 'strict' )

local animation = require( 'Module:Animation' )
local gameTabs = require( 'Module:GameTabs' )
local tableLua = require( 'Module:TableLua' )
local SPRITES_MAP = mw.loadJsonData( 'Module:Creo/Components/Sprites/Map.json' )
local VARIANTS_MAP = mw.loadJsonData( 'Module:Creo/Components/Sprites/Variants.json' )
local getIndexData = require( 'Module:Creo' ).getIndexData

local p = {}


---@param pattern string
---@param data table<string, any>
---@return string
local function format( pattern, data )
	return (pattern:gsub( '%%{(%w+)}', function ( placeholder )
		if data[placeholder] == nil then
			return '%{' .. placeholder .. '}'
		end
		return tostring( data[placeholder] )
	end ))
end

---
---@param creoName string
---@param spriteGroup table
---@param variant table|nil
---@return TableProps
local function getSpriteTableProps( creoName, spriteGroup, variant )
	variant = variant or {}

	local columns = {}
	local rowData = {}
	local templateData = {
		creoName = creoName,
		variantId = variant.id or '',
		variantNumId = variant.numId or ''
	}

	for _, item in ipairs( spriteGroup.items ) do
		table.insert( columns, {
			id = item.label,
			label = item.label
		} )

		local images = {}
		for _, pattern in ipairs( item.imagePatterns ) do
			table.insert( images, format( pattern, templateData ) )
		end

		local animationHtml = animation.render {
			images = images,
			fps = spriteGroup.fps,
		}
		table.insert( rowData, animationHtml )
	end

	return {
		caption = spriteGroup.title,
		columns = columns,
		data = { rowData },
		class = 'wikitable--border wikitable--fluid',
	}
end

---@param itemsContainer HtmlBuilder
---@param creoName string
---@param gameSpriteMap table
---@param variant table
local function renderSpriteGroupsForVariant( itemsContainer, creoName, gameSpriteMap, variant )
	for _, spriteGroup in ipairs( gameSpriteMap ) do
		local item = itemsContainer:tag( 'div' ):addClass( 't-creo-sprites-variant-item' )

		if type( spriteGroup.columnSpan ) == 'number' then
			item:css( 'grid-column', string.format( 'span %d', spriteGroup.columnSpan ) )
		end

		if type( spriteGroup.rowSpan ) == 'number' then
			item:css( 'grid-row', string.format( 'span %d', spriteGroup.rowSpan ) )
		end

		local tableProps = getSpriteTableProps( creoName, spriteGroup, variant )
		item:wikitext( tableLua.render( tableProps ) )
	end
end

---@param root HtmlBuilder
---@param creoName string
---@param gameSpriteMap table
---@param variant table
local function renderVariant( root, creoName, gameSpriteMap, variant )
	local variantDiv = root:tag( 'div' )
		:addClass( 't-creo-sprites-variant' )
		:tag( 'div' )
			:addClass( 't-creo-sprites-variant-title' )
			:wikitext( variant.name )
			:done()

	if type( variant.id ) == 'string' and variant.id ~= '' then
		variantDiv:addClass( 't-creo-sprites-variant--' .. variant.id )
	end

	local items = variantDiv:tag( 'div' ):addClass( 't-creo-sprites-variant-items' )
	renderSpriteGroupsForVariant( items, creoName, gameSpriteMap, variant )
end

---@param root HtmlBuilder
---@param creoName string
---@param gameSpriteMap table
---@param variants table
local function renderWithVariants( root, creoName, gameSpriteMap, variants )
	for _, variant in ipairs( variants ) do
		renderVariant( root, creoName, gameSpriteMap, variant )
	end
end

---@param root HtmlBuilder
---@param creoName string
---@param gameSpriteMap table
local function renderWithoutVariants( root, creoName, gameSpriteMap )
	for _, spriteGroup in ipairs( gameSpriteMap ) do
		local tableProps = getSpriteTableProps( creoName, spriteGroup )
		root:wikitext( tableLua.render( tableProps ) )
	end
end

---@param creoName string
---@param gameSpriteMap table
---@param gameId string
---@return string
local function renderGameTabContent( creoName, gameSpriteMap, gameId )
	local root = mw.html.create( 'div' )
	root:addClass( 't-creo-sprites' )
		:addClass( 'cp-image-pixelated' )

	local variants = VARIANTS_MAP[gameId]
	if variants and variants[1] ~= nil then
		renderWithVariants( root, creoName, gameSpriteMap, variants )
	else
		renderWithoutVariants( root, creoName, gameSpriteMap )
	end

	return tostring( root )
end

---@param creoIndexData table
---@return table
local function getGameTabsArgs( creoIndexData )
	local gameTabsArgs = {
		noPadding = true
	}

	for _, gameId in ipairs( creoIndexData.games ) do
		local gameSpriteMap = SPRITES_MAP[gameId]
		if gameSpriteMap and gameSpriteMap[1] ~= nil then
			gameTabsArgs[gameId] = renderGameTabContent( creoIndexData.name, gameSpriteMap, gameId )
		end
	end

	return gameTabsArgs
end

--- @param context ComponentContext
--- @return string
function p.render( context )
	local creoName = context.args[1] or mw.title.getCurrentTitle().fullText
	local creoIndexData = getIndexData( creoName )

	if not creoIndexData then
		return ''
	end

	return gameTabs._main( getGameTabsArgs( creoIndexData ) ) .. mw.getCurrentFrame():extensionTag {
		name = 'templatestyles', args = { src = 'Module:Creo/Components/Sprites/styles.css' }
	}
end


return p