@pkmn/sim 0.7.47 → 0.7.48

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.
Files changed (38) hide show
  1. package/build/cjs/config/formats.js +98 -56
  2. package/build/cjs/config/formats.js.map +1 -1
  3. package/build/cjs/data/abilities.js +4 -1
  4. package/build/cjs/data/abilities.js.map +1 -1
  5. package/build/cjs/data/aliases.js +1 -1
  6. package/build/cjs/data/formats-data.js +36 -23
  7. package/build/cjs/data/formats-data.js.map +1 -1
  8. package/build/cjs/data/learnsets.js +157 -4
  9. package/build/cjs/data/learnsets.js.map +1 -1
  10. package/build/cjs/data/legality.js +260 -50
  11. package/build/cjs/data/legality.js.map +1 -1
  12. package/build/cjs/data/mods/gen4/moves.js +3 -3
  13. package/build/cjs/data/mods/gen4/moves.js.map +1 -1
  14. package/build/cjs/data/pokedex.js +39 -3
  15. package/build/cjs/data/pokedex.js.map +1 -1
  16. package/build/cjs/sim/team-validator.js +100 -23
  17. package/build/cjs/sim/team-validator.js.map +1 -1
  18. package/build/esm/config/formats.mjs +98 -56
  19. package/build/esm/config/formats.mjs.map +1 -1
  20. package/build/esm/data/abilities.mjs +4 -1
  21. package/build/esm/data/abilities.mjs.map +1 -1
  22. package/build/esm/data/aliases.mjs +1 -1
  23. package/build/esm/data/formats-data.mjs +36 -23
  24. package/build/esm/data/formats-data.mjs.map +1 -1
  25. package/build/esm/data/learnsets.mjs +157 -4
  26. package/build/esm/data/learnsets.mjs.map +1 -1
  27. package/build/esm/data/legality.mjs +260 -50
  28. package/build/esm/data/legality.mjs.map +1 -1
  29. package/build/esm/data/mods/gen4/moves.mjs +3 -3
  30. package/build/esm/data/mods/gen4/moves.mjs.map +1 -1
  31. package/build/esm/data/pokedex.mjs +39 -3
  32. package/build/esm/data/pokedex.mjs.map +1 -1
  33. package/build/esm/sim/team-validator.mjs +100 -23
  34. package/build/esm/sim/team-validator.mjs.map +1 -1
  35. package/build/types/sim/exported-global-types.d.ts +14 -1
  36. package/build/types/sim/global-types.d.ts +14 -1
  37. package/build/types/sim/team-validator.d.ts +16 -0
  38. package/package.json +1 -1
@@ -48,6 +48,9 @@ class PokemonSources {
48
48
  add(source, limitedEggMove) {
49
49
  if (this.sources[this.sources.length - 1] !== source)
50
50
  this.sources.push(source);
51
+ if (limitedEggMove && source.substr(0, 3) === '1ET') {
52
+ this.possiblyLimitedEggMoves = [limitedEggMove];
53
+ }
51
54
  if (limitedEggMove && this.limitedEggMoves !== null) {
52
55
  this.limitedEggMoves = [limitedEggMove];
53
56
  }
@@ -82,6 +85,24 @@ class PokemonSources {
82
85
  return max;
83
86
  }
84
87
  intersectWith(other) {
88
+ if (this.pomegEventEgg && other.pomegEggMoves) {
89
+ const newSources = [];
90
+ for (const source of other.sources) {
91
+ newSources.push(source.substr(0, 2) === '3E' ? this.pomegEventEgg : source);
92
+ }
93
+ other.sources = newSources;
94
+ }
95
+ else if (other.pomegEventEgg && this.pomegEventEgg !== null) {
96
+ const newSources = [];
97
+ for (const source of this.sources) {
98
+ newSources.push(source.substr(0, 2) === '3E' ? other.pomegEventEgg : source);
99
+ }
100
+ this.sources = newSources;
101
+ this.pomegEventEgg = other.pomegEventEgg;
102
+ }
103
+ else if (!other.pomegEggMoves && !other.sourcesBefore) {
104
+ this.pomegEventEgg = null;
105
+ }
85
106
  if (other.sourcesBefore || this.sourcesBefore) {
86
107
  // having sourcesBefore is the equivalent of having everything before that gen
87
108
  // in sources, so we fill the other array in preparation for intersection
@@ -131,6 +152,37 @@ class PokemonSources {
131
152
  this.limitedEggMoves.push(...other.limitedEggMoves);
132
153
  }
133
154
  }
155
+ if (other.possiblyLimitedEggMoves) {
156
+ if (!this.possiblyLimitedEggMoves) {
157
+ this.possiblyLimitedEggMoves = other.possiblyLimitedEggMoves;
158
+ }
159
+ else {
160
+ this.possiblyLimitedEggMoves.push(...other.possiblyLimitedEggMoves);
161
+ }
162
+ }
163
+ if (other.pomegEggMoves) {
164
+ if (!this.pomegEggMoves) {
165
+ this.pomegEggMoves = other.pomegEggMoves;
166
+ }
167
+ else {
168
+ this.pomegEggMoves.push(...other.pomegEggMoves);
169
+ }
170
+ }
171
+ let eggTradebackLegal = false;
172
+ for (const source of this.sources) {
173
+ if (source.substr(0, 3) === '1ET') {
174
+ eggTradebackLegal = true;
175
+ break;
176
+ }
177
+ }
178
+ if (!eggTradebackLegal && this.possiblyLimitedEggMoves) {
179
+ for (const eggMove of this.possiblyLimitedEggMoves) {
180
+ if (!this.limitedEggMoves)
181
+ this.limitedEggMoves = [];
182
+ if (!this.limitedEggMoves.includes(eggMove))
183
+ this.limitedEggMoves.push(eggMove);
184
+ }
185
+ }
134
186
  this.moveEvoCarryCount += other.moveEvoCarryCount;
135
187
  this.dreamWorldMoveCount += other.dreamWorldMoveCount;
136
188
  if (other.sourcesAfter > this.sourcesAfter)
@@ -644,20 +696,23 @@ class TeamValidator {
644
696
  evoSpecies = dex.species.get(evoSpecies.prevo);
645
697
  }
646
698
  }
647
- const moveProblems = this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist);
699
+ let moveProblems;
648
700
  if (ruleTable.has('obtainablemoves')) {
701
+ moveProblems = this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist);
649
702
  problems.push(...moveProblems);
650
703
  }
651
704
  let eventOnlyData;
652
705
  if (!setSources.sourcesBefore && setSources.sources.length) {
653
- let legal = false;
706
+ const legalSources = [];
654
707
  for (const source of setSources.sources) {
655
708
  if (this.validateSource(set, source, setSources, outOfBattleSpecies))
656
709
  continue;
657
- legal = true;
658
- break;
710
+ legalSources.push(source);
659
711
  }
660
- if (!legal) {
712
+ if (legalSources.length) {
713
+ setSources.sources = legalSources;
714
+ }
715
+ else {
661
716
  let nonEggSource = null;
662
717
  for (const source of setSources.sources) {
663
718
  if (source.charAt(1) !== 'E') {
@@ -734,15 +789,6 @@ class TeamValidator {
734
789
  }
735
790
  }
736
791
  }
737
- // Attempt move validation again after verifying Pokemon GO origin
738
- if (setSources.isFromPokemonGo) {
739
- setSources.restrictiveMoves = [];
740
- setSources.sources = ['8V'];
741
- setSources.sourcesBefore = 0;
742
- if (!moveProblems.length && ruleTable.has('obtainablemoves')) {
743
- problems.push(...this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist));
744
- }
745
- }
746
792
  // Hardcoded forced validation for Pokemon GO
747
793
  const pokemonGoOnlySpecies = ['meltan', 'melmetal', 'gimmighoulroaming'];
748
794
  if (ruleTable.has('obtainablemisc') && (pokemonGoOnlySpecies.includes(species.id))) {
@@ -757,6 +803,15 @@ class TeamValidator {
757
803
  if (ruleTable.isBanned('nonexistent')) {
758
804
  problems.push(...this.validateStats(set, species, setSources, pokemonGoProblems));
759
805
  }
806
+ // Attempt move validation again after verifying Pokemon GO origin
807
+ if (ruleTable.has('obtainablemoves') && setSources.isFromPokemonGo) {
808
+ setSources.restrictiveMoves = [];
809
+ setSources.sources = ['8V'];
810
+ setSources.sourcesBefore = 0;
811
+ if (moveProblems && !moveProblems.length) {
812
+ problems.push(...this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist));
813
+ }
814
+ }
760
815
  if (ruleTable.has('obtainablemoves')) {
761
816
  if (species.id === 'keldeo' && set.moves.includes('secretsword') && this.minSourceGen > 5 && dex.gen <= 7) {
762
817
  problems.push(`${name} has Secret Sword, which is only compatible with Keldeo-Ordinary obtained from Gen 5.`);
@@ -822,7 +877,8 @@ class TeamValidator {
822
877
  if (nameSpecies.baseSpecies === species.baseSpecies) {
823
878
  set.name = species.baseSpecies;
824
879
  }
825
- else if (nameSpecies.name !== species.name && nameSpecies.name !== species.baseSpecies) {
880
+ else if (nameSpecies.name !== species.name &&
881
+ nameSpecies.name !== species.baseSpecies && ruleTable.has('nicknameclause')) {
826
882
  // nickname species doesn't match actual species
827
883
  // Nickname Clause
828
884
  problems.push(`${name} must not be nicknamed a different Pokémon species than what it actually is.`);
@@ -1149,16 +1205,18 @@ class TeamValidator {
1149
1205
  const fathers = [];
1150
1206
  // Gen 6+ don't have egg move incompatibilities
1151
1207
  // (except for certain cases with baby Pokemon not handled here)
1152
- if (!getAll && eggGen >= 6)
1208
+ if (!getAll && eggGen >= 6 && species.gender !== 'F')
1153
1209
  return true;
1154
- const eggMoves = setSources.limitedEggMoves;
1210
+ let eggMoves = setSources.limitedEggMoves;
1211
+ if (eggGen === 3)
1212
+ eggMoves = eggMoves?.filter(eggMove => !setSources.pomegEggMoves?.includes(eggMove));
1155
1213
  // must have 2 or more egg moves to have egg move incompatibilities
1156
1214
  if (!eggMoves) {
1157
1215
  // happens often in gen 1-6 LC if your only egg moves are level-up moves,
1158
1216
  // which aren't limited and so aren't in `limitedEggMoves`
1159
1217
  return getAll ? ['*'] : true;
1160
1218
  }
1161
- if (!getAll && eggMoves.length <= 1)
1219
+ if (!getAll && eggMoves.length <= 1 && species.gender !== 'F')
1162
1220
  return true;
1163
1221
  // gen 1 eggs come from gen 2 breeding
1164
1222
  const dex = this.dex.gen === 1 ? this.dex.mod('gen2') : this.dex;
@@ -1249,6 +1307,8 @@ class TeamValidator {
1249
1307
  learnset = this.dex.species.getLearnset(curSpecies.id);
1250
1308
  if (learnset && learnset[move]) {
1251
1309
  for (const moveSource of learnset[move]) {
1310
+ if (eggGen > 8 && parseInt(moveSource.charAt(0)) <= 8)
1311
+ continue;
1252
1312
  if (parseInt(moveSource.charAt(0)) > eggGen)
1253
1313
  continue;
1254
1314
  const canLearnFromSmeargle = moveSource.charAt(1) === 'E' && canBreedWithSmeargle;
@@ -2200,7 +2260,8 @@ class TeamValidator {
2200
2260
  // redundant
2201
2261
  if (learnedGen <= moveSources.sourcesBefore)
2202
2262
  continue;
2203
- if (baseSpecies.evoRegion === 'Alola' && checkingPrevo && learnedGen >= 8) {
2263
+ if (baseSpecies.evoRegion === 'Alola' && checkingPrevo && learnedGen >= 8 &&
2264
+ (dex.gen < 9 || learned.charAt(1) !== 'E')) {
2204
2265
  cantLearnReason = `is from a ${species.name} that can't be transferred to USUM to evolve into ${baseSpecies.name}.`;
2205
2266
  continue;
2206
2267
  }
@@ -2237,6 +2298,7 @@ class TeamValidator {
2237
2298
  }
2238
2299
  else if (level >= 5 && learnedGen === 3 && species.canHatch) {
2239
2300
  // Pomeg Glitch
2301
+ learned = learnedGen + 'Epomeg';
2240
2302
  }
2241
2303
  else if ((!species.gender || species.gender === 'F') &&
2242
2304
  learnedGen >= 2 && species.canHatch && !setSources.isFromPokemonGo) {
@@ -2251,7 +2313,8 @@ class TeamValidator {
2251
2313
  }
2252
2314
  }
2253
2315
  // Gen 8+ egg moves can be taught to any pokemon from any source
2254
- if (learnedGen >= 8 && learned.charAt(1) === 'E' || 'LMTR'.includes(learned.charAt(1))) {
2316
+ if (learnedGen >= 8 && learned.charAt(1) === 'E' && learned.slice(1) !== 'Eany' &&
2317
+ learned.slice(1) !== 'Epomeg' || 'LMTR'.includes(learned.charAt(1))) {
2255
2318
  if (learnedGen === dex.gen && learned.charAt(1) !== 'R') {
2256
2319
  // current-gen level-up, TM or tutor moves:
2257
2320
  // always available
@@ -2280,7 +2343,17 @@ class TeamValidator {
2280
2343
  // only if hatched from an egg
2281
2344
  let limitedEggMove = undefined;
2282
2345
  if (learned.slice(1) === 'Eany') {
2283
- limitedEggMove = null;
2346
+ if (species.gender === 'F') {
2347
+ limitedEggMove = move.id;
2348
+ }
2349
+ else {
2350
+ limitedEggMove = null;
2351
+ }
2352
+ }
2353
+ else if (learned.slice(1) === 'Epomeg') {
2354
+ // Pomeg glitched moves have to be from an egg but since they aren't true egg moves,
2355
+ // there should be no breeding restrictions
2356
+ moveSources.pomegEggMoves = [move.id];
2284
2357
  }
2285
2358
  else if (learnedGen < 6) {
2286
2359
  limitedEggMove = move.id;
@@ -2288,7 +2361,7 @@ class TeamValidator {
2288
2361
  learned = learnedGen + 'E' + (species.prevo ? species.id : '');
2289
2362
  if (tradebackEligible && learnedGen === 2 && move.gen <= 1) {
2290
2363
  // can tradeback
2291
- moveSources.add('1ET' + learned.slice(2));
2364
+ moveSources.add('1ET' + learned.slice(2), limitedEggMove);
2292
2365
  }
2293
2366
  moveSources.add(learned, limitedEggMove);
2294
2367
  }
@@ -2302,6 +2375,10 @@ class TeamValidator {
2302
2375
  moveSources.add('1ST' + learned.slice(2) + ' ' + species.id);
2303
2376
  }
2304
2377
  moveSources.add(learned + ' ' + species.id);
2378
+ const eventLearnset = dex.species.getLearnsetData(species.id);
2379
+ if (eventLearnset.eventData?.[parseInt(learned.charAt(2))].emeraldEventEgg && learnedGen === 3) {
2380
+ moveSources.pomegEventEgg = learned + ' ' + species.id;
2381
+ }
2305
2382
  }
2306
2383
  else if (learned.charAt(1) === 'D') {
2307
2384
  // DW moves:
@@ -2428,7 +2505,7 @@ class TeamValidator {
2428
2505
  // different learnsets. To prevent a leak, we make them show up as their
2429
2506
  // base forme, but hardcode their learnsets into Rockruff-Dusk and
2430
2507
  // Greninja-Ash
2431
- if (['Gastrodon', 'Pumpkaboo', 'Sinistea'].includes(species.baseSpecies) && species.forme) {
2508
+ if (['Gastrodon', 'Pumpkaboo', 'Sinistea', 'Tatsugiri'].includes(species.baseSpecies) && species.forme) {
2432
2509
  return this.dex.species.get(species.baseSpecies);
2433
2510
  }
2434
2511
  else if (species.name === 'Lycanroc-Dusk') {