@pkmn/sim 0.7.45 → 0.7.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/config/formats.js +176 -116
- package/build/cjs/config/formats.js.map +1 -1
- package/build/cjs/data/abilities.js +5 -5
- package/build/cjs/data/abilities.js.map +1 -1
- package/build/cjs/data/aliases.js +3 -2
- package/build/cjs/data/aliases.js.map +1 -1
- package/build/cjs/data/formats-data.js +161 -163
- package/build/cjs/data/formats-data.js.map +1 -1
- package/build/cjs/data/items.js +35 -14
- package/build/cjs/data/items.js.map +1 -1
- package/build/cjs/data/mods/gen2/scripts.js +3 -3
- package/build/cjs/data/mods/gen2/scripts.js.map +1 -1
- package/build/cjs/data/mods/gen3/formats-data.js +2 -2
- package/build/cjs/data/mods/gen3/formats-data.js.map +1 -1
- package/build/cjs/data/mods/gen3/scripts.js +1 -1
- package/build/cjs/data/mods/gen3/scripts.js.map +1 -1
- package/build/cjs/data/mods/gen4/moves.js +1 -1
- package/build/cjs/data/mods/gen4/moves.js.map +1 -1
- package/build/cjs/data/mods/gen5/formats-data.js +1 -1
- package/build/cjs/data/mods/gen5/formats-data.js.map +1 -1
- package/build/cjs/data/mods/gen5/moves.js +1 -1
- package/build/cjs/data/mods/gen5/moves.js.map +1 -1
- package/build/cjs/data/moves.js +13 -18
- package/build/cjs/data/moves.js.map +1 -1
- package/build/cjs/data/pokedex.js +9 -9
- package/build/cjs/data/pokedex.js.map +1 -1
- package/build/cjs/data/pokemongo.js +987 -0
- package/build/cjs/data/pokemongo.js.map +1 -0
- package/build/cjs/data/rulesets.js +51 -0
- package/build/cjs/data/rulesets.js.map +1 -1
- package/build/cjs/sim/battle-actions.js +8 -7
- package/build/cjs/sim/battle-actions.js.map +1 -1
- package/build/cjs/sim/dex-species.js +4 -0
- package/build/cjs/sim/dex-species.js.map +1 -1
- package/build/cjs/sim/dex.js +3 -2
- package/build/cjs/sim/dex.js.map +1 -1
- package/build/cjs/sim/pokemon.js +7 -1
- package/build/cjs/sim/pokemon.js.map +1 -1
- package/build/cjs/sim/team-validator.js +299 -54
- package/build/cjs/sim/team-validator.js.map +1 -1
- package/build/esm/config/formats.mjs +176 -116
- package/build/esm/config/formats.mjs.map +1 -1
- package/build/esm/data/abilities.mjs +5 -5
- package/build/esm/data/abilities.mjs.map +1 -1
- package/build/esm/data/aliases.mjs +3 -2
- package/build/esm/data/aliases.mjs.map +1 -1
- package/build/esm/data/formats-data.mjs +161 -163
- package/build/esm/data/formats-data.mjs.map +1 -1
- package/build/esm/data/items.mjs +35 -14
- package/build/esm/data/items.mjs.map +1 -1
- package/build/esm/data/mods/gen2/scripts.mjs +3 -3
- package/build/esm/data/mods/gen2/scripts.mjs.map +1 -1
- package/build/esm/data/mods/gen3/formats-data.mjs +2 -2
- package/build/esm/data/mods/gen3/formats-data.mjs.map +1 -1
- package/build/esm/data/mods/gen3/scripts.mjs +1 -1
- package/build/esm/data/mods/gen3/scripts.mjs.map +1 -1
- package/build/esm/data/mods/gen4/moves.mjs +1 -1
- package/build/esm/data/mods/gen4/moves.mjs.map +1 -1
- package/build/esm/data/mods/gen5/formats-data.mjs +1 -1
- package/build/esm/data/mods/gen5/formats-data.mjs.map +1 -1
- package/build/esm/data/mods/gen5/moves.mjs +1 -1
- package/build/esm/data/mods/gen5/moves.mjs.map +1 -1
- package/build/esm/data/moves.mjs +13 -18
- package/build/esm/data/moves.mjs.map +1 -1
- package/build/esm/data/pokedex.mjs +9 -9
- package/build/esm/data/pokedex.mjs.map +1 -1
- package/build/esm/data/pokemongo.mjs +984 -0
- package/build/esm/data/pokemongo.mjs.map +1 -0
- package/build/esm/data/rulesets.mjs +51 -0
- package/build/esm/data/rulesets.mjs.map +1 -1
- package/build/esm/sim/battle-actions.mjs +8 -7
- package/build/esm/sim/battle-actions.mjs.map +1 -1
- package/build/esm/sim/dex-species.mjs +4 -0
- package/build/esm/sim/dex-species.mjs.map +1 -1
- package/build/esm/sim/dex.mjs +3 -2
- package/build/esm/sim/dex.mjs.map +1 -1
- package/build/esm/sim/pokemon.mjs +7 -1
- package/build/esm/sim/pokemon.mjs.map +1 -1
- package/build/esm/sim/team-validator.mjs +299 -54
- package/build/esm/sim/team-validator.mjs.map +1 -1
- package/build/types/data/pokemongo.d.ts +31 -0
- package/build/types/sim/battle-actions.d.ts +1 -1
- package/build/types/sim/dex-species.d.ts +12 -0
- package/build/types/sim/dex.d.ts +3 -2
- package/build/types/sim/exported-global-types.d.ts +2 -1
- package/build/types/sim/global-types.d.ts +2 -1
- package/build/types/sim/pokemon.d.ts +2 -0
- package/build/types/sim/team-validator.d.ts +8 -1
- package/package.json +1 -1
|
@@ -571,9 +571,6 @@ export class TeamValidator {
|
|
|
571
571
|
problems.push(`${name} has ${set.moves.length} moves, which is more than the limit of ${ruleTable.maxMoveCount}.`);
|
|
572
572
|
return problems;
|
|
573
573
|
}
|
|
574
|
-
if (ruleTable.isBanned('nonexistent')) {
|
|
575
|
-
problems.push(...this.validateStats(set, species, setSources));
|
|
576
|
-
}
|
|
577
574
|
const moveLegalityWhitelist = {};
|
|
578
575
|
for (const moveName of set.moves) {
|
|
579
576
|
if (!moveName)
|
|
@@ -597,10 +594,56 @@ export class TeamValidator {
|
|
|
597
594
|
}
|
|
598
595
|
}
|
|
599
596
|
}
|
|
597
|
+
const pokemonGoProblems = this.validatePokemonGo(outOfBattleSpecies, set, setSources);
|
|
598
|
+
const learnsetSpecies = dex.species.getLearnsetData(outOfBattleSpecies.id);
|
|
599
|
+
let isFromRBYEncounter = false;
|
|
600
|
+
if (this.gen === 1 && ruleTable.has('obtainablemisc') && !this.ruleTable.has('allowtradeback')) {
|
|
601
|
+
let lowestEncounterLevel;
|
|
602
|
+
for (const encounter of learnsetSpecies.encounters || []) {
|
|
603
|
+
if (encounter.generation !== 1)
|
|
604
|
+
continue;
|
|
605
|
+
if (!encounter.level)
|
|
606
|
+
continue;
|
|
607
|
+
if (lowestEncounterLevel && encounter.level > lowestEncounterLevel)
|
|
608
|
+
continue;
|
|
609
|
+
lowestEncounterLevel = encounter.level;
|
|
610
|
+
}
|
|
611
|
+
if (lowestEncounterLevel) {
|
|
612
|
+
if (set.level < lowestEncounterLevel) {
|
|
613
|
+
problems.push(`${name} is not obtainable at levels below ${lowestEncounterLevel} in Gen 1.`);
|
|
614
|
+
}
|
|
615
|
+
isFromRBYEncounter = true;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (!isFromRBYEncounter && ruleTable.has('obtainablemisc')) {
|
|
619
|
+
// FIXME: Event pokemon given at a level under what it normally can be attained at gives a false positive
|
|
620
|
+
let evoSpecies = species;
|
|
621
|
+
while (evoSpecies.prevo) {
|
|
622
|
+
if (set.level < (evoSpecies.evoLevel || 0)) {
|
|
623
|
+
if (!pokemonGoProblems || (pokemonGoProblems && pokemonGoProblems.length)) {
|
|
624
|
+
problems.push(`${name} must be at least level ${evoSpecies.evoLevel} to be evolved.`);
|
|
625
|
+
if (pokemonGoProblems && pokemonGoProblems.length) {
|
|
626
|
+
problems.push(`It failed to validate as a Pokemon from Pokemon GO because:`);
|
|
627
|
+
for (const pokemonGoProblem of pokemonGoProblems) {
|
|
628
|
+
problems.push(pokemonGoProblem);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
// Pokemon from Pokemon GO can be transferred to LGPE
|
|
634
|
+
setSources.isFromPokemonGo = true;
|
|
635
|
+
setSources.sources.push('8V');
|
|
636
|
+
setSources.sourcesBefore = 0;
|
|
637
|
+
}
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
evoSpecies = dex.species.get(evoSpecies.prevo);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
const moveProblems = this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist);
|
|
600
644
|
if (ruleTable.has('obtainablemoves')) {
|
|
601
|
-
problems.push(...
|
|
645
|
+
problems.push(...moveProblems);
|
|
602
646
|
}
|
|
603
|
-
const learnsetSpecies = dex.species.getLearnsetData(outOfBattleSpecies.id);
|
|
604
647
|
let eventOnlyData;
|
|
605
648
|
if (!setSources.sourcesBefore && setSources.sources.length) {
|
|
606
649
|
let legal = false;
|
|
@@ -624,12 +667,24 @@ export class TeamValidator {
|
|
|
624
667
|
problems.push(`(Is this incorrect? If so, post the chainbreeding instructions in Bug Reports)`);
|
|
625
668
|
}
|
|
626
669
|
else {
|
|
627
|
-
if (
|
|
628
|
-
|
|
670
|
+
if (species.id === 'mew' && pokemonGoProblems && !pokemonGoProblems.length) {
|
|
671
|
+
// Whitelist Pokemon GO Mew, which cannot be sent to Let's Go
|
|
672
|
+
setSources.isFromPokemonGo = true;
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
if (setSources.sources.length > 1) {
|
|
676
|
+
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):`);
|
|
677
|
+
}
|
|
678
|
+
const eventProblems = this.validateSource(set, nonEggSource, setSources, outOfBattleSpecies, ` because it has a move only available`);
|
|
679
|
+
if (eventProblems)
|
|
680
|
+
problems.push(...eventProblems);
|
|
681
|
+
if (species.id === 'mew' && pokemonGoProblems && pokemonGoProblems.length) {
|
|
682
|
+
problems.push(`Additionally, it failed to validate as a Pokemon from Pokemon GO because:`);
|
|
683
|
+
for (const pokemonGoProblem of pokemonGoProblems) {
|
|
684
|
+
problems.push(pokemonGoProblem);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
629
687
|
}
|
|
630
|
-
const eventProblems = this.validateSource(set, nonEggSource, setSources, outOfBattleSpecies, ` because it has a move only available`);
|
|
631
|
-
if (eventProblems)
|
|
632
|
-
problems.push(...eventProblems);
|
|
633
688
|
}
|
|
634
689
|
}
|
|
635
690
|
}
|
|
@@ -646,54 +701,58 @@ export class TeamValidator {
|
|
|
646
701
|
legal = true;
|
|
647
702
|
}
|
|
648
703
|
if (!legal) {
|
|
649
|
-
if (
|
|
650
|
-
|
|
704
|
+
if (!pokemonGoProblems || (pokemonGoProblems && pokemonGoProblems.length)) {
|
|
705
|
+
if (eventData.length === 1) {
|
|
706
|
+
problems.push(`${species.name} is only obtainable from an event - it needs to match its event:`);
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
problems.push(`${species.name} is only obtainable from events - it needs to match one of its events:`);
|
|
710
|
+
}
|
|
711
|
+
for (const [i, event] of eventData.entries()) {
|
|
712
|
+
if (event.generation <= dex.gen && event.generation >= this.minSourceGen) {
|
|
713
|
+
const eventInfo = event;
|
|
714
|
+
const eventNum = i + 1;
|
|
715
|
+
const eventName = eventData.length > 1 ? ` #${eventNum}` : ``;
|
|
716
|
+
const eventProblems = this.validateEvent(set, setSources, eventInfo, eventSpecies, ` to be`, `from its event${eventName}`);
|
|
717
|
+
if (eventProblems)
|
|
718
|
+
problems.push(...eventProblems);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (pokemonGoProblems && pokemonGoProblems.length) {
|
|
722
|
+
problems.push(`Additionally, it failed to validate as a Pokemon from Pokemon GO because:`);
|
|
723
|
+
for (const pokemonGoProblem of pokemonGoProblems) {
|
|
724
|
+
problems.push(pokemonGoProblem);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
651
727
|
}
|
|
652
728
|
else {
|
|
653
|
-
|
|
654
|
-
}
|
|
655
|
-
for (const [i, event] of eventData.entries()) {
|
|
656
|
-
if (event.generation <= dex.gen && event.generation >= this.minSourceGen) {
|
|
657
|
-
const eventInfo = event;
|
|
658
|
-
const eventNum = i + 1;
|
|
659
|
-
const eventName = eventData.length > 1 ? ` #${eventNum}` : ``;
|
|
660
|
-
const eventProblems = this.validateEvent(set, setSources, eventInfo, eventSpecies, ` to be`, `from its event${eventName}`);
|
|
661
|
-
if (eventProblems)
|
|
662
|
-
problems.push(...eventProblems);
|
|
663
|
-
}
|
|
729
|
+
setSources.isFromPokemonGo = true;
|
|
664
730
|
}
|
|
665
731
|
}
|
|
666
732
|
}
|
|
667
|
-
|
|
668
|
-
if (
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
continue;
|
|
675
|
-
if (lowestEncounterLevel && encounter.level > lowestEncounterLevel)
|
|
676
|
-
continue;
|
|
677
|
-
lowestEncounterLevel = encounter.level;
|
|
678
|
-
}
|
|
679
|
-
if (lowestEncounterLevel) {
|
|
680
|
-
if (set.level < lowestEncounterLevel) {
|
|
681
|
-
problems.push(`${name} is not obtainable at levels below ${lowestEncounterLevel} in Gen 1.`);
|
|
682
|
-
}
|
|
683
|
-
isFromRBYEncounter = true;
|
|
733
|
+
// Attempt move validation again after verifying Pokemon GO origin
|
|
734
|
+
if (setSources.isFromPokemonGo) {
|
|
735
|
+
setSources.restrictiveMoves = [];
|
|
736
|
+
setSources.sources = ['8V'];
|
|
737
|
+
setSources.sourcesBefore = 0;
|
|
738
|
+
if (!moveProblems.length && ruleTable.has('obtainablemoves')) {
|
|
739
|
+
problems.push(...this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist));
|
|
684
740
|
}
|
|
685
741
|
}
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
742
|
+
// Hardcoded forced validation for Pokemon GO
|
|
743
|
+
const pokemonGoOnlySpecies = ['meltan', 'melmetal', 'gimmighoulroaming'];
|
|
744
|
+
if (ruleTable.has('obtainablemisc') && (pokemonGoOnlySpecies.includes(species.id))) {
|
|
745
|
+
setSources.isFromPokemonGo = true;
|
|
746
|
+
if (pokemonGoProblems && pokemonGoProblems.length) {
|
|
747
|
+
problems.push(`${name} is only obtainable from Pokemon GO, and failed to validate because:`);
|
|
748
|
+
for (const pokemonGoProblem of pokemonGoProblems) {
|
|
749
|
+
problems.push(pokemonGoProblem);
|
|
693
750
|
}
|
|
694
|
-
evoSpecies = dex.species.get(evoSpecies.prevo);
|
|
695
751
|
}
|
|
696
752
|
}
|
|
753
|
+
if (ruleTable.isBanned('nonexistent')) {
|
|
754
|
+
problems.push(...this.validateStats(set, species, setSources, pokemonGoProblems));
|
|
755
|
+
}
|
|
697
756
|
if (ruleTable.has('obtainablemoves')) {
|
|
698
757
|
if (species.id === 'keldeo' && set.moves.includes('secretsword') && this.minSourceGen > 5 && dex.gen <= 7) {
|
|
699
758
|
problems.push(`${name} has Secret Sword, which is only compatible with Keldeo-Ordinary obtained from Gen 5.`);
|
|
@@ -772,7 +831,7 @@ export class TeamValidator {
|
|
|
772
831
|
}
|
|
773
832
|
return problems;
|
|
774
833
|
}
|
|
775
|
-
validateStats(set, species, setSources) {
|
|
834
|
+
validateStats(set, species, setSources, pokemonGoProblems) {
|
|
776
835
|
const ruleTable = this.ruleTable;
|
|
777
836
|
const dex = this.dex;
|
|
778
837
|
const allowAVs = ruleTable.has('allowavs');
|
|
@@ -831,8 +890,19 @@ export class TeamValidator {
|
|
|
831
890
|
perfectIVs++;
|
|
832
891
|
}
|
|
833
892
|
if (perfectIVs < 3) {
|
|
834
|
-
|
|
835
|
-
|
|
893
|
+
if (!pokemonGoProblems || (pokemonGoProblems && pokemonGoProblems.length)) {
|
|
894
|
+
const reason = (this.minSourceGen === 6 ? ` and this format requires Gen ${dex.gen} Pokémon` : ` in Gen 6 or later`);
|
|
895
|
+
problems.push(`${name} must have at least three perfect IVs because it's a legendary${reason}.`);
|
|
896
|
+
if (pokemonGoProblems && pokemonGoProblems.length) {
|
|
897
|
+
problems.push(`Additionally, it failed to validate as a Pokemon from Pokemon GO because:`);
|
|
898
|
+
for (const pokemonGoProblem of pokemonGoProblems) {
|
|
899
|
+
problems.push(pokemonGoProblem);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
else {
|
|
904
|
+
setSources.isFromPokemonGo = true;
|
|
905
|
+
}
|
|
836
906
|
}
|
|
837
907
|
}
|
|
838
908
|
if (set.hpType && !canBottleCap) {
|
|
@@ -846,6 +916,24 @@ export class TeamValidator {
|
|
|
846
916
|
problems.push(`${name} has Hidden Power ${set.hpType}, but its IVs don't allow this even with (Bottle Cap) Hyper Training.`);
|
|
847
917
|
}
|
|
848
918
|
}
|
|
919
|
+
if (setSources.isFromPokemonGo) {
|
|
920
|
+
// Pokemon from Pokemon GO must have odd IVs in non-Spe stats
|
|
921
|
+
// Since the set can be fixed while making minimal changes, it does not force the IVs to be manually fixed
|
|
922
|
+
for (const stat in set.ivs) {
|
|
923
|
+
if (set.ivs[stat] % 2 === 0 && stat !== 'spe') {
|
|
924
|
+
set.ivs[stat]++;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
if (set.ivs.atk !== set.ivs.spa && !(canBottleCap && (set.ivs.atk === 31 || set.ivs.spa === 31))) {
|
|
928
|
+
problems.push(`${name}'s Atk and Spa IVs must match because it is from Pokemon GO.`);
|
|
929
|
+
}
|
|
930
|
+
if (set.ivs.def !== set.ivs.spd && !(canBottleCap && (set.ivs.def === 31 || set.ivs.spd === 31))) {
|
|
931
|
+
problems.push(`${name}'s Def and Spd IVs must match because it is from Pokemon GO.`);
|
|
932
|
+
}
|
|
933
|
+
if (set.hpType && set.hpType !== 'Dark' && set.hpType !== 'Ice') {
|
|
934
|
+
problems.push(`${name} must have Hidden Power Dark or Ice because it is from Pokemon GO.`);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
849
937
|
if (dex.gen <= 2) {
|
|
850
938
|
// validate DVs
|
|
851
939
|
const ivs = set.ivs;
|
|
@@ -1871,6 +1959,114 @@ export class TeamValidator {
|
|
|
1871
1959
|
}
|
|
1872
1960
|
return problems;
|
|
1873
1961
|
}
|
|
1962
|
+
/**
|
|
1963
|
+
* Returns a list of problems regarding a Pokemon's avilability in Pokemon GO (empty list if no problems)
|
|
1964
|
+
* If the Pokemon cannot be obtained from Pokemon GO, returns null
|
|
1965
|
+
*/
|
|
1966
|
+
validatePokemonGo(species, set, setSources, name = species.name) {
|
|
1967
|
+
let problems = [];
|
|
1968
|
+
let minLevel = 50; // maximum level a Pokemon can be in Pokemon GO
|
|
1969
|
+
let minIVs = 15; // IVs range from 0 to 15 in Pokemon GO
|
|
1970
|
+
const dex = this.dex;
|
|
1971
|
+
const pokemonGoData = dex.species.getPokemonGoData(species.id);
|
|
1972
|
+
if (dex.gen < 8 || this.format.mod === 'gen8dlc1')
|
|
1973
|
+
return null;
|
|
1974
|
+
if (!pokemonGoData) {
|
|
1975
|
+
// Handles forms and evolutions not obtainable from Pokemon GO
|
|
1976
|
+
const otherSpecies = this.learnsetParent(species);
|
|
1977
|
+
// If a Pokemon is somehow not obtainable from Pokemon GO and it must be leveled up to be evolved,
|
|
1978
|
+
// validation for the game should stop because it's more optimal to get the Pokemon outside of the game
|
|
1979
|
+
if (otherSpecies && !species.evoLevel) {
|
|
1980
|
+
const otherProblems = this.validatePokemonGo(otherSpecies, set, setSources, name);
|
|
1981
|
+
if (otherProblems) {
|
|
1982
|
+
problems = otherProblems;
|
|
1983
|
+
}
|
|
1984
|
+
else {
|
|
1985
|
+
return null;
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
else {
|
|
1989
|
+
return null;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
else {
|
|
1993
|
+
const pokemonGoSources = pokemonGoData.encounters;
|
|
1994
|
+
// should never happen
|
|
1995
|
+
if (!pokemonGoSources)
|
|
1996
|
+
throw new Error(`Species with no Pokemon GO data: ${species.id}`);
|
|
1997
|
+
if (set.shiny)
|
|
1998
|
+
name = "Shiny " + name;
|
|
1999
|
+
if (set.shiny && pokemonGoSources.includes('noshiny')) {
|
|
2000
|
+
problems.push(`${name} is not obtainable from Pokemon GO.`);
|
|
2001
|
+
}
|
|
2002
|
+
else {
|
|
2003
|
+
if (pokemonGoSources.includes('wild') && !((set.shiny && pokemonGoSources.includes('nowildshiny')))) {
|
|
2004
|
+
minLevel = 1;
|
|
2005
|
+
minIVs = 0;
|
|
2006
|
+
}
|
|
2007
|
+
if (pokemonGoSources.includes('egg')) {
|
|
2008
|
+
/**
|
|
2009
|
+
* A Pokemon's level when hatched is determined by the trainer's level when it is obtained
|
|
2010
|
+
* It is no longer possible for new accounts to obtain eggs at level 1 because they will have reached
|
|
2011
|
+
* level 2 by the time they can spin a PokeStop. However, it might be possible for a sleeper account
|
|
2012
|
+
* from before XP changes to get a level 1 egg from spinning a PokeStop that sends the account to
|
|
2013
|
+
* level 2, but this needs research
|
|
2014
|
+
*/
|
|
2015
|
+
minLevel = Math.min(minLevel, 2);
|
|
2016
|
+
minIVs = Math.min(minIVs, 10);
|
|
2017
|
+
}
|
|
2018
|
+
if (pokemonGoSources.includes('12kmegg')) {
|
|
2019
|
+
minLevel = Math.min(minLevel, 8);
|
|
2020
|
+
minIVs = Math.min(minIVs, 10);
|
|
2021
|
+
}
|
|
2022
|
+
if (pokemonGoSources.includes('raid')) {
|
|
2023
|
+
minLevel = Math.min(minLevel, 20);
|
|
2024
|
+
minIVs = Math.min(minIVs, 10);
|
|
2025
|
+
}
|
|
2026
|
+
if (species.id === 'mewtwo' && set.level && set.level >= 20) {
|
|
2027
|
+
// A bug allowed Mewtwo to be encountered with an IV floor of 0 from GO Battle League
|
|
2028
|
+
minIVs = Math.min(minIVs, 0);
|
|
2029
|
+
}
|
|
2030
|
+
if (pokemonGoSources.includes('research')) {
|
|
2031
|
+
minLevel = Math.min(minLevel, 15);
|
|
2032
|
+
minIVs = Math.min(minIVs, 10);
|
|
2033
|
+
}
|
|
2034
|
+
if (pokemonGoSources.includes('giovanni') && !set.shiny) {
|
|
2035
|
+
/**
|
|
2036
|
+
* Purified Pokemon can be leveled down to level 8 after trading; they are forced to
|
|
2037
|
+
* special trades, but currently all Giovanni Shadow Pokemon are already forced special trades
|
|
2038
|
+
*/
|
|
2039
|
+
minLevel = Math.min(minLevel, 8);
|
|
2040
|
+
minIVs = Math.min(minIVs, 1);
|
|
2041
|
+
if (set.level && set.level < 12)
|
|
2042
|
+
setSources.pokemonGoSource = "purified";
|
|
2043
|
+
}
|
|
2044
|
+
// Attempt to trade the Pokemon to reduce level and IVs
|
|
2045
|
+
if (!pokemonGoSources.includes('notrade')) {
|
|
2046
|
+
// Special trades require a good friend
|
|
2047
|
+
// Trading with a friend of this level has an IV floor of 1
|
|
2048
|
+
// Note that (non-shiny) Deoxys could be traded for a short time when it was introduced
|
|
2049
|
+
if (!set.shiny || species.id !== 'deoxys') {
|
|
2050
|
+
const specialTrade = pokemonGoSources.includes('specialtrade') || set.shiny;
|
|
2051
|
+
minLevel = Math.min(minLevel, 12);
|
|
2052
|
+
minIVs = Math.min(minIVs, specialTrade ? 1 : 0);
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
if (set.level && set.level < minLevel) {
|
|
2056
|
+
problems.push(`${name} must be at least level ${minLevel} to be from Pokemon GO.`);
|
|
2057
|
+
}
|
|
2058
|
+
const ivs = set.ivs || TeamValidator.fillStats(null, 31);
|
|
2059
|
+
for (const stat in ivs) {
|
|
2060
|
+
if (Math.floor(ivs[stat] / 2) < minIVs && stat !== 'spe') {
|
|
2061
|
+
problems.push(`${name} must have at least ${minIVs} ` +
|
|
2062
|
+
(minIVs === 1 ? `IV` : `IVs`) + ` in non-Speed stats to be from Pokemon GO.`);
|
|
2063
|
+
break;
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
return problems;
|
|
2069
|
+
}
|
|
1874
2070
|
omCheckCanLearn(move, s, setSources = this.allSources(s), set = {}, problem = `${set.name || s.name} can't learn ${move.name}`) {
|
|
1875
2071
|
if (!this.ruleTable.checkCanLearn?.[0])
|
|
1876
2072
|
return problem;
|
|
@@ -2038,7 +2234,8 @@ export class TeamValidator {
|
|
|
2038
2234
|
else if (level >= 5 && learnedGen === 3 && species.canHatch) {
|
|
2039
2235
|
// Pomeg Glitch
|
|
2040
2236
|
}
|
|
2041
|
-
else if ((!species.gender || species.gender === 'F') &&
|
|
2237
|
+
else if ((!species.gender || species.gender === 'F') &&
|
|
2238
|
+
learnedGen >= 2 && species.canHatch && !setSources.isFromPokemonGo) {
|
|
2042
2239
|
// available as egg move
|
|
2043
2240
|
learned = learnedGen + 'Eany';
|
|
2044
2241
|
// falls through to E check below
|
|
@@ -2054,8 +2251,15 @@ export class TeamValidator {
|
|
|
2054
2251
|
if (learnedGen === dex.gen && learned.charAt(1) !== 'R') {
|
|
2055
2252
|
// current-gen level-up, TM or tutor moves:
|
|
2056
2253
|
// always available
|
|
2057
|
-
if (!(learnedGen >= 8 && learned.charAt(1) === 'E') && babyOnly)
|
|
2058
|
-
setSources.
|
|
2254
|
+
if (!(learnedGen >= 8 && learned.charAt(1) === 'E') && babyOnly) {
|
|
2255
|
+
if (setSources.isFromPokemonGo && species.evoLevel) {
|
|
2256
|
+
cantLearnReason = `is from a prevo, which is incompatible with its Pokemon GO origin.`;
|
|
2257
|
+
continue;
|
|
2258
|
+
}
|
|
2259
|
+
else {
|
|
2260
|
+
setSources.babyOnly = babyOnly;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2059
2263
|
if (!moveSources.moveEvoCarryCount)
|
|
2060
2264
|
return null;
|
|
2061
2265
|
}
|
|
@@ -2104,6 +2308,10 @@ export class TeamValidator {
|
|
|
2104
2308
|
else if (learned.charAt(1) === 'V' && this.minSourceGen < learnedGen) {
|
|
2105
2309
|
// Virtual Console or Let's Go transfer moves:
|
|
2106
2310
|
// only if that was the source
|
|
2311
|
+
if (learned === '8V' && setSources.isFromPokemonGo && babyOnly && species.evoLevel) {
|
|
2312
|
+
cantLearnReason = `is from a prevo, which is incompatible with its Pokemon GO origin.`;
|
|
2313
|
+
continue;
|
|
2314
|
+
}
|
|
2107
2315
|
moveSources.add(learned);
|
|
2108
2316
|
}
|
|
2109
2317
|
}
|
|
@@ -2153,6 +2361,41 @@ export class TeamValidator {
|
|
|
2153
2361
|
setSources.restrictiveMoves = [];
|
|
2154
2362
|
}
|
|
2155
2363
|
setSources.restrictiveMoves.push(move.name);
|
|
2364
|
+
const checkedSpecies = babyOnly ? species : baseSpecies;
|
|
2365
|
+
if (checkedSpecies && setSources.isFromPokemonGo &&
|
|
2366
|
+
(setSources.pokemonGoSource === 'purified' || checkedSpecies.id === 'mew')) {
|
|
2367
|
+
// Pokemon that cannot be sent from Pokemon GO to Let's Go can only access Let's Go moves through HOME
|
|
2368
|
+
// It can only obtain a chain of four level up moves and cannot have TM moves
|
|
2369
|
+
const pokemonGoData = dex.species.getPokemonGoData(checkedSpecies.id);
|
|
2370
|
+
if (pokemonGoData.LGPERestrictiveMoves) {
|
|
2371
|
+
let levelUpMoveCount = 0;
|
|
2372
|
+
const restrictiveMovesToID = [];
|
|
2373
|
+
for (const moveName of setSources.restrictiveMoves) {
|
|
2374
|
+
restrictiveMovesToID.push(toID(moveName));
|
|
2375
|
+
}
|
|
2376
|
+
for (const restrictiveMove in pokemonGoData.LGPERestrictiveMoves) {
|
|
2377
|
+
const moveLevel = pokemonGoData.LGPERestrictiveMoves[restrictiveMove];
|
|
2378
|
+
if (toID(move) === restrictiveMove) {
|
|
2379
|
+
if (!moveLevel) {
|
|
2380
|
+
return `'s move ${move.name} is incompatible with its Pokemon GO origin.`;
|
|
2381
|
+
}
|
|
2382
|
+
else if (set.level && set.level < moveLevel) {
|
|
2383
|
+
return ` must be at least level ${moveLevel} to learn ${move.name} due to its Pokemon GO origin.`;
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
if (levelUpMoveCount)
|
|
2387
|
+
levelUpMoveCount++;
|
|
2388
|
+
if (restrictiveMovesToID.includes(restrictiveMove)) {
|
|
2389
|
+
if (!levelUpMoveCount) {
|
|
2390
|
+
levelUpMoveCount++;
|
|
2391
|
+
}
|
|
2392
|
+
else if (levelUpMoveCount > 4) {
|
|
2393
|
+
return `'s moves ${(setSources.restrictiveMoves || []).join(', ')} are incompatible with its Pokemon GO origin.`;
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2156
2399
|
// Now that we have our list of possible sources, intersect it with the current list
|
|
2157
2400
|
if (!moveSources.size()) {
|
|
2158
2401
|
if (cantLearnReason)
|
|
@@ -2167,6 +2410,8 @@ export class TeamValidator {
|
|
|
2167
2410
|
// prevents a crash if OMs override `checkCanLearn` to keep validating after an error
|
|
2168
2411
|
setSources.sources = backupSources;
|
|
2169
2412
|
setSources.sourcesBefore = backupSourcesBefore;
|
|
2413
|
+
if (setSources.isFromPokemonGo)
|
|
2414
|
+
return `'s move ${move.name} is incompatible with its Pokemon GO origin.`;
|
|
2170
2415
|
return `'s moves ${(setSources.restrictiveMoves || []).join(', ')} are incompatible.`;
|
|
2171
2416
|
}
|
|
2172
2417
|
if (babyOnly)
|