@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.
- package/build/cjs/config/formats.js +98 -56
- package/build/cjs/config/formats.js.map +1 -1
- package/build/cjs/data/abilities.js +4 -1
- package/build/cjs/data/abilities.js.map +1 -1
- package/build/cjs/data/aliases.js +1 -1
- package/build/cjs/data/formats-data.js +36 -23
- package/build/cjs/data/formats-data.js.map +1 -1
- package/build/cjs/data/learnsets.js +157 -4
- package/build/cjs/data/learnsets.js.map +1 -1
- package/build/cjs/data/legality.js +260 -50
- package/build/cjs/data/legality.js.map +1 -1
- package/build/cjs/data/mods/gen4/moves.js +3 -3
- package/build/cjs/data/mods/gen4/moves.js.map +1 -1
- package/build/cjs/data/pokedex.js +39 -3
- package/build/cjs/data/pokedex.js.map +1 -1
- package/build/cjs/sim/team-validator.js +100 -23
- package/build/cjs/sim/team-validator.js.map +1 -1
- package/build/esm/config/formats.mjs +98 -56
- package/build/esm/config/formats.mjs.map +1 -1
- package/build/esm/data/abilities.mjs +4 -1
- package/build/esm/data/abilities.mjs.map +1 -1
- package/build/esm/data/aliases.mjs +1 -1
- package/build/esm/data/formats-data.mjs +36 -23
- package/build/esm/data/formats-data.mjs.map +1 -1
- package/build/esm/data/learnsets.mjs +157 -4
- package/build/esm/data/learnsets.mjs.map +1 -1
- package/build/esm/data/legality.mjs +260 -50
- package/build/esm/data/legality.mjs.map +1 -1
- package/build/esm/data/mods/gen4/moves.mjs +3 -3
- package/build/esm/data/mods/gen4/moves.mjs.map +1 -1
- package/build/esm/data/pokedex.mjs +39 -3
- package/build/esm/data/pokedex.mjs.map +1 -1
- package/build/esm/sim/team-validator.mjs +100 -23
- package/build/esm/sim/team-validator.mjs.map +1 -1
- package/build/types/sim/exported-global-types.d.ts +14 -1
- package/build/types/sim/global-types.d.ts +14 -1
- package/build/types/sim/team-validator.d.ts +16 -0
- package/package.json +1 -1
|
@@ -45,6 +45,9 @@ export class PokemonSources {
|
|
|
45
45
|
add(source, limitedEggMove) {
|
|
46
46
|
if (this.sources[this.sources.length - 1] !== source)
|
|
47
47
|
this.sources.push(source);
|
|
48
|
+
if (limitedEggMove && source.substr(0, 3) === '1ET') {
|
|
49
|
+
this.possiblyLimitedEggMoves = [limitedEggMove];
|
|
50
|
+
}
|
|
48
51
|
if (limitedEggMove && this.limitedEggMoves !== null) {
|
|
49
52
|
this.limitedEggMoves = [limitedEggMove];
|
|
50
53
|
}
|
|
@@ -79,6 +82,24 @@ export class PokemonSources {
|
|
|
79
82
|
return max;
|
|
80
83
|
}
|
|
81
84
|
intersectWith(other) {
|
|
85
|
+
if (this.pomegEventEgg && other.pomegEggMoves) {
|
|
86
|
+
const newSources = [];
|
|
87
|
+
for (const source of other.sources) {
|
|
88
|
+
newSources.push(source.substr(0, 2) === '3E' ? this.pomegEventEgg : source);
|
|
89
|
+
}
|
|
90
|
+
other.sources = newSources;
|
|
91
|
+
}
|
|
92
|
+
else if (other.pomegEventEgg && this.pomegEventEgg !== null) {
|
|
93
|
+
const newSources = [];
|
|
94
|
+
for (const source of this.sources) {
|
|
95
|
+
newSources.push(source.substr(0, 2) === '3E' ? other.pomegEventEgg : source);
|
|
96
|
+
}
|
|
97
|
+
this.sources = newSources;
|
|
98
|
+
this.pomegEventEgg = other.pomegEventEgg;
|
|
99
|
+
}
|
|
100
|
+
else if (!other.pomegEggMoves && !other.sourcesBefore) {
|
|
101
|
+
this.pomegEventEgg = null;
|
|
102
|
+
}
|
|
82
103
|
if (other.sourcesBefore || this.sourcesBefore) {
|
|
83
104
|
// having sourcesBefore is the equivalent of having everything before that gen
|
|
84
105
|
// in sources, so we fill the other array in preparation for intersection
|
|
@@ -128,6 +149,37 @@ export class PokemonSources {
|
|
|
128
149
|
this.limitedEggMoves.push(...other.limitedEggMoves);
|
|
129
150
|
}
|
|
130
151
|
}
|
|
152
|
+
if (other.possiblyLimitedEggMoves) {
|
|
153
|
+
if (!this.possiblyLimitedEggMoves) {
|
|
154
|
+
this.possiblyLimitedEggMoves = other.possiblyLimitedEggMoves;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
this.possiblyLimitedEggMoves.push(...other.possiblyLimitedEggMoves);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (other.pomegEggMoves) {
|
|
161
|
+
if (!this.pomegEggMoves) {
|
|
162
|
+
this.pomegEggMoves = other.pomegEggMoves;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
this.pomegEggMoves.push(...other.pomegEggMoves);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
let eggTradebackLegal = false;
|
|
169
|
+
for (const source of this.sources) {
|
|
170
|
+
if (source.substr(0, 3) === '1ET') {
|
|
171
|
+
eggTradebackLegal = true;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (!eggTradebackLegal && this.possiblyLimitedEggMoves) {
|
|
176
|
+
for (const eggMove of this.possiblyLimitedEggMoves) {
|
|
177
|
+
if (!this.limitedEggMoves)
|
|
178
|
+
this.limitedEggMoves = [];
|
|
179
|
+
if (!this.limitedEggMoves.includes(eggMove))
|
|
180
|
+
this.limitedEggMoves.push(eggMove);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
131
183
|
this.moveEvoCarryCount += other.moveEvoCarryCount;
|
|
132
184
|
this.dreamWorldMoveCount += other.dreamWorldMoveCount;
|
|
133
185
|
if (other.sourcesAfter > this.sourcesAfter)
|
|
@@ -640,20 +692,23 @@ export class TeamValidator {
|
|
|
640
692
|
evoSpecies = dex.species.get(evoSpecies.prevo);
|
|
641
693
|
}
|
|
642
694
|
}
|
|
643
|
-
|
|
695
|
+
let moveProblems;
|
|
644
696
|
if (ruleTable.has('obtainablemoves')) {
|
|
697
|
+
moveProblems = this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist);
|
|
645
698
|
problems.push(...moveProblems);
|
|
646
699
|
}
|
|
647
700
|
let eventOnlyData;
|
|
648
701
|
if (!setSources.sourcesBefore && setSources.sources.length) {
|
|
649
|
-
|
|
702
|
+
const legalSources = [];
|
|
650
703
|
for (const source of setSources.sources) {
|
|
651
704
|
if (this.validateSource(set, source, setSources, outOfBattleSpecies))
|
|
652
705
|
continue;
|
|
653
|
-
|
|
654
|
-
break;
|
|
706
|
+
legalSources.push(source);
|
|
655
707
|
}
|
|
656
|
-
if (
|
|
708
|
+
if (legalSources.length) {
|
|
709
|
+
setSources.sources = legalSources;
|
|
710
|
+
}
|
|
711
|
+
else {
|
|
657
712
|
let nonEggSource = null;
|
|
658
713
|
for (const source of setSources.sources) {
|
|
659
714
|
if (source.charAt(1) !== 'E') {
|
|
@@ -730,15 +785,6 @@ export class TeamValidator {
|
|
|
730
785
|
}
|
|
731
786
|
}
|
|
732
787
|
}
|
|
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));
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
788
|
// Hardcoded forced validation for Pokemon GO
|
|
743
789
|
const pokemonGoOnlySpecies = ['meltan', 'melmetal', 'gimmighoulroaming'];
|
|
744
790
|
if (ruleTable.has('obtainablemisc') && (pokemonGoOnlySpecies.includes(species.id))) {
|
|
@@ -753,6 +799,15 @@ export class TeamValidator {
|
|
|
753
799
|
if (ruleTable.isBanned('nonexistent')) {
|
|
754
800
|
problems.push(...this.validateStats(set, species, setSources, pokemonGoProblems));
|
|
755
801
|
}
|
|
802
|
+
// Attempt move validation again after verifying Pokemon GO origin
|
|
803
|
+
if (ruleTable.has('obtainablemoves') && setSources.isFromPokemonGo) {
|
|
804
|
+
setSources.restrictiveMoves = [];
|
|
805
|
+
setSources.sources = ['8V'];
|
|
806
|
+
setSources.sourcesBefore = 0;
|
|
807
|
+
if (moveProblems && !moveProblems.length) {
|
|
808
|
+
problems.push(...this.validateMoves(outOfBattleSpecies, set.moves, setSources, set, name, moveLegalityWhitelist));
|
|
809
|
+
}
|
|
810
|
+
}
|
|
756
811
|
if (ruleTable.has('obtainablemoves')) {
|
|
757
812
|
if (species.id === 'keldeo' && set.moves.includes('secretsword') && this.minSourceGen > 5 && dex.gen <= 7) {
|
|
758
813
|
problems.push(`${name} has Secret Sword, which is only compatible with Keldeo-Ordinary obtained from Gen 5.`);
|
|
@@ -818,7 +873,8 @@ export class TeamValidator {
|
|
|
818
873
|
if (nameSpecies.baseSpecies === species.baseSpecies) {
|
|
819
874
|
set.name = species.baseSpecies;
|
|
820
875
|
}
|
|
821
|
-
else if (nameSpecies.name !== species.name &&
|
|
876
|
+
else if (nameSpecies.name !== species.name &&
|
|
877
|
+
nameSpecies.name !== species.baseSpecies && ruleTable.has('nicknameclause')) {
|
|
822
878
|
// nickname species doesn't match actual species
|
|
823
879
|
// Nickname Clause
|
|
824
880
|
problems.push(`${name} must not be nicknamed a different Pokémon species than what it actually is.`);
|
|
@@ -1145,16 +1201,18 @@ export class TeamValidator {
|
|
|
1145
1201
|
const fathers = [];
|
|
1146
1202
|
// Gen 6+ don't have egg move incompatibilities
|
|
1147
1203
|
// (except for certain cases with baby Pokemon not handled here)
|
|
1148
|
-
if (!getAll && eggGen >= 6)
|
|
1204
|
+
if (!getAll && eggGen >= 6 && species.gender !== 'F')
|
|
1149
1205
|
return true;
|
|
1150
|
-
|
|
1206
|
+
let eggMoves = setSources.limitedEggMoves;
|
|
1207
|
+
if (eggGen === 3)
|
|
1208
|
+
eggMoves = eggMoves?.filter(eggMove => !setSources.pomegEggMoves?.includes(eggMove));
|
|
1151
1209
|
// must have 2 or more egg moves to have egg move incompatibilities
|
|
1152
1210
|
if (!eggMoves) {
|
|
1153
1211
|
// happens often in gen 1-6 LC if your only egg moves are level-up moves,
|
|
1154
1212
|
// which aren't limited and so aren't in `limitedEggMoves`
|
|
1155
1213
|
return getAll ? ['*'] : true;
|
|
1156
1214
|
}
|
|
1157
|
-
if (!getAll && eggMoves.length <= 1)
|
|
1215
|
+
if (!getAll && eggMoves.length <= 1 && species.gender !== 'F')
|
|
1158
1216
|
return true;
|
|
1159
1217
|
// gen 1 eggs come from gen 2 breeding
|
|
1160
1218
|
const dex = this.dex.gen === 1 ? this.dex.mod('gen2') : this.dex;
|
|
@@ -1245,6 +1303,8 @@ export class TeamValidator {
|
|
|
1245
1303
|
learnset = this.dex.species.getLearnset(curSpecies.id);
|
|
1246
1304
|
if (learnset && learnset[move]) {
|
|
1247
1305
|
for (const moveSource of learnset[move]) {
|
|
1306
|
+
if (eggGen > 8 && parseInt(moveSource.charAt(0)) <= 8)
|
|
1307
|
+
continue;
|
|
1248
1308
|
if (parseInt(moveSource.charAt(0)) > eggGen)
|
|
1249
1309
|
continue;
|
|
1250
1310
|
const canLearnFromSmeargle = moveSource.charAt(1) === 'E' && canBreedWithSmeargle;
|
|
@@ -2196,7 +2256,8 @@ export class TeamValidator {
|
|
|
2196
2256
|
// redundant
|
|
2197
2257
|
if (learnedGen <= moveSources.sourcesBefore)
|
|
2198
2258
|
continue;
|
|
2199
|
-
if (baseSpecies.evoRegion === 'Alola' && checkingPrevo && learnedGen >= 8
|
|
2259
|
+
if (baseSpecies.evoRegion === 'Alola' && checkingPrevo && learnedGen >= 8 &&
|
|
2260
|
+
(dex.gen < 9 || learned.charAt(1) !== 'E')) {
|
|
2200
2261
|
cantLearnReason = `is from a ${species.name} that can't be transferred to USUM to evolve into ${baseSpecies.name}.`;
|
|
2201
2262
|
continue;
|
|
2202
2263
|
}
|
|
@@ -2233,6 +2294,7 @@ export class TeamValidator {
|
|
|
2233
2294
|
}
|
|
2234
2295
|
else if (level >= 5 && learnedGen === 3 && species.canHatch) {
|
|
2235
2296
|
// Pomeg Glitch
|
|
2297
|
+
learned = learnedGen + 'Epomeg';
|
|
2236
2298
|
}
|
|
2237
2299
|
else if ((!species.gender || species.gender === 'F') &&
|
|
2238
2300
|
learnedGen >= 2 && species.canHatch && !setSources.isFromPokemonGo) {
|
|
@@ -2247,7 +2309,8 @@ export class TeamValidator {
|
|
|
2247
2309
|
}
|
|
2248
2310
|
}
|
|
2249
2311
|
// Gen 8+ egg moves can be taught to any pokemon from any source
|
|
2250
|
-
if (learnedGen >= 8 && learned.charAt(1) === 'E'
|
|
2312
|
+
if (learnedGen >= 8 && learned.charAt(1) === 'E' && learned.slice(1) !== 'Eany' &&
|
|
2313
|
+
learned.slice(1) !== 'Epomeg' || 'LMTR'.includes(learned.charAt(1))) {
|
|
2251
2314
|
if (learnedGen === dex.gen && learned.charAt(1) !== 'R') {
|
|
2252
2315
|
// current-gen level-up, TM or tutor moves:
|
|
2253
2316
|
// always available
|
|
@@ -2276,7 +2339,17 @@ export class TeamValidator {
|
|
|
2276
2339
|
// only if hatched from an egg
|
|
2277
2340
|
let limitedEggMove = undefined;
|
|
2278
2341
|
if (learned.slice(1) === 'Eany') {
|
|
2279
|
-
|
|
2342
|
+
if (species.gender === 'F') {
|
|
2343
|
+
limitedEggMove = move.id;
|
|
2344
|
+
}
|
|
2345
|
+
else {
|
|
2346
|
+
limitedEggMove = null;
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
else if (learned.slice(1) === 'Epomeg') {
|
|
2350
|
+
// Pomeg glitched moves have to be from an egg but since they aren't true egg moves,
|
|
2351
|
+
// there should be no breeding restrictions
|
|
2352
|
+
moveSources.pomegEggMoves = [move.id];
|
|
2280
2353
|
}
|
|
2281
2354
|
else if (learnedGen < 6) {
|
|
2282
2355
|
limitedEggMove = move.id;
|
|
@@ -2284,7 +2357,7 @@ export class TeamValidator {
|
|
|
2284
2357
|
learned = learnedGen + 'E' + (species.prevo ? species.id : '');
|
|
2285
2358
|
if (tradebackEligible && learnedGen === 2 && move.gen <= 1) {
|
|
2286
2359
|
// can tradeback
|
|
2287
|
-
moveSources.add('1ET' + learned.slice(2));
|
|
2360
|
+
moveSources.add('1ET' + learned.slice(2), limitedEggMove);
|
|
2288
2361
|
}
|
|
2289
2362
|
moveSources.add(learned, limitedEggMove);
|
|
2290
2363
|
}
|
|
@@ -2298,6 +2371,10 @@ export class TeamValidator {
|
|
|
2298
2371
|
moveSources.add('1ST' + learned.slice(2) + ' ' + species.id);
|
|
2299
2372
|
}
|
|
2300
2373
|
moveSources.add(learned + ' ' + species.id);
|
|
2374
|
+
const eventLearnset = dex.species.getLearnsetData(species.id);
|
|
2375
|
+
if (eventLearnset.eventData?.[parseInt(learned.charAt(2))].emeraldEventEgg && learnedGen === 3) {
|
|
2376
|
+
moveSources.pomegEventEgg = learned + ' ' + species.id;
|
|
2377
|
+
}
|
|
2301
2378
|
}
|
|
2302
2379
|
else if (learned.charAt(1) === 'D') {
|
|
2303
2380
|
// DW moves:
|
|
@@ -2424,7 +2501,7 @@ export class TeamValidator {
|
|
|
2424
2501
|
// different learnsets. To prevent a leak, we make them show up as their
|
|
2425
2502
|
// base forme, but hardcode their learnsets into Rockruff-Dusk and
|
|
2426
2503
|
// Greninja-Ash
|
|
2427
|
-
if (['Gastrodon', 'Pumpkaboo', 'Sinistea'].includes(species.baseSpecies) && species.forme) {
|
|
2504
|
+
if (['Gastrodon', 'Pumpkaboo', 'Sinistea', 'Tatsugiri'].includes(species.baseSpecies) && species.forme) {
|
|
2428
2505
|
return this.dex.species.get(species.baseSpecies);
|
|
2429
2506
|
}
|
|
2430
2507
|
else if (species.name === 'Lycanroc-Dusk') {
|