Jump to content

Module:ElementMatchups

From Creopedia

Documentation for this module may be created at Module:ElementMatchups/doc

require( 'strict' )

local TableLua = require( 'Module:TableLua' )
local Element = require( 'Module:Element' )

local p = {}

--- Same source the element chart is built from, so the per-element tables and
--- the chart can never disagree.
local DATA = 'Module:GameData/EvoCreo2/ElementTable.json'

--- FIRE -> Fire
---
--- @param name string
--- @return string
local function toTitle( name )
	return name:sub( 1, 1 ):upper() .. name:sub( 2 ):lower()
end

--- @param entry table
--- @return table
local function getBonuses( entry )
	local bonuses = {}

	for _, comparison in ipairs( entry.elementComparisonMaps or {} ) do
		bonuses[comparison.elementToCompareId] = comparison.bonus
	end

	return bonuses
end

--- @param elements table
--- @param name string
--- @return table|nil
local function findElement( elements, name )
	local target = name:upper()

	for _, element in ipairs( elements ) do
		if element.name:upper() == target then
			return element
		end
	end
end

--- @param badges table
--- @return string
local function join( badges )
	if #badges == 0 then
		return '—'
	end

	return table.concat( badges, ' ' )
end

--- Split every element into how the attacker fares against it.
---
--- @param elements table
--- @param attacker table
--- @return table, table, table
local function split( elements, attacker )
	local bonuses = getBonuses( attacker )
	local strong = {}
	local neutral = {}
	local weak = {}

	for _, defender in ipairs( elements ) do
		local bonus = bonuses[defender.id]
		local badge = Element._main( defender.name )

		if bonus == 1 then
			table.insert( strong, badge )
		elseif bonus == -1 then
			table.insert( weak, badge )
		else
			table.insert( neutral, badge )
		end
	end

	return strong, neutral, weak
end

--- The three-way breakdown for one element, as used on the element pages.
---
--- @param elementName string
--- @return string
local function renderMatchups( elementName )
	local elements = mw.loadJsonData( DATA )
	local attacker = findElement( elements, elementName )

	if not attacker then
		error( 'Unknown element: ' .. tostring( elementName ) )
	end

	local strong, neutral, weak = split( elements, attacker )

	return TableLua.render( {
		caption = string.format( '%s matchups', toTitle( attacker.name ) ),
		hideCaption = true,
		columns = {
			{ label = 'Super effective' },
			{ label = 'Neutral' },
			{ label = 'Not very effective' }
		},
		data = { { join( strong ), join( neutral ), join( weak ) } },
		class = 'wikitable--border'
	} )
end

--- One row per element, as used on the Elements overview page.
---
--- @return string
local function renderList()
	local elements = mw.loadJsonData( DATA )
	local rows = {}

	for _, attacker in ipairs( elements ) do
		local strong, _, weak = split( elements, attacker )

		table.insert( rows, {
			string.format( '[[%s]]', toTitle( attacker.name ) ),
			join( strong ),
			join( weak )
		} )
	end

	return TableLua.render( {
		caption = 'Elements',
		hideCaption = true,
		columns = {
			{ label = 'Element' },
			{ label = 'Strong against' },
			{ label = 'Weak against' }
		},
		data = rows,
		class = 'sortable wikitable--border'
	} )
end

--- 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 {}

	if args.mode == 'list' then
		return renderList()
	end

	local elementName = args.element or args[1]

	if type( elementName ) ~= 'string' or elementName == '' then
		error( 'Module:ElementMatchups requires an element name, or mode=list' )
	end

	return renderMatchups( elementName )
end

return p