Jump to content

Module:Creo/Components/Traits

From Creopedia

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

Output the traits table for Module:Creo using Module:TableLua.


require( 'strict' )

local gameTabs = require( 'Module:GameTabs' )
local tableLua = require( 'Module:TableLua' )
local level = require( 'Module:Level' )._main
local rarity = require( 'Module:Rarity' )._main
local getRaritySortKey = require( 'Module:Rarity' ).getSortKey
local nameCell = require( 'Module:Creo/NameCell' ).render
local getTraitThumbnail = require( 'Module:Trait' ).getThumbnail
local ecGameData = require( 'Module:GameData/EvoCreo' )
local ec2GameData = require( 'Module:GameData/EvoCreo2' )

local p = {}

--- @param levelNum number
--- @return string
local function getLevelWikitext( levelNum )
	-- HACK: Create a hidden element so that Module:TableLua can sort by level
	-- We need this because we are passing HTML in getRows()
	local sort = mw.html.create( 'span' )
	sort
		:attr( 'hidden', 'true' )
		:css( 'display', 'none' )
		:wikitext( tostring( levelNum ) )

	return tostring( sort ) .. ' ' .. level( levelNum )
end

--- EvoCreo 1 shipped no trait art, so only the EvoCreo 2 rows ask for an icon
--- and the EvoCreo 1 tab stays text-only.
---
--- @param name string
--- @param gameId string
--- @return string
local function getTraitWikitext( name, gameId )
	local icon = nil
	if gameId == 'evocreo2' then
		icon = getTraitThumbnail( name )
	end

	return nameCell( icon, name, name )
end

--- The rarity cell, ordered by the tier rather than by the badge's name.
---
--- Sorted on its own text the column runs Ascendant, Common, Mega Prime, which
--- is alphabetical order and says nothing about how rare a trait is. The badge
--- carries the tier's number and the cell repeats it, so that the browser finds
--- it on the cell without having to look inside.
---
--- @param rarityId number
--- @return TableCellProps
local function getRarityCell( rarityId )
	local name = ec2GameData.getRarityById( rarityId ).nameId

	return { value = rarity( name ), sortValue = getRaritySortKey( name ) }
end

--- @param args table
--- @param gameId string
--- @param traitName string
--- @return string|nil
local function getUnlockArg( args, gameId, traitName )
	local argName = string.format( '%s_%s_unlock', gameId, traitName )
	return args[argName]
end

--- @param gameId string
--- @return TableColumn[]
local function getColumns( gameId )
	if gameId == 'evocreo2' then
		return {
			{ id = 'name', label = 'Name' },
			{ id = 'rarity', label = 'Rarity' },
			{ id = 'unlock', label = 'Unlock' }
		}
	elseif gameId == 'evocreo' then
		return {
			{ id = 'name', label = 'Name' },
			{ id = 'unlock', label = 'Unlock' }
		}
	end

	return {}
end

--- @param data table
--- @param gameId string
--- @param args table
--- @return TableRow[]
local function getRows( data, gameId, args )
	local rows = {}

	if gameId == 'evocreo2' then
		for _, traitMap in ipairs( data ) do
			if traitMap.level ~= nil then
				local row = {
					getTraitWikitext( traitMap.trait.name, gameId ),
					getRarityCell( traitMap.trait.rarityId ),
					getUnlockArg( args, gameId, traitMap.trait.name ) or getLevelWikitext( traitMap.level ),
				}
				table.insert( rows, row )
			end
		end
	elseif gameId == 'evocreo' then
		for _, trait in ipairs( data ) do
			if trait.level ~= nil then
				local traitName = ecGameData.getName( trait.id )
				local row = {
					getTraitWikitext( traitName, gameId ),
					getUnlockArg( args, gameId, traitName ) or getLevelWikitext( trait.level ),
				}
				table.insert( rows, row )
			end
		end
	end

	return rows
end

--- @param data table
--- @param gameId string
--- @param args table
--- @return TableProps
local function getTableProps( data, gameId, args )
	return {
		caption = 'Traits',
		hideCaption = true,
		columns = getColumns( gameId ),
		data = getRows( data, gameId, args ),
		-- The unlock cell leads with the level, so this orders by the level a
		-- trait is learned at. Sorting on a column id that no game defines is
		-- silently a no-op, so this must name a real column.
		sort = {
			unlock = 'asc',
		},
		class = table.concat( {
			't-creo-traits-table',
			'wikitable--fluid' -- Citizen built-in class for broad tables
		}, ' ' )
	}
end

--- @param gameData table
--- @param gameId string
--- @param args table
--- @return string
local function getGameTabWikitext( gameData, gameId, args )
	local html = mw.html.create( 'div' ):addClass( 't-tabbedCard-table-container' )
	html:wikitext( tableLua.render( getTableProps( gameData, gameId, args ) ) )
	return tostring( html )
end

--- @param data table
--- @param args table
--- @return mw.html
local function getTraitsHtml( data, args )
	local html = mw.html.create( 'div' ):addClass( 't-creo-traits' )

	local gameTabsData = gameTabs.mapGameArgs( data, function ( gameData, game )
		return getGameTabWikitext( gameData, game.id, args )
	end )
	gameTabsData.noPadding = true

	html:wikitext( gameTabs._main( gameTabsData ) )

	return html
end

--- @param context ComponentContext
--- @return string
function p.render( context )
	return tostring( getTraitsHtml( context.data, context.args ) )
end


return p