Module:NPCTrainer: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| Line 151: | Line 151: | ||
local cell = nonEmpty(iargs.Cell) | local cell = nonEmpty(iargs.Cell) | ||
if not border or not cell then | if not border or not cell then | ||
local normal = typeColor(frame, 'Normal') | local normal = typeColor(frame, 'Normal') | ||
border = border or ('#' .. normal.dark) | border = border or ('#' .. normal.dark) | ||
| Line 190: | Line 188: | ||
local background = nonEmpty(iargs.Background) | local background = nonEmpty(iargs.Background) | ||
if not border or not cell or not background then | if not border or not cell or not background then | ||
local normal = typeColor(frame, 'Normal') | local normal = typeColor(frame, 'Normal') | ||
border = border or ('#' .. normal.dark) | border = border or ('#' .. normal.dark) | ||
| Line 228: | Line 224: | ||
label .. '</div></td></tr>' | label .. '</div></td></tr>' | ||
buf[#buf + 1] = mw.text.trim(pargs.Lineup or '') | buf[#buf + 1] = mw.text.trim(pargs.Lineup or '') | ||
| Line 253: | Line 246: | ||
end | end | ||
function p.table(frame) | function p.table(frame) | ||
local parent = frame:getParent() | local parent = frame:getParent() | ||
| Line 268: | Line 255: | ||
local background = nonEmpty(iargs.Background) | local background = nonEmpty(iargs.Background) | ||
if not border or not cell or not background then | if not border or not cell or not background then | ||
local normal = typeColor(frame, 'Normal') | local normal = typeColor(frame, 'Normal') | ||
border = border or ('#' .. normal.dark) | border = border or ('#' .. normal.dark) | ||
| Line 293: | Line 278: | ||
'All NPCs may have new Pokémons, or higher level Pokémons upon rematch unless noted contrariwise.</p>' .. | 'All NPCs may have new Pokémons, or higher level Pokémons upon rematch unless noted contrariwise.</p>' .. | ||
'</td></tr>' | '</td></tr>' | ||
buf[#buf + 1] = '</table>' | |||
return table.concat(buf) | |||
end | |||
local function gymSlotHtml(rows, pokeName, cell, border) | |||
if not nonEmpty(pokeName) then | |||
return '<td width="16%"><table style="width: 100%; padding: 5px; border: 1px solid ' .. border .. | |||
'; background-color: ' .. border .. '; border-radius: 15px;"><tr><td style="border-radius: 20px; ' .. | |||
'border: 1px solid ' .. border .. '; width: 40px; height: 40px; background-color: ' .. border .. | |||
'; padding: 2px;"></td><td></td></tr></table></td>' | |||
end | |||
local row = rows[pokeName] | |||
local number = (row and nonEmpty(row.number)) or '' | |||
local displayName = (row and nonEmpty(row.name)) or pokeName | |||
return '<td width="16%"><table style="width: 100%; padding: 5px; border: 1px solid ' .. border .. | |||
'; background-color: ' .. cell .. '; border-radius: 15px;">' .. | |||
'<tr><td style="border-radius: 20px; border: 1px solid ' .. border .. '; width: 40px; height: 40px; ' .. | |||
'background-color: #FFFFFF; padding: 2px;">[[File:' .. number .. 'Icon.png]]</td>' .. | |||
'<td>[[' .. displayName .. ']]</td></tr></table></td>' | |||
end | |||
function p.gymLineup(frame) | |||
local parent = frame:getParent() | |||
local pargs = (parent and parent.args) or frame.args | |||
local iargs = frame.args | |||
local border = nonEmpty(iargs.Border) | |||
local cell = nonEmpty(iargs.Cell) | |||
if not border or not cell then | |||
local normal = typeColor(frame, 'Normal') | |||
border = border or ('#' .. normal.dark) | |||
cell = cell or ('#' .. normal.light) | |||
end | |||
local rows = pokemonRows() | |||
local pokeList = splitList(pargs.Pokemon, 6) | |||
local cells = {} | |||
for i = 1, 6 do | |||
cells[#cells + 1] = gymSlotHtml(rows, pokeList[i], cell, border) | |||
end | |||
local out = '<tr class="responsive-npclineup">' .. table.concat(cells) .. '</tr>' | |||
local bonus = nonEmpty(pargs.BonusPayout) | |||
if bonus then | |||
out = out .. '<tr><td colspan="6" style="background-color: ' .. cell .. | |||
'; padding: 3px; text-align: left; border-radius: 15px; border: 1px solid ' .. border .. ';">' .. | |||
'<span style="margin-left: 15px; font-weight: bold; color: ' .. border .. ';">Bonus payout:</span> ' .. | |||
bonus .. '</td></tr>' | |||
end | |||
return out | |||
end | |||
function p.gymTable(frame) | |||
local parent = frame:getParent() | |||
local pargs = (parent and parent.args) or frame.args | |||
local iargs = frame.args | |||
local border = nonEmpty(iargs.Border) | |||
local cell = nonEmpty(iargs.Cell) | |||
local background = nonEmpty(iargs.Background) | |||
if not border or not cell or not background then | |||
local normal = typeColor(frame, 'Normal') | |||
border = border or ('#' .. normal.dark) | |||
cell = cell or ('#' .. normal.light) | |||
background = background or ('#' .. normal.base) | |||
end | |||
local buf = {} | |||
buf[#buf + 1] = '<table align="center" style="width: 95%; border-spacing: 5px; padding: 5px; ' .. | |||
'text-align: center; border: 4px solid ' .. border .. '; border-radius: 15px; background-color: ' .. | |||
cell .. ';">' | |||
buf[#buf + 1] = '<tr><td><div style="margin: auto auto; border-radius: 15px; font-weight: bold; ' .. | |||
'width: 45%; padding: 3px; background-color: ' .. border .. '; color: ' .. cell .. ';">' .. | |||
mw.title.getCurrentTitle().text .. ' Gym Trainers</div></td></tr>' | |||
buf[#buf + 1] = mw.ustring.gsub(mw.text.trim(pargs.Contents or ''), '\n', '') | |||
buf[#buf + 1] = '<tr><td style="text-align: left; background-color: ' .. background .. | |||
'; padding: 3px; border-radius: 15px; border: 1px solid ' .. border .. ';">' .. | |||
'<ul style="margin-left: 15px;">' .. | |||
'<li>All NPCs cool down after 7 days unless noted contrariwise.</li>' .. | |||
'<li>Gym-NPC levels are not known; as such, no level data is displayed hereon.</li>' .. | |||
'</ul></td></tr>' | |||
buf[#buf + 1] = '</table>' | buf[#buf + 1] = '</table>' | ||
Latest revision as of 05:33, 31 July 2026
Documentation for this module may be created at Module:NPCTrainer/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 lcfirst(s)
local first = mw.ustring.sub(s, 1, 1)
local rest = mw.ustring.sub(s, 2)
return mw.ustring.lower(first) .. rest
end
local function splitList(s, count)
local out = {}
if nonEmpty(s) then
for _, part in ipairs(mw.text.split(s, ',')) do
out[#out + 1] = mw.text.trim(part)
end
end
for i = 1, count do
out[i] = out[i] or ''
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', number = 'Pokedex Number' },
}
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 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,number=Pokedex Number',
}
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 PokemonForms = require('Module:PokemonForms')
local FORM_SUFFIXES = PokemonForms.FORM_SUFFIXES
local MEGA_VARIANTS = PokemonForms.MEGA_VARIANTS or { '', ' X', ' Y' }
local function rawListFormName(form, stem)
if form.rawList == 'suffix' then
return stem .. '-' .. form.suffix
elseif form.rawList == 'prefix-hyphen' then
return form.label .. '-' .. stem
elseif form.rawList == 'suffix-label' then
return stem .. '-' .. form.label
elseif form.rawList == 'suffix-space' then
return stem .. ' ' .. form.label
end
return form.label .. ' ' .. stem
end
local function resolveFormRow(rows, baseName, formsText)
local lower = mw.ustring.lower(formsText)
if mw.ustring.sub(lower, 1, 4) == 'mega' then
for _, variant in ipairs(MEGA_VARIANTS) do
if lower == mw.ustring.lower('Mega' .. variant) then
return megaByName(baseName .. variant)
end
end
end
for _, form in ipairs(FORM_SUFFIXES) do
if mw.ustring.lower(form.label) == lower or mw.ustring.lower(form.suffix) == lower then
local candidate = rawListFormName(form, baseName)
if rows[candidate] then
return rows[candidate]
end
end
end
return nil
end
local function slotHtml(rows, pokeName, level, formsText, cell, border)
if not nonEmpty(pokeName) then
return '<td width="16%"><table style="width: 100%; height: 55px; border: 1px solid ' .. border ..
'; background-color: ' .. border .. '; border-radius: 15px;"></table></td>'
end
local row = rows[pokeName]
local formNote = ''
if nonEmpty(formsText) and not tonumber(formsText) then
formNote = ' (' .. formsText .. ')'
local formRow = resolveFormRow(rows, pokeName, formsText)
if formRow then
row = formRow
end
end
local number = (row and nonEmpty(row.number)) or ''
local displayName = (row and nonEmpty(row.name)) or pokeName
return '<td width="16%"><table style="width: 100%; height: 55px; border: 1px solid ' .. border ..
'; background-color: ' .. cell .. '; border-radius: 15px;">' ..
'<tr><td rowspan="2" style="text-align: right;">[[File:' .. number .. 'Icon.png]]</td>' ..
'<td>[[' .. displayName .. ']]' .. formNote .. '</td></tr>' ..
'<tr><td colspan="2" style="font-weight: bold; color: ' .. border .. ';"> Lv. ' ..
(nonEmpty(level) or '???') .. '</td></tr>' ..
'</table></td>'
end
function p.lineup(frame)
local parent = frame:getParent()
local pargs = (parent and parent.args) or frame.args
local iargs = frame.args
local border = nonEmpty(iargs.Border)
local cell = nonEmpty(iargs.Cell)
if not border or not cell then
local normal = typeColor(frame, 'Normal')
border = border or ('#' .. normal.dark)
cell = cell or ('#' .. normal.light)
end
local rows = pokemonRows()
local pokeList = splitList(pargs.Pokemon, 6)
local levels = splitList(pargs.Levels, 6)
local forms = splitList(pargs.Forms, 6)
local cells = {}
for i = 1, 6 do
cells[#cells + 1] = slotHtml(rows, pokeList[i], levels[i], forms[i], cell, border)
end
local out = '<tr>' .. table.concat(cells) .. '</tr>'
local bonus = nonEmpty(pargs.BonusPayout)
if bonus then
out = out .. '<tr><td colspan="6" style="background-color: ' .. cell ..
'; padding: 3px; text-align: left; border-radius: 15px; border: 1px solid ' .. border .. ';">' ..
'<span style="margin-left: 15px; font-weight: bold; color: ' .. border .. ';">Bonus payout:</span> ' ..
bonus .. '</td></tr>'
end
return out
end
function p.trainer(frame)
local parent = frame:getParent()
local pargs = (parent and parent.args) or frame.args
local iargs = frame.args
local border = nonEmpty(iargs.Border)
local cell = nonEmpty(iargs.Cell)
local background = nonEmpty(iargs.Background)
if not border or not cell or not background then
local normal = typeColor(frame, 'Normal')
border = border or ('#' .. normal.dark)
cell = cell or ('#' .. normal.light)
background = background or ('#' .. normal.base)
end
local class = nonEmpty(pargs.Class)
local gender = nonEmpty(pargs.Gender)
local name = nonEmpty(pargs.Name)
local showClassRaw = pargs.ShowClass
if showClassRaw == nil then showClassRaw = 'yes' end
local showClass = nonEmpty(showClassRaw) ~= nil
local portrait
if class then
local genderSuffix = gender and ('_(' .. lcfirst(gender) .. ')') or ''
portrait = '[[File:' .. class .. genderSuffix .. '.png]]'
elseif name then
portrait = '[[File:' .. name .. '.png]]'
else
portrait = ''
end
local classPart = (class and showClass) and class or ''
local namePart = name or ''
local label = mw.text.trim(classPart .. ' ' .. namePart)
local buf = {}
buf[#buf + 1] = '<table style="width: 100%; padding: 5px; border-spacing: 7px; border: 4px solid ' .. border ..
'; background-color: ' .. background .. '; border-radius: 15px;">'
buf[#buf + 1] = '<tr><td colspan="6"><div style="border-radius: 15px; font-weight: bold; color: ' .. border ..
'; background-color: ' .. cell .. '; padding: 8px; margin: auto auto; width: 50%; border: 1px solid ' ..
border .. ';"><div class="middle-align" style="margin-top: 5px;">' .. portrait .. '</div>' ..
label .. '</div></td></tr>'
buf[#buf + 1] = mw.text.trim(pargs.Lineup or '')
local notes = nonEmpty(pargs.Notes)
if notes then
buf[#buf + 1] = '<tr><td colspan="6" style="text-align:left; background-color:' .. cell ..
'; padding: 3px; border-radius: 15px; border: 1px solid ' .. border .. ';">' ..
'<p style="margin-left: 15px;"><b>Notes:</b> ' .. notes .. '.</p></td></tr>'
end
local cooldown = nonEmpty(pargs.Cooldown)
if cooldown then
local cdText = (cooldown == 'none') and 'None, this is a one-time battle.' or cooldown
buf[#buf + 1] = '<tr><td colspan="6" style="text-align: left; background-color: ' .. cell ..
'; padding: 3px; border-radius: 15px; border: 1px solid ' .. border .. ';">' ..
'<p style="margin-left: 15px;"><b>Cooldown:</b> ' .. cdText .. '</p></td></tr>'
end
buf[#buf + 1] = '</table>'
return '<tr><td>' .. table.concat(buf) .. '</td></tr>'
end
function p.table(frame)
local parent = frame:getParent()
local pargs = (parent and parent.args) or frame.args
local iargs = frame.args
local border = nonEmpty(iargs.Border)
local cell = nonEmpty(iargs.Cell)
local background = nonEmpty(iargs.Background)
if not border or not cell or not background then
local normal = typeColor(frame, 'Normal')
border = border or ('#' .. normal.dark)
cell = cell or ('#' .. normal.light)
background = background or ('#' .. normal.base)
end
local location = nonEmpty(pargs.Location) or mw.title.getCurrentTitle().text
local buf = {}
buf[#buf + 1] = '<table align="center" style="width: 97%; border-spacing: 5px; padding: 5px; ' ..
'text-align: center; border: 4px solid ' .. border .. '; border-radius: 15px; background-color: ' ..
cell .. ';">'
buf[#buf + 1] = '<tr><td><div style="margin: auto auto; border-radius: 15px; font-weight: bold; ' ..
'width: 45%; padding: 3px; background-color: ' .. border .. '; color: ' .. cell .. ';">' ..
location .. ' Trainers</div></td></tr>'
buf[#buf + 1] = mw.ustring.gsub(mw.text.trim(pargs.Contents or ''), '\n', '')
buf[#buf + 1] = '<tr><td style="text-align: left; background-color: #FFFFFF; padding: 3px; ' ..
'border-radius: 15px; border: 1px solid ' .. border .. '; color:#000000;">' ..
'<p style="margin-left: 15px;">All NPCs cool down after 7 days unless noted contrariwise.<br>' ..
'All NPCs may have new Pokémons, or higher level Pokémons upon rematch unless noted contrariwise.</p>' ..
'</td></tr>'
buf[#buf + 1] = '</table>'
return table.concat(buf)
end
local function gymSlotHtml(rows, pokeName, cell, border)
if not nonEmpty(pokeName) then
return '<td width="16%"><table style="width: 100%; padding: 5px; border: 1px solid ' .. border ..
'; background-color: ' .. border .. '; border-radius: 15px;"><tr><td style="border-radius: 20px; ' ..
'border: 1px solid ' .. border .. '; width: 40px; height: 40px; background-color: ' .. border ..
'; padding: 2px;"></td><td></td></tr></table></td>'
end
local row = rows[pokeName]
local number = (row and nonEmpty(row.number)) or ''
local displayName = (row and nonEmpty(row.name)) or pokeName
return '<td width="16%"><table style="width: 100%; padding: 5px; border: 1px solid ' .. border ..
'; background-color: ' .. cell .. '; border-radius: 15px;">' ..
'<tr><td style="border-radius: 20px; border: 1px solid ' .. border .. '; width: 40px; height: 40px; ' ..
'background-color: #FFFFFF; padding: 2px;">[[File:' .. number .. 'Icon.png]]</td>' ..
'<td>[[' .. displayName .. ']]</td></tr></table></td>'
end
function p.gymLineup(frame)
local parent = frame:getParent()
local pargs = (parent and parent.args) or frame.args
local iargs = frame.args
local border = nonEmpty(iargs.Border)
local cell = nonEmpty(iargs.Cell)
if not border or not cell then
local normal = typeColor(frame, 'Normal')
border = border or ('#' .. normal.dark)
cell = cell or ('#' .. normal.light)
end
local rows = pokemonRows()
local pokeList = splitList(pargs.Pokemon, 6)
local cells = {}
for i = 1, 6 do
cells[#cells + 1] = gymSlotHtml(rows, pokeList[i], cell, border)
end
local out = '<tr class="responsive-npclineup">' .. table.concat(cells) .. '</tr>'
local bonus = nonEmpty(pargs.BonusPayout)
if bonus then
out = out .. '<tr><td colspan="6" style="background-color: ' .. cell ..
'; padding: 3px; text-align: left; border-radius: 15px; border: 1px solid ' .. border .. ';">' ..
'<span style="margin-left: 15px; font-weight: bold; color: ' .. border .. ';">Bonus payout:</span> ' ..
bonus .. '</td></tr>'
end
return out
end
function p.gymTable(frame)
local parent = frame:getParent()
local pargs = (parent and parent.args) or frame.args
local iargs = frame.args
local border = nonEmpty(iargs.Border)
local cell = nonEmpty(iargs.Cell)
local background = nonEmpty(iargs.Background)
if not border or not cell or not background then
local normal = typeColor(frame, 'Normal')
border = border or ('#' .. normal.dark)
cell = cell or ('#' .. normal.light)
background = background or ('#' .. normal.base)
end
local buf = {}
buf[#buf + 1] = '<table align="center" style="width: 95%; border-spacing: 5px; padding: 5px; ' ..
'text-align: center; border: 4px solid ' .. border .. '; border-radius: 15px; background-color: ' ..
cell .. ';">'
buf[#buf + 1] = '<tr><td><div style="margin: auto auto; border-radius: 15px; font-weight: bold; ' ..
'width: 45%; padding: 3px; background-color: ' .. border .. '; color: ' .. cell .. ';">' ..
mw.title.getCurrentTitle().text .. ' Gym Trainers</div></td></tr>'
buf[#buf + 1] = mw.ustring.gsub(mw.text.trim(pargs.Contents or ''), '\n', '')
buf[#buf + 1] = '<tr><td style="text-align: left; background-color: ' .. background ..
'; padding: 3px; border-radius: 15px; border: 1px solid ' .. border .. ';">' ..
'<ul style="margin-left: 15px;">' ..
'<li>All NPCs cool down after 7 days unless noted contrariwise.</li>' ..
'<li>Gym-NPC levels are not known; as such, no level data is displayed hereon.</li>' ..
'</ul></td></tr>'
buf[#buf + 1] = '</table>'
return table.concat(buf)
end
return p