@pkmn/randoms 0.5.10 → 0.5.13

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/src/gen1.ts CHANGED
@@ -41,19 +41,24 @@ export class RandomGen1Teams extends RandomGen2Teams {
41
41
  mbst += (stats["spd"] * 2 + 30 + 63 + 100) + 5;
42
42
  mbst += (stats["spe"] * 2 + 30 + 63 + 100) + 5;
43
43
 
44
- let level = Math.floor(100 * mbstmin / mbst); // Initial level guess will underestimate
45
-
46
- while (level < 100) {
47
- mbst = Math.floor((stats["hp"] * 2 + 30 + 63 + 100) * level / 100 + 10);
48
- // Since damage is roughly proportional to lvl
49
- mbst += Math.floor(((stats["atk"] * 2 + 30 + 63 + 100) * level / 100 + 5) * level / 100);
50
- mbst += Math.floor((stats["def"] * 2 + 30 + 63 + 100) * level / 100 + 5);
51
- mbst += Math.floor(((stats["spa"] * 2 + 30 + 63 + 100) * level / 100 + 5) * level / 100);
52
- mbst += Math.floor((stats["spd"] * 2 + 30 + 63 + 100) * level / 100 + 5);
53
- mbst += Math.floor((stats["spe"] * 2 + 30 + 63 + 100) * level / 100 + 5);
54
-
55
- if (mbst >= mbstmin) break;
56
- level++;
44
+ let level;
45
+ if (this.adjustLevel) {
46
+ level = this.adjustLevel;
47
+ } else {
48
+ level = Math.floor(100 * mbstmin / mbst); // Initial level guess will underestimate
49
+
50
+ while (level < 100) {
51
+ mbst = Math.floor((stats["hp"] * 2 + 30 + 63 + 100) * level / 100 + 10);
52
+ // Since damage is roughly proportional to lvl
53
+ mbst += Math.floor(((stats["atk"] * 2 + 30 + 63 + 100) * level / 100 + 5) * level / 100);
54
+ mbst += Math.floor((stats["def"] * 2 + 30 + 63 + 100) * level / 100 + 5);
55
+ mbst += Math.floor(((stats["spa"] * 2 + 30 + 63 + 100) * level / 100 + 5) * level / 100);
56
+ mbst += Math.floor((stats["spd"] * 2 + 30 + 63 + 100) * level / 100 + 5);
57
+ mbst += Math.floor((stats["spe"] * 2 + 30 + 63 + 100) * level / 100 + 5);
58
+
59
+ if (mbst >= mbstmin) break;
60
+ level++;
61
+ }
57
62
  }
58
63
 
59
64
  // Random DVs.
@@ -298,24 +303,24 @@ export class RandomGen1Teams extends RandomGen2Teams {
298
303
  const SpecialSetup = ['amnesia', 'growth'];
299
304
 
300
305
  // Either add all moves or add none
301
- if (species.comboMoves && this.randomChance(1, 2)) {
306
+ if (species.comboMoves && species.comboMoves.length <= this.maxMoveCount && this.randomChance(1, 2)) {
302
307
  for (const m of species.comboMoves) moves.add(m);
303
308
  }
304
309
 
305
310
  // Add one of the semi-mandatory moves
306
311
  // Often, these are used so that the Pokemon only gets one of the less useful moves
307
- if (moves.size < 4 && species.exclusiveMoves) {
312
+ if (moves.size < this.maxMoveCount && species.exclusiveMoves) {
308
313
  moves.add(this.sample(species.exclusiveMoves));
309
314
  }
310
315
 
311
316
  // Add the mandatory move. SD Mew and Amnesia Snorlax are exceptions.
312
- if (moves.size < 4 && species.essentialMove) {
317
+ if (moves.size < this.maxMoveCount && species.essentialMove) {
313
318
  moves.add(species.essentialMove);
314
319
  }
315
320
 
316
- while (moves.size < 4 && movePool.length) {
321
+ while (moves.size < this.maxMoveCount && movePool.length) {
317
322
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
318
- while (moves.size < 4 && movePool.length) {
323
+ while (moves.size < this.maxMoveCount && movePool.length) {
319
324
  const moveid = this.sampleNoReplace(movePool);
320
325
  moves.add(moveid);
321
326
  }
@@ -361,8 +366,7 @@ export class RandomGen1Teams extends RandomGen2Teams {
361
366
  Caterpie: 100, Metapod: 100, Weedle: 100, Kakuna: 100, Magikarp: 100,
362
367
  Ditto: 88,
363
368
  };
364
- let level = levelScale[species.tier] || 80;
365
- if (customScale[species.name]) level = customScale[species.name];
369
+ const level = this.adjustLevel || customScale[species.name] || levelScale[species.tier] || 80;
366
370
 
367
371
  return {
368
372
  name: species.name,
@@ -420,7 +424,7 @@ export class RandomGen1Teams extends RandomGen2Teams {
420
424
  if (move.gen <= this.gen && !move.isNonstandard && !move.name.startsWith('Hidden Power ')) {
421
425
  moves.push(move.id);
422
426
  }
423
- } while (moves.length < 4);
427
+ } while (moves.length < this.maxMoveCount);
424
428
 
425
429
  // Random EVs
426
430
  const evs = {
@@ -463,16 +467,21 @@ export class RandomGen1Teams extends RandomGen2Teams {
463
467
  mbst += calcStat(statName as StatID);
464
468
  if (statName === 'hp') mbst += 5;
465
469
  }
466
- let level = Math.floor(100 * mbstmin / mbst);
467
- while (level < 100) {
468
- for (const statName of Object.keys(baseStats)) {
469
- mbst += calcStat(statName as StatID, level);
470
- if (statName === 'hp') mbst += 5;
470
+ let level;
471
+ if (this.adjustLevel) {
472
+ level = this.adjustLevel;
473
+ } else {
474
+ level = Math.floor(100 * mbstmin / mbst);
475
+ while (level < 100) {
476
+ for (const statName of Object.keys(baseStats)) {
477
+ mbst += calcStat(statName as StatID, level);
478
+ if (statName === 'hp') mbst += 5;
479
+ }
480
+ if (mbst >= mbstmin) break;
481
+ level++;
471
482
  }
472
- if (mbst >= mbstmin) break;
473
- level++;
483
+ if (level > 100) level = 100;
474
484
  }
475
- if (level > 100) level = 100;
476
485
 
477
486
  team.push({
478
487
  name: species.baseSpecies,
package/src/gen2.ts CHANGED
@@ -175,7 +175,7 @@ export class RandomGen2Teams extends RandomGen3Teams {
175
175
 
176
176
  do {
177
177
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
178
- while (moves.size < 4 && movePool.length) {
178
+ while (moves.size < this.maxMoveCount && movePool.length) {
179
179
  const moveid = this.sampleNoReplace(movePool);
180
180
  if (moveid.startsWith('hiddenpower')) {
181
181
  availableHP--;
@@ -184,7 +184,7 @@ export class RandomGen2Teams extends RandomGen3Teams {
184
184
  }
185
185
  moves.add(moveid);
186
186
  }
187
- while (moves.size < 4 && rejectedPool.length) {
187
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
188
188
  const moveid = this.sampleNoReplace(rejectedPool);
189
189
  if (moveid.startsWith('hiddenpower')) {
190
190
  if (hasHiddenPower) continue;
@@ -259,7 +259,7 @@ export class RandomGen2Teams extends RandomGen3Teams {
259
259
  break;
260
260
  }
261
261
  }
262
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
262
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
263
263
 
264
264
  // Adjust IVs for Hidden Power
265
265
  for (const setMoveid of moves) {
@@ -302,8 +302,7 @@ export class RandomGen2Teams extends RandomGen3Teams {
302
302
  const customScale: {[k: string]: number} = {
303
303
  Ditto: 83, Unown: 87, Wobbuffet: 83,
304
304
  };
305
- let level = levelScale[species.tier] || 80;
306
- if (customScale[species.name]) level = customScale[species.name];
305
+ const level = this.adjustLevel || customScale[species.name] || levelScale[species.tier] || 80;
307
306
 
308
307
  return {
309
308
  name: species.name,
package/src/gen3.ts CHANGED
@@ -86,6 +86,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
86
86
 
87
87
  // Not very useful without their supporting moves
88
88
  case 'amnesia': case 'sleeptalk':
89
+ if (moves.has('roar')) return {cull: true};
89
90
  if (!moves.has('rest')) return {cull: true};
90
91
  if (movePool.length > 1) {
91
92
  const rest = movePool.indexOf('rest');
@@ -176,6 +177,8 @@ export class RandomGen3Teams extends RandomGen4Teams {
176
177
  return {cull: !!counter.setupType || moves.has('rest') || !!teamDetails.rapidSpin};
177
178
  case 'reflect':
178
179
  return {cull: !!counter.setupType || !!counter.get('speedsetup')};
180
+ case 'roar':
181
+ return {cull: moves.has('sleeptalk') || moves.has('rest')};
179
182
  case 'seismictoss':
180
183
  return {cull: !!counter.setupType || moves.has('thunderbolt')};
181
184
  case 'spikes':
@@ -363,7 +366,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
363
366
 
364
367
  do {
365
368
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
366
- while (moves.size < 4 && movePool.length) {
369
+ while (moves.size < this.maxMoveCount && movePool.length) {
367
370
  const moveid = this.sampleNoReplace(movePool);
368
371
  if (moveid.startsWith('hiddenpower')) {
369
372
  availableHP--;
@@ -373,7 +376,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
373
376
  moves.add(moveid);
374
377
  }
375
378
 
376
- while (moves.size < 4 && rejectedPool.length) {
379
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
377
380
  const moveid = this.sampleNoReplace(rejectedPool);
378
381
  if (moveid.startsWith('hiddenpower')) {
379
382
  if (hasHiddenPower) continue;
@@ -397,7 +400,6 @@ export class RandomGen3Teams extends RandomGen4Teams {
397
400
  ) {
398
401
  cull = true;
399
402
  }
400
-
401
403
  const moveIsRejectable = (
402
404
  !move.weather &&
403
405
  (move.category !== 'Status' || !move.flags.heal) &&
@@ -489,7 +491,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
489
491
  break;
490
492
  }
491
493
  }
492
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
494
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
493
495
 
494
496
  if (hasHiddenPower) {
495
497
  let hpType;
@@ -543,8 +545,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
543
545
  Ditto: 99, Unown: 99,
544
546
  };
545
547
  const tier = species.tier;
546
- let level = levelScale[tier] || (species.nfe ? 90 : 80);
547
- if (customScale[species.name]) level = customScale[species.name];
548
+ const level = this.adjustLevel || customScale[species.name] || levelScale[tier] || (species.nfe ? 90 : 80);
548
549
 
549
550
  // Prepare optimal HP
550
551
  let hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
package/src/gen4.ts CHANGED
@@ -547,7 +547,7 @@ export class RandomGen4Teams extends RandomGen5Teams {
547
547
 
548
548
  do {
549
549
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
550
- while (moves.size < 4 && movePool.length) {
550
+ while (moves.size < this.maxMoveCount && movePool.length) {
551
551
  const moveid = this.sampleNoReplace(movePool);
552
552
  if (moveid.startsWith('hiddenpower')) {
553
553
  availableHP--;
@@ -557,7 +557,7 @@ export class RandomGen4Teams extends RandomGen5Teams {
557
557
  moves.add(moveid);
558
558
  }
559
559
 
560
- while (moves.size < 4 && rejectedPool.length) {
560
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
561
561
  const moveid = this.sampleNoReplace(rejectedPool);
562
562
  if (moveid.startsWith('hiddenpower')) {
563
563
  if (hasHiddenPower) continue;
@@ -726,7 +726,7 @@ export class RandomGen4Teams extends RandomGen5Teams {
726
726
  break;
727
727
  }
728
728
  }
729
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
729
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
730
730
 
731
731
  if (hasHiddenPower) {
732
732
  let hpType;
@@ -800,10 +800,9 @@ export class RandomGen4Teams extends RandomGen5Teams {
800
800
  NU: 88,
801
801
  };
802
802
  const customScale: {[k: string]: number} = {
803
- Delibird: 100, Ditto: 100, 'Farfetch\u2019d': 100, Unown: 100,
803
+ Delibird: 100, Ditto: 100, 'Farfetch\u2019d': 100, Unown: 100, Castform: 100,
804
804
  };
805
- let level = levelScale[species.tier] || (species.nfe ? 90 : 80);
806
- if (customScale[species.name]) level = customScale[species.name];
805
+ const level = this.adjustLevel || customScale[species.name] || levelScale[species.tier] || (species.nfe ? 90 : 80);
807
806
 
808
807
  // Prepare optimal HP
809
808
  let hp = Math.floor(
package/src/gen5.ts CHANGED
@@ -42,6 +42,9 @@ export class RandomGen5Teams extends RandomGen6Teams {
42
42
  !counter.get('Ground') && !moves.has('rest') && !moves.has('sleeptalk')
43
43
  ),
44
44
  Ice: (movePool, moves, abilities, types, counter) => !counter.get('Ice'),
45
+ Normal: (movePool, moves, abilities, types, counter, species) => (
46
+ movePool.includes('return') && species.baseStats.atk > 80
47
+ ),
45
48
  Rock: (movePool, moves, abilities, types, counter, species) => !counter.get('Rock') && species.baseStats.atk >= 80,
46
49
  Steel: (movePool, moves, abilities, types, counter) => !counter.get('Steel') && abilities.has('Technician'),
47
50
  Water: (movePool, moves, abilities, types, counter) => (
@@ -486,7 +489,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
486
489
 
487
490
  do {
488
491
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
489
- while (moves.size < 4 && movePool.length) {
492
+ while (moves.size < this.maxMoveCount && movePool.length) {
490
493
  const moveid = this.sampleNoReplace(movePool);
491
494
  if (moveid.startsWith('hiddenpower')) {
492
495
  availableHP--;
@@ -496,7 +499,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
496
499
  moves.add(moveid);
497
500
  }
498
501
 
499
- while (moves.size < 4 && rejectedPool.length) {
502
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
500
503
  const moveid = this.sampleNoReplace(rejectedPool);
501
504
  if (moveid.startsWith('hiddenpower')) {
502
505
  if (hasHiddenPower) {
@@ -651,7 +654,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
651
654
  break;
652
655
  }
653
656
  }
654
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
657
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
655
658
 
656
659
  if (hasHiddenPower) {
657
660
  let hpType;
@@ -736,8 +739,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
736
739
  const customScale: {[forme: string]: number} = {
737
740
  Delibird: 100, 'Farfetch\u2019d': 100, Luvdisc: 100, Unown: 100,
738
741
  };
739
- let level = levelScale[species.tier] || (species.nfe ? 90 : 80);
740
- if (customScale[species.name]) level = customScale[species.name];
742
+ const level = this.adjustLevel || customScale[species.name] || levelScale[species.tier] || (species.nfe ? 90 : 80);
741
743
 
742
744
  // Prepare optimal HP
743
745
  const srWeakness = this.dex.getEffectiveness('Rock', species);
package/src/gen6.ts CHANGED
@@ -315,7 +315,9 @@ export class RandomGen6Teams extends RandomGen7Teams {
315
315
  case 'lavaplume':
316
316
  return {cull: moves.has('firepunch') || moves.has('fireblast') && (!!counter.setupType || !!counter.get('speedsetup'))};
317
317
  case 'airslash': case 'hurricane':
318
- return {cull: moves.has('bravebird') || moves.has(move.id === 'hurricane' ? 'airslash' : 'hurricane')};
318
+ return {cull: (
319
+ [(move.id === 'hurricane' ? 'airslash' : 'hurricane'), 'acrobatics', 'bravebird'].some(m => moves.has(m))
320
+ )};
319
321
  case 'shadowball':
320
322
  return {cull: moves.has('darkpulse') || (moves.has('hex') && moves.has('willowisp'))};
321
323
  case 'shadowclaw':
@@ -409,7 +411,11 @@ export class RandomGen6Teams extends RandomGen7Teams {
409
411
  case 'originpulse': case 'surf':
410
412
  return {cull: moves.has('hydropump') || moves.has('scald')};
411
413
  case 'scald':
412
- return {cull: moves.has('waterfall') || moves.has('waterpulse')};
414
+ return {cull: (
415
+ moves.has('waterfall') ||
416
+ moves.has('waterpulse') ||
417
+ (species.id === 'quagsire' && movePool.includes('recover'))
418
+ )};
413
419
 
414
420
  // Status:
415
421
  case 'glare': case 'headbutt':
@@ -567,7 +573,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
567
573
  case 'Unburden':
568
574
  return (!!species.isMega || abilities.has('Prankster') || !counter.setupType && !moves.has('acrobatics'));
569
575
  case 'Water Absorb':
570
- return (moves.has('raindance') || abilities.has('Drizzle') || abilities.has('Volt Absorb'));
576
+ return (moves.has('raindance') || ['Drizzle', 'Unaware', 'Volt Absorb'].some(a => abilities.has(a)));
571
577
  case 'Weak Armor':
572
578
  return counter.setupType !== 'Physical';
573
579
  }
@@ -794,9 +800,8 @@ export class RandomGen6Teams extends RandomGen7Teams {
794
800
  const ivs = {hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31};
795
801
 
796
802
  const types = new Set(species.types);
797
- const abilities = new Set(Object.values(species.abilities));
803
+ let abilities = new Set(Object.values(species.abilities));
798
804
  if (species.unreleasedHidden) abilities.delete(species.abilities.H);
799
-
800
805
  let availableHP = 0;
801
806
  for (const setMoveid of movePool) {
802
807
  if (setMoveid.startsWith('hiddenpower')) availableHP++;
@@ -813,7 +818,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
813
818
 
814
819
  do {
815
820
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
816
- while (moves.size < 4 && movePool.length) {
821
+ while (moves.size < this.maxMoveCount && movePool.length) {
817
822
  const moveid = this.sampleNoReplace(movePool);
818
823
  if (moveid.startsWith('hiddenpower')) {
819
824
  availableHP--;
@@ -823,7 +828,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
823
828
  moves.add(moveid);
824
829
  }
825
830
 
826
- while (moves.size < 4 && rejectedPool.length) {
831
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
827
832
  const moveid = this.sampleNoReplace(rejectedPool);
828
833
  if (moveid.startsWith('hiddenpower')) {
829
834
  if (hasHiddenPower) continue;
@@ -967,7 +972,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
967
972
  break;
968
973
  }
969
974
  }
970
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
975
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
971
976
 
972
977
  if (hasHiddenPower) {
973
978
  let hpType;
@@ -995,10 +1000,10 @@ export class RandomGen6Teams extends RandomGen7Teams {
995
1000
  moves.add('thunder');
996
1001
  }
997
1002
 
998
- const battleOnly = species.battleOnly && !species.requiredAbility;
999
- const baseSpecies: Species = battleOnly ? this.dex.species.get(species.battleOnly as string) : species;
1000
-
1001
- const abilityData = Object.values(baseSpecies.abilities).map(a => this.dex.abilities.get(a));
1003
+ if (species.battleOnly && !species.requiredAbility) {
1004
+ abilities = new Set(Object.values(this.dex.species.get(species.battleOnly as string).abilities));
1005
+ }
1006
+ const abilityData = [...abilities].map(a => this.dex.abilities.get(a));
1002
1007
  Utils.sortBy(abilityData, abil => -abil.rating);
1003
1008
 
1004
1009
  if (abilityData.length > 1) {
@@ -1068,8 +1073,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
1068
1073
  Castform: 100, Delibird: 100, 'Genesect-Douse': 80, Luvdisc: 100, Spinda: 100, Unown: 100,
1069
1074
  };
1070
1075
  const tier = toID(species.tier).replace('bl', '');
1071
- let level = levelScale[tier] || (species.nfe ? 90 : 80);
1072
- if (customScale[forme]) level = customScale[forme];
1076
+ const level = this.adjustLevel || customScale[species.name] || levelScale[tier] || (species.nfe ? 90 : 80);
1073
1077
 
1074
1078
  // Prepare optimal HP
1075
1079
  const srWeakness = this.dex.getEffectiveness('Rock', species);
@@ -1197,7 +1201,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
1197
1201
  item: setData.set.item || '',
1198
1202
  ability: setData.set.ability || species.abilities['0'],
1199
1203
  shiny: typeof setData.set.shiny === 'undefined' ? this.randomChance(1, 1024) : setData.set.shiny,
1200
- level: 100,
1204
+ level: this.adjustLevel || 100,
1201
1205
  happiness: typeof setData.set.happiness === 'undefined' ? 255 : setData.set.happiness,
1202
1206
  evs: setData.set.evs || {hp: 84, atk: 84, def: 84, spa: 84, spd: 84, spe: 84},
1203
1207
  ivs: setData.set.ivs || {hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31},
package/src/gen7.ts CHANGED
@@ -46,6 +46,8 @@ export class RandomGen7Teams extends RandomTeams {
46
46
  constructor(dex: ModdedDex, format: Format, prng: PRNG | PRNGSeed | null) {
47
47
  super(dex, format, prng);
48
48
 
49
+ this.noStab = [...this.noStab, 'voltswitch'];
50
+
49
51
  this.moveEnforcementCheckers = {
50
52
  Bug: movePool => movePool.includes('megahorn') || movePool.includes('pinmissile'),
51
53
  Dark: (movePool, moves, abilities, types, counter, species) => (
@@ -59,7 +61,7 @@ export class RandomGen7Teams extends RandomTeams {
59
61
  ),
60
62
  Electric: (movePool, moves, abilities, types, counter) => !counter.get('Electric') || movePool.includes('thunder'),
61
63
  Fairy: (movePool, moves, abilities, types, counter) => (
62
- !counter.get('Fairy') && !types.has('Flying') && !abilities.has('Pixilate')
64
+ (!counter.get('Fairy') && !types.has('Flying') && !abilities.has('Pixilate'))
63
65
  ),
64
66
  Fighting: (movePool, moves, abilities, types, counter) => !counter.get('Fighting') || !counter.get('stab'),
65
67
  Fire: (movePool, moves, abilities, types, counter) => (
@@ -344,7 +346,7 @@ export class RandomGen7Teams extends RandomTeams {
344
346
  (moves.has('clangingscales') && !teamDetails.zMove)
345
347
  )};
346
348
  case 'thunderbolt':
347
- return {cull: moves.has('discharge') || (moves.has('voltswitch') && moves.has('wildcharge'))};
349
+ return {cull: ['discharge', 'voltswitch', 'wildcharge'].some(m => moves.has(m))};
348
350
  case 'moonblast':
349
351
  return {cull: isDoubles && moves.has('dazzlinggleam')};
350
352
  case 'aurasphere': case 'focusblast':
@@ -458,7 +460,12 @@ export class RandomGen7Teams extends RandomTeams {
458
460
  case 'facade':
459
461
  return {cull: moves.has('bulkup') || hasRestTalk};
460
462
  case 'hiddenpower':
461
- return {cull: moves.has('rest') || !counter.get('stab') && counter.damagingMoves.size < 2};
463
+ return {cull: (
464
+ moves.has('rest') ||
465
+ (!counter.get('stab') && counter.damagingMoves.size < 2) ||
466
+ // Force Moonblast on Special-setup Fairies
467
+ (counter.setupType === 'Special' && types.has('Fairy') && movePool.includes('moonblast'))
468
+ )};
462
469
  case 'hypervoice':
463
470
  return {cull: moves.has('blizzard')};
464
471
  case 'judgment':
@@ -1041,7 +1048,7 @@ export class RandomGen7Teams extends RandomTeams {
1041
1048
  // Random Multi Battle uses doubles move pools, but Ally Switch fails in multi battles
1042
1049
  const allySwitch = movePool.indexOf('allyswitch');
1043
1050
  if (allySwitch > -1) {
1044
- if (movePool.length > 4) {
1051
+ if (movePool.length > this.maxMoveCount) {
1045
1052
  this.fastPop(movePool, allySwitch);
1046
1053
  } else {
1047
1054
  // Ideally, we'll never get here, but better to have a move that usually does nothing than one that always does
@@ -1078,7 +1085,7 @@ export class RandomGen7Teams extends RandomTeams {
1078
1085
 
1079
1086
  do {
1080
1087
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
1081
- while (moves.size < 4 && movePool.length) {
1088
+ while (moves.size < this.maxMoveCount && movePool.length) {
1082
1089
  const moveid = this.sampleNoReplace(movePool);
1083
1090
  if (moveid.startsWith('hiddenpower')) {
1084
1091
  availableHP--;
@@ -1087,7 +1094,7 @@ export class RandomGen7Teams extends RandomTeams {
1087
1094
  }
1088
1095
  moves.add(moveid);
1089
1096
  }
1090
- while (moves.size < 4 && rejectedPool.length) {
1097
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
1091
1098
  const moveid = this.sampleNoReplace(rejectedPool);
1092
1099
  if (moveid.startsWith('hiddenpower')) {
1093
1100
  if (hasHiddenPower) continue;
@@ -1243,7 +1250,7 @@ export class RandomGen7Teams extends RandomTeams {
1243
1250
  break;
1244
1251
  }
1245
1252
  }
1246
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
1253
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
1247
1254
 
1248
1255
  // Moveset modifications
1249
1256
  if (moves.has('autotomize') && moves.has('heavyslam')) {
@@ -1356,7 +1363,9 @@ export class RandomGen7Teams extends RandomTeams {
1356
1363
  }
1357
1364
 
1358
1365
  let level: number;
1359
- if (!isDoubles) {
1366
+ if (this.adjustLevel) {
1367
+ level = this.adjustLevel;
1368
+ } else if (!isDoubles) {
1360
1369
  const levelScale: {[k: string]: number} = {uber: 76, ou: 80, uu: 82, ru: 84, nu: 86, pu: 88};
1361
1370
  const customScale: {[k: string]: number} = {
1362
1371
  // Banned Ability
@@ -1726,7 +1735,7 @@ export class RandomGen7Teams extends RandomTeams {
1726
1735
  const item = this.sampleIfArray(setData.set.item);
1727
1736
  const ability = this.sampleIfArray(setData.set.ability);
1728
1737
  const nature = this.sampleIfArray(setData.set.nature);
1729
- const level = setData.set.level || (tier === "LC" ? 5 : 100);
1738
+ const level = this.adjustLevel || setData.set.level || (tier === "LC" ? 5 : 100);
1730
1739
 
1731
1740
  return {
1732
1741
  name: setData.set.name || species.baseSpecies,