|
|
| Line 1: |
Line 1: |
| local p = {} | | local p = {} |
|
| |
|
| local DATA_FORMAT = 'CSV with header'
| | p.FORM_SUFFIXES = { |
| | | { suffix = 'Alolan', label = 'Alolan', rawList = 'prefix' }, |
| local COLUMNS = {
| | { suffix = 'Galar', label = 'Galarian', rawList = 'prefix' }, |
| number = 'Pokedex Number',
| | { suffix = 'Hisui', label = 'Hisuian', rawList = 'prefix' }, |
| name = 'Name',
| | { suffix = 'Paldea', label = 'Paldean', rawList = 'prefix' }, |
| type1 = 'Type1',
| | { suffix = 'Sandy', label = 'Sandy', rawList = 'suffix' }, |
| type2 = 'Type2',
| | { suffix = 'Trash', label = 'Trash', rawList = 'suffix' }, |
| ability1 = 'Ability 1',
| | { suffix = 'Sky', label = 'Sky', rawList = 'suffix' }, |
| ability2 = 'Ability 2',
| | { suffix = 'Fan', label = 'Fan', rawList = 'suffix' }, |
| ha = 'Hidden Ability',
| | { suffix = 'Frost', label = 'Frost', rawList = 'suffix' }, |
| generation = 'Generation',
| | { suffix = 'Heat', label = 'Heat', rawList = 'suffix' }, |
| hp = 'HP',
| | { suffix = 'Mow', label = 'Mow', rawList = 'suffix' }, |
| atk = 'Attack',
| | { suffix = 'Wash', label = 'Wash', rawList = 'suffix' }, |
| def = 'Defense',
| | { suffix = 'Ash', label = 'Ash', learnsetStyle = 'prefix-space', rawList = 'prefix-hyphen' }, |
| spatk = 'Special Attack',
| | { suffix = 'Bloodmoon', label = 'Bloodmoon', rawList = 'suffix' }, |
| spdef = 'Special Defense',
| | { suffix = 'Low-Key', label = 'Low Key', rawList = 'suffix-label' }, |
| spd = 'Speed',
| | { suffix = 'F', label = 'Female', rawList = 'suffix-space', baseLabel = 'Male' }, |
| catch = 'Catch Rate',
| | { suffix = 'Blue-Striped', label = 'Blue-Striped', rawList = 'suffix-label' }, |
| evhp = 'EVHP',
| | { suffix = 'White-Striped', label = 'White-Striped', rawList = 'suffix-label' }, |
| evatk = 'EVATK',
| | { suffix = 'Rainy', label = 'Rainy', rawList = 'suffix-label' }, |
| evdef = 'EVDEF',
| | { suffix = 'Snowy', label = 'Snowy', rawList = 'suffix-label' }, |
| evspa = 'EVSPA',
| | { suffix = 'Sunny', label = 'Sunny', rawList = 'suffix-label' }, |
| evspd = 'EVSPD',
| | { suffix = 'Sunshine', label = 'Sunshine', rawList = 'suffix-label' }, |
| evsp = 'EVSP',
| | { suffix = 'Attack', label = 'Attack', rawList = 'suffix-label' }, |
| male = 'Male Ratio',
| | { suffix = 'Defense', label = 'Defense', rawList = 'suffix-label' }, |
| height = 'Height',
| | { suffix = 'Speed', label = 'Speed', rawList = 'suffix-label' }, |
| weight = 'Weight',
| | { suffix = 'Unbound', label = 'Unbound', rawList = 'suffix-label' }, |
| npc = 'NPC',
| | { suffix = 'Black', label = 'Black', rawList = 'suffix-label' }, |
| exp = 'Base Experience',
| | { suffix = 'White', label = 'White', rawList = 'suffix-label' }, |
| rarity = 'Tier',
| | { suffix = 'Dusk', label = 'Dusk', rawList = 'suffix-label' }, |
| | { suffix = 'Midnight', label = 'Midnight', rawList = 'suffix-label' }, |
| | { suffix = 'Pirouette', label = 'Pirouette', rawList = 'suffix-label' }, |
| | { suffix = 'Yellow', label = 'Yellow', rawList = 'suffix-label' }, |
| | { suffix = 'School', label = 'School', rawList = 'suffix-label' }, |
| | { suffix = 'Crowned', label = 'Crowned', rawList = 'suffix-label' }, |
| | { suffix = 'Noice-Face', label = 'Noice Face', rawList = 'suffix-label' }, |
| } | | } |
|
| |
|
| local GEN_NUMERALS = { 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX' }
| | p.STRIP_SUFFIXES = { |
| | | 'Alolan', 'Galar', 'Hisui', 'Paldea', 'Sandy', 'Trash', 'Plant', 'Amped', 'Male', |
| local STATS = {
| | 'Ice Face', 'Noice Face', 'Midday', 'Solo', |
| { key = 'hp', label = 'HP', template = 'HP' },
| |
| { key = 'atk', label = 'Atk', template = 'Attack' },
| |
| { key = 'def', label = 'Def', template = 'Defense' },
| |
| { key = 'spatk', label = 'Sp.Atk', template = 'Special Attack' },
| |
| { key = 'spdef', label = 'Sp.Def', template = 'Special Defense' },
| |
| { key = 'spd', label = 'Spd', template = 'Speed' },
| |
| } | | } |
|
| |
|
| local EV_KEYS = { 'evhp', 'evatk', 'evdef', 'evspa', 'evspd', 'evsp' }
| | p.RAW_LIST_ALIASES = { |
| | | ['Nidoran M'] = 'Nidoran Male', |
| local function nonEmpty(s)
| | ['Nidoran F'] = 'Nidoran Female', |
| if s == nil then return nil end
| | ['Farfetchd'] = "Farfetch'd", |
| s = mw.text.trim(tostring(s))
| | ['Sirfetchd'] = "Sirfetch'd", |
| if s == '' then return nil end
| | ['Ho-oh'] = 'Ho-Oh', |
| return s
| | ['Porygon-z'] = 'Porygon-Z', |
| end
| | ['Eiscue'] = 'Eiscue-Ice Face', |
| | | ['Indeedee'] = 'Indeedee Male', |
| local function templateArgs(frame)
| | ['Meowstic'] = 'Meowstic Male', |
| local parent = frame:getParent()
| | ['Basculegion'] = 'Basculegion-Male', |
| return (parent and parent.args) or frame.args
| | ['Oinkologne'] = 'Oinkologne-Male', |
| end
| | ['Calyrex-Ice-Rider'] = 'Calyrex-Ice Rider', |
| | | ['Calyrex-Shadow-Rider'] = 'Calyrex-Shadow Rider', |
| local function padNumber(n)
| | ['Necrozma-Dusk-Mane'] = 'Dusk Mane Necrozma', |
| n = tonumber(n) or 0
| | ['Necrozma-Dawn-Wings'] = 'Dawn Wings Necrozma', |
| return string.format('%03d', n)
| | ['Ogerpon'] = 'Ogerpon-Teal Mask', |
| end
| | ['Ogerpon-Wellspring'] = 'Ogerpon-Wellspring Mask', |
| | | ['Ogerpon-Hearthflame'] = 'Ogerpon-Hearthflame Mask', |
| local PokemonForms = require('Module:PokemonForms')
| | ['Ogerpon-Cornerstone'] = 'Ogerpon-Cornerstone Mask', |
| local FORM_SUFFIXES = PokemonForms.FORM_SUFFIXES
| | ['Ogerpon-Wellspring-Tera'] = 'Ogerpon-Wellspring Mask', |
| local STRIP_SUFFIXES = PokemonForms.STRIP_SUFFIXES
| | ['Ogerpon-Hearthflame-Tera'] = 'Ogerpon-Hearthflame Mask', |
| local MEGA_VARIANTS = PokemonForms.MEGA_VARIANTS or { '', ' X', ' Y' }
| | ['Ogerpon-Cornerstone-Tera'] = 'Ogerpon-Cornerstone Mask', |
| | | ['Oricorio'] = 'Oricorio Baile', |
| -- The single data fetch: the whole raw list is loaded once per page render
| | ['Oricorio-Pom-Pom'] = 'Oricorio Pom-Pom', |
| -- and every lookup (by name, by number, form probing) reads from it.
| | ['Oricorio-Pau'] = "Oricorio Pa'u", |
| local allRowsCache = nil
| | ['Tauros-Paldea-Combat'] = 'Paldean Tauros-Combat', |
| local numberIndexCache = nil
| | ['Tauros-Paldea-Blaze'] = 'Paldean Tauros-Blaze', |
| | | ['Tauros-Paldea-Aqua'] = 'Paldean Tauros-Aqua', |
| local function loadAllRows()
| | ['Toxtricity'] = 'Toxtricity-Amped', |
| if allRowsCache then
| | ['Urshifu'] = 'Urshifu-Single Strike', |
| return allRowsCache
| | ['Urshifu-Rapid-Strike'] = 'Urshifu-Rapid Strike', |
| end
| | ['Wishiwashi'] = 'Wishiwashi Solo', |
| local csvData = mw.ext.externalData.getExternalData{
| | ['Wormadam'] = 'Wormadam-Plant', |
| url = 'https://wiki.pokemonrevolution.net/index.php?title=Special:GetData/PokemonRawList',
| | ['Lycanroc'] = 'Lycanroc-Midday', |
| format = DATA_FORMAT,
| | ['Terapagos-Terastal'] = 'Terapagos-Terestal', |
| data = COLUMNS,
| |
| }
| |
| allRowsCache = {}
| |
| numberIndexCache = {}
| |
| if csvData then
| |
| for _, row in ipairs(csvData) do
| |
| if nonEmpty(row.name) then
| |
| allRowsCache[row.name] = row
| |
| local num = nonEmpty(row.number)
| |
| -- First occurrence wins so base forms beat Megas sharing a number.
| |
| if num and numberIndexCache[num] == nil then
| |
| numberIndexCache[num] = row
| |
| end
| |
| end
| |
| end
| |
| end
| |
| return allRowsCache
| |
| end
| |
| | |
| local function hyphenSpaceVariant(s)
| |
| if mw.ustring.find(s, '-', 1, true) then
| |
| return (mw.ustring.gsub(s, '%-', ' '))
| |
| end
| |
| return (mw.ustring.gsub(s, ' ', '-'))
| |
| end
| |
| | |
| local function byName(name)
| |
| local rows = loadAllRows()
| |
| return rows[name] or rows[hyphenSpaceVariant(name)]
| |
| end
| |
| | |
| local function byNumber(number)
| |
| loadAllRows()
| |
| return numberIndexCache[tostring(number)]
| |
| end
| |
| | |
| local MEGA_COLUMNS = {
| |
| number = 'Pokedex Number',
| |
| name = 'Name',
| |
| type1 = 'Type1',
| |
| type2 = 'Type2',
| |
| ability1 = 'Ability 1',
| |
| ability2 = 'Ability 2',
| |
| ha = 'Hidden Ability',
| |
| generation = 'Generation',
| |
| hp = 'HP',
| |
| atk = 'Attack',
| |
| def = 'Defense',
| |
| spatk = 'Special Attack',
| |
| spdef = 'Special Defense',
| |
| spd = 'Speed',
| |
| evhp = 'EVHP',
| |
| evatk = 'EVATK',
| |
| evdef = 'EVDEF',
| |
| evspa = 'EVSPA',
| |
| evspd = 'EVSPD',
| |
| evsp = 'EVSP',
| |
| height = 'Height',
| |
| weight = 'Weight',
| |
| stone = 'Stone',
| |
| } | | } |
|
| |
|
| local MEGA_SPEC
| | p.MOB_PREFIXES = { 'Baby', 'Crystal', 'Shadow' } |
| do
| |
| local parts = {}
| |
| for key, header in pairs(MEGA_COLUMNS) do
| |
| parts[#parts + 1] = key .. '=' .. header
| |
| end
| |
| MEGA_SPEC = table.concat(parts, ',')
| |
| 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 = MEGA_SPEC,
| |
| }
| |
| end)
| |
| if ok and values and values.name ~= nil then
| |
| megaCache[name] = values
| |
| else
| |
| megaCache[name] = false
| |
| end
| |
| end
| |
| return megaCache[name] or nil
| |
| end
| |
| | |
| local function formStem(name)
| |
| for _, form in ipairs(FORM_SUFFIXES) do
| |
| local head = form.label .. ' '
| |
| if mw.ustring.sub(name, 1, mw.ustring.len(head)) == head then
| |
| return mw.ustring.sub(name, mw.ustring.len(head) + 1)
| |
| end
| |
| end
| |
| for _, suffix in ipairs(STRIP_SUFFIXES) do
| |
| for _, sep in ipairs({ '-', ' ' }) do
| |
| local tail = sep .. suffix
| |
| if mw.ustring.sub(name, -mw.ustring.len(tail)) == tail then
| |
| return mw.ustring.sub(name, 1, -mw.ustring.len(tail) - 1)
| |
| end
| |
| end
| |
| end
| |
| return name
| |
| end
| |
| | |
| 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 typeColors(frame, pokeType)
| |
| return {
| |
| light = frame:expandTemplate{ title = pokeType .. ' color light' },
| |
| base = frame:expandTemplate{ title = pokeType .. ' color' },
| |
| dark = frame:expandTemplate{ title = pokeType .. ' color dark' },
| |
| }
| |
| end
| |
| | |
| local statColorCache = {}
| |
| local function statColors(frame, statTemplate)
| |
| if not statColorCache[statTemplate] then
| |
| statColorCache[statTemplate] = {
| |
| base = frame:expandTemplate{ title = statTemplate .. ' color' },
| |
| dark = frame:expandTemplate{ title = statTemplate .. ' color dark' },
| |
| }
| |
| end
| |
| return statColorCache[statTemplate]
| |
| end
| |
| | |
| local function navTableHtml(frame, data, colors, pageName)
| |
| local number = tonumber(data.number)
| |
| | |
| local prevCell = ''
| |
| if number and number > 1 then
| |
| local prev = byNumber(number - 1)
| |
| if prev then
| |
| prevCell = ' [[File:' .. prev.number .. 'Icon.png|' .. prev.name .. '|link=' .. prev.name ..
| |
| ']] #' .. padNumber(prev.number) .. ' [[' .. prev.name .. ']]'
| |
| end
| |
| end
| |
| | |
| local nextCell = ''
| |
| if number then
| |
| local nxt = byNumber(number + 1)
| |
| if nxt then
| |
| nextCell = '[[' .. nxt.name .. ']] #' .. padNumber(nxt.number) .. ' [[File:' ..
| |
| nxt.number .. 'Icon.png|' .. nxt.name .. '|link=' .. nxt.name .. ']]'
| |
| end
| |
| end
| |
| | |
| return '<table style="margin-left: auto; margin-right: auto; margin-bottom: 15px; height: 60px; ' ..
| |
| 'border: 4px #' .. colors.dark .. ' solid; font-weight: bold; width: 65%; color: #' .. colors.dark ..
| |
| '; border-radius: 20px; padding: 3px; background: #' .. colors.base .. ';">' ..
| |
| '<tr>' ..
| |
| '<td style="text-align: left; width: 36%; background: #' .. colors.light ..
| |
| '; border-radius: 15px 1px 1px 15px; border: 1px solid #' .. colors.dark .. ';">' .. prevCell .. '</td>' ..
| |
| '<td style="text-align: center; width: 28%; background: #' .. colors.light ..
| |
| '; border: 1px solid #' .. colors.dark .. ';">#' .. padNumber(number) .. ' - ' ..
| |
| pageName .. '</td>' ..
| |
| '<td style="text-align: right; width: 36%; padding-right: 10px; background: #' .. colors.light ..
| |
| '; border: 1px solid #' .. colors.dark .. '; border-radius: 1px 15px 15px 1px;">' .. nextCell .. '</td>' ..
| |
| '</tr></table>'
| |
| end
| |
| | |
| function p.navTable(frame)
| |
| local args = templateArgs(frame)
| |
| local pageName = mw.title.getCurrentTitle().text
| |
| local name = nonEmpty(args.Name) or pageName
| |
| | |
| local data = byName(name)
| |
| if not data then
| |
| return '<strong class="error">PokeNavTable: no data found for "' .. name .. '"</strong>'
| |
| end
| |
| | |
| return navTableHtml(frame, data, typeColors(frame, data.type1), pageName)
| |
| end
| |
| | |
| local function infoCell(colors, labelHtml, valueHtml)
| |
| return '<td colspan="3" style="width: 50%; border: 1px solid #' .. colors.dark .. '; background-color: #' .. colors.light ..
| |
| '; border-radius: 15px; padding: 5px;">' ..
| |
| '<p style="margin-bottom: 7px; font-weight: bold; color: #' .. colors.dark .. ';">' .. labelHtml .. '</p>' ..
| |
| '<span style="border-radius: 12px; padding: 4px 10px; border: 1px solid #' .. colors.dark ..
| |
| '; background-color: #FFFFFF;"> ' .. valueHtml .. ' </span></td>'
| |
| end
| |
| | |
| local function abilityCell(colors, label, ability, widthPercent)
| |
| if not ability then return '' end
| |
| local style = 'border-radius: 12px; padding: 4px 10px; border: 1px solid #' .. colors.dark ..
| |
| '; background-color: #FFFFFF;'
| |
| if widthPercent then
| |
| style = 'width: ' .. widthPercent .. '%; ' .. style
| |
| end
| |
| return '<td style="' .. style .. '"><b>' .. label .. '</b><br>[[' .. ability .. '_(ability)|' .. ability ..
| |
| ']]</td>'
| |
| end
| |
| | |
| local function abilitiesRow(colors, data)
| |
| local entries = {
| |
| { 'Ability 1', nonEmpty(data.ability1) },
| |
| { 'Ability 2', nonEmpty(data.ability2) },
| |
| { 'Hidden Ability', nonEmpty(data.ha) },
| |
| }
| |
| local present = {}
| |
| for _, entry in ipairs(entries) do
| |
| if entry[2] then present[#present + 1] = entry end
| |
| end
| |
| local widthPercent = (#present > 0) and string.format('%.2f', 100 / #present) or nil
| |
| local cells = {}
| |
| for _, entry in ipairs(present) do
| |
| cells[#cells + 1] = abilityCell(colors, entry[1], entry[2], widthPercent)
| |
| end
| |
| return table.concat(cells)
| |
| end
| |
| | |
| local function statValueCell(frame, stat, value)
| |
| local colors = statColors(frame, stat.template)
| |
| return '<td style="width: 16.66%; border: 1px solid #' .. colors.dark .. '; background-color: #' .. colors.base ..
| |
| '; border-radius: 12px; padding: 4px; font-size: 11px;">\'\'\'' .. stat.label .. '\'\'\'<br>' ..
| |
| value .. '</td>'
| |
| end
| |
| | |
| local function statBarRow(frame, stat, value)
| |
| local labelColors = statColors(frame, stat.template)
| |
| local pct = math.floor(value / 255 * 100 + 0.5)
| |
| if pct < 2 then pct = 2 end
| |
| if pct > 100 then pct = 100 end
| |
| local hue = math.floor(math.max(0, math.min(180, value * 180 / 255)) + 0.5)
| |
| local fill = 'hsl(' .. hue .. ', 85%, 45%)'
| |
| return '<tr>' ..
| |
| '<td style="text-align: right; padding: 2px 8px 2px 4px; font-weight: bold; font-size: 12px; ' ..
| |
| 'color: #' .. labelColors.dark .. '; white-space: nowrap;">' .. stat.label .. '</td>' ..
| |
| '<td style="width: 100%; padding: 2px 0;"><div style="background-color: #FFFFFF; border: 1px solid ' ..
| |
| '#999999; border-radius: 8px; height: 13px; overflow: hidden;">' ..
| |
| '<div style="width: ' .. pct .. '%; height: 100%; background-color: ' .. fill .. ';"></div>' ..
| |
| '</div></td>' ..
| |
| '<td style="text-align: left; padding: 2px 4px 2px 8px; font-weight: bold; font-size: 12px; ' ..
| |
| 'width: 34px;">' .. value .. '</td></tr>'
| |
| end
| |
| | |
| local MALE_COLOR = '3B6BF5'
| |
| local FEMALE_COLOR = 'F5629C'
| |
| | |
| local function genderRatioHtml(male)
| |
| if male == 'Genderless' then
| |
| return '<span style="display: inline-block; color: #000000; background-color: #FFFFFF; ' ..
| |
| 'border-radius: 12px; border: 1px solid #000000; padding: 3px 12px; font-weight: bold;">' ..
| |
| 'Genderless</span>'
| |
| end
| |
| local m = tonumber(male)
| |
| if m == nil then
| |
| m = nonEmpty(male) and 100 or 0
| |
| end
| |
| if m < 0 then m = 0 end
| |
| if m > 100 then m = 100 end
| |
| local f = 100 - m
| |
| | |
| local segments = ''
| |
| if m > 0 then
| |
| segments = segments .. '<div style="width: ' .. m .. '%; background-color: #' .. MALE_COLOR .. ';"></div>'
| |
| end
| |
| if f > 0 then
| |
| segments = segments .. '<div style="width: ' .. f .. '%; background-color: #' .. FEMALE_COLOR .. ';"></div>'
| |
| end
| |
| | |
| local labels = {}
| |
| if m > 0 then
| |
| labels[#labels + 1] = '<span style="color: #' .. MALE_COLOR .. '; font-weight: bold;">' .. m .. '% ♂</span>'
| |
| end
| |
| if f > 0 then
| |
| labels[#labels + 1] = '<span style="color: #' .. FEMALE_COLOR .. '; font-weight: bold;">' .. f .. '% ♀</span>'
| |
| end
| |
| | |
| return '<div style="width: 85%; margin: 4px auto 0;">' ..
| |
| '<div style="display: flex; height: 12px; border-radius: 8px; overflow: hidden; ' ..
| |
| 'border: 1px solid #555555; background-color: #FFFFFF;">' .. segments .. '</div>' ..
| |
| '<div style="margin-top: 4px; font-size: 12px;">' .. table.concat(labels, ' · ') ..
| |
| '</div></div>'
| |
| end
| |
| | |
| local function categories(data, gen, bstCategory, args)
| |
| local cats = { '[[Category:Pokémon species]]' }
| |
| if gen then
| |
| cats[#cats + 1] = '[[Category:Generation ' .. gen .. ' Pokémon]]'
| |
| end
| |
| cats[#cats + 1] = '[[Category:' .. data.type1 .. '-type Pokémon]]'
| |
| if nonEmpty(data.type2) then
| |
| cats[#cats + 1] = '[[Category:' .. data.type2 .. '-type Pokémon]]'
| |
| end
| |
| cats[#cats + 1] = '[[Category:' .. data.rarity .. ' Pokémon]]'
| |
| if nonEmpty(data.npc) then
| |
| cats[#cats + 1] = '[[Category:NPC-obtainable Pokémon]]'
| |
| end
| |
| if not nonEmpty(args.EvolvesFrom) then
| |
| cats[#cats + 1] = '[[Category:Base-stage Pokémon]]'
| |
| end
| |
| cats[#cats + 1] = '[[Category:' .. bstCategory .. '-plus-BST Pokémon]]'
| |
| return table.concat(cats, ' ')
| |
| end
| |
| | |
| local function infoboxHtml(frame, args, data, displayName, width, pageName, includeNav)
| |
| local colors = typeColors(frame, data.type1)
| |
| -- Regional forms carry values like '1A'/'5A'; use the leading digits.
| |
| local gen = GEN_NUMERALS[tonumber(mw.ustring.match(tostring(data.generation or ''), '^%d+') or '')]
| |
| | |
| -- Types pill(s).
| |
| local typesHtml
| |
| if nonEmpty(data.type2) then
| |
| local type2Colors = typeColors(frame, data.type2)
| |
| typesHtml =
| |
| '<td style="width: 50%; background-color: #' .. colors.dark .. '; border-radius: 25px 1px 1px 25px;">' ..
| |
| '[[' .. data.type1 .. '_(type)|<span style="color: #FFFFFF;">' .. data.type1 .. '</span>]]</td>' ..
| |
| '<td style="width: 50%; background-color: #' .. type2Colors.dark .. '; border-radius: 1px 25px 25px 1px;">' ..
| |
| '[[' .. data.type2 .. '_(type)|<span style="color: #FFFFFF;">' .. data.type2 .. '</span>]]</td>'
| |
| else
| |
| typesHtml =
| |
| '<td style="width:100%; background-color: #' .. colors.dark .. '; border-radius: 25px;">' ..
| |
| '[[' .. data.type1 .. '_(type)|<span style="color: #FFFFFF;">' .. data.type1 .. '</span>]]</td>'
| |
| end
| |
| | |
| -- Base stats
| |
| local statRows, bst = {}, 0
| |
| for _, stat in ipairs(STATS) do
| |
| local value = tonumber(data[stat.key]) or 0
| |
| bst = bst + value
| |
| statRows[#statRows + 1] = statBarRow(frame, stat, value)
| |
| end
| |
| local bstCategory = math.floor(bst / 100 + 0.5) * 100
| |
| | |
| -- EV yield.
| |
| local evCells, evTotal = {}, 0
| |
| for i, stat in ipairs(STATS) do
| |
| local ev = tonumber(data[EV_KEYS[i]]) or 0
| |
| evTotal = evTotal + ev
| |
| evCells[#evCells + 1] = statValueCell(frame, stat, ev)
| |
| end
| |
| | |
| -- Catch rate.
| |
| local catchRaw = tonumber(data.catch) or 0
| |
| local catchPercent = string.format('%.2f', catchRaw / 255 / 3 * 100)
| |
| | |
| local buf = {}
| |
| if includeNav then
| |
| buf[#buf + 1] = navTableHtml(frame, data, colors, pageName)
| |
| end
| |
| buf[#buf + 1] = '<table align="right" class="informational-box" cellpadding="4" cellspacing="4" ' ..
| |
| 'style="width: ' .. width .. '%; border: 4px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.base .. '; padding: 4px; border-radius: 15px;">'
| |
| | |
| -- Header: dex number + icon, name.
| |
| buf[#buf + 1] = '<tr><td colspan="3" style="width: 50%; border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px;"><span style="margin-bottom: 7px; font-weight: bold; color:#' ..
| |
| colors.dark .. ';">#' .. padNumber(data.number) .. '</span> [[File:' .. data.number ..
| |
| 'Icon.png]]</td><td colspan="3" style="width: 50%; border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px;"><span style="margin-bottom: 7px; font-weight: bold; color:#' ..
| |
| colors.dark .. ';">' .. displayName .. '</span></td></tr>'
| |
| | |
| -- Artwork.
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px; padding: 5px;"><div style="border-radius: 15px; ' ..
| |
| 'text-align: center; padding: 5px; background-color: #FFFFFF;">[[File:' .. data.number .. data.name ..
| |
| '.png|150px]]</div></td></tr>'
| |
| | |
| -- Types + Generation.
| |
| local genHtml = '—'
| |
| if gen then
| |
| genHtml = '[[:Category:Generation ' .. gen .. ' Pokémon|<span style="color:#' ..
| |
| colors.dark .. ';">' .. gen .. '</span>]]'
| |
| end
| |
| buf[#buf + 1] = '<tr><td colspan="3" style="width: 50%; border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; padding: 11px; border-radius: 15px;"><p style="margin-bottom: 7px; font-weight: bold; ' ..
| |
| 'color: #' .. colors.dark .. ';">Types</p><table align="center" style="width: 75%; font-weight: bold; ' ..
| |
| 'padding: 3px;"><tr>' .. typesHtml .. '</tr></table></td>' ..
| |
| '<td colspan="3" style="width: 50%; border: 1px solid #' .. colors.dark .. '; background-color: #' .. colors.light ..
| |
| '; border-radius: 15px;"><p style="margin-bottom: 7px; font-weight: bold; color: #' .. colors.dark ..
| |
| ';">Generation</p><span style="border-radius: 12px; padding: 4px 10px; border: 1px solid #' .. colors.dark ..
| |
| '; background-color: #FFFFFF;"> ' .. genHtml .. ' </span></td></tr>'
| |
| | |
| -- Abilities.
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; padding: 11px; border-radius: 15px; width: 100%;"><table width="100%">' ..
| |
| '<tr><th colspan="6"><p style="margin-bottom: 7px; font-weight: bold; color:#' .. colors.dark ..
| |
| ';">[[Abilities|<span style="color:#' .. colors.dark .. ';">Abilities</span>]]</p></th></tr>' ..
| |
| '<tr>' .. abilitiesRow(colors, data) .. '</tr></table></td></tr>'
| |
| | |
| -- Rarity + Catch rate.
| |
| buf[#buf + 1] = '<tr>' ..
| |
| infoCell(colors, '[[List of Pokémon by Rarity Tier|<span style="color:#' .. colors.dark ..
| |
| ';">Rarity Tier</span>]]', '[[:Category:' .. data.rarity .. ' Pokémon|<span style="color:#' ..
| |
| colors.dark .. ';">' .. data.rarity .. '</span>]]') ..
| |
| infoCell(colors, '[[Catch Rates|<span style="color:#' .. colors.dark .. ';">Catch rate</span>]]',
| |
| data.catch .. '/255 (' .. catchPercent .. '%)') ..
| |
| '</tr>'
| |
| | |
| -- Base stats.
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px; padding: 8px; width: 100%">' ..
| |
| '<table width="100%" style="border-collapse: collapse;">' ..
| |
| '<tr><th colspan="3"><p style="margin-bottom: 7px; font-weight: bold; color: #' .. colors.dark ..
| |
| ';">[[Base stats|<span style="color: #' .. colors.dark .. ';">Base stats</span>]]</p></th></tr>' ..
| |
| table.concat(statRows) ..
| |
| '<tr><td colspan="3" style="text-align: center; padding-top: 6px;">' ..
| |
| '<div style="display: inline-block; background-color: #FFFFFF; border: 1px solid #' .. colors.dark ..
| |
| '; padding: 4px 14px; border-radius: 12px;">Base-stat total: ' .. bst .. '</div></td></tr>' ..
| |
| '</table></td></tr>'
| |
| | |
| -- EV yield.
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px; padding: 5px; width: 100%"><table width="100%">' ..
| |
| '<tr><th colspan="6">[[EVs|<span style="margin-bottom: 7px; font-weight: bold; color: #' .. colors.dark ..
| |
| ';">EV Yield</span>]]</th></tr><tr>' .. table.concat(evCells) .. '</tr>' ..
| |
| '<tr><td colspan="6"><div style="margin: auto; background-color:#FFFFFF; border: 1px solid #' ..
| |
| colors.dark .. '; padding: 4px 14px; border-radius: 12px; margin-bottom: 5px; width: 50%;">' ..
| |
| 'EV-yield total: ' .. evTotal .. '</div></td></tr></table></td></tr>'
| |
| | |
| -- Base experience + Gender ratio.
| |
| buf[#buf + 1] = '<tr>' ..
| |
| infoCell(colors, '[[Experience System#Base Experience|<span style="color:#' .. colors.dark ..
| |
| ';">Base Experience</span>]]', data.exp) ..
| |
| '<td colspan="3" style="width: 50%; border: 1px solid #' .. colors.dark .. '; background-color: #' .. colors.light ..
| |
| '; border-radius: 15px; padding: 5px;"><p style="margin-bottom: 7px; font-weight: bold; color: #' ..
| |
| colors.dark .. ';">Gender Ratio</p>' .. genderRatioHtml(data.male) .. '</td>' ..
| |
| '</tr>'
| |
| | |
| -- Height + Weight.
| |
| buf[#buf + 1] = '<tr>' ..
| |
| infoCell(colors, 'Height', data.height .. 'm') ..
| |
| infoCell(colors, 'Weight', data.weight .. 'kg') ..
| |
| '</tr>'
| |
| | |
| buf[#buf + 1] = '</table>'
| |
| buf[#buf + 1] = categories(data, gen, bstCategory, args)
| |
| | |
| return table.concat(buf)
| |
| end
| |
| | |
| local function megaInfoboxHtml(frame, data, width)
| |
| local colors = typeColors(frame, data.type1)
| |
| local gen = GEN_NUMERALS[tonumber(mw.ustring.match(tostring(data.generation or ''), '^%d+') or '')]
| |
| local displayName = 'Mega ' .. (data.name or '')
| |
| | |
| local typesHtml
| |
| if nonEmpty(data.type2) then
| |
| local type2Colors = typeColors(frame, data.type2)
| |
| typesHtml =
| |
| '<td style="width: 50%; background-color: #' .. colors.dark .. '; border-radius: 25px 1px 1px 25px;">' ..
| |
| '[[' .. data.type1 .. '_(type)|<span style="color: #FFFFFF;">' .. data.type1 .. '</span>]]</td>' ..
| |
| '<td style="width: 50%; background-color: #' .. type2Colors.dark .. '; border-radius: 1px 25px 25px 1px;">' ..
| |
| '[[' .. data.type2 .. '_(type)|<span style="color: #FFFFFF;">' .. data.type2 .. '</span>]]</td>'
| |
| else
| |
| typesHtml =
| |
| '<td style="width:100%; background-color: #' .. colors.dark .. '; border-radius: 25px;">' ..
| |
| '[[' .. data.type1 .. '_(type)|<span style="color: #FFFFFF;">' .. data.type1 .. '</span>]]</td>'
| |
| end
| |
| | |
| local statRows, bst = {}, 0
| |
| for _, stat in ipairs(STATS) do
| |
| local value = tonumber(data[stat.key]) or 0
| |
| bst = bst + value
| |
| statRows[#statRows + 1] = statBarRow(frame, stat, value)
| |
| end
| |
| | |
| local evCells, evTotal = {}, 0
| |
| for i, stat in ipairs(STATS) do
| |
| local ev = tonumber(data[EV_KEYS[i]]) or 0
| |
| evTotal = evTotal + ev
| |
| evCells[#evCells + 1] = statValueCell(frame, stat, ev)
| |
| end
| |
| | |
| local buf = {}
| |
| buf[#buf + 1] = '<table align="right" class="informational-box" cellpadding="4" cellspacing="4" ' ..
| |
| 'style="width: ' .. width .. '%; border: 4px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.base .. '; padding: 4px; border-radius: 15px;">'
| |
| | |
| -- Header: name across the whole top line.
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px;"><span style="margin-bottom: 7px; font-weight: bold; color:#' ..
| |
| colors.dark .. ';">' .. displayName .. '</span></td></tr>'
| |
| | |
| -- Artwork.
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px; padding: 5px;"><div style="border-radius: 15px; ' ..
| |
| 'text-align: center; padding: 5px; background-color: #FFFFFF;">[[File:' .. (data.number or '') .. (data.name or '') ..
| |
| '-Mega.png|150px]]</div></td></tr>'
| |
| | |
| -- Types + Generation.
| |
| local genHtml = '—'
| |
| if gen then
| |
| genHtml = '[[:Category:Generation ' .. gen .. ' Pokémon|<span style="color:#' ..
| |
| colors.dark .. ';">' .. gen .. '</span>]]'
| |
| end
| |
| buf[#buf + 1] = '<tr><td colspan="3" style="width: 50%; border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; padding: 11px; border-radius: 15px;"><p style="margin-bottom: 7px; font-weight: bold; ' ..
| |
| 'color: #' .. colors.dark .. ';">Types</p><table align="center" style="width: 75%; font-weight: bold; ' ..
| |
| 'padding: 3px;"><tr>' .. typesHtml .. '</tr></table></td>' ..
| |
| '<td colspan="3" style="width: 50%; border: 1px solid #' .. colors.dark .. '; background-color: #' .. colors.light ..
| |
| '; border-radius: 15px;"><p style="margin-bottom: 7px; font-weight: bold; color: #' .. colors.dark ..
| |
| ';">Generation</p><span style="border-radius: 12px; padding: 4px 10px; border: 1px solid #' .. colors.dark ..
| |
| '; background-color: #FFFFFF;"> ' .. genHtml .. ' </span></td></tr>'
| |
| | |
| -- Abilities.
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; padding: 11px; border-radius: 15px; width: 100%;"><table width="100%">' ..
| |
| '<tr><th colspan="6"><p style="margin-bottom: 7px; font-weight: bold; color:#' .. colors.dark ..
| |
| ';">[[Abilities|<span style="color:#' .. colors.dark .. ';">Abilities</span>]]</p></th></tr>' ..
| |
| '<tr>' .. abilitiesRow(colors, data) .. '</tr></table></td></tr>'
| |
| | |
| -- Mega Stone, linked to its quest page ("Venusaurite (quest)").
| |
| local stone = nonEmpty(data.stone)
| |
| local stoneHtml = '—'
| |
| if stone then
| |
| stoneHtml = '[[' .. stone .. ' (quest)|<span style="color:#' .. colors.dark .. ';">' .. stone .. '</span>]]'
| |
| end
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px; padding: 5px;">' ..
| |
| '<p style="margin-bottom: 7px; font-weight: bold; color: #' .. colors.dark .. ';">Mega Stone</p>' ..
| |
| '<span style="border-radius: 12px; padding: 4px 10px; border: 1px solid #' .. colors.dark ..
| |
| '; background-color: #FFFFFF;"> ' .. stoneHtml .. ' </span></td></tr>'
| |
| | |
| -- Base stats.
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px; padding: 8px; width: 100%">' ..
| |
| '<table width="100%" style="border-collapse: collapse;">' ..
| |
| '<tr><th colspan="3"><p style="margin-bottom: 7px; font-weight: bold; color: #' .. colors.dark ..
| |
| ';">[[Base stats|<span style="color: #' .. colors.dark .. ';">Base stats</span>]]</p></th></tr>' ..
| |
| table.concat(statRows) ..
| |
| '<tr><td colspan="3" style="text-align: center; padding-top: 6px;">' ..
| |
| '<div style="display: inline-block; background-color: #FFFFFF; border: 1px solid #' .. colors.dark ..
| |
| '; padding: 4px 14px; border-radius: 12px;">Base-stat total: ' .. bst .. '</div></td></tr>' ..
| |
| '</table></td></tr>'
| |
| | |
| -- EV yield.
| |
| buf[#buf + 1] = '<tr><td colspan="6" style="border: 1px solid #' .. colors.dark .. '; background-color: #' ..
| |
| colors.light .. '; border-radius: 15px; padding: 5px; width: 100%"><table width="100%">' ..
| |
| '<tr><th colspan="6">[[EVs|<span style="margin-bottom: 7px; font-weight: bold; color: #' .. colors.dark ..
| |
| ';">EV Yield</span>]]</th></tr><tr>' .. table.concat(evCells) .. '</tr>' ..
| |
| '<tr><td colspan="6"><div style="margin: auto; background-color:#FFFFFF; border: 1px solid #' ..
| |
| colors.dark .. '; padding: 4px 14px; border-radius: 12px; margin-bottom: 5px; width: 50%;">' ..
| |
| 'EV-yield total: ' .. evTotal .. '</div></td></tr></table></td></tr>'
| |
| | |
| -- Height + Weight.
| |
| buf[#buf + 1] = '<tr>' ..
| |
| infoCell(colors, 'Height', (data.height or '—') .. 'm') ..
| |
| infoCell(colors, 'Weight', (data.weight or '—') .. 'kg') ..
| |
| '</tr>'
| |
| | |
| buf[#buf + 1] = '</table>'
| |
| buf[#buf + 1] = '[[Category:Mega-Evolvable Pokémon]]'
| |
| | |
| return table.concat(buf)
| |
| end
| |
| | |
| function p.infobox(frame)
| |
| local args = templateArgs(frame)
| |
| local pageName = mw.title.getCurrentTitle().text
| |
| local name = nonEmpty(args.Name) or pageName
| |
| local width = nonEmpty(args.Width) or '45'
| |
| | |
| local data = byName(name)
| |
| if not data then
| |
| return '<strong class="error">PokemonInfo: no data found for "' .. name .. '"</strong>'
| |
| end
| |
| | |
| frame:callParserFunction('#vardefine', 'type', data.type1 or 'Normal')
| |
| | |
| return infoboxHtml(frame, args, data, name, width, pageName, true)
| |
| end
| |
| | |
| function p.primaryType(frame)
| |
| local args = templateArgs(frame)
| |
| local name = nonEmpty(args.Name) or mw.title.getCurrentTitle().text
| |
| local data = byName(name) or byName(formStem(name))
| |
| return (data and nonEmpty(data.type1)) or 'Normal'
| |
| end
| |
| | |
| local function requestedName(frame)
| |
| local parent = frame:getParent()
| |
| return nonEmpty(frame.args.Name)
| |
| or (parent and nonEmpty(parent.args.Name))
| |
| or mw.title.getCurrentTitle().text
| |
| end
| |
| | |
| local participantsCache = {}
| |
| | |
| local function computeParticipants(frame, name)
| |
| if participantsCache[name] ~= nil then
| |
| return participantsCache[name] or nil
| |
| end
| |
| local rows = loadAllRows()
| |
| local function rowFor(n)
| |
| return rows[n] or rows[hyphenSpaceVariant(n)]
| |
| end
| |
| local stem = formStem(name)
| |
| local baseData = rowFor(stem) or rowFor(name)
| |
| if not baseData then
| |
| participantsCache[name] = false
| |
| return nil
| |
| end
| |
| local baseDexNumber = mw.ustring.match(tostring(baseData.number or ''), '^%d+')
| |
| | |
| local parts = { { data = baseData, label = 'Normal' } }
| |
| local seen = { [baseData.name] = true }
| |
| for _, form in ipairs(FORM_SUFFIXES) do
| |
| local row = rowFor(rawListFormName(form, stem))
| |
| -- A candidate must share the same base dex number to be a real form of
| |
| -- this Pokémon. Without this check, stripping "Nidoran Male" down to
| |
| -- the stem "Nidoran" (done because "Male" is a real form suffix for
| |
| -- Indeedee/Meowstic-style species) lets "Nidoran" + " Female" happen to
| |
| -- match the raw list's "Nidoran Female" row — a wholly different
| |
| -- species (dex #29 vs Male's #32), not this one's gender form.
| |
| local rowDexNumber = row and mw.ustring.match(tostring(row.number or ''), '^%d+')
| |
| if row and not seen[row.name] and rowDexNumber == baseDexNumber then
| |
| seen[row.name] = true
| |
| parts[#parts + 1] = { data = row, label = form.label }
| |
| if form.baseLabel then
| |
| parts[1].label = form.baseLabel
| |
| end
| |
| end
| |
| end
| |
| for _, variant in ipairs(MEGA_VARIANTS) do
| |
| local row = megaByName(stem .. variant)
| |
| if row then
| |
| parts[#parts + 1] = { data = row, label = 'Mega' .. variant, mega = true }
| |
| end
| |
| end
| |
| participantsCache[name] = parts
| |
| return parts
| |
| end
| |
| | |
| function p.formLabel(frame)
| |
| local idx = tonumber(frame.args[1]) or 0
| |
| local parts = computeParticipants(frame, requestedName(frame))
| |
| if not parts then
| |
| return ''
| |
| end
| |
| local part = parts[idx + 1]
| |
| return part and part.label or ''
| |
| end
| |
|
| |
|
| function p.rawName(frame)
| | p.MEGA_VARIANTS = { '', ' X', ' Y' } |
| local name = requestedName(frame)
| |
| local parts = computeParticipants(frame, name)
| |
| return (parts and parts[1].data.name) or name
| |
| end
| |
|
| |
|
| function p.formBox(frame)
| | p.LEARNSET_ALIASES = {} |
| local idx = tonumber(frame.args[1]) or 0
| | for learnsetName, rawListName in pairs(p.RAW_LIST_ALIASES) do |
| local width = nonEmpty(frame.args.Width) or '100'
| | p.LEARNSET_ALIASES[rawListName] = learnsetName |
| local name = requestedName(frame)
| |
| local parts = computeParticipants(frame, name)
| |
| if not parts then
| |
| return '<strong class="error">PokemonInfo: no data found for "' .. name .. '"</strong>'
| |
| end
| |
| local part = parts[idx + 1]
| |
| if not part then
| |
| return ''
| |
| end
| |
| if part.mega then
| |
| return megaInfoboxHtml(frame, part.data, width)
| |
| end
| |
| local parent = frame:getParent()
| |
| local args = (parent and parent.args) or frame.args
| |
| return infoboxHtml(frame, args, part.data, part.data.name, width, mw.title.getCurrentTitle().text, false)
| |
| end | | end |
|
| |
|
| return p | | return p |
Documentation for this module may be created at Module:PokemonForms/doc
local p = {}
p.FORM_SUFFIXES = {
{ suffix = 'Alolan', label = 'Alolan', rawList = 'prefix' },
{ suffix = 'Galar', label = 'Galarian', rawList = 'prefix' },
{ suffix = 'Hisui', label = 'Hisuian', rawList = 'prefix' },
{ suffix = 'Paldea', label = 'Paldean', rawList = 'prefix' },
{ suffix = 'Sandy', label = 'Sandy', rawList = 'suffix' },
{ suffix = 'Trash', label = 'Trash', rawList = 'suffix' },
{ suffix = 'Sky', label = 'Sky', rawList = 'suffix' },
{ suffix = 'Fan', label = 'Fan', rawList = 'suffix' },
{ suffix = 'Frost', label = 'Frost', rawList = 'suffix' },
{ suffix = 'Heat', label = 'Heat', rawList = 'suffix' },
{ suffix = 'Mow', label = 'Mow', rawList = 'suffix' },
{ suffix = 'Wash', label = 'Wash', rawList = 'suffix' },
{ suffix = 'Ash', label = 'Ash', learnsetStyle = 'prefix-space', rawList = 'prefix-hyphen' },
{ suffix = 'Bloodmoon', label = 'Bloodmoon', rawList = 'suffix' },
{ suffix = 'Low-Key', label = 'Low Key', rawList = 'suffix-label' },
{ suffix = 'F', label = 'Female', rawList = 'suffix-space', baseLabel = 'Male' },
{ suffix = 'Blue-Striped', label = 'Blue-Striped', rawList = 'suffix-label' },
{ suffix = 'White-Striped', label = 'White-Striped', rawList = 'suffix-label' },
{ suffix = 'Rainy', label = 'Rainy', rawList = 'suffix-label' },
{ suffix = 'Snowy', label = 'Snowy', rawList = 'suffix-label' },
{ suffix = 'Sunny', label = 'Sunny', rawList = 'suffix-label' },
{ suffix = 'Sunshine', label = 'Sunshine', rawList = 'suffix-label' },
{ suffix = 'Attack', label = 'Attack', rawList = 'suffix-label' },
{ suffix = 'Defense', label = 'Defense', rawList = 'suffix-label' },
{ suffix = 'Speed', label = 'Speed', rawList = 'suffix-label' },
{ suffix = 'Unbound', label = 'Unbound', rawList = 'suffix-label' },
{ suffix = 'Black', label = 'Black', rawList = 'suffix-label' },
{ suffix = 'White', label = 'White', rawList = 'suffix-label' },
{ suffix = 'Dusk', label = 'Dusk', rawList = 'suffix-label' },
{ suffix = 'Midnight', label = 'Midnight', rawList = 'suffix-label' },
{ suffix = 'Pirouette', label = 'Pirouette', rawList = 'suffix-label' },
{ suffix = 'Yellow', label = 'Yellow', rawList = 'suffix-label' },
{ suffix = 'School', label = 'School', rawList = 'suffix-label' },
{ suffix = 'Crowned', label = 'Crowned', rawList = 'suffix-label' },
{ suffix = 'Noice-Face', label = 'Noice Face', rawList = 'suffix-label' },
}
p.STRIP_SUFFIXES = {
'Alolan', 'Galar', 'Hisui', 'Paldea', 'Sandy', 'Trash', 'Plant', 'Amped', 'Male',
'Ice Face', 'Noice Face', 'Midday', 'Solo',
}
p.RAW_LIST_ALIASES = {
['Nidoran M'] = 'Nidoran Male',
['Nidoran F'] = 'Nidoran Female',
['Farfetchd'] = "Farfetch'd",
['Sirfetchd'] = "Sirfetch'd",
['Ho-oh'] = 'Ho-Oh',
['Porygon-z'] = 'Porygon-Z',
['Eiscue'] = 'Eiscue-Ice Face',
['Indeedee'] = 'Indeedee Male',
['Meowstic'] = 'Meowstic Male',
['Basculegion'] = 'Basculegion-Male',
['Oinkologne'] = 'Oinkologne-Male',
['Calyrex-Ice-Rider'] = 'Calyrex-Ice Rider',
['Calyrex-Shadow-Rider'] = 'Calyrex-Shadow Rider',
['Necrozma-Dusk-Mane'] = 'Dusk Mane Necrozma',
['Necrozma-Dawn-Wings'] = 'Dawn Wings Necrozma',
['Ogerpon'] = 'Ogerpon-Teal Mask',
['Ogerpon-Wellspring'] = 'Ogerpon-Wellspring Mask',
['Ogerpon-Hearthflame'] = 'Ogerpon-Hearthflame Mask',
['Ogerpon-Cornerstone'] = 'Ogerpon-Cornerstone Mask',
['Ogerpon-Wellspring-Tera'] = 'Ogerpon-Wellspring Mask',
['Ogerpon-Hearthflame-Tera'] = 'Ogerpon-Hearthflame Mask',
['Ogerpon-Cornerstone-Tera'] = 'Ogerpon-Cornerstone Mask',
['Oricorio'] = 'Oricorio Baile',
['Oricorio-Pom-Pom'] = 'Oricorio Pom-Pom',
['Oricorio-Pau'] = "Oricorio Pa'u",
['Tauros-Paldea-Combat'] = 'Paldean Tauros-Combat',
['Tauros-Paldea-Blaze'] = 'Paldean Tauros-Blaze',
['Tauros-Paldea-Aqua'] = 'Paldean Tauros-Aqua',
['Toxtricity'] = 'Toxtricity-Amped',
['Urshifu'] = 'Urshifu-Single Strike',
['Urshifu-Rapid-Strike'] = 'Urshifu-Rapid Strike',
['Wishiwashi'] = 'Wishiwashi Solo',
['Wormadam'] = 'Wormadam-Plant',
['Lycanroc'] = 'Lycanroc-Midday',
['Terapagos-Terastal'] = 'Terapagos-Terestal',
}
p.MOB_PREFIXES = { 'Baby', 'Crystal', 'Shadow' }
p.MEGA_VARIANTS = { '', ' X', ' Y' }
p.LEARNSET_ALIASES = {}
for learnsetName, rawListName in pairs(p.RAW_LIST_ALIASES) do
p.LEARNSET_ALIASES[rawListName] = learnsetName
end
return p