Jump to content

Module:Creo

From Creopedia

This documentation is transcluded from Module:Creo/doc.

A meta module for all Creo-related templates.

Page Description
Module:Creo/Index.json Contains basic data of all Creo that is shared across games
Module:Creo/Components/Prevnext Renders the top navigation
Module:Creo/Components/Infobox Renders the infobox
Module:Creo/Components/Stats Renders Template:Creo/Stats
Module:Creo/Components/LevelMoves Renders Template:Creo/LevelMoves
Module:Creo/Components/ItemMoves Renders Template:Creo/ItemMoves
Module:Creo/Components/Traits Renders Template:Creo/Traits
Module:Creo/Components/Abilities Renders Template:Creo/Abilities
Module:Creo/Components/Evolution Renders Template:Creo/Evolution
Module:Creo/Components/Sprites Renders Template:Creo/Sprites

require( 'strict' )

--- @class ComponentConfig
--- @field moduleName string The name of the Lua module to render.
--- @field useData? boolean If true, fetches Creo data and adds it to the context.
--- @field dataSelectors? table<string, string|nil> The key to access specific data within the Creo data object.
--- @field useArgs? boolean If true, adds the wikitext arguments to the context.
---
--- @class ComponentContext
--- @field data? table The data for the component.
--- @field args? table The wikitext arguments for the component.

local p = {}

local gameData = require( 'Module:GameData' )

local creoData = {}
local templateArgs = {}

--- Wikitext entry point for the module
---
--- @param frame mw.frame
--- @return string
function p.main( frame )
	local getArgs = require( 'Module:Arguments' ).getArgs
	return p._main( getArgs( frame ) )
end

--- Lua entry point for the module
---
--- @param args table
--- @return string
function p._main( args )
	args = args or {}

	local creoName = args.name or mw.title.getCurrentTitle().fullText

	--- TODO: Load the shared data of Creo here
	creoData = p.getData( creoName )

	--- TODO: Set the shared data with the wikitext args if needed
	templateArgs = args

	local wikitext = {
		p.renderPrevnext(),
		p.renderInfobox(),
		p.renderCategories( p.getCategories() )
	}

	if not creoData.evocreo2 then
		table.insert( wikitext, 1, p.renderUnavailable() )
	end

	return table.concat( wikitext )
end

--- Get the data for the Creo
---
--- @param name string
--- @param game string|nil
--- @return table
function p.getData( name, game )
	return gameData.getCreo( name, game )
end

--- Return the wikitext for the prevnext
---
--- @return string
function p.renderPrevnext()
	if not creoData.evocreo2 then
		return ''
	end

	return require( 'Module:Creo/Components/Prevnext' ).render( { data = { id = creoData.evocreo2.id } } )
end

--- Return the wikitext for the infobox
---
--- @return string
function p.renderInfobox()
	local data = creoData.evocreo2 or p.getData( mw.title.getCurrentTitle().fullText ).evocreo2
	if not data then
		return ''
	end

	return require( 'Module:Creo/Components/Infobox' ).render( {
		data = data,
		args = templateArgs
	} )
end

--- Return a visible error box shown when EvoCreo 2 Creo data is unavailable
--- (API failure, or the Creo is absent from the API).
---
--- @return string
function p.renderUnavailable()
	return tostring(
		mw.html.create( 'div' )
			:addClass( 'error' )
			:wikitext( 'Creo data is currently unavailable.' )
	)
end


--- Get the page categories for the Creo
---
--- @return table
function p.getCategories()
	local categories = {
		'Creo'
	}

	if creoData.evocreo2 then
		table.insert( categories, 'Creo in EvoCreo 2' )
	end

	if creoData.evocreo then
		table.insert( categories, 'Creo in EvoCreo' )
	end

	return categories
end

--- Return the wikitext for the category
---
--- @param categories table
--- @return string
function p.renderCategories( categories )
	local wikitext = {}

	for _, category in ipairs( categories ) do
		table.insert( wikitext, string.format( '[[Category:%s]]', category ) )
	end

	return table.concat( wikitext, '' )
end

--- Get the thumbnail for a Creo
---
--- The first frame of the front-facing battle idle.
---
--- @param name string
--- @return string
function p.getThumbnail( name )
	return string.format( '%s_bf_idle0000 - evocreo2.png', string.lower( name ) )
end

--- Get the display image for a Creo
---
--- The same front-facing battle idle as getThumbnail, but cropped to the Creo
--- and re-centred on one canvas shared by every Creo. The game's own battle
--- sprites have no canvas in common -- their content runs from 21x22 up to
--- 118x114, each sitting inside its own asymmetric transparent padding -- so
--- the infobox's width-only 240px spec rendered a box whose height swung about
--- 80px from page to page and put the Creo somewhere different in it every
--- time. One canvas makes 240px mean one box, and because nothing is scaled a
--- big Creo still reads as bigger than a small one.
---
--- Built by .claude/tools/creodisplay.py in the wiki's content repository.
---
--- @param name string
--- @return string
function p.getDisplayImage( name )
	return string.format( '%s_display - evocreo2.png', string.lower( name ) )
end

--- Get the overworld thumbnail for a Creo
---
--- The Creo as it is met in the field rather than as it is seen across a
--- battle, taken from the down-facing walk frame and cropped to the Creo. The
--- game's own sprite carries an 80x80 canvas that the Creo occupies a median of
--- 22x27 of, which is far too much empty space for a listing, so these are
--- separate files trimmed to the Creo's own bounding box.
---
--- @param name string
--- @return string
function p.getOverworldThumbnail( name )
	return string.format( '%s_icon - evocreo2.png', string.lower( name ) )
end

--- Get the index data for a Creo
---
--- @param name string
--- @return table|nil
function p.getIndexData( name )
	local creoIndex = mw.loadJsonData( 'Module:Creo/Index.json' )

	for _, creo in ipairs( creoIndex ) do
		if creo.name == name then
			return creo
		end
	end

	return nil
end

--- Get the index data for a Creo by ID
---
--- @param id number
--- @return table|nil
function p.getIndexDataById( id )
	local creoIndex = mw.loadJsonData( 'Module:Creo/Index.json' )

	for _, creo in ipairs( creoIndex ) do
		if creo.id == id then
			return creo
		end
	end

	return nil
end

-------------------------------------------------------------------
--- Wikitext templates
--- Public methods that are only accessed by the wikitext templates
-------------------------------------------------------------------

--- Get the data for the component from the data selectors
---
--- @param dataSelectors table<string, string|nil>
--- @param creoName string
--- @return table|nil
local function getContextData( dataSelectors, creoName )
	local game
	if dataSelectors then
		local keys = {}
		for k in pairs( dataSelectors ) do
			table.insert( keys, k )
		end
		if #keys == 1 then
			game = keys[1]
		end
	end

	local creoData = p.getData( creoName, game )
	if creoData == nil then
		return nil
	end

	if not dataSelectors then
		return creoData
	end

	if game then -- A single game was specified via dataSelectors
		local dataKey = dataSelectors[game]
		return dataKey and creoData[dataKey] or creoData
	end

	-- Multiple games in dataSelectors, or dataSelectors is an empty table
	local data = {}
	for gameName, dataKey in pairs( dataSelectors ) do
		local gameDataForGame = creoData[gameName]
		if gameDataForGame then
			data[gameName] = dataKey and gameDataForGame[dataKey] or gameDataForGame
		end
	end
	return data
end

--- Factory function to render a component.
---
--- @param frame mw.frame
--- @param config ComponentConfig
--- @return string
local function renderComponent( frame, config )
	local context = {}
	local wikitextArgs = require( 'Module:Arguments' ).getArgs( frame )

	if config.useData then
		local creoName = wikitextArgs[1] or mw.title.getCurrentTitle().fullText
		context.data = getContextData( config.dataSelectors, creoName )

		if context.data == nil then
			return ''
		end
	end

	if config.useArgs then
		context.args = wikitextArgs
	end

	return require( config.moduleName ).render( context )
end

--- Implements {{Creo/Stats}}
---
--- @param frame mw.frame
--- @return string
function p.renderStats( frame )
	return renderComponent( frame, {
		moduleName = 'Module:Creo/Components/Stats',
		useData = true,
		dataSelectors = {
			evocreo2 = 'creo',
			evocreo = 'a'
		}
	} )
end

--- Implements {{Creo/LevelMoves}}
---
--- @param frame mw.frame
--- @return string
function p.renderLevelMoves( frame )
	return renderComponent( frame, {
		moduleName = 'Module:Creo/Components/LevelMoves',
		useData = true,
		dataSelectors = {
			evocreo2 = 'creoMoveMaps',
			evocreo = 'move'
		}
	} )
end

--- Implements {{Creo/ItemMoves}}
---
--- @param frame mw.frame
--- @return string
function p.renderItemMoves( frame )
	return renderComponent( frame, {
		moduleName = 'Module:Creo/Components/ItemMoves',
		useData = true,
		dataSelectors = {
			evocreo2 = 'creoMoveMaps',
			evocreo = 'movecompatible'
		}
	} )
end

--- Implements {{Creo/Traits}}
---
--- @param frame mw.frame
--- @return string
function p.renderTraits( frame )
	return renderComponent( frame, {
		moduleName = 'Module:Creo/Components/Traits',
		useData = true,
		useArgs = true,
		dataSelectors = {
			evocreo2 = 'creoTraitMaps',
			evocreo = 'trait'
		}
	} )
end

--- Implements {{Creo/Abilities}}
---
--- @param frame mw.frame
--- @return string
function p.renderAbilities( frame )
	return renderComponent( frame, {
		moduleName = 'Module:Creo/Components/Abilities',
		useData = true,
		useArgs = true,
		dataSelectors = {
			evocreo2 = 'creoTypes',
			evocreo = 'ability'
		}
	} )
end

--- Implements {{Creo/Evolution}}
---
--- @param frame mw.frame
--- @return string
function p.renderEvolution( frame )
	return renderComponent( frame, {
		moduleName = 'Module:Creo/Components/Evolution',
		useArgs = true
	} )
end

--- Implements {{Creo/Sprites}}
---
--- @param frame mw.frame
--- @return string
function p.renderSprites( frame )
	return renderComponent( frame, {
		moduleName = 'Module:Creo/Components/Sprites',
		useArgs = true
	} )
end

return p