@pkmn/randoms 0.4.19 → 0.4.23

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/gen8.ts CHANGED
@@ -194,7 +194,7 @@ export class RandomTeams {
194
194
  ),
195
195
  Poison: (movePool, moves, abilities, types, counter) => {
196
196
  if (counter.get('Poison')) return false;
197
- return types.has('Ground') || types.has('Psychic') || !!counter.setupType || movePool.includes('gunkshot');
197
+ return types.has('Ground') || types.has('Psychic') || types.has('Grass') || !!counter.setupType || movePool.includes('gunkshot');
198
198
  },
199
199
  Psychic: (movePool, moves, abilities, types, counter) => {
200
200
  if (counter.get('Psychic')) return false;
@@ -209,7 +209,7 @@ export class RandomTeams {
209
209
  },
210
210
  Water: (movePool, moves, abilities, types, counter, species) => {
211
211
  if (!counter.get('Water') && !moves.has('hypervoice')) return true;
212
- if (movePool.includes('hypervoice') || movePool.includes('liquidation')) return true;
212
+ if (['hypervoice', 'liquidation', 'surgingstrikes'].some(m => movePool.includes(m))) return true;
213
213
  return abilities.has('Huge Power') && movePool.includes('aquajet');
214
214
  },
215
215
  };
@@ -307,8 +307,8 @@ export class RandomTeams {
307
307
  const dex = this.dex;
308
308
  const team = [];
309
309
 
310
- const natures = Object.keys(this.dex.data.Natures);
311
- const items = Object.keys(this.dex.data.Items);
310
+ const natures = this.dex.natures.all();
311
+ const items = this.dex.items.all();
312
312
 
313
313
  const randomN = this.randomNPokemon(this.maxTeamSize, this.forceMonotype);
314
314
 
@@ -320,8 +320,8 @@ export class RandomTeams {
320
320
  let item = '';
321
321
  if (this.gen >= 2) {
322
322
  do {
323
- item = this.sample(items);
324
- } while (this.dex.items.get(item).gen > this.gen || this.dex.data.Items[item].isNonstandard);
323
+ item = this.sample(items).name;
324
+ } while (this.dex.items.get(item).gen > this.gen || this.dex.items.get(item).isNonstandard);
325
325
  }
326
326
 
327
327
  // Make sure forme is legal
@@ -342,8 +342,8 @@ export class RandomTeams {
342
342
  let itemData = this.dex.items.get(item);
343
343
  if (itemData.forcedForme && forme === this.dex.species.get(itemData.forcedForme).baseSpecies) {
344
344
  do {
345
- item = this.sample(items);
346
- itemData = this.dex.items.get(item);
345
+ itemData = this.sample(items);
346
+ item = itemData.name;
347
347
  } while (
348
348
  itemData.gen > this.gen ||
349
349
  itemData.isNonstandard ||
@@ -353,27 +353,28 @@ export class RandomTeams {
353
353
 
354
354
  // Random legal ability
355
355
  const abilities = Object.values(species.abilities).filter(a => this.dex.abilities.get(a).gen <= this.gen);
356
- const ability: string = this.gen <= 2 ? 'None' : this.sample(abilities);
356
+ const ability: string = this.gen <= 2 ? 'No Ability' : this.sample(abilities);
357
357
 
358
358
  // Four random unique moves from the movepool
359
359
  let pool = ['struggle'];
360
360
  if (forme === 'Smeargle') {
361
- pool = Object.keys(this.dex.data.Moves).filter(moveid => {
362
- const move = this.dex.data.Moves[moveid];
363
- return !(move.isNonstandard || move.isZ || move.isMax || move.realMove);
364
- });
361
+ pool = this.dex.moves
362
+ .all()
363
+ .filter(move => !(move.isNonstandard || move.isZ || move.isMax || move.realMove))
364
+ .map(m => m.id);
365
365
  } else {
366
366
  const formes = ['gastrodoneast', 'pumpkaboosuper', 'zygarde10'];
367
- let learnset = this.dex.data.Learnsets[species.id]?.learnset && !formes.includes(species.id) ?
368
- this.dex.data.Learnsets[species.id].learnset :
369
- this.dex.data.Learnsets[this.dex.species.get(species.baseSpecies).id].learnset;
367
+ let learnset = this.dex.species.getLearnset(species.id);
368
+ if (formes.includes(species.id) || !learnset) {
369
+ learnset = this.dex.species.getLearnset(this.dex.species.get(species.baseSpecies).id);
370
+ }
370
371
  if (learnset) {
371
372
  pool = Object.keys(learnset).filter(
372
373
  moveid => learnset![moveid].find(learned => learned.startsWith(String(this.gen)))
373
374
  );
374
375
  }
375
376
  if (species.changesFrom) {
376
- learnset = this.dex.data.Learnsets[toID(species.changesFrom)].learnset;
377
+ learnset = this.dex.species.getLearnset(toID(species.changesFrom));
377
378
  const basePool = Object.keys(learnset!).filter(
378
379
  moveid => learnset![moveid].find(learned => learned.startsWith(String(this.gen)))
379
380
  );
@@ -405,7 +406,7 @@ export class RandomTeams {
405
406
  };
406
407
 
407
408
  // Random nature
408
- const nature = this.sample(natures);
409
+ const nature = this.sample(natures).name;
409
410
 
410
411
  // Level balance--calculate directly from stats rather than using some silly lookup table
411
412
  const mbstmin = 1307; // Sunkern has the lowest modified base stat total, and that total is 807
@@ -447,15 +448,15 @@ export class RandomTeams {
447
448
  name: species.baseSpecies,
448
449
  species: species.name,
449
450
  gender: species.gender,
450
- item: item,
451
- ability: ability,
452
- moves: moves,
453
- evs: evs,
454
- ivs: ivs,
455
- nature: nature,
451
+ item,
452
+ ability,
453
+ moves,
454
+ evs,
455
+ ivs,
456
+ nature,
456
457
  level,
457
- happiness: happiness,
458
- shiny: shiny,
458
+ happiness,
459
+ shiny,
459
460
  });
460
461
  }
461
462
 
@@ -474,14 +475,11 @@ export class RandomTeams {
474
475
  }
475
476
 
476
477
  const pool: number[] = [];
477
- for (const id in this.dex.data.FormatsData) {
478
- if (
479
- !this.dex.data.Pokedex[id] ||
480
- (this.dex.data.FormatsData[id].isNonstandard && this.dex.data.FormatsData[id].isNonstandard !== 'Unobtainable')
481
- ) continue;
482
- if (requiredType && !this.dex.data.Pokedex[id].types.includes(requiredType)) continue;
483
- if (minSourceGen && (this.dex.data.Pokedex[id].gen || 8) < minSourceGen) continue;
484
- const num = this.dex.data.Pokedex[id].num;
478
+ for (const species of this.dex.species.all()) {
479
+ if (species.isNonstandard && species.isNonstandard !== 'Unobtainable') continue;
480
+ if (requiredType && !species.types.includes(requiredType)) continue;
481
+ if (minSourceGen && species.gen < minSourceGen) continue;
482
+ const num = species.num;
485
483
  if (num <= 0 || pool.includes(num)) continue;
486
484
  if (num > last) break;
487
485
  pool.push(num);
@@ -494,9 +492,8 @@ export class RandomTeams {
494
492
  }
495
493
 
496
494
  const formes: string[][] = [];
497
- for (const id in this.dex.data.Pokedex) {
498
- if (!(this.dex.data.Pokedex[id].num in hasDexNumber)) continue;
499
- const species = this.dex.species.get(id);
495
+ for (const species of this.dex.species.all()) {
496
+ if (!(species.num in hasDexNumber)) continue;
500
497
  if (species.gen <= this.gen && (!species.isNonstandard || species.isNonstandard === 'Unobtainable')) {
501
498
  if (!formes[hasDexNumber[species.num]]) formes[hasDexNumber[species.num]] = [];
502
499
  formes[hasDexNumber[species.num]].push(species.name);
@@ -516,10 +513,10 @@ export class RandomTeams {
516
513
  randomHCTeam(): PokemonSet[] {
517
514
  const team = [];
518
515
 
519
- const itemPool = Object.keys(this.dex.data.Items);
520
- const abilityPool = Object.keys(this.dex.data.Abilities);
521
- const movePool = Object.keys(this.dex.data.Moves);
522
- const naturePool = Object.keys(this.dex.data.Natures);
516
+ const itemPool = [...this.dex.items.all()];
517
+ const abilityPool = [...this.dex.abilities.all()];
518
+ const movePool = [...this.dex.moves.all()];
519
+ const naturePool = this.dex.natures.all();
523
520
 
524
521
  const randomN = this.randomNPokemon(this.maxTeamSize, this.forceMonotype);
525
522
 
@@ -529,27 +526,30 @@ export class RandomTeams {
529
526
 
530
527
  // Random unique item
531
528
  let item = '';
529
+ let itemData;
532
530
  if (this.gen >= 2) {
533
531
  do {
534
- item = this.sampleNoReplace(itemPool);
535
- } while (this.dex.items.get(item).gen > this.gen || this.dex.data.Items[item].isNonstandard);
532
+ itemData = this.sampleNoReplace(itemPool);
533
+ item = itemData.name;
534
+ } while (itemData.gen > this.gen || itemData.isNonstandard);
536
535
  }
537
536
 
538
537
  // Random unique ability
539
- let ability = 'None';
538
+ let ability = 'No Ability';
539
+ let abilityData;
540
540
  if (this.gen >= 3) {
541
541
  do {
542
- ability = this.sampleNoReplace(abilityPool);
543
- } while (this.dex.abilities.get(ability).gen > this.gen || this.dex.data.Abilities[ability].isNonstandard);
542
+ abilityData = this.sampleNoReplace(abilityPool);
543
+ ability = abilityData.name;
544
+ } while (abilityData.gen > this.gen || abilityData.isNonstandard);
544
545
  }
545
546
 
546
547
  // Random unique moves
547
548
  const m = [];
548
549
  do {
549
- const moveid = this.sampleNoReplace(movePool);
550
- const move = this.dex.moves.get(moveid);
550
+ const move = this.sampleNoReplace(movePool);
551
551
  if (move.gen <= this.gen && !move.isNonstandard && !move.name.startsWith('Hidden Power ')) {
552
- m.push(moveid);
552
+ m.push(move.id);
553
553
  }
554
554
  } while (m.length < 4);
555
555
 
@@ -580,7 +580,7 @@ export class RandomTeams {
580
580
  };
581
581
 
582
582
  // Random nature
583
- const nature = this.sample(naturePool);
583
+ const nature = this.sample(naturePool).name;
584
584
 
585
585
  // Level balance
586
586
  const mbstmin = 1307;
@@ -613,15 +613,15 @@ export class RandomTeams {
613
613
  name: species.baseSpecies,
614
614
  species: species.name,
615
615
  gender: species.gender,
616
- item: item,
617
- ability: ability,
616
+ item,
617
+ ability,
618
618
  moves: m,
619
- evs: evs,
620
- ivs: ivs,
621
- nature: nature,
619
+ evs,
620
+ ivs,
621
+ nature,
622
622
  level,
623
- happiness: happiness,
624
- shiny: shiny,
623
+ happiness,
624
+ shiny,
625
625
  });
626
626
  }
627
627
 
@@ -1243,8 +1243,8 @@ export class RandomTeams {
1243
1243
  return (moves.has('rapidspin') || species.nfe || isDoubles);
1244
1244
  case 'Blaze':
1245
1245
  return (isDoubles && abilities.has('Solar Power')) || (!isDoubles && !isNoDynamax && species.id === 'charizard');
1246
- case 'Bulletproof': case 'Overcoat':
1247
- return !!counter.setupType;
1246
+ // case 'Bulletproof': case 'Overcoat':
1247
+ // return !!counter.setupType;
1248
1248
  case 'Chlorophyll':
1249
1249
  return (species.baseStats.spe > 100 || !counter.get('Fire') && !moves.has('sunnyday') && !teamDetails.sun);
1250
1250
  case 'Cloud Nine':
@@ -1731,7 +1731,7 @@ export class RandomTeams {
1731
1731
  (isDoubles && species.randomDoubleBattleMoves) ||
1732
1732
  (isNoDynamax && species.randomBattleNoDynamaxMoves) ||
1733
1733
  species.randomBattleMoves;
1734
- const movePool = (randMoves || Object.keys(this.dex.data.Learnsets[species.id]!.learnset!)).slice();
1734
+ const movePool = (randMoves || Object.keys(this.dex.species.getLearnset(species.id)!)).slice();
1735
1735
  if (this.format.gameType === 'multi' || this.format.gameType === 'freeforall') {
1736
1736
  // Random Multi Battle uses doubles move pools, but Ally Switch fails in multi battles
1737
1737
  // Random Free-For-All also uses doubles move pools, for now
@@ -1967,8 +1967,10 @@ export class RandomTeams {
1967
1967
  }
1968
1968
 
1969
1969
  let level: number;
1970
+ // doubles levelling
1970
1971
  if (isDoubles && species.randomDoubleBattleLevel) {
1971
1972
  level = species.randomDoubleBattleLevel;
1973
+ // No Dmax levelling
1972
1974
  } else if (isNoDynamax) {
1973
1975
  const tier = species.name.endsWith('-Gmax') ? this.dex.species.get(species.changesFrom).tier : species.tier;
1974
1976
  const tierScale: {[k: string]: number} = {
@@ -1994,19 +1996,38 @@ export class RandomTeams {
1994
1996
  decidueye: 87, noivern: 85, magnezone: 82, slowking: 81,
1995
1997
  };
1996
1998
  level = customScale[species.id] || tierScale[tier];
1999
+ // BDSP tier levelling
2000
+ } else if (this.dex.currentMod === 'gen8bdsp') {
2001
+ const tierScale: {[k: string]: number} = {
2002
+ Uber: 76,
2003
+ OU: 80,
2004
+ UUBL: 81,
2005
+ UU: 82,
2006
+ RUBL: 83,
2007
+ RU: 84,
2008
+ NUBL: 85,
2009
+ NU: 86,
2010
+ PUBL: 87,
2011
+ PU: 88, "(PU)": 88, NFE: 88,
2012
+ };
2013
+ // to override tier scaling if needed
2014
+ const customScale: {[k: string]: number} = {};
2015
+
2016
+ level = customScale[species.id] || tierScale[species.tier];
2017
+ // Arbitrary levelling base on data files (typically winrate-influenced)
1997
2018
  } else if (species.randomBattleLevel) {
1998
2019
  level = species.randomBattleLevel;
2020
+ // Default to level 80
1999
2021
  } else {
2000
2022
  level = 80;
2001
2023
  }
2002
2024
 
2003
-
2004
2025
  // Prepare optimal HP
2005
2026
  const srImmunity = ability === 'Magic Guard' || item === 'Heavy-Duty Boots';
2006
2027
  const srWeakness = srImmunity ? 0 : this.dex.getEffectiveness('Rock', species);
2007
2028
  while (evs.hp > 1) {
2008
2029
  const hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
2009
- const multipleOfFourNecessary = (moves.has('substitute') && (
2030
+ const multipleOfFourNecessary = (moves.has('substitute') && !['Leftovers', 'Black Sludge'].includes(item) && (
2010
2031
  item === 'Sitrus Berry' ||
2011
2032
  item === 'Salac Berry' ||
2012
2033
  ability === 'Power Construct'
@@ -2030,7 +2051,12 @@ export class RandomTeams {
2030
2051
  if (moves.has('shellsidearm') && item === 'Choice Specs') evs.atk -= 8;
2031
2052
 
2032
2053
  // Minimize confusion damage
2033
- if (!counter.get('Physical') && !moves.has('transform') && (!moves.has('shellsidearm') || !counter.get('Status'))) {
2054
+ const noAttackStatMoves = [...moves].every(m => {
2055
+ const move = this.dex.moves.get(m);
2056
+ if (move.damageCallback || move.damage) return false;
2057
+ return move.category !== 'Physical' || move.id === 'bodypress';
2058
+ });
2059
+ if (noAttackStatMoves && !moves.has('transform') && (!moves.has('shellsidearm') || !counter.get('Status'))) {
2034
2060
  evs.atk = 0;
2035
2061
  ivs.atk = 0;
2036
2062
  }
@@ -2065,8 +2091,7 @@ export class RandomTeams {
2065
2091
  ) {
2066
2092
  const exclude = pokemonToExclude.map(p => toID(p.species));
2067
2093
  const pokemonPool = [];
2068
- for (const id in this.dex.data.FormatsData) {
2069
- let species = this.dex.species.get(id);
2094
+ for (let species of this.dex.species.all()) {
2070
2095
  if (species.gen > this.gen || exclude.includes(species.id)) continue;
2071
2096
  if (isMonotype) {
2072
2097
  if (!species.types.includes(type)) continue;
@@ -2075,7 +2100,7 @@ export class RandomTeams {
2075
2100
  if (!species.types.includes(type)) continue;
2076
2101
  }
2077
2102
  }
2078
- pokemonPool.push(id);
2103
+ pokemonPool.push(species.id);
2079
2104
  }
2080
2105
  return pokemonPool;
2081
2106
  }