Module:GymLeaderLineup: Difference between revisions

From Pokemon Revolution Online Wiki
Jump to navigation Jump to search
Cae (talk | contribs)
No edit summary
Cae (talk | contribs)
No edit summary
 
(8 intermediate revisions by the same user not shown)
Line 94: Line 94:
category = nonEmpty(category) or 'Status'
category = nonEmpty(category) or 'Status'
if not catColorCache[category] then
if not catColorCache[category] then
catColorCache[category] = frame:expandTemplate{ title = category .. ' color' }
catColorCache[category] = {
base = frame:expandTemplate{ title = category .. ' color' },
dark = frame:expandTemplate{ title = category .. ' color dark' },
}
end
end
return catColorCache[category]
return catColorCache[category]
Line 118: Line 121:
end
end


local mColors = typeColor(frame, mtype)
return '<tr style="background-color:#FFFFFF; color:#000000;">' ..
return '<tr style="background-color:#FFFFFF; color:#000000;">' ..
'<td><span style="' .. nameStyle .. '">[[' .. moveName .. ']]</span></td>' ..
'<td><span style="' .. nameStyle .. '">[[' .. moveName .. ']]</span></td>' ..
'<td style="background-color: #' .. typeColor(frame, mtype).base .. ';">[[' .. mtype ..
'<td style="background-color: #' .. mColors.base .. '; border: 2px solid #' .. mColors.dark .. ';">[[' .. mtype ..
'_(type)|<span style="color:#FFFFFF;">' .. mtype .. '</span>]]</td>' ..
'_(type)|<span style="color:#FFFFFF;">' .. mtype .. '</span>]]</td>' ..
'<td style="background-color:#' .. categoryColor(frame, category) .. ';">[[' .. category ..
'<td style="background-color:#' .. categoryColor(frame, category).base .. '; border: 2px solid #' ..
categoryColor(frame, category).dark .. ';">[[' .. category ..
' Moves|<span style="color:#FFFFFF;">' .. category .. '</span>]]</td>' ..
' Moves|<span style="color:#FFFFFF;">' .. category .. '</span>]]</td>' ..
'<td>' .. (nonEmpty(m.power) or '—') .. '</td>' ..
'<td>' .. (nonEmpty(m.power) or '—') .. '</td>' ..
Line 145: Line 150:
end
end


return '<tr><td style="background-color:' .. border .. '; border-radius: 25px; padding: 5px;">' ..
return '<tr><td style="background-color:' .. border .. '; border-radius: 15px; padding: 5px;">' ..
'<table width="100%" style="text-align: center; padding: 5px;">' ..
'<table width="100%" style="text-align: center; padding: 5px;">' ..
'<tr><td colspan="5"><div style="background-color:#' .. colors.light .. '; border-radius: 25px; ' ..
'<tr><td colspan="5"><div style="background-color:#' .. colors.light .. '; border-radius: 15px; ' ..
'border: 3px solid #' .. colors.dark .. '; padding: 3px; margin: auto auto; width: 30%;">' ..
'border: 1px solid #' .. colors.dark .. '; padding: 3px; margin: auto auto; width: 30%;">' ..
'[[File:' .. spriteFile .. '.png]]' ..
'[[File:' .. spriteFile .. '.png]]' ..
'<div style="background-color:#FFFFFF; border-radius: 25px; border: 3px solid #' .. colors.dark ..
'<div style="background-color:#FFFFFF; border-radius: 12px; border: 1px solid #' .. colors.dark ..
'; padding: 3px; margin: auto auto; margin-top: 5px; width: 45%;">' .. displayName .. '</div>' ..
'; padding: 3px; margin: auto auto; margin-top: 5px; width: 45%;">' .. displayName .. '</div>' ..
'</div></td></tr>' ..
'</div></td></tr>' ..
'<tr><td colspan="5"><table class="collapsible collapsed" style="width: 100%; text-align: center; padding: 4px;">' ..
'<tr><td colspan="5"><table class="collapsible collapsed" style="width: 100%; text-align: center; padding: 4px;">' ..
'<tr style="background-color: ' .. cell .. '; color:' .. border .. ';">' ..
'<tr style="background-color: ' .. cell .. '; color:' .. border .. ';">' ..
'<th>Move</th><th>Type</th><th>Category</th><th>Base Power</th><th>Accuracy</th></tr>' ..
'<th style="width: 25%; position: relative;"><div style="position: absolute; left: 0; right: 0; ' ..
'top: 50%; transform: translateY(-50%); text-align: center; pointer-events: none;">Move</div></th>' ..
'<th style="width: 20%;">Type</th><th style="width: 20%;">Category</th>' ..
'<th style="width: 20%;">Base Power</th><th style="width: 15%;">Accuracy</th></tr>' ..
table.concat(moveRowsHtml) ..
table.concat(moveRowsHtml) ..
'</table></td></tr>' ..
'</table></td></tr>' ..
Line 161: Line 169:
end
end


-- When no Theme is given and no outer template has bridged in Trichrome-style
-- colors, pick the lineup's own most common primary type as the theme
-- (e.g. an all-Normal team) rather than falling back to plain white/black.
local function inferTheme(lineup, megaFlags)
local function inferTheme(lineup, megaFlags)
local counts, order = {}, {}
local counts, order = {}, {}
Line 211: Line 216:
border = '#' .. frame:expandTemplate{ title = theme .. ' color dark' }
border = '#' .. frame:expandTemplate{ title = theme .. ' color dark' }
else
else
-- Falls back to whatever Trichrome-style vars an outer template already
-- set; Lua can't read #var: directly, so the template bridges them in
-- as invoke arguments.
background = nonEmpty(iargs.Background) or '#FFFFFF'
background = nonEmpty(iargs.Background) or '#FFFFFF'
cell = nonEmpty(iargs.Cell) or '#FFFFFF'
cell = nonEmpty(iargs.Cell) or '#FFFFFF'
Line 235: Line 237:


return '<table align="center" style="width: 75%; max-width: 100%; background-color:' .. background ..
return '<table align="center" style="width: 75%; max-width: 100%; background-color:' .. background ..
'; border: 5px solid ' .. border .. '; border-radius: 25px; padding: 5px;">' ..
'; border: 4px solid ' .. border .. '; border-radius: 15px; padding: 5px;">' ..
'<tr><td colspan="6"><table style="margin: auto auto; width: 35%; text-align: center; ' ..
'<tr><td colspan="6"><table style="margin: auto auto; width: 35%; text-align: center; ' ..
'border-radius: 25px; border: 3px solid ' .. border .. '; padding: 5px; background-color:' .. cell ..
'border-radius: 15px; border: 1px solid ' .. border .. '; padding: 5px; background-color:' .. cell ..
'; color:' .. border .. '; font-weight: bold;">' ..
'; color:' .. border .. '; font-weight: bold;">' ..
headerIcon .. '<tr><td>' .. headerName .. '</td></tr></table></td></tr>' ..
headerIcon .. '<tr><td>' .. headerName .. '</td></tr></table></td></tr>' ..
table.concat(slots) ..
table.concat(slots) ..
'<tr><td style="background-color: ' .. cell .. '; border: 1px solid ' .. border .. '; border-radius: 25px;">' ..
'<tr><td style="background-color: ' .. cell .. '; border: 1px solid ' .. border .. '; border-radius: 15px;">' ..
'<ul>' ..
'<ul>' ..
"<li>'''Emboldened''' moves avail from a STAB bonus when deployed by that Pokémon.</li>" ..
"<li>'''Emboldened''' moves avail from a STAB bonus when deployed by that Pokémon.</li>" ..

Latest revision as of 15:24, 30 July 2026

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

local p = {}

local DATA_FORMAT = 'CSV with header'

local function nonEmpty(s)
	if s == nil then return nil end
	s = mw.text.trim(tostring(s))
	if s == '' then return nil end
	return s
end

local function splitList(s)
	if not nonEmpty(s) then return {} end
	local out = {}
	for _, part in ipairs(mw.text.split(s, ',')) do
		out[#out + 1] = mw.text.trim(part)
	end
	return out
end

local pokemonRowsCache = nil
local function pokemonRows()
	if pokemonRowsCache then return pokemonRowsCache end
	local csvData = mw.ext.externalData.getExternalData{
		url = 'https://wiki.pokemonrevolution.net/index.php?title=Special:GetData/PokemonRawList',
		format = DATA_FORMAT,
		data = { name = 'Name', type1 = 'Type1', type2 = 'Type2' },
	}
	pokemonRowsCache = {}
	if csvData then
		for _, row in ipairs(csvData) do
			if nonEmpty(row.name) then
				pokemonRowsCache[row.name] = row
			end
		end
	end
	return pokemonRowsCache
end

local moveRowsCache = nil
local function moveRows()
	if moveRowsCache then return moveRowsCache end
	local csvData = mw.ext.externalData.getExternalData{
		url = 'https://wiki.pokemonrevolution.net/index.php?title=Special:GetData/RawMovesList',
		format = DATA_FORMAT,
		data = {
			name = 'Name', type = 'Type', category = 'Category',
			power = 'Power', accuracy = 'Accuracy', broken = 'Broken', typeless = 'Typeless',
		},
	}
	moveRowsCache = {}
	if csvData then
		for _, row in ipairs(csvData) do
			if nonEmpty(row.name) then
				moveRowsCache[row.name] = row
			end
		end
	end
	return moveRowsCache
end

local megaCache = {}
local function megaByName(name)
	if megaCache[name] == nil then
		local ok, values = pcall(function()
			return mw.ext.externalData.getFileData{
				source = 'data',
				['file name'] = 'RawMegaPokemonList.csv',
				format = DATA_FORMAT,
				filters = 'Name=' .. name,
				data = 'name=Name,type1=Type1,type2=Type2',
			}
		end)
		megaCache[name] = (ok and values and values.name ~= nil) and values or false
	end
	return megaCache[name] or nil
end

local typeColorCache = {}
local function typeColor(frame, pokeType)
	pokeType = nonEmpty(pokeType) or 'Normal'
	if not typeColorCache[pokeType] then
		typeColorCache[pokeType] = {
			base = frame:expandTemplate{ title = pokeType .. ' color' },
			light = frame:expandTemplate{ title = pokeType .. ' color light' },
			dark = frame:expandTemplate{ title = pokeType .. ' color dark' },
		}
	end
	return typeColorCache[pokeType]
end

local catColorCache = {}
local function categoryColor(frame, category)
	category = nonEmpty(category) or 'Status'
	if not catColorCache[category] then
		catColorCache[category] = {
			base = frame:expandTemplate{ title = category .. ' color' },
			dark = frame:expandTemplate{ title = category .. ' color dark' },
		}
	end
	return catColorCache[category]
end

local function fileExists(frame, fileName)
	return frame:callParserFunction('#ifexist', 'File:' .. fileName, 'Y', '') == 'Y'
end

local function moveRowHtml(frame, moveName, primaryType, secondaryType)
	moveName = mw.text.trim(moveName)
	local m = moveRows()[moveName] or {}
	local mtype = nonEmpty(m.type) or 'Normal'
	local category = nonEmpty(m.category) or 'Status'
	local typeless = m.typeless or 'N'

	local nameStyle = ''
	if category ~= 'Status' and typeless == 'N' and (mtype == primaryType or mtype == secondaryType) then
		nameStyle = nameStyle .. 'font-weight: bold; '
	end
	if m.broken == 'Y' then
		nameStyle = nameStyle .. 'font-style: italic;'
	end

	local mColors = typeColor(frame, mtype)
	return '<tr style="background-color:#FFFFFF; color:#000000;">' ..
		'<td><span style="' .. nameStyle .. '">[[' .. moveName .. ']]</span></td>' ..
		'<td style="background-color: #' .. mColors.base .. '; border: 2px solid #' .. mColors.dark .. ';">[[' .. mtype ..
		'_(type)|<span style="color:#FFFFFF;">' .. mtype .. '</span>]]</td>' ..
		'<td style="background-color:#' .. categoryColor(frame, category).base .. '; border: 2px solid #' ..
		categoryColor(frame, category).dark .. ';">[[' .. category ..
		' Moves|<span style="color:#FFFFFF;">' .. category .. '</span>]]</td>' ..
		'<td>' .. (nonEmpty(m.power) or '—') .. '</td>' ..
		'<td>' .. (nonEmpty(m.accuracy) or '') .. '</td></tr>'
end

local function slotHtml(frame, name, isMega, sprite, moves, cell, border)
	local data = isMega and megaByName(name) or pokemonRows()[name]
	local type1 = data and nonEmpty(data.type1) or 'Normal'
	local type2 = data and nonEmpty(data.type2) or nil

	local spriteFile = nonEmpty(sprite) or ((isMega and 'Mega_' or '') .. name .. '_Front_Sprite')
	local displayName = (isMega and 'Mega ' or '') .. '[[' .. name .. ']]'

	local colors = typeColor(frame, type1)

	local moveRowsHtml = {}
	for _, moveName in ipairs(moves) do
		if nonEmpty(moveName) then
			moveRowsHtml[#moveRowsHtml + 1] = moveRowHtml(frame, moveName, type1, type2)
		end
	end

	return '<tr><td style="background-color:' .. border .. '; border-radius: 15px; padding: 5px;">' ..
		'<table width="100%" style="text-align: center; padding: 5px;">' ..
		'<tr><td colspan="5"><div style="background-color:#' .. colors.light .. '; border-radius: 15px; ' ..
		'border: 1px solid #' .. colors.dark .. '; padding: 3px; margin: auto auto; width: 30%;">' ..
		'[[File:' .. spriteFile .. '.png]]' ..
		'<div style="background-color:#FFFFFF; border-radius: 12px; border: 1px solid #' .. colors.dark ..
		'; padding: 3px; margin: auto auto; margin-top: 5px; width: 45%;">' .. displayName .. '</div>' ..
		'</div></td></tr>' ..
		'<tr><td colspan="5"><table class="collapsible collapsed" style="width: 100%; text-align: center; padding: 4px;">' ..
		'<tr style="background-color: ' .. cell .. '; color:' .. border .. ';">' ..
		'<th style="width: 25%; position: relative;"><div style="position: absolute; left: 0; right: 0; ' ..
		'top: 50%; transform: translateY(-50%); text-align: center; pointer-events: none;">Move</div></th>' ..
		'<th style="width: 20%;">Type</th><th style="width: 20%;">Category</th>' ..
		'<th style="width: 20%;">Base Power</th><th style="width: 15%;">Accuracy</th></tr>' ..
		table.concat(moveRowsHtml) ..
		'</table></td></tr>' ..
		'</table></td></tr>'
end

local function inferTheme(lineup, megaFlags)
	local counts, order = {}, {}
	for i, name in ipairs(lineup) do
		local isMega = (tonumber(megaFlags[i]) or 0) > 0
		local data = isMega and megaByName(name) or pokemonRows()[name]
		local t = data and nonEmpty(data.type1)
		if t then
			if not counts[t] then
				counts[t] = 0
				order[#order + 1] = t
			end
			counts[t] = counts[t] + 1
		end
	end
	local best, bestCount = nil, 0
	for _, t in ipairs(order) do
		if counts[t] > bestCount then
			best, bestCount = t, counts[t]
		end
	end
	return best
end

function p.main(frame)
	local parent = frame:getParent()
	local pargs = (parent and parent.args) or frame.args
	local iargs = frame.args

	local headerName = nonEmpty(pargs.NPC) or nonEmpty(iargs.Leader) or ''

	local lineup = splitList(pargs.Lineup)
	local megaFlags = splitList(pargs.Mega)
	if #megaFlags == 0 then
		megaFlags = { '0', '0', '0', '0', '0', '0' }
	end

	local background, cell, border
	local theme = nonEmpty(pargs.Theme)
	local hasBridgedColors = nonEmpty(iargs.Background) or nonEmpty(iargs.Cell) or nonEmpty(iargs.Border)
	if not theme and not hasBridgedColors then
		theme = inferTheme(lineup, megaFlags)
	end
	if theme then
		background = '#' .. frame:expandTemplate{ title = theme .. ' color' }
		cell = '#' .. frame:expandTemplate{ title = theme .. ' color light' }
		border = '#' .. frame:expandTemplate{ title = theme .. ' color dark' }
	else
		background = nonEmpty(iargs.Background) or '#FFFFFF'
		cell = nonEmpty(iargs.Cell) or '#FFFFFF'
		border = nonEmpty(iargs.Border) or '#000000'
	end

	local slots = {}
	for i, name in ipairs(lineup) do
		if nonEmpty(name) then
			local isMega = (tonumber(megaFlags[i]) or 0) > 0
			local moves = splitList(pargs['Moves' .. (i - 1)])
			local sprite = pargs['Sprite' .. (i - 1)]
			slots[#slots + 1] = slotHtml(frame, name, isMega, sprite, moves, cell, border)
		end
	end

	local headerIcon = ''
	if headerName ~= '' and fileExists(frame, headerName .. '.png') then
		headerIcon = '<tr><td>[[File:' .. headerName .. '.png]]</td></tr>'
	end

	return '<table align="center" style="width: 75%; max-width: 100%; background-color:' .. background ..
		'; border: 4px solid ' .. border .. '; border-radius: 15px; padding: 5px;">' ..
		'<tr><td colspan="6"><table style="margin: auto auto; width: 35%; text-align: center; ' ..
		'border-radius: 15px; border: 1px solid ' .. border .. '; padding: 5px; background-color:' .. cell ..
		'; color:' .. border .. '; font-weight: bold;">' ..
		headerIcon .. '<tr><td>' .. headerName .. '</td></tr></table></td></tr>' ..
		table.concat(slots) ..
		'<tr><td style="background-color: ' .. cell .. '; border: 1px solid ' .. border .. '; border-radius: 15px;">' ..
		'<ul>' ..
		"<li>'''Emboldened''' moves avail from a STAB bonus when deployed by that Pokémon.</li>" ..
		"<li>''Italicized'' moves are functionally broken; see their individualized pages for more information.</li>" ..
		'</ul></td></tr></table>'
end

return p