@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/build/gen1.js +36 -62
- package/build/gen1.js.map +1 -1
- package/build/gen7.js +1 -0
- package/build/gen7.js.map +1 -1
- package/build/gen8.js +28 -3
- package/build/gen8.js.map +1 -1
- package/package.json +2 -2
- package/src/gen1.ts +38 -64
- package/src/gen7.ts +1 -0
- package/src/gen8.ts +26 -4
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
|
|
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
|
-
|
|
43
|
-
|
|
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:
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
(typeCount[
|
|
206
|
-
|
|
207
|
-
|
|
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
|
|
219
|
-
const increaseCount = this.dex.getImmunity(
|
|
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[
|
|
195
|
+
if (weaknessCount[typeName] >= 2 * limitFactor) {
|
|
222
196
|
skip = true;
|
|
223
197
|
break;
|
|
224
198
|
}
|
|
225
|
-
pokemonWeaknesses.push(
|
|
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
|
|
239
|
-
if (typeCount[
|
|
240
|
-
typeCount[
|
|
212
|
+
for (const typeName of species.types) {
|
|
213
|
+
if (typeCount[typeName]) {
|
|
214
|
+
typeCount[typeName]++;
|
|
241
215
|
} else {
|
|
242
|
-
typeCount[
|
|
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 && !
|
|
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)
|