Add Pokemon GO support (#9646)

This commit is contained in:
dot-Comfey 2023-07-31 17:27:06 -07:00 committed by GitHub
parent 66824f09a6
commit 01e35f4f2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1339 additions and 80 deletions

983
data/pokemongo.ts Normal file
View File

@ -0,0 +1,983 @@
/**
* A listing of every Pokemon that can be obtained from Pokemon GO and how the can be obtained.
* If a Pokemon is not listed here, it cannot be obtained from Pokemon GO.
*
* Key:
* - Origin:
* - wild: Can be found in the overworld, either as a regular spawn or through a similar source such as GO Snapshot
* - egg: Hatches from 2, 5, or 10 km eggs
* - giovanni: Shadow Pokemon rescued from Giovanni and purified
* - 12kmegg: Hatches from a 12 km egg, which is obtained from Team GO Rocket Leaders which unlock at level 8
* - raid: Caught from defeating a raid boss
* - research: Reward from field research, special research, or research breakthrough
* If the Pokemon is obtainable from the wild, other sources do not need to be included due to redundancy.
* For shinies that can't be obtained from the wild, all other sources should be included.
*
* - Shiny origin restrictions:
* - noshiny: This Pokemon's shiny form is unavailable in Pokemon GO
* - nowildshiny: This Pokemon can't be obtained as shiny from the wild
*
* - Trade restrictions:
* - notrade: This Pokemon cannot be traded at all
* - specialtrade: This Pokemon must be traded in a special trade
*
* Certain sources have been excluded from this list, which are:
* - GO Battle League: same level and IV floor as raid bosses, and all from GO Battle League have also been in raids
* - Shadow Pokemon: most can also be obtained from the wild, and those that can't are from defeating Giovanni, which
* is handled as as its own encounter
*/
export const PokemonGoData: {[source: string]: PokemonGoData} = {
bulbasaur: {encounters: ['wild']},
ivysaur: {encounters: ['wild']},
venusaur: {encounters: ['wild']},
charmander: {encounters: ['wild']},
charmeleon: {encounters: ['wild']},
charizard: {encounters: ['wild']},
squirtle: {encounters: ['wild']},
wartortle: {encounters: ['wild']},
blastoise: {encounters: ['wild']},
caterpie: {encounters: ['wild']},
metapod: {encounters: ['wild']},
butterfree: {encounters: ['wild']},
weedle: {encounters: ['wild']},
kakuna: {encounters: ['wild']},
beedrill: {encounters: ['wild']},
pidgey: {encounters: ['wild']},
pidgeotto: {encounters: ['wild']},
pidgeot: {encounters: ['wild']},
rattata: {encounters: ['wild']},
rattataalola: {encounters: ['wild']},
raticate: {encounters: ['wild']},
raticatealola: {encounters: ['wild']},
spearow: {encounters: ['wild']},
fearow: {encounters: ['wild']},
ekans: {encounters: ['wild']},
arbok: {encounters: ['wild']},
pikachu: {encounters: ['wild']},
raichu: {encounters: ['wild']},
raichualola: {encounters: ['wild']},
sandshrew: {encounters: ['wild']},
sandshrewalola: {encounters: ['wild']},
sandslash: {encounters: ['wild']},
sandslashalola: {encounters: ['wild']},
nidoranf: {encounters: ['wild']},
nidorina: {encounters: ['wild']},
nidoqueen: {encounters: ['wild']},
nidoranm: {encounters: ['wild']},
nidorino: {encounters: ['wild']},
nidoking: {encounters: ['wild']},
clefairy: {encounters: ['wild']},
clefable: {encounters: ['wild']},
vulpix: {encounters: ['wild']},
vulpixalola: {encounters: ['wild']},
ninetales: {encounters: ['wild']},
ninetalesalola: {encounters: ['wild']},
jigglypuff: {encounters: ['wild']},
wigglytuff: {encounters: ['wild']},
zubat: {encounters: ['wild']},
golbat: {encounters: ['wild']},
oddish: {encounters: ['wild']},
gloom: {encounters: ['wild']},
vileplume: {encounters: ['wild']},
paras: {encounters: ['wild']},
parasect: {encounters: ['wild']},
venonat: {encounters: ['wild']},
venomoth: {encounters: ['wild']},
diglett: {encounters: ['wild']},
diglettalola: {encounters: ['wild']},
dugtrio: {encounters: ['wild']},
dugtrioalola: {encounters: ['wild']},
meowth: {encounters: ['wild']},
meowthalola: {encounters: ['wild']},
meowthgalar: {encounters: ['wild']},
persian: {encounters: ['wild']},
persianalola: {encounters: ['wild']},
psyduck: {encounters: ['wild']},
golduck: {encounters: ['wild']},
mankey: {encounters: ['wild']},
primeape: {encounters: ['wild']},
growlithe: {encounters: ['wild']},
growlithehisui: {encounters: ['egg', 'raid', 'research', 'noshiny']}, // wild encounter available on 2023-08-26
arcanine: {encounters: ['wild']},
arcaninehisui: {encounters: ['egg', 'raid', 'research', 'noshiny']}, // wild encounter available on 2023-08-26
poliwag: {encounters: ['wild']},
poliwhirl: {encounters: ['wild']},
poliwrath: {encounters: ['wild']},
abra: {encounters: ['wild']},
kadabra: {encounters: ['wild']},
alakazam: {encounters: ['wild']},
machop: {encounters: ['wild']},
machoke: {encounters: ['wild']},
machamp: {encounters: ['wild']},
bellsprout: {encounters: ['wild']},
weepinbell: {encounters: ['wild']},
victreebel: {encounters: ['wild']},
tentacool: {encounters: ['wild']},
tentacruel: {encounters: ['wild']},
geodude: {encounters: ['wild']},
geodudealola: {encounters: ['wild']},
graveler: {encounters: ['wild']},
graveleralola: {encounters: ['wild']},
golem: {encounters: ['wild']},
golemalola: {encounters: ['wild']},
ponyta: {encounters: ['wild']},
ponytagalar: {encounters: ['wild']},
rapidash: {encounters: ['wild']},
rapidashgalar: {encounters: ['wild']},
slowpoke: {encounters: ['wild']},
slowpokegalar: {encounters: ['wild']},
slowbro: {encounters: ['wild']},
slowbrogalar: {encounters: ['wild']},
magnemite: {encounters: ['wild']},
magneton: {encounters: ['wild']},
farfetchd: {encounters: ['wild']},
farfetchdgalar: {encounters: ['wild']},
doduo: {encounters: ['wild']},
dodrio: {encounters: ['wild']},
seel: {encounters: ['wild']},
dewgong: {encounters: ['wild']},
grimer: {encounters: ['wild']},
grimeralola: {encounters: ['wild']},
muk: {encounters: ['wild']},
mukalola: {encounters: ['wild']},
shellder: {encounters: ['wild']},
cloyster: {encounters: ['wild']},
gastly: {encounters: ['wild']},
haunter: {encounters: ['wild']},
gengar: {encounters: ['wild']},
onix: {encounters: ['wild']},
drowzee: {encounters: ['wild']},
hypno: {encounters: ['wild']},
krabby: {encounters: ['wild']},
kingler: {encounters: ['wild']},
voltorb: {encounters: ['wild']},
voltorbhisui: {encounters: ['wild', 'noshiny']},
electrode: {encounters: ['wild']},
electrodehisui: {encounters: ['wild', 'noshiny']},
exeggcute: {encounters: ['wild']},
exeggutor: {encounters: ['wild']},
exeggutoralola: {encounters: ['wild']},
cubone: {encounters: ['wild']},
marowak: {encounters: ['wild']},
marowakalola: {encounters: ['wild']},
hitmonlee: {encounters: ['wild']},
hitmonchan: {encounters: ['wild']},
lickitung: {encounters: ['wild']},
koffing: {encounters: ['wild']},
weezing: {encounters: ['wild']},
weezinggalar: {encounters: ['wild']},
rhyhorn: {encounters: ['wild']},
rhydon: {encounters: ['wild']},
chansey: {encounters: ['wild']},
tangela: {encounters: ['wild']},
kangaskhan: {encounters: ['wild']},
horsea: {encounters: ['wild']},
seadra: {encounters: ['wild']},
goldeen: {encounters: ['wild']},
seaking: {encounters: ['wild']},
staryu: {encounters: ['wild']},
starmie: {encounters: ['wild']},
mrmime: {encounters: ['wild']},
mrmimegalar: {encounters: ['wild']},
scyther: {encounters: ['wild']},
jynx: {encounters: ['wild']},
electabuzz: {encounters: ['wild']},
magmar: {encounters: ['wild']},
pinsir: {encounters: ['wild']},
tauros: {encounters: ['wild']},
magikarp: {encounters: ['wild']},
gyarados: {encounters: ['wild']},
ditto: {encounters: ['wild']},
eevee: {encounters: ['wild']},
vaporeon: {encounters: ['wild']},
jolteon: {encounters: ['wild']},
flareon: {encounters: ['wild']},
porygon: {encounters: ['wild']},
omanyte: {encounters: ['wild']},
omastar: {encounters: ['wild']},
kabuto: {encounters: ['wild']},
kabutops: {encounters: ['wild']},
aerodactyl: {encounters: ['wild']},
snorlax: {encounters: ['wild']},
articuno: {encounters: ['wild']},
articunogalar: {encounters: ['wild']},
zapdos: {encounters: ['wild']},
zapdosgalar: {encounters: ['wild']},
moltres: {encounters: ['wild']},
moltresgalar: {encounters: ['wild']},
dratini: {encounters: ['wild']},
dragonair: {encounters: ['wild']},
dragonite: {encounters: ['wild']},
mewtwo: {
encounters: ['giovanni', 'raid', 'research', 'specialtrade'],
LGPERestrictiveMoves: {
amnesia: 44,
swift: 33,
psybeam: 22,
mist: 11,
teleport: 1,
confuseray: 1,
confusion: 1,
disable: 1,
},
},
mew: {
encounters: ['research', 'notrade'],
LGPERestrictiveMoves: {
barrier: 44,
psywave: 33,
amnesia: 22,
swift: 11,
pound: 1,
confusion: 1,
mimic: 1,
},
},
chikorita: {encounters: ['wild']},
bayleef: {encounters: ['wild']},
meganium: {encounters: ['wild']},
cyndaquil: {encounters: ['wild']},
quilava: {encounters: ['wild']},
typhlosion: {encounters: ['wild']},
totodile: {encounters: ['wild']},
croconaw: {encounters: ['wild']},
feraligatr: {encounters: ['wild']},
sentret: {encounters: ['wild']},
furret: {encounters: ['wild']},
hoothoot: {encounters: ['wild']},
noctowl: {encounters: ['wild']},
ledyba: {encounters: ['wild']},
ledian: {encounters: ['wild']},
spinarak: {encounters: ['wild']},
ariados: {encounters: ['wild']},
crobat: {encounters: ['wild']},
chinchou: {encounters: ['wild']},
lanturn: {encounters: ['wild']},
pichu: {encounters: ['egg']},
cleffa: {encounters: ['egg']},
igglybuff: {encounters: ['egg']},
togepi: {encounters: ['egg']},
togetic: {encounters: ['wild']},
natu: {encounters: ['wild']},
xatu: {encounters: ['wild']},
mareep: {encounters: ['wild']},
flaaffy: {encounters: ['wild']},
ampharos: {encounters: ['wild']},
bellossom: {encounters: ['wild']},
marill: {encounters: ['wild']},
azumarill: {encounters: ['wild']},
sudowoodo: {encounters: ['wild']},
politoed: {encounters: ['wild']},
hoppip: {encounters: ['wild']},
skiploom: {encounters: ['wild']},
jumpluff: {encounters: ['wild']},
aipom: {encounters: ['wild']},
sunkern: {encounters: ['wild']},
sunflora: {encounters: ['wild']},
yanma: {encounters: ['wild']},
wooper: {encounters: ['wild']},
quagsire: {encounters: ['wild']},
espeon: {encounters: ['wild']},
umbreon: {encounters: ['wild']},
murkrow: {encounters: ['wild']},
slowking: {encounters: ['wild']},
slowkinggalar: {encounters: ['wild']},
misdreavus: {encounters: ['wild']},
unown: {encounters: ['wild']},
unownb: {encounters: ['wild']},
unownc: {encounters: ['wild']},
unownd: {encounters: ['wild']},
unowne: {encounters: ['wild']},
unownf: {encounters: ['wild']},
unowng: {encounters: ['wild']},
unownh: {encounters: ['wild']},
unowni: {encounters: ['wild']},
unownj: {encounters: ['wild']},
unownk: {encounters: ['wild', 'noshiny']},
unownl: {encounters: ['wild']},
unownm: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
unownn: {encounters: ['wild']},
unowno: {encounters: ['wild']},
unownp: {encounters: ['wild']},
unownq: {encounters: ['wild', 'noshiny']},
unownr: {encounters: ['wild']},
unowns: {encounters: ['wild']},
unownt: {encounters: ['wild']},
unownu: {encounters: ['wild']},
unownv: {encounters: ['wild']},
unownw: {encounters: ['wild', 'noshiny']},
unownx: {encounters: ['wild']},
unowny: {encounters: ['wild']},
unownz: {encounters: ['wild', 'noshiny']},
unownexclamation: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
unownquestion: {encounters: ['wild', 'noshiny']},
wobbuffet: {encounters: ['wild']},
girafarig: {encounters: ['wild']},
pineco: {encounters: ['wild']},
forretress: {encounters: ['wild']},
dunsparce: {encounters: ['wild']},
gligar: {encounters: ['wild']},
steelix: {encounters: ['wild']},
snubbull: {encounters: ['wild']},
granbull: {encounters: ['wild']},
qwilfish: {encounters: ['wild']},
qwilfishhisui: {encounters: ['wild', 'noshiny']},
scizor: {encounters: ['wild']},
shuckle: {encounters: ['wild']},
heracross: {encounters: ['wild']},
sneasel: {encounters: ['wild']},
sneaselhisui: {encounters: ['wild', 'noshiny']},
teddiursa: {encounters: ['wild']},
ursaring: {encounters: ['wild']},
slugma: {encounters: ['wild']},
magcargo: {encounters: ['wild']},
swinub: {encounters: ['wild']},
piloswine: {encounters: ['wild']},
corsola: {encounters: ['wild']},
remoraid: {encounters: ['wild']},
octillery: {encounters: ['wild']},
delibird: {encounters: ['wild']},
mantine: {encounters: ['wild']},
skarmory: {encounters: ['wild']},
houndour: {encounters: ['wild']},
houndoom: {encounters: ['wild']},
kingdra: {encounters: ['wild']},
phanpy: {encounters: ['wild']},
donphan: {encounters: ['wild']},
porygon2: {encounters: ['wild']},
stantler: {encounters: ['wild']},
smeargle: {encounters: ['wild']},
tyrogue: {encounters: ['egg']},
hitmontop: {encounters: ['wild']},
smoochum: {encounters: ['egg', 'research']},
elekid: {encounters: ['egg', 'research']},
magby: {encounters: ['egg']},
miltank: {encounters: ['wild']},
blissey: {encounters: ['wild']},
raikou: {encounters: ['wild']},
entei: {encounters: ['wild']},
suicune: {encounters: ['wild']},
larvitar: {encounters: ['wild']},
pupitar: {encounters: ['wild']},
tyranitar: {encounters: ['wild']},
lugia: {encounters: ['giovanni', 'raid', 'research', 'specialtrade']},
hooh: {encounters: ['giovanni', 'raid', 'research', 'specialtrade']},
celebi: {encounters: ['research', 'notrade']},
treecko: {encounters: ['wild']},
grovyle: {encounters: ['wild']},
sceptile: {encounters: ['wild']},
torchic: {encounters: ['wild']},
combusken: {encounters: ['wild']},
blaziken: {encounters: ['wild']},
mudkip: {encounters: ['wild']},
marshtomp: {encounters: ['wild']},
swampert: {encounters: ['wild']},
poochyena: {encounters: ['wild']},
mightyena: {encounters: ['wild']},
zigzagoon: {encounters: ['wild']},
zigzagoongalar: {encounters: ['wild']},
linoone: {encounters: ['wild']},
linoonegalar: {encounters: ['wild']},
wurmple: {encounters: ['wild']},
silcoon: {encounters: ['wild']},
beautifly: {encounters: ['wild']},
cascoon: {encounters: ['wild']},
dustox: {encounters: ['wild']},
lotad: {encounters: ['wild']},
lombre: {encounters: ['wild']},
ludicolo: {encounters: ['wild']},
seedot: {encounters: ['wild']},
nuzleaf: {encounters: ['wild']},
shiftry: {encounters: ['wild']},
taillow: {encounters: ['wild']},
swellow: {encounters: ['wild']},
wingull: {encounters: ['wild']},
pelipper: {encounters: ['wild']},
ralts: {encounters: ['wild']},
kirlia: {encounters: ['wild']},
gardevoir: {encounters: ['wild']},
surskit: {encounters: ['wild']},
masquerain: {encounters: ['wild']},
shroomish: {encounters: ['wild']},
breloom: {encounters: ['wild']},
slakoth: {encounters: ['wild']},
vigoroth: {encounters: ['wild']},
slaking: {encounters: ['wild']},
nincada: {encounters: ['wild']},
ninjask: {encounters: ['wild']},
shedinja: {encounters: ['research']},
whismur: {encounters: ['wild']},
loudred: {encounters: ['wild']},
exploud: {encounters: ['wild']},
makuhita: {encounters: ['wild']},
hariyama: {encounters: ['wild']},
azurill: {encounters: ['egg']},
nosepass: {encounters: ['wild']},
skitty: {encounters: ['wild']},
delcatty: {encounters: ['wild']},
sableye: {encounters: ['wild']},
mawile: {encounters: ['wild']},
aron: {encounters: ['wild']},
lairon: {encounters: ['wild']},
aggron: {encounters: ['wild']},
meditite: {encounters: ['wild']},
medicham: {encounters: ['wild']},
electrike: {encounters: ['wild']},
manectric: {encounters: ['wild']},
plusle: {encounters: ['wild']},
minun: {encounters: ['wild']},
volbeat: {encounters: ['wild']},
illumise: {encounters: ['wild']},
roselia: {encounters: ['wild']},
gulpin: {encounters: ['wild']},
swalot: {encounters: ['wild']},
carvanha: {encounters: ['wild']},
sharpedo: {encounters: ['wild']},
wailmer: {encounters: ['wild']},
wailord: {encounters: ['wild']},
numel: {encounters: ['wild']},
camerupt: {encounters: ['wild']},
torkoal: {encounters: ['wild']},
spoink: {encounters: ['wild']},
grumpig: {encounters: ['wild']},
trapinch: {encounters: ['wild']},
vibrava: {encounters: ['wild']},
flygon: {encounters: ['wild']},
cacnea: {encounters: ['wild']},
cacturne: {encounters: ['wild']},
swablu: {encounters: ['wild']},
altaria: {encounters: ['wild']},
zangoose: {encounters: ['wild']},
seviper: {encounters: ['wild']},
lunatone: {encounters: ['wild']},
solrock: {encounters: ['wild']},
barboach: {encounters: ['wild']},
whiscash: {encounters: ['wild']},
corphish: {encounters: ['wild']},
crawdaunt: {encounters: ['wild']},
baltoy: {encounters: ['wild']},
claydol: {encounters: ['wild']},
lileep: {encounters: ['wild']},
cradily: {encounters: ['wild']},
anorith: {encounters: ['wild']},
armaldo: {encounters: ['wild']},
feebas: {encounters: ['wild']},
milotic: {encounters: ['wild']},
castform: {encounters: ['wild']},
kecleon: {encounters: ['wild']},
shuppet: {encounters: ['wild']},
banette: {encounters: ['wild']},
duskull: {encounters: ['wild']},
dusclops: {encounters: ['wild']},
tropius: {encounters: ['wild']},
chimecho: {encounters: ['wild']},
absol: {encounters: ['wild']},
wynaut: {encounters: ['egg']},
snorunt: {encounters: ['wild']},
glalie: {encounters: ['wild']},
spheal: {encounters: ['wild']},
sealeo: {encounters: ['wild']},
walrein: {encounters: ['wild']},
clamperl: {encounters: ['wild']},
gorebyss: {encounters: ['wild']},
huntail: {encounters: ['wild']},
relicanth: {encounters: ['wild']},
luvdisc: {encounters: ['wild']},
bagon: {encounters: ['wild']},
shelgon: {encounters: ['wild']},
salamence: {encounters: ['wild']},
beldum: {encounters: ['wild']},
metang: {encounters: ['wild']},
metagross: {encounters: ['wild']},
regirock: {encounters: ['giovanni', 'raid', 'research', 'specialtrade']},
regice: {encounters: ['giovanni', 'raid', 'research', 'specialtrade']},
registeel: {encounters: ['giovanni', 'raid', 'research', 'specialtrade']},
latias: {encounters: ['wild']},
latios: {encounters: ['wild']},
kyogre: {encounters: ['raid', 'research', 'specialtrade']},
groudon: {encounters: ['raid', 'research', 'specialtrade']},
rayquaza: {encounters: ['raid', 'research', 'specialtrade']},
jirachi: {encounters: ['research', 'notrade']},
deoxys: {encounters: ['raid', 'specialtrade']},
turtwig: {encounters: ['wild']},
grotle: {encounters: ['wild']},
torterra: {encounters: ['wild']},
chimchar: {encounters: ['wild']},
monferno: {encounters: ['wild']},
infernape: {encounters: ['wild']},
piplup: {encounters: ['wild']},
prinplup: {encounters: ['wild']},
empoleon: {encounters: ['wild']},
starly: {encounters: ['wild']},
staravia: {encounters: ['wild']},
staraptor: {encounters: ['wild']},
bidoof: {encounters: ['wild']},
bibarel: {encounters: ['wild']},
kricketot: {encounters: ['wild']},
kricketune: {encounters: ['wild']},
shinx: {encounters: ['wild']},
luxio: {encounters: ['wild']},
luxray: {encounters: ['wild']},
budew: {encounters: ['egg']},
roserade: {encounters: ['wild']},
cranidos: {encounters: ['wild']},
rampardos: {encounters: ['wild']},
shieldon: {encounters: ['wild']},
bastiodon: {encounters: ['wild']},
burmy: {encounters: ['wild']},
wormadam: {encounters: ['wild']},
wormadamsandy: {encounters: ['wild']},
wormadamtrash: {encounters: ['wild']},
mothim: {encounters: ['wild']},
combee: {encounters: ['wild']},
vespiquen: {encounters: ['wild']},
pachirisu: {encounters: ['wild', 'noshiny']},
buizel: {encounters: ['wild']},
floatzel: {encounters: ['wild']},
cherubi: {encounters: ['wild']},
shellos: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
shelloseast: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
gastrodon: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
gastrodoneast: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
ambipom: {encounters: ['wild']},
drifloon: {encounters: ['wild']},
drifblim: {encounters: ['wild']},
buneary: {encounters: ['wild']},
lopunny: {encounters: ['wild']},
mismagius: {encounters: ['wild']},
honchkrow: {encounters: ['wild']},
glameow: {encounters: ['wild']},
purugly: {encounters: ['wild']},
chingling: {encounters: ['egg', 'noshiny']},
stunky: {encounters: ['wild', 'noshiny']},
skuntank: {encounters: ['wild', 'noshiny']},
bronzor: {encounters: ['wild']},
bronzong: {encounters: ['wild']},
bonsly: {encounters: ['egg']},
mimejr: {encounters: ['egg']},
happiny: {encounters: ['egg']},
chatot: {encounters: ['wild', 'noshiny']},
spiritomb: {encounters: ['research']},
gible: {encounters: ['wild']},
gabite: {encounters: ['wild']},
garchomp: {encounters: ['wild']},
munchlax: {encounters: ['egg']},
riolu: {encounters: ['egg']},
lucario: {encounters: ['egg', 'research']}, // wild encounter available on 2023-08-18
hippopotas: {encounters: ['wild']},
hippowdon: {encounters: ['wild']},
skorupi: {encounters: ['wild']},
drapion: {encounters: ['wild']},
croagunk: {encounters: ['wild']},
toxicroak: {encounters: ['wild']},
carnivine: {encounters: ['wild', 'noshiny']},
finneon: {encounters: ['wild']},
lumineon: {encounters: ['wild']},
mantyke: {encounters: ['egg']},
snover: {encounters: ['wild']},
abomasnow: {encounters: ['wild']},
weavile: {encounters: ['wild']},
magnezone: {encounters: ['wild']},
lickilicky: {encounters: ['wild']},
rhyperior: {encounters: ['wild']},
tangrowth: {encounters: ['wild']},
electivire: {encounters: ['wild']},
magmortar: {encounters: ['wild']},
togekiss: {encounters: ['wild']},
yanmega: {encounters: ['wild']},
leafeon: {encounters: ['wild']},
glaceon: {encounters: ['wild']},
gliscor: {encounters: ['wild']},
mamoswine: {encounters: ['wild']},
porygonz: {encounters: ['wild']},
gallade: {encounters: ['wild']},
probopass: {encounters: ['wild']},
dusknoir: {encounters: ['wild']},
froslass: {encounters: ['wild']},
rotom: {encounters: ['wild', 'noshiny']},
uxie: {encounters: ['wild']},
mesprit: {encounters: ['wild']},
azelf: {encounters: ['wild']},
dialga: {encounters: ['raid', 'specialtrade']},
palkia: {encounters: ['raid', 'specialtrade']},
heatran: {encounters: ['raid', 'specialtrade']},
regigigas: {encounters: ['raid', 'research', 'specialtrade']},
giratina: {encounters: ['raid', 'specialtrade']},
cresselia: {encounters: ['raid', 'research', 'specialtrade']},
darkrai: {encounters: ['raid', 'notrade']},
shaymin: {encounters: ['research', 'noshiny', 'notrade']},
victini: {encounters: ['research', 'noshiny', 'notrade']},
snivy: {encounters: ['wild']},
servine: {encounters: ['wild']},
serperior: {encounters: ['wild']},
tepig: {encounters: ['wild']},
pignite: {encounters: ['wild']},
emboar: {encounters: ['wild']},
oshawott: {encounters: ['wild']},
dewott: {encounters: ['wild']},
samurott: {encounters: ['wild']},
patrat: {encounters: ['wild']},
watchog: {encounters: ['wild']},
lillipup: {encounters: ['wild']},
herdier: {encounters: ['wild']},
stoutland: {encounters: ['wild']},
purrloin: {encounters: ['wild']},
liepard: {encounters: ['wild']},
pansage: {encounters: ['wild']},
simisage: {encounters: ['wild']},
pansear: {encounters: ['wild']},
simisear: {encounters: ['wild']},
panpour: {encounters: ['wild']},
simipour: {encounters: ['wild']},
munna: {encounters: ['wild']},
musharna: {encounters: ['wild']},
pidove: {encounters: ['wild']},
tranquill: {encounters: ['wild']},
unfezant: {encounters: ['wild']},
blitzle: {encounters: ['wild']},
zebstrika: {encounters: ['wild']},
roggenrola: {encounters: ['wild']},
boldore: {encounters: ['wild']},
gigalith: {encounters: ['wild']},
woobat: {encounters: ['wild']},
swoobat: {encounters: ['wild']},
drilbur: {encounters: ['wild']},
exacdrill: {encounters: ['wild']},
audino: {encounters: ['wild']},
timburr: {encounters: ['egg', 'raid']}, // wild encounter available on 2023-08-26
gurdurr: {encounters: ['egg', 'raid']}, // wild encounter available on 2023-08-26
conkeldurr: {encounters: ['egg', 'raid']}, // wild encounter available on 2023-08-26
tympole: {encounters: ['wild']},
palpitoad: {encounters: ['wild']},
seismitoad: {encounters: ['wild']},
throh: {encounters: ['wild']},
sawk: {encounters: ['wild']},
sewaddle: {encounters: ['wild']},
swadloon: {encounters: ['wild']},
leavanny: {encounters: ['wild']},
venipede: {encounters: ['wild']},
whirlipede: {encounters: ['wild']},
scolipede: {encounters: ['wild']},
cottonee: {encounters: ['wild']},
whimsicott: {encounters: ['wild']},
petilil: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
lilligant: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
basculin: {encounters: ['wild', 'noshiny']},
basculinbluestriped: {encounters: ['wild', 'noshiny']},
sandile: {encounters: ['12kmegg', 'research', 'noshiny']},
krokorok: {encounters: ['12kmegg', 'research', 'noshiny']},
krookodile: {encounters: ['12kmegg', 'research', 'noshiny']},
darumaka: {encounters: ['wild']},
darumakagalar: {encounters: ['wild']},
darmanitan: {encounters: ['wild']},
darmanitangalar: {encounters: ['wild']},
maractus: {encounters: ['wild', 'noshiny']},
dwebble: {encounters: ['wild']},
crustle: {encounters: ['wild']},
scraggy: {encounters: ['wild', 'noshiny']},
scrafty: {encounters: ['wild', 'noshiny']},
sigilyph: {encounters: ['wild', 'noshiny']},
yamask: {encounters: ['wild']},
yamaskgalar: {encounters: ['egg', 'raid', 'research']},
cofagrigus: {encounters: ['wild']},
tirtouga: {encounters: ['wild']},
carracosta: {encounters: ['wild']},
archen: {encounters: ['wild']},
archeops: {encounters: ['wild']},
trubbish: {encounters: ['wild']},
garbodor: {encounters: ['wild']},
zorua: {encounters: ['wild', 'noshiny']},
zoroark: {encounters: ['wild', 'noshiny']},
minccino: {encounters: ['wild']},
cinccino: {encounters: ['wild']},
gothita: {encounters: ['wild', 'noshiny']},
gothorita: {encounters: ['wild', 'noshiny']},
gothitelle: {encounters: ['wild', 'noshiny']},
solosis: {encounters: ['wild', 'noshiny']},
duosion: {encounters: ['wild', 'noshiny']},
reuniclus: {encounters: ['wild', 'noshiny']},
ducklett: {encounters: ['wild', 'noshiny']},
swanna: {encounters: ['wild', 'noshiny']},
vanillite: {encounters: ['wild', 'noshiny']},
vanillish: {encounters: ['wild', 'noshiny']},
vanilluxe: {encounters: ['wild', 'noshiny']},
deerling: {encounters: ['wild', 'noshiny']},
deerlingsummer: {encounters: ['wild', 'noshiny']},
deerlingautumn: {encounters: ['wild', 'noshiny']},
deerlingwinter: {encounters: ['wild', 'noshiny']},
sawsbuck: {encounters: ['wild', 'noshiny']},
sawsbucksummer: {encounters: ['wild', 'noshiny']},
sawsbuckautumn: {encounters: ['wild', 'noshiny']},
sawsbuckwinter: {encounters: ['wild', 'noshiny']},
emolga: {encounters: ['wild', 'noshiny']},
karrablast: {encounters: ['wild']},
escavalier: {encounters: ['wild']},
foongus: {encounters: ['wild']},
amoonguss: {encounters: ['wild']},
frillish: {encounters: ['wild']},
jellicent: {encounters: ['wild']},
alomomola: {encounters: ['wild']},
joltik: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
galvantula: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
ferroseed: {encounters: ['wild']},
ferrothorn: {encounters: ['wild']},
klink: {encounters: ['wild']},
klang: {encounters: ['wild']},
klinklang: {encounters: ['wild']},
tynamo: {encounters: ['wild', 'noshiny']},
eelektrik: {encounters: ['wild', 'noshiny']},
eelektross: {encounters: ['wild', 'noshiny']},
elgyem: {encounters: ['wild']},
beheeyem: {encounters: ['wild']},
litwick: {encounters: ['wild']},
lampent: {encounters: ['wild']},
chandelure: {encounters: ['wild']},
axew: {encounters: ['wild']},
fraxure: {encounters: ['wild']},
haxorus: {encounters: ['wild']},
cubchoo: {encounters: ['wild']},
beartic: {encounters: ['wild']},
cryogonal: {encounters: ['wild', 'noshiny']},
shelmet: {encounters: ['wild']},
accelgor: {encounters: ['wild']},
stunfisk: {encounters: ['wild']},
stunfiskgalar: {encounters: ['wild']},
mienfoo: {encounters: ['wild', 'noshiny']},
mienshao: {encounters: ['wild', 'noshiny']},
druddigon: {encounters: ['raid', 'research']},
golett: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-18
golurk: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-18
pawniard: {encounters: ['12kmegg', 'research']}, // wild encounter available on 2023-08-18
bisharp: {encounters: ['12kmegg', 'research']}, // wild encounter available on 2023-08-18
bouffalant: {encounters: ['wild', 'noshiny']},
rufflet: {encounters: ['wild']},
braviary: {encounters: ['wild']},
braviaryhisui: {encounters: ['raid']},
vullaby: {encounters: ['wild']},
mandibuzz: {encounters: ['wild']},
heatmor: {encounters: ['wild']},
durant: {encounters: ['wild']},
deino: {encounters: ['wild']},
zweilous: {encounters: ['wild']},
hydreigon: {encounters: ['wild']},
larvesta: {encounters: ['egg', 'noshiny']},
volcarona: {encounters: ['egg', 'noshiny']},
cobalion: {encounters: ['raid', 'specialtrade']},
terrakion: {encounters: ['raid', 'specialtrade']},
virizion: {encounters: ['raid', 'specialtrade']},
tornadus: {encounters: ['raid', 'specialtrade']},
thundurus: {encounters: ['raid', 'specialtrade']},
reshiram: {encounters: ['raid', 'specialtrade']},
zekrom: {encounters: ['raid', 'specialtrade']},
landorus: {encounters: ['raid', 'specialtrade']},
kyurem: {encounters: ['raid', 'specialtrade']},
// Kyurem-Black/White are not directly obtained from Pokemon GO but should be able to have legal Pokemon GO origin
kyuremblack: {encounters: ['raid', 'specialtrade']},
kyuremwhite: {encounters: ['raid', 'specialtrade']},
keldeo: {encounters: ['research', 'noshiny', 'notrade']},
meloetta: {encounters: ['research', 'noshiny', 'notrade']},
genesect: {encounters: ['raid', 'research', 'notrade']},
chespin: {encounters: ['wild']},
quilladin: {encounters: ['wild']},
chesnaught: {encounters: ['wild']},
fennekin: {encounters: ['wild']},
braixen: {encounters: ['wild']},
delphox: {encounters: ['wild']},
froakie: {encounters: ['wild', 'noshiny']},
frogadier: {encounters: ['wild', 'noshiny']},
greninja: {encounters: ['wild', 'noshiny']},
bunnelby: {encounters: ['wild']},
diggersby: {encounters: ['wild']},
fletchling: {encounters: ['wild']},
fletchinder: {encounters: ['wild']},
talonflame: {encounters: ['wild']},
// Scatterbug is actually obtained in a special type of encounter,
// but the level and IV floors are the same as research encounters
scatterbug: {encounters: ['research', 'noshiny']},
spewpa: {encounters: ['research', 'noshiny']},
vivillon: {encounters: ['research', 'noshiny']},
vivillonarchipelago: {encounters: ['research', 'noshiny']},
vivilloncontinent: {encounters: ['research', 'noshiny']},
vivillonelegant: {encounters: ['research', 'noshiny']},
vivillongarden: {encounters: ['research', 'noshiny']},
vivillonhighplains: {encounters: ['research', 'noshiny']},
vivillonicysnow: {encounters: ['research', 'noshiny']},
vivillonjungle: {encounters: ['research', 'noshiny']},
vivillonmarine: {encounters: ['research', 'noshiny']},
vivillonmodern: {encounters: ['research', 'noshiny']},
vivillonmonsoon: {encounters: ['research', 'noshiny']},
vivillonocean: {encounters: ['research', 'noshiny']},
vivillonpolar: {encounters: ['research', 'noshiny']},
vivillonriver: {encounters: ['research', 'noshiny']},
vivillonsandstorm: {encounters: ['research', 'noshiny']},
vivillonsavanna: {encounters: ['research', 'noshiny']},
vivillonsun: {encounters: ['research', 'noshiny']},
vivillontundra: {encounters: ['research', 'noshiny']},
litleo: {encounters: ['wild']},
pyroar: {encounters: ['wild']},
flabebe: {encounters: ['wild', 'noshiny']},
flabebeblue: {encounters: ['wild', 'noshiny']},
flabebeorange: {encounters: ['wild', 'noshiny']},
flabebewhite: {encounters: ['wild', 'noshiny']},
flabebeyellow: {encounters: ['wild', 'noshiny']},
floette: {encounters: ['wild', 'noshiny']},
floetteblue: {encounters: ['wild', 'noshiny']},
floetteorange: {encounters: ['wild', 'noshiny']},
floettewhite: {encounters: ['wild', 'noshiny']},
floetteyellow: {encounters: ['wild', 'noshiny']},
florges: {encounters: ['wild', 'noshiny']},
florgesblue: {encounters: ['wild', 'noshiny']},
florgesorange: {encounters: ['wild', 'noshiny']},
florgeswhite: {encounters: ['wild', 'noshiny']},
florgesyellow: {encounters: ['wild', 'noshiny']},
pancham: {encounters: ['wild', '12kmegg', 'raid', 'research', 'nowildshiny']},
pangoro: {encounters: ['wild', '12kmegg', 'raid', 'research', 'nowildshiny']},
furfrou: {encounters: ['wild']},
furfroudandy: {encounters: ['wild']},
furfroudebutante: {encounters: ['wild']},
furfroudiamond: {encounters: ['wild']},
furfrouheart: {encounters: ['wild']},
furfroukabuki: {encounters: ['wild']},
furfroulareine: {encounters: ['wild']},
furfroumatron: {encounters: ['wild']},
furfroupharaoh: {encounters: ['wild']},
furfroustar: {encounters: ['wild']},
espurr: {encounters: ['wild']},
meowstic: {encounters: ['wild']},
meowsticf: {encounters: ['wild']},
spritzee: {encounters: ['wild']},
aromatisse: {encounters: ['wild']},
swirlix: {encounters: ['wild']},
slurpuff: {encounters: ['wild']},
inkay: {encounters: ['wild']},
malamar: {encounters: ['wild']},
binacle: {encounters: ['wild']},
barbaracle: {encounters: ['wild']},
skrelp: {encounters: ['wild', 'noshiny']},
dragalge: {encounters: ['wild', 'noshiny']},
clauncher: {encounters: ['wild']},
clawitzer: {encounters: ['wild']},
helioptile: {encounters: ['wild']},
heliolisk: {encounters: ['wild']},
tyrunt: {encounters: ['wild', 'noshiny']},
tyrantrum: {encounters: ['wild', 'noshiny']},
amaura: {encounters: ['wild', 'noshiny']},
aurorus: {encounters: ['wild', 'noshiny']},
sylveon: {encounters: ['wild']},
hawlucha: {encounters: ['wild', 'noshiny']},
dedenne: {encounters: ['wild']},
carbink: {encounters: ['research', 'noshiny']},
goomy: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
sliggoo: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
goodra: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
klefki: {encounters: ['wild', 'noshiny']},
phantump: {encounters: ['wild', 'noshiny']},
trevenant: {encounters: ['wild', 'noshiny']},
pumpkaboo: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
pumpkaboolarge: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
pumpkaboosmall: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
pumpkaboosuper: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
gourgeist: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
gourgeistlarge: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
gourgeistsmall: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
gourgeistsuper: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
bergmite: {encounters: ['wild']},
avalugg: {encounters: ['wild']},
avalugghisui: {encounters: ['raid']},
noibat: {encounters: ['wild']},
noivern: {encounters: ['wild']},
xerneas: {encounters: ['raid', 'specialtrade']},
yveltal: {encounters: ['raid', 'specialtrade']},
// zygarde: {encounters: ['research', 'noshiny']}, trading/transferring may be made available in the future
// diancie: {encounters: ['research', 'noshiny', 'notrade']}, transferring may be made available in the future
hoopa: {encounters: ['raid', 'research', 'noshiny', 'notrade']},
rowlet: {encounters: ['wild', 'noshiny']},
dartrix: {encounters: ['wild', 'noshiny']},
decidueye: {encounters: ['wild', 'noshiny']},
litten: {encounters: ['wild', 'noshiny']},
torracat: {encounters: ['wild', 'noshiny']},
incineroar: {encounters: ['wild', 'noshiny']},
popplio: {encounters: ['wild', 'noshiny']},
brionne: {encounters: ['wild', 'noshiny']},
primarina: {encounters: ['wild', 'noshiny']},
pikipek: {encounters: ['wild', 'noshiny']},
trumbeak: {encounters: ['wild', 'noshiny']},
toucannon: {encounters: ['wild', 'noshiny']},
yungoos: {encounters: ['wild']},
gumshoos: {encounters: ['wild']},
grubbin: {encounters: ['wild', 'noshiny']},
charjabug: {encounters: ['wild', 'noshiny']},
vikavolt: {encounters: ['wild', 'noshiny']},
crabrawler: {encounters: ['wild', 'noshiny']},
crabominable: {encounters: ['wild', 'noshiny']},
oricorio: {encounters: ['wild', 'noshiny']},
cutiefly: {encounters: ['wild', 'noshiny']},
ribombee: {encounters: ['wild', 'noshiny']},
rockruff: {encounters: ['wild']},
lycanroc: {encounters: ['wild']},
lycanrocmidnight: {encounters: ['wild']},
mareanie: {encounters: ['wild', 'noshiny']},
toxapex: {encounters: ['wild', 'noshiny']},
dewpider: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
araquanid: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-04
fomantis: {encounters: ['wild']},
lurantis: {encounters: ['wild']},
morelull: {encounters: ['wild', 'noshiny']},
shiinotic: {encounters: ['wild', 'noshiny']},
salandit: {encounters: ['12kmegg', 'noshiny']},
salazzle: {encounters: ['12kmegg', 'noshiny']},
stufful: {encounters: ['wild']},
bewear: {encounters: ['wild']},
bounsweet: {encounters: ['wild', 'noshiny']},
steenee: {encounters: ['wild', 'noshiny']},
tsareena: {encounters: ['wild', 'noshiny']},
comfey: {encounters: ['wild', 'noshiny']},
oranguru: {encounters: ['wild', 'noshiny']}, // shiny available on 2023-08-26
wimpod: {encounters: ['wild', 'noshiny']},
golisopod: {encounters: ['wild', 'noshiny']},
sandygast: {encounters: ['raid', 'research', 'noshiny']},
palossand: {encounters: ['raid', 'research', 'noshiny']},
komala: {encounters: ['wild', 'noshiny']},
turtonator: {encounters: ['raid', 'research']},
togedemaru: {encounters: ['wild', 'noshiny']},
bruxish: {encounters: ['wild', 'noshiny']},
jangmoo: {encounters: ['wild', 'noshiny']},
hakamoo: {encounters: ['wild', 'noshiny']},
kommoo: {encounters: ['wild', 'noshiny']},
tapukoko: {encounters: ['raid']},
tapulele: {encounters: ['raid']},
tapubulu: {encounters: ['raid']},
tapufini: {encounters: ['raid']},
cosmog: {encounters: ['research', 'noshiny', 'specialtrade']},
cosmoem: {encounters: ['research', 'noshiny', 'specialtrade']},
solgaleo: {encounters: ['research', 'noshiny', 'specialtrade']},
lunala: {encounters: ['research', 'noshiny', 'specialtrade']},
nihilego: {encounters: ['raid', 'research', 'specialtrade']},
buzzwole: {encounters: ['raid', 'research', 'noshiny', 'specialtrade']},
pheromosa: {encounters: ['raid', 'research', 'noshiny', 'specialtrade']},
xurkitree: {encounters: ['raid', 'research', 'noshiny', 'specialtrade']},
celesteela: {encounters: ['raid', 'research', 'noshiny', 'specialtrade']},
kartana: {encounters: ['raid', 'research', 'noshiny', 'specialtrade']},
guzzlord: {encounters: ['raid', 'research', 'noshiny', 'specialtrade']},
meltan: {encounters: ['wild']},
melmetal: {encounters: ['wild']},
skwovet: {encounters: ['wild', 'noshiny']},
greedent: {encounters: ['wild', 'noshiny']},
obstagoon: {encounters: ['wild']},
perrserker: {encounters: ['wild']},
sirfetchd: {encounters: ['wild']},
mrrime: {encounters: ['wild']},
runerigus: {encounters: ['egg', 'raid', 'research']},
falinks: {encounters: ['wild', 'noshiny']},
zacian: {encounters: ['raid', 'noshiny', 'specialtrade']},
zamazenta: {encounters: ['raid', 'noshiny', 'specialtrade']},
zarude: {encounters: ['research', 'noshiny', 'notrade']},
regieleki: {encounters: ['raid', 'noshiny', 'specialtrade']},
regidrago: {encounters: ['raid', 'noshiny', 'specialtrade']},
kleavor: {encounters: ['wild']},
ursaluna: {encounters: ['wild']},
sneasler: {encounters: ['wild', 'noshiny']},
overqwil: {encounters: ['wild', 'noshiny']},
gimmighoulroaming: {encounters: ['wild', 'noshiny']},
gholdengo: {encounters: ['wild', 'noshiny']},
};

View File

@ -43,6 +43,11 @@ export interface LearnsetData {
export type ModdedLearnsetData = LearnsetData & {inherit?: true};
export interface PokemonGoData {
encounters?: string[];
LGPERestrictiveMoves?: {[moveid: string]: number | null};
}
export class Species extends BasicEffect implements Readonly<BasicEffect & SpeciesFormatsData> {
declare readonly effectType: 'Pokemon';
/**
@ -206,6 +211,12 @@ export class Species extends BasicEffect implements Readonly<BasicEffect & Speci
*/
readonly changesFrom?: string;
/**
* List of sources and other availability for a Pokemon transferred from
* Pokemon GO.
*/
readonly pokemonGoData?: string[];
/**
* Singles Tier. The Pokemon's location in the Smogon tier system.
*/
@ -273,6 +284,7 @@ export class Species extends BasicEffect implements Readonly<BasicEffect & Speci
this.battleOnly = data.battleOnly || (this.isMega ? this.baseSpecies : undefined);
this.changesFrom = data.changesFrom ||
(this.battleOnly !== this.baseSpecies ? this.battleOnly : this.baseSpecies);
this.pokemonGoData = data.pokemonGoData || undefined;
if (Array.isArray(data.changesFrom)) this.changesFrom = data.changesFrom[0];
if (!this.gen && this.num >= 1) {
@ -521,6 +533,10 @@ export class DexSpecies {
return learnsetData;
}
getPokemonGoData(id: ID): PokemonGoData {
return this.dex.data.PokemonGoData[id];
}
all(): readonly Species[] {
if (this.allCache) return this.allCache;
const species = [];

View File

@ -46,10 +46,10 @@ const dexes: {[mod: string]: ModdedDex} = Object.create(null);
type DataType =
'Abilities' | 'Rulesets' | 'FormatsData' | 'Items' | 'Learnsets' | 'Moves' |
'Natures' | 'Pokedex' | 'Scripts' | 'Conditions' | 'TypeChart';
'Natures' | 'Pokedex' | 'Scripts' | 'Conditions' | 'TypeChart' | 'PokemonGoData';
const DATA_TYPES: (DataType | 'Aliases')[] = [
'Abilities', 'Rulesets', 'FormatsData', 'Items', 'Learnsets', 'Moves',
'Natures', 'Pokedex', 'Scripts', 'Conditions', 'TypeChart',
'Natures', 'Pokedex', 'Scripts', 'Conditions', 'TypeChart', 'PokemonGoData',
];
const DATA_FILES = {
@ -62,6 +62,7 @@ const DATA_FILES = {
Moves: 'moves',
Natures: 'natures',
Pokedex: 'pokedex',
PokemonGoData: 'pokemongo',
Scripts: 'scripts',
Conditions: 'conditions',
TypeChart: 'typechart',
@ -81,6 +82,7 @@ interface DexTableData {
Moves: DexTable<MoveData>;
Natures: DexTable<NatureData>;
Pokedex: DexTable<SpeciesData>;
PokemonGoData: DexTable<PokemonGoData>;
Scripts: DexTable<AnyObject>;
Conditions: DexTable<EffectData>;
TypeChart: DexTable<TypeData>;

View File

@ -168,6 +168,7 @@ type ModdedSpeciesFormatsData = import('./dex-species').ModdedSpeciesFormatsData
type LearnsetData = import('./dex-species').LearnsetData;
type ModdedLearnsetData = import('./dex-species').ModdedLearnsetData;
type Species = import('./dex-species').Species;
type PokemonGoData = import('./dex-species').PokemonGoData;
type FormatData = import('./dex-formats').FormatData;
type FormatList = import('./dex-formats').FormatList;

View File

@ -89,6 +89,8 @@ export class PokemonSources {
sketchMove?: string;
dreamWorldMoveCount: number;
hm?: string;
isFromPokemonGo?: boolean;
pokemonGoSource?: string;
restrictiveMoves?: string[];
/** Obscure learn methods */
restrictedMove?: ID;
@ -647,10 +649,6 @@ export class TeamValidator {
return problems;
}
if (ruleTable.isBanned('nonexistent')) {
problems.push(...this.validateStats(set, species, setSources));
}
const moveLegalityWhitelist: {[k: string]: true | undefined} = {};
for (const moveName of set.moves) {
if (!moveName) continue;
@ -673,74 +671,8 @@ export class TeamValidator {
}
}
if (ruleTable.has('obtainablemoves')) {
problems.push(...this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist));
}
const pokemonGoProblems = this.validatePokemonGo(outOfBattleSpecies, set, setSources);
const learnsetSpecies = dex.species.getLearnsetData(outOfBattleSpecies.id);
let eventOnlyData;
if (!setSources.sourcesBefore && setSources.sources.length) {
let legal = false;
for (const source of setSources.sources) {
if (this.validateSource(set, source, setSources, outOfBattleSpecies)) continue;
legal = true;
break;
}
if (!legal) {
let nonEggSource = null;
for (const source of setSources.sources) {
if (source.charAt(1) !== 'E') {
nonEggSource = source;
break;
}
}
if (!nonEggSource) {
// all egg moves
problems.push(`${name} can't get its egg move combination (${setSources.limitedEggMoves!.join(', ')}) from any possible father.`);
problems.push(`(Is this incorrect? If so, post the chainbreeding instructions in Bug Reports)`);
} else {
if (setSources.sources.length > 1) {
problems.push(`${name} has an event-exclusive move that it doesn't qualify for (only one of several ways to get the move will be listed):`);
}
const eventProblems = this.validateSource(
set, nonEggSource, setSources, outOfBattleSpecies, ` because it has a move only available`
);
if (eventProblems) problems.push(...eventProblems);
}
}
} else if (ruleTable.has('obtainablemisc') && (eventOnlyData = this.getEventOnlyData(outOfBattleSpecies))) {
const {species: eventSpecies, eventData} = eventOnlyData;
let legal = false;
for (const event of eventData) {
if (this.validateEvent(set, setSources, event, eventSpecies)) continue;
legal = true;
break;
}
if (!legal && species.gen <= 2 && dex.gen >= 7 && !this.validateSource(set, '7V', setSources, species)) {
legal = true;
}
if (!legal) {
if (eventData.length === 1) {
problems.push(`${species.name} is only obtainable from an event - it needs to match its event:`);
} else {
problems.push(`${species.name} is only obtainable from events - it needs to match one of its events:`);
}
for (const [i, event] of eventData.entries()) {
if (event.generation <= dex.gen && event.generation >= this.minSourceGen) {
const eventInfo = event;
const eventNum = i + 1;
const eventName = eventData.length > 1 ? ` #${eventNum}` : ``;
const eventProblems = this.validateEvent(
set, setSources, eventInfo, eventSpecies, ` to be`, `from its event${eventName}`
);
if (eventProblems) problems.push(...eventProblems);
}
}
}
}
let isFromRBYEncounter = false;
if (this.gen === 1 && ruleTable.has('obtainablemisc') && !this.ruleTable.has('allowtradeback')) {
let lowestEncounterLevel;
@ -764,13 +696,142 @@ export class TeamValidator {
let evoSpecies = species;
while (evoSpecies.prevo) {
if (set.level < (evoSpecies.evoLevel || 0)) {
problems.push(`${name} must be at least level ${evoSpecies.evoLevel} to be evolved.`);
if (!pokemonGoProblems || (pokemonGoProblems && pokemonGoProblems.length)) {
problems.push(`${name} must be at least level ${evoSpecies.evoLevel} to be evolved.`);
if (pokemonGoProblems && pokemonGoProblems.length) {
problems.push(`It failed to validate as a Pokemon from Pokemon GO because:`);
for (const pokemonGoProblem of pokemonGoProblems) {
problems.push(pokemonGoProblem);
}
}
} else {
// Pokemon from Pokemon GO can be transferred to LGPE
setSources.isFromPokemonGo = true;
setSources.sources.push('8V');
setSources.sourcesBefore = 0;
}
break;
}
evoSpecies = dex.species.get(evoSpecies.prevo);
}
}
const moveProblems = this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist);
if (ruleTable.has('obtainablemoves')) {
problems.push(...moveProblems);
}
let eventOnlyData;
if (!setSources.sourcesBefore && setSources.sources.length) {
let legal = false;
for (const source of setSources.sources) {
if (this.validateSource(set, source, setSources, outOfBattleSpecies)) continue;
legal = true;
break;
}
if (!legal) {
let nonEggSource = null;
for (const source of setSources.sources) {
if (source.charAt(1) !== 'E') {
nonEggSource = source;
break;
}
}
if (!nonEggSource) {
// all egg moves
problems.push(`${name} can't get its egg move combination (${setSources.limitedEggMoves!.join(', ')}) from any possible father.`);
problems.push(`(Is this incorrect? If so, post the chainbreeding instructions in Bug Reports)`);
} else {
if (species.id === 'mew' && pokemonGoProblems && !pokemonGoProblems.length) {
// Whitelist Pokemon GO Mew, which cannot be sent to Let's Go
setSources.isFromPokemonGo = true;
} else {
if (setSources.sources.length > 1) {
problems.push(`${name} has an event-exclusive move that it doesn't qualify for (only one of several ways to get the move will be listed):`);
}
const eventProblems = this.validateSource(
set, nonEggSource, setSources, outOfBattleSpecies, ` because it has a move only available`
);
if (eventProblems) problems.push(...eventProblems);
if (species.id === 'mew' && pokemonGoProblems && pokemonGoProblems.length) {
problems.push(`Additionally, it failed to validate as a Pokemon from Pokemon GO because:`);
for (const pokemonGoProblem of pokemonGoProblems) {
problems.push(pokemonGoProblem);
}
}
}
}
}
} else if (ruleTable.has('obtainablemisc') && (eventOnlyData = this.getEventOnlyData(outOfBattleSpecies))) {
const {species: eventSpecies, eventData} = eventOnlyData;
let legal = false;
for (const event of eventData) {
if (this.validateEvent(set, setSources, event, eventSpecies)) continue;
legal = true;
break;
}
if (!legal && species.gen <= 2 && dex.gen >= 7 && !this.validateSource(set, '7V', setSources, species)) {
legal = true;
}
if (!legal) {
if (!pokemonGoProblems || (pokemonGoProblems && pokemonGoProblems.length)) {
if (eventData.length === 1) {
problems.push(`${species.name} is only obtainable from an event - it needs to match its event:`);
} else {
problems.push(`${species.name} is only obtainable from events - it needs to match one of its events:`);
}
for (const [i, event] of eventData.entries()) {
if (event.generation <= dex.gen && event.generation >= this.minSourceGen) {
const eventInfo = event;
const eventNum = i + 1;
const eventName = eventData.length > 1 ? ` #${eventNum}` : ``;
const eventProblems = this.validateEvent(
set, setSources, eventInfo, eventSpecies, ` to be`, `from its event${eventName}`
);
if (eventProblems) problems.push(...eventProblems);
}
}
if (pokemonGoProblems && pokemonGoProblems.length) {
problems.push(`Additionally, it failed to validate as a Pokemon from Pokemon GO because:`);
for (const pokemonGoProblem of pokemonGoProblems) {
problems.push(pokemonGoProblem);
}
}
} else {
setSources.isFromPokemonGo = true;
}
}
}
// Attempt move validation again after verifying Pokemon GO origin
if (setSources.isFromPokemonGo) {
setSources.restrictiveMoves = [];
setSources.sources = ['8V'];
setSources.sourcesBefore = 0;
if (!moveProblems.length && ruleTable.has('obtainablemoves')) {
problems.push(...this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name,
moveLegalityWhitelist));
}
}
// Hardcoded forced validation for Pokemon GO
const pokemonGoOnlySpecies = ['meltan', 'melmetal', 'gimmighoulroaming'];
if (ruleTable.has('obtainablemisc') && (pokemonGoOnlySpecies.includes(species.id))) {
setSources.isFromPokemonGo = true;
if (pokemonGoProblems && pokemonGoProblems.length) {
problems.push(`${name} is only obtainable from Pokemon GO, and failed to validate because:`);
for (const pokemonGoProblem of pokemonGoProblems) {
problems.push(pokemonGoProblem);
}
}
}
if (ruleTable.isBanned('nonexistent')) {
problems.push(...this.validateStats(set, species, setSources, pokemonGoProblems));
}
if (ruleTable.has('obtainablemoves')) {
if (species.id === 'keldeo' && set.moves.includes('secretsword') && this.minSourceGen > 5 && dex.gen <= 7) {
problems.push(`${name} has Secret Sword, which is only compatible with Keldeo-Ordinary obtained from Gen 5.`);
@ -850,7 +911,7 @@ export class TeamValidator {
return problems;
}
validateStats(set: PokemonSet, species: Species, setSources: PokemonSources) {
validateStats(set: PokemonSet, species: Species, setSources: PokemonSources, pokemonGoProblems: string[] | null) {
const ruleTable = this.ruleTable;
const dex = this.dex;
@ -911,8 +972,18 @@ export class TeamValidator {
if (set.ivs[stat as 'hp'] >= 31) perfectIVs++;
}
if (perfectIVs < 3) {
const reason = (this.minSourceGen === 6 ? ` and this format requires Gen ${dex.gen} Pokémon` : ` in Gen 6 or later`);
problems.push(`${name} must have at least three perfect IVs because it's a legendary${reason}.`);
if (!pokemonGoProblems || (pokemonGoProblems && pokemonGoProblems.length)) {
const reason = (this.minSourceGen === 6 ? ` and this format requires Gen ${dex.gen} Pokémon` : ` in Gen 6 or later`);
problems.push(`${name} must have at least three perfect IVs because it's a legendary${reason}.`);
if (pokemonGoProblems && pokemonGoProblems.length) {
problems.push(`Additionally, it failed to validate as a Pokemon from Pokemon GO because:`);
for (const pokemonGoProblem of pokemonGoProblems) {
problems.push(pokemonGoProblem);
}
}
} else {
setSources.isFromPokemonGo = true;
}
}
}
@ -927,6 +998,25 @@ export class TeamValidator {
}
}
if (setSources.isFromPokemonGo) {
// Pokemon from Pokemon GO must have odd IVs in non-Spe stats
// Since the set can be fixed while making minimal changes, it does not force the IVs to be manually fixed
for (const stat in set.ivs) {
if (set.ivs[stat as 'hp'] % 2 === 0 && stat !== 'spe') {
set.ivs[stat as 'hp']++;
}
}
if (set.ivs.atk !== set.ivs.spa && !(canBottleCap && (set.ivs.atk === 31 || set.ivs.spa === 31))) {
problems.push(`${name}'s Atk and Spa IVs must match because it is from Pokemon GO.`);
}
if (set.ivs.def !== set.ivs.spd && !(canBottleCap && (set.ivs.def === 31 || set.ivs.spd === 31))) {
problems.push(`${name}'s Def and Spd IVs must match because it is from Pokemon GO.`);
}
if (set.hpType && set.hpType !== 'Dark' && set.hpType !== 'Ice') {
problems.push(`${name} must have Hidden Power Dark or Ice because it is from Pokemon GO.`);
}
}
if (dex.gen <= 2) {
// validate DVs
const ivs = set.ivs;
@ -1980,6 +2070,108 @@ export class TeamValidator {
return problems;
}
/**
* Returns a list of problems regarding a Pokemon's avilability in Pokemon GO (empty list if no problems)
* If the Pokemon cannot be obtained from Pokemon GO, returns null
*/
validatePokemonGo(
species: Species, set: Partial<PokemonSet>, setSources: PokemonSources, name: string = species.name,
): string[] | null {
let problems = [];
let minLevel = 50; // maximum level a Pokemon can be in Pokemon GO
let minIVs = 15; // IVs range from 0 to 15 in Pokemon GO
const dex = this.dex;
const pokemonGoData = dex.species.getPokemonGoData(species.id);
if (dex.gen < 8 || this.format.mod === 'gen8dlc1') return null;
if (!pokemonGoData) {
// Handles forms and evolutions not obtainable from Pokemon GO
const otherSpecies = this.learnsetParent(species);
// If a Pokemon is somehow not obtainable from Pokemon GO and it must be leveled up to be evolved,
// validation for the game should stop because it's more optimal to get the Pokemon outside of the game
if (otherSpecies && !species.evoLevel) {
const otherProblems = this.validatePokemonGo(otherSpecies, set, setSources, name);
if (otherProblems) {
problems = otherProblems;
} else {
return null;
}
} else {
return null;
}
} else {
const pokemonGoSources = pokemonGoData.encounters;
// should never happen
if (!pokemonGoSources) throw new Error(`Species with no Pokemon GO data: ${species.id}`);
if (set.shiny) name = "Shiny " + name;
if (set.shiny && pokemonGoSources.includes('noshiny')) {
problems.push(`${name} is not obtainable from Pokemon GO.`);
} else {
if (pokemonGoSources.includes('wild') && !((set.shiny && pokemonGoSources.includes('nowildshiny')))) {
minLevel = 1;
minIVs = 0;
}
if (pokemonGoSources.includes('egg')) {
/**
* A Pokemon's level when hatched is determined by the trainer's level when it is obtained
* It is no longer possible for new accounts to obtain eggs at level 1 because they will have reached
* level 2 by the time they can spin a PokeStop. However, it might be possible for a sleeper account
* from before XP changes to get a level 1 egg from spinning a PokeStop that sends the account to
* level 2, but this needs research
*/
minLevel = Math.min(minLevel, 2);
minIVs = Math.min(minIVs, 10);
}
if (pokemonGoSources.includes('12kmegg')) {
minLevel = Math.min(minLevel, 8);
minIVs = Math.min(minIVs, 10);
}
if (pokemonGoSources.includes('raid')) {
minLevel = Math.min(minLevel, 20);
minIVs = Math.min(minIVs, 10);
}
if (species.id === 'mewtwo' && set.level && set.level >= 20) {
// A bug allowed Mewtwo to be encountered with an IV floor of 0 from GO Battle League
minIVs = Math.min(minIVs, 0);
}
if (pokemonGoSources.includes('research')) {
minLevel = Math.min(minLevel, 15);
minIVs = Math.min(minIVs, 10);
}
if (pokemonGoSources.includes('giovanni') && !set.shiny) {
/**
* Purified Pokemon can be leveled down to level 8 after trading; they are forced to
* special trades, but currently all Giovanni Shadow Pokemon are already forced special trades
*/
minLevel = Math.min(minLevel, 8);
minIVs = Math.min(minIVs, 1);
if (set.level && set.level < 12) setSources.pokemonGoSource = "purified";
}
// Attempt to trade the Pokemon to reduce level and IVs
if (!pokemonGoSources.includes('notrade')) {
// Special trades require a good friend
// Trading with a friend of this level has an IV floor of 1
// Note that (non-shiny) Deoxys could be traded for a short time when it was introduced
if (!set.shiny || species.id !== 'deoxys') {
const specialTrade = pokemonGoSources.includes('specialtrade') || set.shiny;
minLevel = Math.min(minLevel, 12);
minIVs = Math.min(minIVs, specialTrade ? 1 : 0);
}
}
if (set.level && set.level < minLevel) {
problems.push(`${name} must be at least level ${minLevel} to be from Pokemon GO.`);
}
const ivs = set.ivs || TeamValidator.fillStats(null, 31);
for (const stat in ivs) {
if (Math.floor(ivs[stat as 'hp'] / 2) < minIVs && stat !== 'spe') {
problems.push(`${name} must have at least ${minIVs} ` +
(minIVs === 1 ? `IV` : `IVs`) + ` in non-Speed stats to be from Pokemon GO.`);
break;
}
}
}
}
return problems;
}
omCheckCanLearn(
move: Move,
@ -2168,7 +2360,8 @@ export class TeamValidator {
// falls through to LMT check below
} else if (level >= 5 && learnedGen === 3 && species.canHatch) {
// Pomeg Glitch
} else if ((!species.gender || species.gender === 'F') && learnedGen >= 2 && species.canHatch) {
} else if ((!species.gender || species.gender === 'F') &&
learnedGen >= 2 && species.canHatch && !setSources.isFromPokemonGo) {
// available as egg move
learned = learnedGen + 'Eany';
// falls through to E check below
@ -2184,7 +2377,14 @@ export class TeamValidator {
if (learnedGen === dex.gen && learned.charAt(1) !== 'R') {
// current-gen level-up, TM or tutor moves:
// always available
if (!(learnedGen >= 8 && learned.charAt(1) === 'E') && babyOnly) setSources.babyOnly = babyOnly;
if (!(learnedGen >= 8 && learned.charAt(1) === 'E') && babyOnly) {
if (setSources.isFromPokemonGo && species.evoLevel) {
cantLearnReason = `is from a prevo, which is incompatible with its Pokemon GO origin.`;
continue;
} else {
setSources.babyOnly = babyOnly;
}
}
if (!moveSources.moveEvoCarryCount) return null;
}
// past-gen level-up, TM, or tutor moves:
@ -2227,6 +2427,10 @@ export class TeamValidator {
} else if (learned.charAt(1) === 'V' && this.minSourceGen < learnedGen) {
// Virtual Console or Let's Go transfer moves:
// only if that was the source
if (learned === '8V' && setSources.isFromPokemonGo && babyOnly && species.evoLevel) {
cantLearnReason = `is from a prevo, which is incompatible with its Pokemon GO origin.`;
continue;
}
moveSources.add(learned);
}
}
@ -2283,6 +2487,39 @@ export class TeamValidator {
}
setSources.restrictiveMoves.push(move.name);
const checkedSpecies = babyOnly ? species : baseSpecies;
if (checkedSpecies && setSources.isFromPokemonGo &&
(setSources.pokemonGoSource === 'purified' || checkedSpecies.id === 'mew')) {
// Pokemon that cannot be sent from Pokemon GO to Let's Go can only access Let's Go moves through HOME
// It can only obtain a chain of four level up moves and cannot have TM moves
const pokemonGoData = dex.species.getPokemonGoData(checkedSpecies.id);
if (pokemonGoData.LGPERestrictiveMoves) {
let levelUpMoveCount = 0;
const restrictiveMovesToID = [];
for (const moveName of setSources.restrictiveMoves) {
restrictiveMovesToID.push(toID(moveName));
}
for (const restrictiveMove in pokemonGoData.LGPERestrictiveMoves) {
const moveLevel = pokemonGoData.LGPERestrictiveMoves[restrictiveMove];
if (toID(move) === restrictiveMove) {
if (!moveLevel) {
return `'s move ${move.name} is incompatible with its Pokemon GO origin.`;
} else if (set.level && set.level < moveLevel) {
return ` must be at least level ${moveLevel} to learn ${move.name} due to its Pokemon GO origin.`;
}
}
if (levelUpMoveCount) levelUpMoveCount++;
if (restrictiveMovesToID.includes(restrictiveMove)) {
if (!levelUpMoveCount) {
levelUpMoveCount++;
} else if (levelUpMoveCount > 4) {
return `'s moves ${(setSources.restrictiveMoves || []).join(', ')} are incompatible with its Pokemon GO origin.`;
}
}
}
}
}
// Now that we have our list of possible sources, intersect it with the current list
if (!moveSources.size()) {
if (cantLearnReason) return `'s move ${move.name} ${cantLearnReason}`;
@ -2296,6 +2533,7 @@ export class TeamValidator {
// prevents a crash if OMs override `checkCanLearn` to keep validating after an error
setSources.sources = backupSources;
setSources.sourcesBefore = backupSourcesBefore;
if (setSources.isFromPokemonGo) return `'s move ${move.name} is incompatible with its Pokemon GO origin.`;
return `'s moves ${(setSources.restrictiveMoves || []).join(', ')} are incompatible.`;
}

View File

@ -51,7 +51,7 @@ describe('Team Validator', function () {
{species: 'nidoking', level: 1, ability: 'sheerforce', moves: ['earthpower'], evs: {hp: 1}},
{species: 'mamoswine', level: 1, ability: 'oblivious', moves: ['earthquake'], evs: {hp: 1}},
];
assert.false.legalTeam(team, 'gen8anythinggoes');
assert.false.legalTeam(team, 'gen7anythinggoes');
});
it('should require Pokémon transferred from Gens 1 and 2 to be above Level 2', () => {
@ -135,4 +135,23 @@ describe('Team Validator', function () {
assert.legalTeam(team, 'gen8purehackmons');
});
});
it('should allow various (underleveled) from Pokemon GO', function () {
const team = [
{species: 'mewtwo', level: 20, ability: 'pressure', moves: ['agility'], evs: {hp: 1}, ivs: {hp: 1, atk: 1, def: 1, spa: 1, spd: 1}},
{species: 'donphan', level: 1, ability: 'sturdy', moves: ['endeavor']},
{species: 'mew', shiny: true, level: 15, ability: 'synchronize', moves: ['pound'], evs: {hp: 1}},
{species: 'uxie', level: 1, ability: 'levitate', moves: ['acrobatics']},
{species: 'zacian', ability: 'intrepidsword', moves: ['agility'], evs: {hp: 1}},
{species: 'volcarona', level: 2, ability: 'flamebody', moves: ['acrobatics'], evs: {hp: 1}},
];
assert.legalTeam(team, 'gen9ubers');
});
it('should disallow Pokemon from Pokemon GO knowing incompatible moves', function () {
const team = [
{species: 'mew', shiny: true, level: 15, ability: 'synchronize', moves: ['aircutter'], evs: {hp: 1}, ivs: {hp: 21, atk: 31, def: 21, spa: 21, spd: 31, spe: 0}},
];
assert.false.legalTeam(team, 'gen8ou');
});
});