@pkmn/randoms 0.5.11 → 0.5.14

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
@@ -366,7 +366,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
366
366
 
367
367
  do {
368
368
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
369
- while (moves.size < 4 && movePool.length) {
369
+ while (moves.size < this.maxMoveCount && movePool.length) {
370
370
  const moveid = this.sampleNoReplace(movePool);
371
371
  if (moveid.startsWith('hiddenpower')) {
372
372
  availableHP--;
@@ -376,7 +376,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
376
376
  moves.add(moveid);
377
377
  }
378
378
 
379
- while (moves.size < 4 && rejectedPool.length) {
379
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
380
380
  const moveid = this.sampleNoReplace(rejectedPool);
381
381
  if (moveid.startsWith('hiddenpower')) {
382
382
  if (hasHiddenPower) continue;
@@ -491,7 +491,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
491
491
  break;
492
492
  }
493
493
  }
494
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
494
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
495
495
 
496
496
  if (hasHiddenPower) {
497
497
  let hpType;
@@ -545,8 +545,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
545
545
  Ditto: 99, Unown: 99,
546
546
  };
547
547
  const tier = species.tier;
548
- let level = levelScale[tier] || (species.nfe ? 90 : 80);
549
- if (customScale[species.name]) level = customScale[species.name];
548
+ const level = this.adjustLevel || customScale[species.name] || levelScale[tier] || (species.nfe ? 90 : 80);
550
549
 
551
550
  // Prepare optimal HP
552
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
@@ -489,7 +489,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
489
489
 
490
490
  do {
491
491
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
492
- while (moves.size < 4 && movePool.length) {
492
+ while (moves.size < this.maxMoveCount && movePool.length) {
493
493
  const moveid = this.sampleNoReplace(movePool);
494
494
  if (moveid.startsWith('hiddenpower')) {
495
495
  availableHP--;
@@ -499,7 +499,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
499
499
  moves.add(moveid);
500
500
  }
501
501
 
502
- while (moves.size < 4 && rejectedPool.length) {
502
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
503
503
  const moveid = this.sampleNoReplace(rejectedPool);
504
504
  if (moveid.startsWith('hiddenpower')) {
505
505
  if (hasHiddenPower) {
@@ -654,7 +654,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
654
654
  break;
655
655
  }
656
656
  }
657
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
657
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
658
658
 
659
659
  if (hasHiddenPower) {
660
660
  let hpType;
@@ -739,8 +739,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
739
739
  const customScale: {[forme: string]: number} = {
740
740
  Delibird: 100, 'Farfetch\u2019d': 100, Luvdisc: 100, Unown: 100,
741
741
  };
742
- let level = levelScale[species.tier] || (species.nfe ? 90 : 80);
743
- if (customScale[species.name]) level = customScale[species.name];
742
+ const level = this.adjustLevel || customScale[species.name] || levelScale[species.tier] || (species.nfe ? 90 : 80);
744
743
 
745
744
  // Prepare optimal HP
746
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':
@@ -816,7 +818,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
816
818
 
817
819
  do {
818
820
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
819
- while (moves.size < 4 && movePool.length) {
821
+ while (moves.size < this.maxMoveCount && movePool.length) {
820
822
  const moveid = this.sampleNoReplace(movePool);
821
823
  if (moveid.startsWith('hiddenpower')) {
822
824
  availableHP--;
@@ -826,7 +828,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
826
828
  moves.add(moveid);
827
829
  }
828
830
 
829
- while (moves.size < 4 && rejectedPool.length) {
831
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
830
832
  const moveid = this.sampleNoReplace(rejectedPool);
831
833
  if (moveid.startsWith('hiddenpower')) {
832
834
  if (hasHiddenPower) continue;
@@ -970,7 +972,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
970
972
  break;
971
973
  }
972
974
  }
973
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
975
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
974
976
 
975
977
  if (hasHiddenPower) {
976
978
  let hpType;
@@ -1071,8 +1073,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
1071
1073
  Castform: 100, Delibird: 100, 'Genesect-Douse': 80, Luvdisc: 100, Spinda: 100, Unown: 100,
1072
1074
  };
1073
1075
  const tier = toID(species.tier).replace('bl', '');
1074
- let level = levelScale[tier] || (species.nfe ? 90 : 80);
1075
- if (customScale[forme]) level = customScale[forme];
1076
+ const level = this.adjustLevel || customScale[species.name] || levelScale[tier] || (species.nfe ? 90 : 80);
1076
1077
 
1077
1078
  // Prepare optimal HP
1078
1079
  const srWeakness = this.dex.getEffectiveness('Rock', species);
@@ -1200,7 +1201,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
1200
1201
  item: setData.set.item || '',
1201
1202
  ability: setData.set.ability || species.abilities['0'],
1202
1203
  shiny: typeof setData.set.shiny === 'undefined' ? this.randomChance(1, 1024) : setData.set.shiny,
1203
- level: 100,
1204
+ level: this.adjustLevel || 100,
1204
1205
  happiness: typeof setData.set.happiness === 'undefined' ? 255 : setData.set.happiness,
1205
1206
  evs: setData.set.evs || {hp: 84, atk: 84, def: 84, spa: 84, spd: 84, spe: 84},
1206
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,
package/src/gen8.ts CHANGED
@@ -103,6 +103,8 @@ export class RandomTeams {
103
103
  prng: PRNG;
104
104
  noStab: string[];
105
105
  readonly maxTeamSize: number;
106
+ readonly adjustLevel: number | null;
107
+ readonly maxMoveCount: number;
106
108
  readonly forceMonotype: string | undefined;
107
109
 
108
110
  /**
@@ -119,6 +121,8 @@ export class RandomTeams {
119
121
 
120
122
  const ruleTable = this.dex.formats.getRuleTable(format);
121
123
  this.maxTeamSize = ruleTable.maxTeamSize;
124
+ this.adjustLevel = ruleTable.adjustLevel;
125
+ this.maxMoveCount = ruleTable.maxMoveCount;
122
126
  const forceMonotype = ruleTable.valueRules.get('forcemonotype');
123
127
  this.forceMonotype = forceMonotype && this.dex.types.get(forceMonotype).exists ?
124
128
  this.dex.types.get(forceMonotype).name : undefined;
@@ -442,7 +446,7 @@ export class RandomTeams {
442
446
  }
443
447
  }
444
448
 
445
- const moves = this.multipleSamplesNoReplace(pool, 4);
449
+ const moves = this.multipleSamplesNoReplace(pool, this.maxMoveCount);
446
450
 
447
451
  // Random EVs
448
452
  const evs: StatsTable = {hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0};
@@ -483,19 +487,24 @@ export class RandomTeams {
483
487
  mbst += (stats["spd"] * 2 + 31 + 21 + 100) + 5;
484
488
  mbst += (stats["spe"] * 2 + 31 + 21 + 100) + 5;
485
489
 
486
- let level = Math.floor(100 * mbstmin / mbst); // Initial level guess will underestimate
487
-
488
- while (level < 100) {
489
- mbst = Math.floor((stats["hp"] * 2 + 31 + 21 + 100) * level / 100 + 10);
490
- // Since damage is roughly proportional to level
491
- mbst += Math.floor(((stats["atk"] * 2 + 31 + 21 + 100) * level / 100 + 5) * level / 100);
492
- mbst += Math.floor((stats["def"] * 2 + 31 + 21 + 100) * level / 100 + 5);
493
- mbst += Math.floor(((stats["spa"] * 2 + 31 + 21 + 100) * level / 100 + 5) * level / 100);
494
- mbst += Math.floor((stats["spd"] * 2 + 31 + 21 + 100) * level / 100 + 5);
495
- mbst += Math.floor((stats["spe"] * 2 + 31 + 21 + 100) * level / 100 + 5);
496
-
497
- if (mbst >= mbstmin) break;
498
- level++;
490
+ let level;
491
+ if (this.adjustLevel) {
492
+ level = this.adjustLevel;
493
+ } else {
494
+ level = Math.floor(100 * mbstmin / mbst); // Initial level guess will underestimate
495
+
496
+ while (level < 100) {
497
+ mbst = Math.floor((stats["hp"] * 2 + 31 + 21 + 100) * level / 100 + 10);
498
+ // Since damage is roughly proportional to level
499
+ mbst += Math.floor(((stats["atk"] * 2 + 31 + 21 + 100) * level / 100 + 5) * level / 100);
500
+ mbst += Math.floor((stats["def"] * 2 + 31 + 21 + 100) * level / 100 + 5);
501
+ mbst += Math.floor(((stats["spa"] * 2 + 31 + 21 + 100) * level / 100 + 5) * level / 100);
502
+ mbst += Math.floor((stats["spd"] * 2 + 31 + 21 + 100) * level / 100 + 5);
503
+ mbst += Math.floor((stats["spe"] * 2 + 31 + 21 + 100) * level / 100 + 5);
504
+
505
+ if (mbst >= mbstmin) break;
506
+ level++;
507
+ }
499
508
  }
500
509
 
501
510
  // Random happiness
@@ -825,16 +834,22 @@ export class RandomTeams {
825
834
  mbst += (stats['spa'] * 2 + 31 + 21 + 100) + 5;
826
835
  mbst += (stats['spd'] * 2 + 31 + 21 + 100) + 5;
827
836
  mbst += (stats['spe'] * 2 + 31 + 21 + 100) + 5;
828
- let level = Math.floor(100 * mbstmin / mbst);
829
- while (level < 100) {
830
- mbst = Math.floor((stats['hp'] * 2 + 31 + 21 + 100) * level / 100 + 10);
831
- mbst += Math.floor(((stats['atk'] * 2 + 31 + 21 + 100) * level / 100 + 5) * level / 100);
832
- mbst += Math.floor((stats['def'] * 2 + 31 + 21 + 100) * level / 100 + 5);
833
- mbst += Math.floor(((stats['spa'] * 2 + 31 + 21 + 100) * level / 100 + 5) * level / 100);
834
- mbst += Math.floor((stats['spd'] * 2 + 31 + 21 + 100) * level / 100 + 5);
835
- mbst += Math.floor((stats['spe'] * 2 + 31 + 21 + 100) * level / 100 + 5);
836
- if (mbst >= mbstmin) break;
837
- level++;
837
+
838
+ let level;
839
+ if (this.adjustLevel) {
840
+ level = this.adjustLevel;
841
+ } else {
842
+ level = Math.floor(100 * mbstmin / mbst);
843
+ while (level < 100) {
844
+ mbst = Math.floor((stats['hp'] * 2 + 31 + 21 + 100) * level / 100 + 10);
845
+ mbst += Math.floor(((stats['atk'] * 2 + 31 + 21 + 100) * level / 100 + 5) * level / 100);
846
+ mbst += Math.floor((stats['def'] * 2 + 31 + 21 + 100) * level / 100 + 5);
847
+ mbst += Math.floor(((stats['spa'] * 2 + 31 + 21 + 100) * level / 100 + 5) * level / 100);
848
+ mbst += Math.floor((stats['spd'] * 2 + 31 + 21 + 100) * level / 100 + 5);
849
+ mbst += Math.floor((stats['spe'] * 2 + 31 + 21 + 100) * level / 100 + 5);
850
+ if (mbst >= mbstmin) break;
851
+ level++;
852
+ }
838
853
  }
839
854
 
840
855
  // Random happiness
@@ -1965,7 +1980,7 @@ export class RandomTeams {
1965
1980
  // Random Free-For-All also uses doubles move pools, for now
1966
1981
  const allySwitch = movePool.indexOf('allyswitch');
1967
1982
  if (allySwitch > -1) {
1968
- if (movePool.length > 4) {
1983
+ if (movePool.length > this.maxMoveCount) {
1969
1984
  this.fastPop(movePool, allySwitch);
1970
1985
  } else {
1971
1986
  // Ideally, we'll never get here, but better to have a move that usually does nothing than one that always does
@@ -1993,7 +2008,7 @@ export class RandomTeams {
1993
2008
  do {
1994
2009
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
1995
2010
  const pool = (movePool.length ? movePool : rejectedPool);
1996
- while (moves.size < 4 && pool.length) {
2011
+ while (moves.size < this.maxMoveCount && pool.length) {
1997
2012
  const moveid = this.sampleNoReplace(pool);
1998
2013
  if (moveid.startsWith('hiddenpower')) {
1999
2014
  if (hasHiddenPower) continue;
@@ -2100,7 +2115,7 @@ export class RandomTeams {
2100
2115
  break;
2101
2116
  }
2102
2117
  }
2103
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
2118
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
2104
2119
 
2105
2120
  // for BD/SP only
2106
2121
  if (hasHiddenPower) {
@@ -2218,8 +2233,10 @@ export class RandomTeams {
2218
2233
  }
2219
2234
 
2220
2235
  let level: number;
2236
+ if (this.adjustLevel) {
2237
+ level = this.adjustLevel;
2221
2238
  // doubles levelling
2222
- if (isDoubles && species.randomDoubleBattleLevel) {
2239
+ } else if (isDoubles && species.randomDoubleBattleLevel) {
2223
2240
  level = species.randomDoubleBattleLevel;
2224
2241
  // No Dmax levelling
2225
2242
  } else if (isNoDynamax) {
@@ -2549,11 +2566,13 @@ export class RandomTeams {
2549
2566
  item: this.sampleIfArray(setData.item) || '',
2550
2567
  ability: (this.sampleIfArray(setData.ability)),
2551
2568
  shiny: this.randomChance(1, 1024),
2569
+ level: this.adjustLevel || 100,
2552
2570
  evs: {hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0, ...setData.evs},
2553
2571
  nature: setData.nature,
2554
2572
  ivs: {hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31, ...setData.ivs || {}},
2555
2573
  moves: setData.moves.map((move: any) => this.sampleIfArray(move)),
2556
2574
  };
2575
+ if (this.adjustLevel) set.level = this.adjustLevel;
2557
2576
  pokemon.push(set);
2558
2577
  }
2559
2578
  return pokemon;