@pkmn/randoms 0.4.20 → 0.4.24

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
@@ -21,37 +21,10 @@ export class RandomGen1Teams extends RandomGen2Teams {
21
21
  randomCCTeam() {
22
22
  const team = [];
23
23
 
24
- const hasDexNumber: {[k: string]: number} = {};
25
- const formes: string[][] = [[], [], [], [], [], []];
26
-
27
- // Pick six random Pokémon, no repeats.
28
- let num: number;
29
- for (let i = 0; i < this.maxTeamSize; i++) {
30
- do {
31
- num = this.random(151) + 1;
32
- } while (num in hasDexNumber);
33
- hasDexNumber[num] = i;
34
- }
35
-
36
- let formeCounter = 0;
37
- for (const species of this.dex.species.all()) {
38
- if (!(species.num in hasDexNumber)) continue;
39
-
40
- if (this.forceMonotype && !species.types.includes(this.forceMonotype)) continue;
24
+ const randomN = this.randomNPokemon(this.maxTeamSize, this.forceMonotype);
41
25
 
42
- const learnset = this.dex.species.getLearnset(species.id);
43
- if (!learnset || species.forme) continue;
44
- formes[hasDexNumber[species.num]].push(species.name);
45
- if (++formeCounter >= 6) {
46
- // Gen 1 had no alternate formes, so we can break out of the loop already.
47
- break;
48
- }
49
- }
50
-
51
- for (let i = 0; i < this.maxTeamSize; i++) {
52
- // Choose forme.
53
- const poke = this.sample(formes[i]);
54
- const species = this.dex.species.get(poke);
26
+ for (const pokemon of randomN) {
27
+ const species = this.dex.species.get(pokemon);
55
28
  const learnset = this.dex.species.getLearnset(species.id);
56
29
 
57
30
  // Level balance: calculate directly from stats rather than using some silly lookup table.
@@ -113,7 +86,7 @@ export class RandomGen1Teams extends RandomGen2Teams {
113
86
  }
114
87
 
115
88
  team.push({
116
- name: poke,
89
+ name: species.baseSpecies,
117
90
  species: species.name,
118
91
  moves: this.multipleSamplesNoReplace(pool, 4),
119
92
  gender: false,
@@ -134,22 +107,21 @@ export class RandomGen1Teams extends RandomGen2Teams {
134
107
  // Random team generation for Gen 1 Random Battles.
135
108
  randomTeam() {
136
109
  // Get what we need ready.
137
- const pokemon = [];
138
110
  const seed = this.prng.seed;
111
+ const ruleTable = this.dex.formats.getRuleTable(this.format);
112
+ const pokemon: RandomTeamsTypes.RandomSet[] = [];
113
+
114
+ // For Monotype
115
+ const isMonotype = !!this.forceMonotype || ruleTable.has('sametypeclause');
116
+ const typePool = this.dex.types.names();
117
+ const type = this.forceMonotype || this.sample(typePool);
139
118
 
119
+ /** Pokémon that are not wholly incompatible with the team, but still pretty bad */
120
+ const rejectedButNotInvalidPool: string[] = [];
140
121
  const handicapMons = ['magikarp', 'weedle', 'kakuna', 'caterpie', 'metapod'];
141
122
  const nuTiers = ['UU', 'UUBL', 'NFE', 'LC', 'NU'];
142
123
  const uuTiers = ['NFE', 'UU', 'UUBL', 'NU'];
143
124
 
144
- const pokemonPool = [];
145
- /** Pokémon that are not wholly incompatible with the team, but still pretty bad */
146
- const rejectedButNotInvalidPool = [];
147
- for (const species of this.dex.species.all()) {
148
- if (!species.isNonstandard && species.randomBattleMoves) {
149
- pokemonPool.push(species.id);
150
- }
151
- }
152
-
153
125
  // Now let's store what we are getting.
154
126
  const typeCount: {[k: string]: number} = {};
155
127
  const weaknessCount: {[k: string]: number} = {Electric: 0, Psychic: 0, Water: 0, Ice: 0, Ground: 0};
@@ -157,9 +129,10 @@ export class RandomGen1Teams extends RandomGen2Teams {
157
129
  let nuCount = 0;
158
130
  let hasShitmon = false;
159
131
 
132
+ const pokemonPool = this.getPokemonPool(type, pokemon, isMonotype);
160
133
  while (pokemonPool.length && pokemon.length < this.maxTeamSize) {
161
134
  const species = this.dex.species.get(this.sampleNoReplace(pokemonPool));
162
- if (!species.exists) continue;
135
+ if (!species.exists || !species.randomBattleMoves) continue;
163
136
  // Only one Ditto is allowed per battle in Generation 1,
164
137
  // as it can cause an endless battle if two Dittos are forced
165
138
  // to face each other.
@@ -172,8 +145,6 @@ export class RandomGen1Teams extends RandomGen2Teams {
172
145
  continue;
173
146
  }
174
147
 
175
- if (this.forceMonotype && !species.types.includes(this.forceMonotype)) continue;
176
-
177
148
  // Dynamically scale limits for different team sizes. The default and minimum value is 1.
178
149
  const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
179
150
 
@@ -198,31 +169,34 @@ export class RandomGen1Teams extends RandomGen2Teams {
198
169
 
199
170
  let skip = false;
200
171
 
201
- // Limit 2 of any type as well. Diversity and minor weakness count.
202
- // The second of a same type has halved chance of being added.
203
- for (const type of species.types) {
204
- if (typeCount[type] >= 2 * limitFactor ||
205
- (typeCount[type] >= 1 * limitFactor && this.randomChance(1, 2) && pokemonPool.length > 1)) {
206
- skip = true;
207
- break;
172
+ if (!isMonotype && !this.forceMonotype) {
173
+ // Limit 2 of any type as well. Diversity and minor weakness count.
174
+ // The second of a same type has halved chance of being added.
175
+ for (const typeName of species.types) {
176
+ if (typeCount[typeName] >= 2 * limitFactor ||
177
+ (typeCount[typeName] >= 1 * limitFactor && this.randomChance(1, 2) && pokemonPool.length > 1)) {
178
+ skip = true;
179
+ break;
180
+ }
181
+ }
182
+
183
+ if (skip) {
184
+ rejectedButNotInvalidPool.push(species.id);
185
+ continue;
208
186
  }
209
- }
210
- if (skip) {
211
- rejectedButNotInvalidPool.push(species.id);
212
- continue;
213
187
  }
214
188
 
215
189
  // We need a weakness count of spammable attacks to avoid being swept by those.
216
190
  // Spammable attacks are: Thunderbolt, Psychic, Surf, Blizzard, Earthquake.
217
191
  const pokemonWeaknesses = [];
218
- for (const type in weaknessCount) {
219
- const increaseCount = this.dex.getImmunity(type, species) && this.dex.getEffectiveness(type, species) > 0;
192
+ for (const typeName in weaknessCount) {
193
+ const increaseCount = this.dex.getImmunity(typeName, species) && this.dex.getEffectiveness(typeName, species) > 0;
220
194
  if (!increaseCount) continue;
221
- if (weaknessCount[type] >= 2 * limitFactor) {
195
+ if (weaknessCount[typeName] >= 2 * limitFactor) {
222
196
  skip = true;
223
197
  break;
224
198
  }
225
- pokemonWeaknesses.push(type);
199
+ pokemonWeaknesses.push(typeName);
226
200
  }
227
201
 
228
202
  if (skip) {
@@ -235,11 +209,11 @@ export class RandomGen1Teams extends RandomGen2Teams {
235
209
 
236
210
  // Now let's increase the counters.
237
211
  // Type counter.
238
- for (const type of species.types) {
239
- if (typeCount[type]) {
240
- typeCount[type]++;
212
+ for (const typeName of species.types) {
213
+ if (typeCount[typeName]) {
214
+ typeCount[typeName]++;
241
215
  } else {
242
- typeCount[type] = 1;
216
+ typeCount[typeName] = 1;
243
217
  }
244
218
  }
245
219
 
@@ -268,7 +242,7 @@ export class RandomGen1Teams extends RandomGen2Teams {
268
242
  pokemon.push(this.randomSet(species));
269
243
  }
270
244
 
271
- if (pokemon.length < this.maxTeamSize && pokemon.length < 12 && !this.forceMonotype) {
245
+ if (pokemon.length < this.maxTeamSize && pokemon.length < 12 && !isMonotype) {
272
246
  throw new Error(`Could not build a random team for ${this.format} (seed=${seed})`);
273
247
  }
274
248
 
package/src/gen7.ts CHANGED
@@ -517,6 +517,7 @@ export class RandomGen7Teams extends RandomTeams {
517
517
  return {cull: (
518
518
  counter.get('Physical') + counter.get('Special') < 2 ||
519
519
  hasRestTalk ||
520
+ moves.has('rest') ||
520
521
  (!types.has('Water') && !counter.get('Water'))
521
522
  )};
522
523
  case 'sunnyday':
package/src/gen8.ts CHANGED
@@ -1962,13 +1962,15 @@ export class RandomTeams {
1962
1962
  if (item === 'Leftovers' && types.has('Poison')) {
1963
1963
  item = 'Black Sludge';
1964
1964
  }
1965
- if (species.baseSpecies === 'Pikachu' && !gmax) {
1965
+ if (species.baseSpecies === 'Pikachu' && !gmax && this.dex.currentMod !== 'gen8bdsp') {
1966
1966
  forme = 'Pikachu' + this.sample(['', '-Original', '-Hoenn', '-Sinnoh', '-Unova', '-Kalos', '-Alola', '-Partner', '-World']);
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,13 +1996,32 @@ 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);
@@ -2072,6 +2093,7 @@ export class RandomTeams {
2072
2093
  const pokemonPool = [];
2073
2094
  for (let species of this.dex.species.all()) {
2074
2095
  if (species.gen > this.gen || exclude.includes(species.id)) continue;
2096
+ if (this.dex.currentMod === 'gen8bdsp' && species.gen > 4) continue;
2075
2097
  if (isMonotype) {
2076
2098
  if (!species.types.includes(type)) continue;
2077
2099
  if (typeof species.battleOnly === 'string') {
@@ -2112,9 +2134,9 @@ export class RandomTeams {
2112
2134
 
2113
2135
  // Check if the forme has moves for random battle
2114
2136
  if (this.format.gameType === 'singles') {
2115
- if (!species.randomBattleMoves) continue;
2137
+ if (!species.randomBattleMoves?.length) continue;
2116
2138
  } else {
2117
- if (!species.randomDoubleBattleMoves) continue;
2139
+ if (!species.randomDoubleBattleMoves?.length) continue;
2118
2140
  }
2119
2141
 
2120
2142
  // Limit to one of each species (Species Clause)