@pkmn/randoms 0.5.9 → 0.5.12

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;
@@ -802,8 +802,7 @@ export class RandomGen4Teams extends RandomGen5Teams {
802
802
  const customScale: {[k: string]: number} = {
803
803
  Delibird: 100, Ditto: 100, 'Farfetch\u2019d': 100, Unown: 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
@@ -409,7 +409,11 @@ export class RandomGen6Teams extends RandomGen7Teams {
409
409
  case 'originpulse': case 'surf':
410
410
  return {cull: moves.has('hydropump') || moves.has('scald')};
411
411
  case 'scald':
412
- return {cull: moves.has('waterfall') || moves.has('waterpulse')};
412
+ return {cull: (
413
+ moves.has('waterfall') ||
414
+ moves.has('waterpulse') ||
415
+ (species.id === 'quagsire' && movePool.includes('recover'))
416
+ )};
413
417
 
414
418
  // Status:
415
419
  case 'glare': case 'headbutt':
@@ -567,7 +571,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
567
571
  case 'Unburden':
568
572
  return (!!species.isMega || abilities.has('Prankster') || !counter.setupType && !moves.has('acrobatics'));
569
573
  case 'Water Absorb':
570
- return (moves.has('raindance') || abilities.has('Drizzle') || abilities.has('Volt Absorb'));
574
+ return (moves.has('raindance') || ['Drizzle', 'Unaware', 'Volt Absorb'].some(a => abilities.has(a)));
571
575
  case 'Weak Armor':
572
576
  return counter.setupType !== 'Physical';
573
577
  }
@@ -794,9 +798,8 @@ export class RandomGen6Teams extends RandomGen7Teams {
794
798
  const ivs = {hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31};
795
799
 
796
800
  const types = new Set(species.types);
797
- const abilities = new Set(Object.values(species.abilities));
801
+ let abilities = new Set(Object.values(species.abilities));
798
802
  if (species.unreleasedHidden) abilities.delete(species.abilities.H);
799
-
800
803
  let availableHP = 0;
801
804
  for (const setMoveid of movePool) {
802
805
  if (setMoveid.startsWith('hiddenpower')) availableHP++;
@@ -813,7 +816,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
813
816
 
814
817
  do {
815
818
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
816
- while (moves.size < 4 && movePool.length) {
819
+ while (moves.size < this.maxMoveCount && movePool.length) {
817
820
  const moveid = this.sampleNoReplace(movePool);
818
821
  if (moveid.startsWith('hiddenpower')) {
819
822
  availableHP--;
@@ -823,7 +826,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
823
826
  moves.add(moveid);
824
827
  }
825
828
 
826
- while (moves.size < 4 && rejectedPool.length) {
829
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
827
830
  const moveid = this.sampleNoReplace(rejectedPool);
828
831
  if (moveid.startsWith('hiddenpower')) {
829
832
  if (hasHiddenPower) continue;
@@ -967,7 +970,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
967
970
  break;
968
971
  }
969
972
  }
970
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
973
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
971
974
 
972
975
  if (hasHiddenPower) {
973
976
  let hpType;
@@ -995,10 +998,10 @@ export class RandomGen6Teams extends RandomGen7Teams {
995
998
  moves.add('thunder');
996
999
  }
997
1000
 
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));
1001
+ if (species.battleOnly && !species.requiredAbility) {
1002
+ abilities = new Set(Object.values(this.dex.species.get(species.battleOnly as string).abilities));
1003
+ }
1004
+ const abilityData = [...abilities].map(a => this.dex.abilities.get(a));
1002
1005
  Utils.sortBy(abilityData, abil => -abil.rating);
1003
1006
 
1004
1007
  if (abilityData.length > 1) {
@@ -1068,8 +1071,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
1068
1071
  Castform: 100, Delibird: 100, 'Genesect-Douse': 80, Luvdisc: 100, Spinda: 100, Unown: 100,
1069
1072
  };
1070
1073
  const tier = toID(species.tier).replace('bl', '');
1071
- let level = levelScale[tier] || (species.nfe ? 90 : 80);
1072
- if (customScale[forme]) level = customScale[forme];
1074
+ const level = this.adjustLevel || customScale[species.name] || levelScale[tier] || (species.nfe ? 90 : 80);
1073
1075
 
1074
1076
  // Prepare optimal HP
1075
1077
  const srWeakness = this.dex.getEffectiveness('Rock', species);
@@ -1197,7 +1199,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
1197
1199
  item: setData.set.item || '',
1198
1200
  ability: setData.set.ability || species.abilities['0'],
1199
1201
  shiny: typeof setData.set.shiny === 'undefined' ? this.randomChance(1, 1024) : setData.set.shiny,
1200
- level: 100,
1202
+ level: this.adjustLevel || 100,
1201
1203
  happiness: typeof setData.set.happiness === 'undefined' ? 255 : setData.set.happiness,
1202
1204
  evs: setData.set.evs || {hp: 84, atk: 84, def: 84, spa: 84, spd: 84, spe: 84},
1203
1205
  ivs: setData.set.ivs || {hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31},
package/src/gen7.ts CHANGED
@@ -1041,7 +1041,7 @@ export class RandomGen7Teams extends RandomTeams {
1041
1041
  // Random Multi Battle uses doubles move pools, but Ally Switch fails in multi battles
1042
1042
  const allySwitch = movePool.indexOf('allyswitch');
1043
1043
  if (allySwitch > -1) {
1044
- if (movePool.length > 4) {
1044
+ if (movePool.length > this.maxMoveCount) {
1045
1045
  this.fastPop(movePool, allySwitch);
1046
1046
  } else {
1047
1047
  // Ideally, we'll never get here, but better to have a move that usually does nothing than one that always does
@@ -1078,7 +1078,7 @@ export class RandomGen7Teams extends RandomTeams {
1078
1078
 
1079
1079
  do {
1080
1080
  // Choose next 4 moves from learnset/viable moves and add them to moves list:
1081
- while (moves.size < 4 && movePool.length) {
1081
+ while (moves.size < this.maxMoveCount && movePool.length) {
1082
1082
  const moveid = this.sampleNoReplace(movePool);
1083
1083
  if (moveid.startsWith('hiddenpower')) {
1084
1084
  availableHP--;
@@ -1087,7 +1087,7 @@ export class RandomGen7Teams extends RandomTeams {
1087
1087
  }
1088
1088
  moves.add(moveid);
1089
1089
  }
1090
- while (moves.size < 4 && rejectedPool.length) {
1090
+ while (moves.size < this.maxMoveCount && rejectedPool.length) {
1091
1091
  const moveid = this.sampleNoReplace(rejectedPool);
1092
1092
  if (moveid.startsWith('hiddenpower')) {
1093
1093
  if (hasHiddenPower) continue;
@@ -1243,7 +1243,7 @@ export class RandomGen7Teams extends RandomTeams {
1243
1243
  break;
1244
1244
  }
1245
1245
  }
1246
- } while (moves.size < 4 && (movePool.length || rejectedPool.length));
1246
+ } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
1247
1247
 
1248
1248
  // Moveset modifications
1249
1249
  if (moves.has('autotomize') && moves.has('heavyslam')) {
@@ -1356,7 +1356,9 @@ export class RandomGen7Teams extends RandomTeams {
1356
1356
  }
1357
1357
 
1358
1358
  let level: number;
1359
- if (!isDoubles) {
1359
+ if (this.adjustLevel) {
1360
+ level = this.adjustLevel;
1361
+ } else if (!isDoubles) {
1360
1362
  const levelScale: {[k: string]: number} = {uber: 76, ou: 80, uu: 82, ru: 84, nu: 86, pu: 88};
1361
1363
  const customScale: {[k: string]: number} = {
1362
1364
  // Banned Ability
@@ -1726,7 +1728,7 @@ export class RandomGen7Teams extends RandomTeams {
1726
1728
  const item = this.sampleIfArray(setData.set.item);
1727
1729
  const ability = this.sampleIfArray(setData.set.ability);
1728
1730
  const nature = this.sampleIfArray(setData.set.nature);
1729
- const level = setData.set.level || (tier === "LC" ? 5 : 100);
1731
+ const level = this.adjustLevel || setData.set.level || (tier === "LC" ? 5 : 100);
1730
1732
 
1731
1733
  return {
1732
1734
  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
@@ -563,7 +572,7 @@ export class RandomTeams {
563
572
 
564
573
  banReason = ruleTable.check('basepokemon:' + toID(species.baseSpecies));
565
574
  if (banReason) continue;
566
- if (banReason !== '' || this.dex.species.get(species.baseSpecies).isNonstandard === species.isNonstandard) {
575
+ if (banReason !== '' || this.dex.species.get(species.baseSpecies).isNonstandard !== species.isNonstandard) {
567
576
  const nonexistentCheck = Tags.nonexistent.genericFilter!(species) && nonexistentBanReason;
568
577
  let tagWhitelisted = false;
569
578
  let tagBlacklisted = false;
@@ -588,10 +597,10 @@ export class RandomTeams {
588
597
  }
589
598
  }
590
599
  }
600
+ speciesPool.push(species);
591
601
  const num = species.num;
592
602
  if (pool.includes(num)) continue;
593
603
  pool.push(num);
594
- speciesPool.push(species);
595
604
  }
596
605
  }
597
606
 
@@ -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) {
@@ -2261,7 +2278,7 @@ export class RandomTeams {
2261
2278
  PUBL: 87,
2262
2279
  PU: 88, "(PU)": 88, NFE: 88,
2263
2280
  };
2264
- const customScale: {[k: string]: number} = {delibird: 100, luvdisc: 100, spinda: 100, unown: 100};
2281
+ const customScale: {[k: string]: number} = {delibird: 100, glalie: 76, luvdisc: 100, spinda: 100, unown: 100};
2265
2282
 
2266
2283
  level = customScale[species.id] || tierScale[species.tier] || 80;
2267
2284
  // Arbitrary levelling base on data files (typically winrate-influenced)
@@ -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;