@pkmn/randoms 0.5.4 → 0.5.5
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/gen1.js +7 -1
- package/build/gen1.js.map +1 -1
- package/build/gen3.js +10 -2
- package/build/gen3.js.map +1 -1
- package/build/gen5.js +4 -0
- package/build/gen5.js.map +1 -1
- package/build/gen6.js +1 -0
- package/build/gen6.js.map +1 -1
- package/build/gen7.js +3 -0
- package/build/gen7.js.map +1 -1
- package/build/gen8.d.ts +19 -2
- package/build/gen8.js +289 -40
- package/build/gen8.js.map +1 -1
- package/package.json +2 -2
- package/src/gen1.ts +10 -1
- package/src/gen3.ts +9 -2
- package/src/gen5.ts +5 -0
- package/src/gen6.ts +2 -0
- package/src/gen7.ts +6 -0
- package/src/gen8.ts +272 -36
package/src/gen3.ts
CHANGED
|
@@ -28,7 +28,10 @@ export class RandomGen3Teams extends RandomGen4Teams {
|
|
|
28
28
|
Fighting: (movePool, moves, abilities, types, counter) => !counter.get('Fighting'),
|
|
29
29
|
Fire: (movePool, moves, abilities, types, counter) => !counter.get('Fire'),
|
|
30
30
|
Ground: (movePool, moves, abilities, types, counter) => !counter.get('Ground'),
|
|
31
|
-
Normal: (movePool, moves, abilities, types, counter) =>
|
|
31
|
+
Normal: (movePool, moves, abilities, types, counter, species) => {
|
|
32
|
+
if (species.id === 'blissey' && movePool.includes('softboiled')) return true;
|
|
33
|
+
return !counter.get('Normal') && counter.setupType === 'Physical';
|
|
34
|
+
},
|
|
32
35
|
Psychic: (movePool, moves, abilities, types, counter, species) => (
|
|
33
36
|
types.has('Psychic') &&
|
|
34
37
|
(movePool.includes('psychic') || movePool.includes('psychoboost')) &&
|
|
@@ -41,6 +44,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
|
|
|
41
44
|
// If the Pokémon has this move, the other move will be forced
|
|
42
45
|
protect: movePool => movePool.includes('wish'),
|
|
43
46
|
sunnyday: movePool => movePool.includes('solarbeam'),
|
|
47
|
+
sleeptalk: movePool => movePool.includes('rest'),
|
|
44
48
|
};
|
|
45
49
|
}
|
|
46
50
|
|
|
@@ -82,11 +86,12 @@ export class RandomGen3Teams extends RandomGen4Teams {
|
|
|
82
86
|
|
|
83
87
|
// Not very useful without their supporting moves
|
|
84
88
|
case 'amnesia': case 'sleeptalk':
|
|
89
|
+
if (!moves.has('rest')) return {cull: true};
|
|
85
90
|
if (movePool.length > 1) {
|
|
86
91
|
const rest = movePool.indexOf('rest');
|
|
87
92
|
if (rest >= 0) this.fastPop(movePool, rest);
|
|
88
93
|
}
|
|
89
|
-
|
|
94
|
+
break;
|
|
90
95
|
case 'barrier':
|
|
91
96
|
return {cull: !moves.has('calmmind') && !moves.has('batonpass') && !moves.has('mirrorcoat')};
|
|
92
97
|
case 'batonpass':
|
|
@@ -575,6 +580,8 @@ export class RandomGen3Teams extends RandomGen4Teams {
|
|
|
575
580
|
}
|
|
576
581
|
|
|
577
582
|
randomTeam() {
|
|
583
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
584
|
+
|
|
578
585
|
const seed = this.prng.seed;
|
|
579
586
|
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
|
580
587
|
const pokemon: RandomTeamsTypes.RandomSet[] = [];
|
package/src/gen5.ts
CHANGED
|
@@ -729,6 +729,9 @@ export class RandomGen5Teams extends RandomGen6Teams {
|
|
|
729
729
|
NUBL: 86,
|
|
730
730
|
NU: 86,
|
|
731
731
|
'(NU)': 88,
|
|
732
|
+
PUBL: 88,
|
|
733
|
+
PU: 88,
|
|
734
|
+
'(PU)': 90,
|
|
732
735
|
};
|
|
733
736
|
const customScale: {[forme: string]: number} = {
|
|
734
737
|
Delibird: 100, 'Farfetch\u2019d': 100, Luvdisc: 100, Unown: 100,
|
|
@@ -780,6 +783,8 @@ export class RandomGen5Teams extends RandomGen6Teams {
|
|
|
780
783
|
}
|
|
781
784
|
|
|
782
785
|
randomTeam() {
|
|
786
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
787
|
+
|
|
783
788
|
const seed = this.prng.seed;
|
|
784
789
|
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
|
785
790
|
const pokemon: RandomTeamsTypes.RandomSet[] = [];
|
package/src/gen6.ts
CHANGED
|
@@ -1207,6 +1207,8 @@ export class RandomGen6Teams extends RandomGen7Teams {
|
|
|
1207
1207
|
}
|
|
1208
1208
|
|
|
1209
1209
|
randomFactoryTeam(side: PlayerOptions, depth = 0): RandomTeamsTypes.RandomFactorySet[] {
|
|
1210
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
1211
|
+
|
|
1210
1212
|
const forceResult = (depth >= 4);
|
|
1211
1213
|
|
|
1212
1214
|
// The teams generated depend on the tier choice in such a way that
|
package/src/gen7.ts
CHANGED
|
@@ -1467,6 +1467,8 @@ export class RandomGen7Teams extends RandomTeams {
|
|
|
1467
1467
|
}
|
|
1468
1468
|
|
|
1469
1469
|
randomTeam() {
|
|
1470
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
1471
|
+
|
|
1470
1472
|
const seed = this.prng.seed;
|
|
1471
1473
|
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
|
1472
1474
|
const pokemon = [];
|
|
@@ -1739,6 +1741,8 @@ export class RandomGen7Teams extends RandomTeams {
|
|
|
1739
1741
|
}
|
|
1740
1742
|
|
|
1741
1743
|
randomFactoryTeam(side: PlayerOptions, depth = 0): RandomTeamsTypes.RandomFactorySet[] {
|
|
1744
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
1745
|
+
|
|
1742
1746
|
const forceResult = (depth >= 4);
|
|
1743
1747
|
const isMonotype = !!this.forceMonotype || this.dex.formats.getRuleTable(this.format).has('sametypeclause');
|
|
1744
1748
|
|
|
@@ -2026,6 +2030,8 @@ export class RandomGen7Teams extends RandomTeams {
|
|
|
2026
2030
|
}
|
|
2027
2031
|
|
|
2028
2032
|
randomBSSFactoryTeam(side: PlayerOptions, depth = 0): RandomTeamsTypes.RandomFactorySet[] {
|
|
2033
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
2034
|
+
|
|
2029
2035
|
const forceResult = (depth >= 4);
|
|
2030
2036
|
|
|
2031
2037
|
const pokemon = [];
|
package/src/gen8.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import {Utils} from './utils';
|
|
2
2
|
import {
|
|
3
|
+
Ability,
|
|
3
4
|
AnyObject,
|
|
5
|
+
BasicEffect,
|
|
6
|
+
Dex,
|
|
4
7
|
Format,
|
|
5
|
-
|
|
8
|
+
Item,
|
|
6
9
|
ModdedDex,
|
|
7
10
|
Move,
|
|
11
|
+
Nature,
|
|
8
12
|
PRNG,
|
|
9
13
|
PRNGSeed,
|
|
10
14
|
PlayerOptions,
|
|
@@ -13,6 +17,7 @@ import {
|
|
|
13
17
|
Species,
|
|
14
18
|
StatID,
|
|
15
19
|
StatsTable,
|
|
20
|
+
Tags,
|
|
16
21
|
toID,
|
|
17
22
|
} from '@pkmn/sim';
|
|
18
23
|
|
|
@@ -276,6 +281,7 @@ export class RandomTeams {
|
|
|
276
281
|
*/
|
|
277
282
|
sampleNoReplace(list: any[]) {
|
|
278
283
|
const length = list.length;
|
|
284
|
+
if (length === 0) return null;
|
|
279
285
|
const index = this.random(length);
|
|
280
286
|
return this.fastPop(list, index);
|
|
281
287
|
}
|
|
@@ -294,6 +300,54 @@ export class RandomTeams {
|
|
|
294
300
|
return samples;
|
|
295
301
|
}
|
|
296
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Check if user has directly tried to ban/unban/restrict things in a custom battle.
|
|
305
|
+
* Doesn't count bans nested inside other formats/rules.
|
|
306
|
+
*/
|
|
307
|
+
private hasDirectCustomBanlistChanges() {
|
|
308
|
+
if (!this.format.customRules) return false;
|
|
309
|
+
for (const rule of this.format.customRules) {
|
|
310
|
+
for (const banlistOperator of ['-', '+', '*']) {
|
|
311
|
+
if (rule.startsWith(banlistOperator)) return true;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Inform user when custom bans are unsupported in a team generator.
|
|
319
|
+
*/
|
|
320
|
+
protected enforceNoDirectCustomBanlistChanges() {
|
|
321
|
+
if (this.hasDirectCustomBanlistChanges()) {
|
|
322
|
+
throw new Error(`Custom bans are not currently supported in ${this.format.name}.`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Inform user when complex bans are unsupported in a team generator.
|
|
328
|
+
*/
|
|
329
|
+
protected enforceNoDirectComplexBans() {
|
|
330
|
+
if (!this.format.customRules) return false;
|
|
331
|
+
for (const rule of this.format.customRules) {
|
|
332
|
+
if (rule.includes('+') && !rule.startsWith('+')) {
|
|
333
|
+
throw new Error(`Complex bans are not currently supported in ${this.format.name}.`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Validate set element pool size is sufficient to support size requirements after simple bans.
|
|
340
|
+
*/
|
|
341
|
+
private enforceCustomPoolSizeNoComplexBans(
|
|
342
|
+
effectTypeName: string,
|
|
343
|
+
basicEffectPool: BasicEffect[],
|
|
344
|
+
requiredCount: number,
|
|
345
|
+
requiredCountExplanation: string
|
|
346
|
+
) {
|
|
347
|
+
if (basicEffectPool.length >= requiredCount) return;
|
|
348
|
+
throw new Error(`Legal ${effectTypeName} count is insufficient to support ${requiredCountExplanation} (${basicEffectPool.length} / ${requiredCount}).`);
|
|
349
|
+
}
|
|
350
|
+
|
|
297
351
|
unrejectableMovesInSingles(move: Move) {
|
|
298
352
|
// These moves cannot be rejected in favor of a forced move in singles
|
|
299
353
|
return (move.category !== 'Status' || !move.flags.heal) && ![
|
|
@@ -308,6 +362,8 @@ export class RandomTeams {
|
|
|
308
362
|
}
|
|
309
363
|
|
|
310
364
|
randomCCTeam(): RandomTeamsTypes.RandomSet[] {
|
|
365
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
366
|
+
|
|
311
367
|
const dex = this.dex;
|
|
312
368
|
const team = [];
|
|
313
369
|
|
|
@@ -467,7 +523,7 @@ export class RandomTeams {
|
|
|
467
523
|
return team;
|
|
468
524
|
}
|
|
469
525
|
|
|
470
|
-
randomNPokemon(n: number, requiredType?: string, minSourceGen?: number) {
|
|
526
|
+
randomNPokemon(n: number, requiredType?: string, minSourceGen?: number, ruleTable?: Dex.RuleTable) {
|
|
471
527
|
// Picks `n` random pokemon--no repeats, even among formes
|
|
472
528
|
// Also need to either normalize for formes or select formes at random
|
|
473
529
|
// Unreleased are okay but no CAP
|
|
@@ -478,15 +534,65 @@ export class RandomTeams {
|
|
|
478
534
|
throw new Error(`"${requiredType}" is not a valid type.`);
|
|
479
535
|
}
|
|
480
536
|
|
|
537
|
+
const isNotCustom = !ruleTable;
|
|
538
|
+
|
|
481
539
|
const pool: number[] = [];
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
540
|
+
let speciesPool: Species[] = [];
|
|
541
|
+
if (isNotCustom) {
|
|
542
|
+
speciesPool = [...this.dex.species.all()];
|
|
543
|
+
for (const species of speciesPool) {
|
|
544
|
+
if (species.isNonstandard && species.isNonstandard !== 'Unobtainable') continue;
|
|
545
|
+
if (requiredType && !species.types.includes(requiredType)) continue;
|
|
546
|
+
if (minSourceGen && species.gen < minSourceGen) continue;
|
|
547
|
+
const num = species.num;
|
|
548
|
+
if (num <= 0 || pool.includes(num)) continue;
|
|
549
|
+
if (num > last) break;
|
|
550
|
+
pool.push(num);
|
|
551
|
+
}
|
|
552
|
+
} else {
|
|
553
|
+
const EXISTENCE_TAG = ['past', 'future', 'lgpe', 'unobtainable', 'cap', 'custom', 'nonexistent'];
|
|
554
|
+
const nonexistentBanReason = ruleTable.check('nonexistent');
|
|
555
|
+
// Assume tierSpecies does not differ from species here (mega formes can be used without their stone, etc)
|
|
556
|
+
for (const species of this.dex.species.all()) {
|
|
557
|
+
if (requiredType && !species.types.includes(requiredType)) continue;
|
|
558
|
+
|
|
559
|
+
let banReason = ruleTable.check('pokemon:' + species.id);
|
|
560
|
+
if (banReason) continue;
|
|
561
|
+
if (banReason !== '') {
|
|
562
|
+
if (species.isMega && ruleTable.check('pokemontag:mega')) continue;
|
|
563
|
+
|
|
564
|
+
banReason = ruleTable.check('basepokemon:' + toID(species.baseSpecies));
|
|
565
|
+
if (banReason) continue;
|
|
566
|
+
if (banReason !== '' || this.dex.species.get(species.baseSpecies).isNonstandard === species.isNonstandard) {
|
|
567
|
+
const nonexistentCheck = Tags.nonexistent.genericFilter!(species) && nonexistentBanReason;
|
|
568
|
+
let tagWhitelisted = false;
|
|
569
|
+
let tagBlacklisted = false;
|
|
570
|
+
for (const ruleid of ruleTable.tagRules) {
|
|
571
|
+
if (ruleid.startsWith('*')) continue;
|
|
572
|
+
const tagid = ruleid.slice(12);
|
|
573
|
+
const tag = Tags[tagid];
|
|
574
|
+
if ((tag.speciesFilter || tag.genericFilter)!(species)) {
|
|
575
|
+
const existenceTag = EXISTENCE_TAG.includes(tagid);
|
|
576
|
+
if (ruleid.startsWith('+')) {
|
|
577
|
+
if (!existenceTag && nonexistentCheck) continue;
|
|
578
|
+
tagWhitelisted = true;
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
tagBlacklisted = true;
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (tagBlacklisted) continue;
|
|
586
|
+
if (!tagWhitelisted) {
|
|
587
|
+
if (ruleTable.check('pokemontag:allpokemon')) continue;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
const num = species.num;
|
|
592
|
+
if (pool.includes(num)) continue;
|
|
593
|
+
pool.push(num);
|
|
594
|
+
speciesPool.push(species);
|
|
595
|
+
}
|
|
490
596
|
}
|
|
491
597
|
|
|
492
598
|
const hasDexNumber: {[k: string]: number} = {};
|
|
@@ -496,12 +602,16 @@ export class RandomTeams {
|
|
|
496
602
|
}
|
|
497
603
|
|
|
498
604
|
const formes: string[][] = [];
|
|
499
|
-
for (const species of
|
|
605
|
+
for (const species of speciesPool) {
|
|
500
606
|
if (!(species.num in hasDexNumber)) continue;
|
|
501
|
-
if (species.gen
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
607
|
+
if (isNotCustom && (species.gen > this.gen ||
|
|
608
|
+
(species.isNonstandard && species.isNonstandard !== 'Unobtainable'))) continue;
|
|
609
|
+
if (!formes[hasDexNumber[species.num]]) formes[hasDexNumber[species.num]] = [];
|
|
610
|
+
formes[hasDexNumber[species.num]].push(species.name);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (formes.length < n) {
|
|
614
|
+
throw new Error(`Legal Pokemon forme count insufficient to support Max Team Size: (${formes.length} / ${n}).`);
|
|
505
615
|
}
|
|
506
616
|
|
|
507
617
|
const nPokemon = [];
|
|
@@ -515,15 +625,138 @@ export class RandomTeams {
|
|
|
515
625
|
}
|
|
516
626
|
|
|
517
627
|
randomHCTeam(): PokemonSet[] {
|
|
518
|
-
const
|
|
628
|
+
const hasCustomBans = this.hasDirectCustomBanlistChanges();
|
|
629
|
+
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
|
630
|
+
const hasNonexistentBan = hasCustomBans && ruleTable.check('nonexistent');
|
|
631
|
+
const hasNonexistentWhitelist = hasCustomBans && (hasNonexistentBan === '');
|
|
519
632
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const naturePool = this.dex.natures.all();
|
|
633
|
+
if (hasCustomBans) {
|
|
634
|
+
this.enforceNoDirectComplexBans();
|
|
635
|
+
}
|
|
524
636
|
|
|
525
|
-
|
|
637
|
+
// Item Pool
|
|
638
|
+
const doItemsExist = this.gen > 1;
|
|
639
|
+
let itemPool: Item[] = [];
|
|
640
|
+
if (doItemsExist) {
|
|
641
|
+
if (!hasCustomBans) {
|
|
642
|
+
itemPool = [...this.dex.items.all()].filter(item => (item.gen <= this.gen && !item.isNonstandard));
|
|
643
|
+
} else {
|
|
644
|
+
const hasAllItemsBan = ruleTable.check('pokemontag:allitems');
|
|
645
|
+
for (const item of this.dex.items.all()) {
|
|
646
|
+
let banReason = ruleTable.check('item:' + item.id);
|
|
647
|
+
if (banReason) continue;
|
|
648
|
+
if (banReason !== '' && item.id) {
|
|
649
|
+
if (hasAllItemsBan) continue;
|
|
650
|
+
if (item.isNonstandard) {
|
|
651
|
+
banReason = ruleTable.check('pokemontag:' + toID(item.isNonstandard));
|
|
652
|
+
if (banReason) continue;
|
|
653
|
+
if (banReason !== '' && item.isNonstandard !== 'Unobtainable') {
|
|
654
|
+
if (hasNonexistentBan) continue;
|
|
655
|
+
if (!hasNonexistentWhitelist) continue;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
itemPool.push(item);
|
|
660
|
+
}
|
|
661
|
+
if (ruleTable.check('item:noitem')) {
|
|
662
|
+
this.enforceCustomPoolSizeNoComplexBans('item', itemPool, this.maxTeamSize, 'Max Team Size');
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
526
666
|
|
|
667
|
+
// Ability Pool
|
|
668
|
+
const doAbilitiesExist = (this.gen > 2) && (this.dex.currentMod !== 'gen7letsgo');
|
|
669
|
+
let abilityPool: Ability[] = [];
|
|
670
|
+
if (doAbilitiesExist) {
|
|
671
|
+
if (!hasCustomBans) {
|
|
672
|
+
abilityPool = [...this.dex.abilities.all()].filter(ability => (ability.gen <= this.gen && !ability.isNonstandard));
|
|
673
|
+
} else {
|
|
674
|
+
const hasAllAbilitiesBan = ruleTable.check('pokemontag:allabilities');
|
|
675
|
+
for (const ability of this.dex.abilities.all()) {
|
|
676
|
+
let banReason = ruleTable.check('ability:' + ability.id);
|
|
677
|
+
if (banReason) continue;
|
|
678
|
+
if (banReason !== '') {
|
|
679
|
+
if (hasAllAbilitiesBan) continue;
|
|
680
|
+
if (ability.isNonstandard) {
|
|
681
|
+
banReason = ruleTable.check('pokemontag:' + toID(ability.isNonstandard));
|
|
682
|
+
if (banReason) continue;
|
|
683
|
+
if (banReason !== '') {
|
|
684
|
+
if (hasNonexistentBan) continue;
|
|
685
|
+
if (!hasNonexistentWhitelist) continue;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
abilityPool.push(ability);
|
|
690
|
+
}
|
|
691
|
+
if (ruleTable.check('ability:noability')) {
|
|
692
|
+
this.enforceCustomPoolSizeNoComplexBans('ability', abilityPool, this.maxTeamSize, 'Max Team Size');
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// Move Pool
|
|
698
|
+
const setMoveCount = ruleTable.maxMoveCount;
|
|
699
|
+
let movePool: Move[] = [];
|
|
700
|
+
if (!hasCustomBans) {
|
|
701
|
+
movePool = [...this.dex.moves.all()].filter(move =>
|
|
702
|
+
(move.gen <= this.gen && !move.isNonstandard && !move.name.startsWith('Hidden Power ')));
|
|
703
|
+
} else {
|
|
704
|
+
const hasAllMovesBan = ruleTable.check('pokemontag:allmoves');
|
|
705
|
+
for (const move of this.dex.moves.all()) {
|
|
706
|
+
// Legality of specific HP types can't be altered in built formats anyway
|
|
707
|
+
if (move.name.startsWith('Hidden Power ')) continue;
|
|
708
|
+
let banReason = ruleTable.check('move:' + move.id);
|
|
709
|
+
if (banReason) continue;
|
|
710
|
+
if (banReason !== '') {
|
|
711
|
+
if (hasAllMovesBan) continue;
|
|
712
|
+
if (move.isNonstandard) {
|
|
713
|
+
banReason = ruleTable.check('pokemontag:' + toID(move.isNonstandard));
|
|
714
|
+
if (banReason) continue;
|
|
715
|
+
if (banReason !== '' && move.isNonstandard !== 'Unobtainable') {
|
|
716
|
+
if (hasNonexistentBan) continue;
|
|
717
|
+
if (!hasNonexistentWhitelist) continue;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
movePool.push(move);
|
|
722
|
+
}
|
|
723
|
+
this.enforceCustomPoolSizeNoComplexBans('move', movePool, this.maxTeamSize * setMoveCount, 'Max Team Size * Max Move Count');
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// Nature Pool
|
|
727
|
+
const doNaturesExist = this.gen > 2;
|
|
728
|
+
let naturePool: Nature[] = [];
|
|
729
|
+
if (doNaturesExist) {
|
|
730
|
+
if (!hasCustomBans) {
|
|
731
|
+
if (!hasCustomBans) {
|
|
732
|
+
naturePool = [...this.dex.natures.all()];
|
|
733
|
+
} else {
|
|
734
|
+
const hasAllNaturesBan = ruleTable.check('pokemontag:allnatures');
|
|
735
|
+
for (const nature of this.dex.natures.all()) {
|
|
736
|
+
let banReason = ruleTable.check('nature:' + nature.id);
|
|
737
|
+
if (banReason) continue;
|
|
738
|
+
if (banReason !== '' && nature.id) {
|
|
739
|
+
if (hasAllNaturesBan) continue;
|
|
740
|
+
if (nature.isNonstandard) {
|
|
741
|
+
banReason = ruleTable.check('pokemontag:' + toID(nature.isNonstandard));
|
|
742
|
+
if (banReason) continue;
|
|
743
|
+
if (banReason !== '' && nature.isNonstandard !== 'Unobtainable') {
|
|
744
|
+
if (hasNonexistentBan) continue;
|
|
745
|
+
if (!hasNonexistentWhitelist) continue;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
naturePool.push(nature);
|
|
750
|
+
}
|
|
751
|
+
// There is no 'nature:nonature' rule so do not constrain pool size
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const randomN = this.randomNPokemon(this.maxTeamSize, this.forceMonotype, undefined,
|
|
757
|
+
hasCustomBans ? ruleTable : undefined);
|
|
758
|
+
|
|
759
|
+
const team = [];
|
|
527
760
|
for (const forme of randomN) {
|
|
528
761
|
// Choose forme
|
|
529
762
|
const species = this.dex.species.get(forme);
|
|
@@ -531,31 +764,25 @@ export class RandomTeams {
|
|
|
531
764
|
// Random unique item
|
|
532
765
|
let item = '';
|
|
533
766
|
let itemData;
|
|
534
|
-
if (
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
item = itemData.name;
|
|
538
|
-
} while (itemData.gen > this.gen || itemData.isNonstandard);
|
|
767
|
+
if (doItemsExist) {
|
|
768
|
+
itemData = this.sampleNoReplace(itemPool);
|
|
769
|
+
item = itemData?.name;
|
|
539
770
|
}
|
|
540
771
|
|
|
541
772
|
// Random unique ability
|
|
542
773
|
let ability = 'No Ability';
|
|
543
774
|
let abilityData;
|
|
544
|
-
if (
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
ability = abilityData.name;
|
|
548
|
-
} while (abilityData.gen > this.gen || abilityData.isNonstandard);
|
|
775
|
+
if (doAbilitiesExist) {
|
|
776
|
+
abilityData = this.sampleNoReplace(abilityPool);
|
|
777
|
+
ability = abilityData?.name;
|
|
549
778
|
}
|
|
550
779
|
|
|
551
780
|
// Random unique moves
|
|
552
781
|
const m = [];
|
|
553
782
|
do {
|
|
554
783
|
const move = this.sampleNoReplace(movePool);
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}
|
|
558
|
-
} while (m.length < 4);
|
|
784
|
+
m.push(move.id);
|
|
785
|
+
} while (m.length < setMoveCount);
|
|
559
786
|
|
|
560
787
|
// Random EVs
|
|
561
788
|
const evs = {hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0};
|
|
@@ -584,7 +811,10 @@ export class RandomTeams {
|
|
|
584
811
|
};
|
|
585
812
|
|
|
586
813
|
// Random nature
|
|
587
|
-
|
|
814
|
+
let nature = '';
|
|
815
|
+
if (doNaturesExist && (naturePool.length > 0)) {
|
|
816
|
+
nature = this.sample(naturePool).name;
|
|
817
|
+
}
|
|
588
818
|
|
|
589
819
|
// Level balance
|
|
590
820
|
const mbstmin = 1307;
|
|
@@ -2127,6 +2357,8 @@ export class RandomTeams {
|
|
|
2127
2357
|
}
|
|
2128
2358
|
|
|
2129
2359
|
randomTeam() {
|
|
2360
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
2361
|
+
|
|
2130
2362
|
const seed = this.prng.seed;
|
|
2131
2363
|
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
|
2132
2364
|
const pokemon: RandomTeamsTypes.RandomSet[] = [];
|
|
@@ -2299,6 +2531,8 @@ export class RandomTeams {
|
|
|
2299
2531
|
randomCAP1v1Sets: AnyObject = {};
|
|
2300
2532
|
|
|
2301
2533
|
randomCAP1v1Team() {
|
|
2534
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
2535
|
+
|
|
2302
2536
|
const pokemon = [];
|
|
2303
2537
|
const pokemonPool = Object.keys(this.randomCAP1v1Sets);
|
|
2304
2538
|
|
|
@@ -2402,6 +2636,8 @@ export class RandomTeams {
|
|
|
2402
2636
|
}
|
|
2403
2637
|
|
|
2404
2638
|
randomBSSFactoryTeam(side: PlayerOptions, depth = 0): RandomTeamsTypes.RandomFactorySet[] {
|
|
2639
|
+
this.enforceNoDirectCustomBanlistChanges();
|
|
2640
|
+
|
|
2405
2641
|
const forceResult = (depth >= 4);
|
|
2406
2642
|
|
|
2407
2643
|
const pokemon = [];
|