@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/build/gen8.js CHANGED
@@ -133,7 +133,7 @@ class RandomTeams {
133
133
  Poison: (movePool, moves, abilities, types, counter) => {
134
134
  if (counter.get('Poison'))
135
135
  return false;
136
- return types.has('Ground') || types.has('Psychic') || !!counter.setupType || movePool.includes('gunkshot');
136
+ return types.has('Ground') || types.has('Psychic') || types.has('Grass') || !!counter.setupType || movePool.includes('gunkshot');
137
137
  },
138
138
  Psychic: (movePool, moves, abilities, types, counter) => {
139
139
  if (counter.get('Psychic'))
@@ -153,7 +153,7 @@ class RandomTeams {
153
153
  Water: (movePool, moves, abilities, types, counter, species) => {
154
154
  if (!counter.get('Water') && !moves.has('hypervoice'))
155
155
  return true;
156
- if (movePool.includes('hypervoice') || movePool.includes('liquidation'))
156
+ if (['hypervoice', 'liquidation', 'surgingstrikes'].some(m => movePool.includes(m)))
157
157
  return true;
158
158
  return abilities.has('Huge Power') && movePool.includes('aquajet');
159
159
  },
@@ -233,11 +233,10 @@ class RandomTeams {
233
233
  return move.id !== 'bodypress';
234
234
  }
235
235
  randomCCTeam() {
236
- var _a;
237
236
  const dex = this.dex;
238
237
  const team = [];
239
- const natures = Object.keys(this.dex.data.Natures);
240
- const items = Object.keys(this.dex.data.Items);
238
+ const natures = this.dex.natures.all();
239
+ const items = this.dex.items.all();
241
240
  const randomN = this.randomNPokemon(this.maxTeamSize, this.forceMonotype);
242
241
  for (let forme of randomN) {
243
242
  let species = dex.species.get(forme);
@@ -247,8 +246,8 @@ class RandomTeams {
247
246
  let item = '';
248
247
  if (this.gen >= 2) {
249
248
  do {
250
- item = this.sample(items);
251
- } while (this.dex.items.get(item).gen > this.gen || this.dex.data.Items[item].isNonstandard);
249
+ item = this.sample(items).name;
250
+ } while (this.dex.items.get(item).gen > this.gen || this.dex.items.get(item).isNonstandard);
252
251
  }
253
252
  // Make sure forme is legal
254
253
  if (species.battleOnly) {
@@ -270,33 +269,34 @@ class RandomTeams {
270
269
  let itemData = this.dex.items.get(item);
271
270
  if (itemData.forcedForme && forme === this.dex.species.get(itemData.forcedForme).baseSpecies) {
272
271
  do {
273
- item = this.sample(items);
274
- itemData = this.dex.items.get(item);
272
+ itemData = this.sample(items);
273
+ item = itemData.name;
275
274
  } while (itemData.gen > this.gen ||
276
275
  itemData.isNonstandard ||
277
276
  (itemData.forcedForme && forme === this.dex.species.get(itemData.forcedForme).baseSpecies));
278
277
  }
279
278
  // Random legal ability
280
279
  const abilities = Object.values(species.abilities).filter(a => this.dex.abilities.get(a).gen <= this.gen);
281
- const ability = this.gen <= 2 ? 'None' : this.sample(abilities);
280
+ const ability = this.gen <= 2 ? 'No Ability' : this.sample(abilities);
282
281
  // Four random unique moves from the movepool
283
282
  let pool = ['struggle'];
284
283
  if (forme === 'Smeargle') {
285
- pool = Object.keys(this.dex.data.Moves).filter(moveid => {
286
- const move = this.dex.data.Moves[moveid];
287
- return !(move.isNonstandard || move.isZ || move.isMax || move.realMove);
288
- });
284
+ pool = this.dex.moves
285
+ .all()
286
+ .filter(move => !(move.isNonstandard || move.isZ || move.isMax || move.realMove))
287
+ .map(m => m.id);
289
288
  }
290
289
  else {
291
290
  const formes = ['gastrodoneast', 'pumpkaboosuper', 'zygarde10'];
292
- let learnset = ((_a = this.dex.data.Learnsets[species.id]) === null || _a === void 0 ? void 0 : _a.learnset) && !formes.includes(species.id) ?
293
- this.dex.data.Learnsets[species.id].learnset :
294
- this.dex.data.Learnsets[this.dex.species.get(species.baseSpecies).id].learnset;
291
+ let learnset = this.dex.species.getLearnset(species.id);
292
+ if (formes.includes(species.id) || !learnset) {
293
+ learnset = this.dex.species.getLearnset(this.dex.species.get(species.baseSpecies).id);
294
+ }
295
295
  if (learnset) {
296
296
  pool = Object.keys(learnset).filter(moveid => learnset[moveid].find(learned => learned.startsWith(String(this.gen))));
297
297
  }
298
298
  if (species.changesFrom) {
299
- learnset = this.dex.data.Learnsets[(0, sim_1.toID)(species.changesFrom)].learnset;
299
+ learnset = this.dex.species.getLearnset((0, sim_1.toID)(species.changesFrom));
300
300
  const basePool = Object.keys(learnset).filter(moveid => learnset[moveid].find(learned => learned.startsWith(String(this.gen))));
301
301
  pool = [...new Set(pool.concat(basePool))];
302
302
  }
@@ -322,7 +322,7 @@ class RandomTeams {
322
322
  spe: this.random(32),
323
323
  };
324
324
  // Random nature
325
- const nature = this.sample(natures);
325
+ const nature = this.sample(natures).name;
326
326
  // Level balance--calculate directly from stats rather than using some silly lookup table
327
327
  const mbstmin = 1307; // Sunkern has the lowest modified base stat total, and that total is 807
328
328
  let stats = species.baseStats;
@@ -357,15 +357,15 @@ class RandomTeams {
357
357
  name: species.baseSpecies,
358
358
  species: species.name,
359
359
  gender: species.gender,
360
- item: item,
361
- ability: ability,
362
- moves: moves,
363
- evs: evs,
364
- ivs: ivs,
365
- nature: nature,
360
+ item,
361
+ ability,
362
+ moves,
363
+ evs,
364
+ ivs,
365
+ nature,
366
366
  level,
367
- happiness: happiness,
368
- shiny: shiny,
367
+ happiness,
368
+ shiny,
369
369
  });
370
370
  }
371
371
  return team;
@@ -381,15 +381,14 @@ class RandomTeams {
381
381
  throw new Error(`"${requiredType}" is not a valid type.`);
382
382
  }
383
383
  const pool = [];
384
- for (const id in this.dex.data.FormatsData) {
385
- if (!this.dex.data.Pokedex[id] ||
386
- (this.dex.data.FormatsData[id].isNonstandard && this.dex.data.FormatsData[id].isNonstandard !== 'Unobtainable'))
384
+ for (const species of this.dex.species.all()) {
385
+ if (species.isNonstandard && species.isNonstandard !== 'Unobtainable')
387
386
  continue;
388
- if (requiredType && !this.dex.data.Pokedex[id].types.includes(requiredType))
387
+ if (requiredType && !species.types.includes(requiredType))
389
388
  continue;
390
- if (minSourceGen && (this.dex.data.Pokedex[id].gen || 8) < minSourceGen)
389
+ if (minSourceGen && species.gen < minSourceGen)
391
390
  continue;
392
- const num = this.dex.data.Pokedex[id].num;
391
+ const num = species.num;
393
392
  if (num <= 0 || pool.includes(num))
394
393
  continue;
395
394
  if (num > last)
@@ -402,10 +401,9 @@ class RandomTeams {
402
401
  hasDexNumber[num] = i;
403
402
  }
404
403
  const formes = [];
405
- for (const id in this.dex.data.Pokedex) {
406
- if (!(this.dex.data.Pokedex[id].num in hasDexNumber))
404
+ for (const species of this.dex.species.all()) {
405
+ if (!(species.num in hasDexNumber))
407
406
  continue;
408
- const species = this.dex.species.get(id);
409
407
  if (species.gen <= this.gen && (!species.isNonstandard || species.isNonstandard === 'Unobtainable')) {
410
408
  if (!formes[hasDexNumber[species.num]])
411
409
  formes[hasDexNumber[species.num]] = [];
@@ -423,35 +421,38 @@ class RandomTeams {
423
421
  }
424
422
  randomHCTeam() {
425
423
  const team = [];
426
- const itemPool = Object.keys(this.dex.data.Items);
427
- const abilityPool = Object.keys(this.dex.data.Abilities);
428
- const movePool = Object.keys(this.dex.data.Moves);
429
- const naturePool = Object.keys(this.dex.data.Natures);
424
+ const itemPool = [...this.dex.items.all()];
425
+ const abilityPool = [...this.dex.abilities.all()];
426
+ const movePool = [...this.dex.moves.all()];
427
+ const naturePool = this.dex.natures.all();
430
428
  const randomN = this.randomNPokemon(this.maxTeamSize, this.forceMonotype);
431
429
  for (const forme of randomN) {
432
430
  // Choose forme
433
431
  const species = this.dex.species.get(forme);
434
432
  // Random unique item
435
433
  let item = '';
434
+ let itemData;
436
435
  if (this.gen >= 2) {
437
436
  do {
438
- item = this.sampleNoReplace(itemPool);
439
- } while (this.dex.items.get(item).gen > this.gen || this.dex.data.Items[item].isNonstandard);
437
+ itemData = this.sampleNoReplace(itemPool);
438
+ item = itemData.name;
439
+ } while (itemData.gen > this.gen || itemData.isNonstandard);
440
440
  }
441
441
  // Random unique ability
442
- let ability = 'None';
442
+ let ability = 'No Ability';
443
+ let abilityData;
443
444
  if (this.gen >= 3) {
444
445
  do {
445
- ability = this.sampleNoReplace(abilityPool);
446
- } while (this.dex.abilities.get(ability).gen > this.gen || this.dex.data.Abilities[ability].isNonstandard);
446
+ abilityData = this.sampleNoReplace(abilityPool);
447
+ ability = abilityData.name;
448
+ } while (abilityData.gen > this.gen || abilityData.isNonstandard);
447
449
  }
448
450
  // Random unique moves
449
451
  const m = [];
450
452
  do {
451
- const moveid = this.sampleNoReplace(movePool);
452
- const move = this.dex.moves.get(moveid);
453
+ const move = this.sampleNoReplace(movePool);
453
454
  if (move.gen <= this.gen && !move.isNonstandard && !move.name.startsWith('Hidden Power ')) {
454
- m.push(moveid);
455
+ m.push(move.id);
455
456
  }
456
457
  } while (m.length < 4);
457
458
  // Random EVs
@@ -480,7 +481,7 @@ class RandomTeams {
480
481
  spe: this.random(32),
481
482
  };
482
483
  // Random nature
483
- const nature = this.sample(naturePool);
484
+ const nature = this.sample(naturePool).name;
484
485
  // Level balance
485
486
  const mbstmin = 1307;
486
487
  const stats = species.baseStats;
@@ -510,15 +511,15 @@ class RandomTeams {
510
511
  name: species.baseSpecies,
511
512
  species: species.name,
512
513
  gender: species.gender,
513
- item: item,
514
- ability: ability,
514
+ item,
515
+ ability,
515
516
  moves: m,
516
- evs: evs,
517
- ivs: ivs,
518
- nature: nature,
517
+ evs,
518
+ ivs,
519
+ nature,
519
520
  level,
520
- happiness: happiness,
521
- shiny: shiny,
521
+ happiness,
522
+ shiny,
522
523
  });
523
524
  }
524
525
  return team;
@@ -1136,9 +1137,8 @@ class RandomTeams {
1136
1137
  return (moves.has('rapidspin') || species.nfe || isDoubles);
1137
1138
  case 'Blaze':
1138
1139
  return (isDoubles && abilities.has('Solar Power')) || (!isDoubles && !isNoDynamax && species.id === 'charizard');
1139
- case 'Bulletproof':
1140
- case 'Overcoat':
1141
- return !!counter.setupType;
1140
+ // case 'Bulletproof': case 'Overcoat':
1141
+ // return !!counter.setupType;
1142
1142
  case 'Chlorophyll':
1143
1143
  return (species.baseStats.spe > 100 || !counter.get('Fire') && !moves.has('sunnyday') && !teamDetails.sun);
1144
1144
  case 'Cloud Nine':
@@ -1545,7 +1545,7 @@ class RandomTeams {
1545
1545
  const randMoves = (isDoubles && species.randomDoubleBattleMoves) ||
1546
1546
  (isNoDynamax && species.randomBattleNoDynamaxMoves) ||
1547
1547
  species.randomBattleMoves;
1548
- const movePool = (randMoves || Object.keys(this.dex.data.Learnsets[species.id].learnset)).slice();
1548
+ const movePool = (randMoves || Object.keys(this.dex.species.getLearnset(species.id))).slice();
1549
1549
  if (this.format.gameType === 'multi' || this.format.gameType === 'freeforall') {
1550
1550
  // Random Multi Battle uses doubles move pools, but Ally Switch fails in multi battles
1551
1551
  // Random Free-For-All also uses doubles move pools, for now
@@ -1767,8 +1767,10 @@ class RandomTeams {
1767
1767
  forme = 'Pikachu' + this.sample(['', '-Original', '-Hoenn', '-Sinnoh', '-Unova', '-Kalos', '-Alola', '-Partner', '-World']);
1768
1768
  }
1769
1769
  let level;
1770
+ // doubles levelling
1770
1771
  if (isDoubles && species.randomDoubleBattleLevel) {
1771
1772
  level = species.randomDoubleBattleLevel;
1773
+ // No Dmax levelling
1772
1774
  }
1773
1775
  else if (isNoDynamax) {
1774
1776
  const tier = species.name.endsWith('-Gmax') ? this.dex.species.get(species.changesFrom).tier : species.tier;
@@ -1795,9 +1797,29 @@ class RandomTeams {
1795
1797
  decidueye: 87, noivern: 85, magnezone: 82, slowking: 81,
1796
1798
  };
1797
1799
  level = customScale[species.id] || tierScale[tier];
1800
+ // BDSP tier levelling
1801
+ }
1802
+ else if (this.dex.currentMod === 'gen8bdsp') {
1803
+ const tierScale = {
1804
+ Uber: 76,
1805
+ OU: 80,
1806
+ UUBL: 81,
1807
+ UU: 82,
1808
+ RUBL: 83,
1809
+ RU: 84,
1810
+ NUBL: 85,
1811
+ NU: 86,
1812
+ PUBL: 87,
1813
+ PU: 88, "(PU)": 88, NFE: 88,
1814
+ };
1815
+ // to override tier scaling if needed
1816
+ const customScale = {};
1817
+ level = customScale[species.id] || tierScale[species.tier];
1818
+ // Arbitrary levelling base on data files (typically winrate-influenced)
1798
1819
  }
1799
1820
  else if (species.randomBattleLevel) {
1800
1821
  level = species.randomBattleLevel;
1822
+ // Default to level 80
1801
1823
  }
1802
1824
  else {
1803
1825
  level = 80;
@@ -1807,7 +1829,7 @@ class RandomTeams {
1807
1829
  const srWeakness = srImmunity ? 0 : this.dex.getEffectiveness('Rock', species);
1808
1830
  while (evs.hp > 1) {
1809
1831
  const hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
1810
- const multipleOfFourNecessary = (moves.has('substitute') && (item === 'Sitrus Berry' ||
1832
+ const multipleOfFourNecessary = (moves.has('substitute') && !['Leftovers', 'Black Sludge'].includes(item) && (item === 'Sitrus Berry' ||
1811
1833
  item === 'Salac Berry' ||
1812
1834
  ability === 'Power Construct'));
1813
1835
  if (multipleOfFourNecessary) {
@@ -1835,7 +1857,13 @@ class RandomTeams {
1835
1857
  if (moves.has('shellsidearm') && item === 'Choice Specs')
1836
1858
  evs.atk -= 8;
1837
1859
  // Minimize confusion damage
1838
- if (!counter.get('Physical') && !moves.has('transform') && (!moves.has('shellsidearm') || !counter.get('Status'))) {
1860
+ const noAttackStatMoves = [...moves].every(m => {
1861
+ const move = this.dex.moves.get(m);
1862
+ if (move.damageCallback || move.damage)
1863
+ return false;
1864
+ return move.category !== 'Physical' || move.id === 'bodypress';
1865
+ });
1866
+ if (noAttackStatMoves && !moves.has('transform') && (!moves.has('shellsidearm') || !counter.get('Status'))) {
1839
1867
  evs.atk = 0;
1840
1868
  ivs.atk = 0;
1841
1869
  }
@@ -1863,8 +1891,7 @@ class RandomTeams {
1863
1891
  getPokemonPool(type, pokemonToExclude = [], isMonotype = false) {
1864
1892
  const exclude = pokemonToExclude.map(p => (0, sim_1.toID)(p.species));
1865
1893
  const pokemonPool = [];
1866
- for (const id in this.dex.data.FormatsData) {
1867
- let species = this.dex.species.get(id);
1894
+ for (let species of this.dex.species.all()) {
1868
1895
  if (species.gen > this.gen || exclude.includes(species.id))
1869
1896
  continue;
1870
1897
  if (isMonotype) {
@@ -1876,7 +1903,7 @@ class RandomTeams {
1876
1903
  continue;
1877
1904
  }
1878
1905
  }
1879
- pokemonPool.push(id);
1906
+ pokemonPool.push(species.id);
1880
1907
  }
1881
1908
  return pokemonPool;
1882
1909
  }