@pkmn/randoms 0.6.3 → 0.7.0

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/gen7.js DELETED
@@ -1,2022 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RandomGen7Teams = void 0;
4
- const gen8_1 = require("./gen8");
5
- const utils_1 = require("./utils");
6
- const sim_1 = require("@pkmn/sim");
7
- const ZeroAttackHPIVs = {
8
- grass: { hp: 30, spa: 30 },
9
- fire: { spa: 30, spe: 30 },
10
- ice: { def: 30 },
11
- ground: { spa: 30, spd: 30 },
12
- fighting: { def: 30, spa: 30, spd: 30, spe: 30 },
13
- electric: { def: 30, spe: 30 },
14
- psychic: { spe: 30 },
15
- flying: { spa: 30, spd: 30, spe: 30 },
16
- rock: { def: 30, spd: 30, spe: 30 },
17
- };
18
- class RandomGen7Teams extends gen8_1.RandomTeams {
19
- constructor(dex, format, prng) {
20
- super(dex, format, prng);
21
- this.randomFactorySets = {};
22
- this.randomBSSFactorySets = {};
23
- this.noStab = [...this.noStab, 'voltswitch'];
24
- this.moveEnforcementCheckers = {
25
- Bug: movePool => movePool.includes('megahorn') || movePool.includes('pinmissile'),
26
- Dark: (movePool, moves, abilities, types, counter, species) => ((!counter.get('Dark') && !abilities.has('Protean')) ||
27
- (moves.has('pursuit') && species.types.length > 1 && counter.get('Dark') === 1)),
28
- Dragon: (movePool, moves, abilities, types, counter) => (!counter.get('Dragon') &&
29
- !abilities.has('Aerilate') && !abilities.has('Pixilate') &&
30
- !moves.has('fly') && !moves.has('rest') && !moves.has('sleeptalk')),
31
- Electric: (movePool, moves, abilities, types, counter) => !counter.get('Electric') || movePool.includes('thunder'),
32
- Fairy: (movePool, moves, abilities, types, counter) => ((!counter.get('Fairy') && !types.has('Flying') && !abilities.has('Pixilate'))),
33
- Fighting: (movePool, moves, abilities, types, counter) => !counter.get('Fighting') || !counter.get('stab'),
34
- Fire: (movePool, moves, abilities, types, counter) => (!counter.get('Fire') || ['eruption', 'flareblitz', 'quiverdance'].some(m => movePool.includes(m))),
35
- Flying: (movePool, moves, abilities, types, counter, species) => (!counter.get('Flying') && (species.id === 'rotomfan' ||
36
- abilities.has('Gale Wings') ||
37
- abilities.has('Serene Grace') || (types.has('Normal') && (movePool.includes('beakblast') || movePool.includes('bravebird'))))),
38
- Ghost: (movePool, moves, abilities, types, counter) => ((!counter.get('Ghost') || movePool.includes('spectralthief')) &&
39
- !types.has('Dark') &&
40
- !abilities.has('Steelworker')),
41
- Grass: (movePool, moves, abilities, types, counter, species) => (!counter.get('Grass') && (species.baseStats.atk >= 100 || movePool.includes('leafstorm'))),
42
- Ground: (movePool, moves, abilities, types, counter) => (!counter.get('Ground') && !moves.has('rest') && !moves.has('sleeptalk')),
43
- Ice: (movePool, moves, abilities, types, counter) => (!abilities.has('Refrigerate') && (!counter.get('Ice') ||
44
- movePool.includes('iciclecrash') ||
45
- (abilities.has('Snow Warning') && movePool.includes('blizzard')))),
46
- Normal: movePool => movePool.includes('facade'),
47
- Poison: (movePool, moves, abilities, types, counter) => (!counter.get('Poison') &&
48
- (!!counter.setupType || abilities.has('Adaptability') || abilities.has('Sheer Force') || movePool.includes('gunkshot'))),
49
- Psychic: (movePool, moves, abilities, types, counter, species) => (!counter.get('Psychic') && (abilities.has('Psychic Surge') ||
50
- movePool.includes('psychicfangs') ||
51
- (!types.has('Flying') && !abilities.has('Pixilate') && counter.get('stab') < species.types.length))),
52
- Rock: (movePool, moves, abilities, types, counter, species) => (!counter.get('Rock') &&
53
- !types.has('Fairy') &&
54
- (counter.setupType === 'Physical' || species.baseStats.atk >= 105 || abilities.has('Rock Head'))),
55
- Steel: (movePool, moves, abilities, types, counter, species) => (!counter.get('Steel') && (species.baseStats.atk >= 100 || abilities.has('Steelworker'))),
56
- Water: (movePool, moves, abilities, types, counter, species) => ((!counter.get('Water') && !abilities.has('Protean')) ||
57
- !counter.get('stab') ||
58
- movePool.includes('crabhammer') ||
59
- (abilities.has('Huge Power') && movePool.includes('aquajet'))),
60
- Adaptability: (movePool, moves, abilities, types, counter, species) => (!counter.setupType &&
61
- species.types.length > 1 &&
62
- (!counter.get(species.types[0]) || !counter.get(species.types[1]))),
63
- Contrary: (movePool, moves, abilities, types, counter, species) => (!counter.get('contrary') && species.name !== 'Shuckle'),
64
- 'Slow Start': movePool => movePool.includes('substitute'),
65
- };
66
- }
67
- shouldCullMove(move, types, moves, abilities, counter, movePool, teamDetails, species, isLead, isDoubles) {
68
- const hasRestTalk = moves.has('rest') && moves.has('sleeptalk');
69
- switch (move.id) {
70
- // Not very useful without their supporting moves
71
- case 'clangingscales':
72
- case 'electricterrain':
73
- case 'happyhour':
74
- case 'holdhands':
75
- return {
76
- cull: !!teamDetails.zMove || hasRestTalk,
77
- isSetup: move.id === 'happyhour' || move.id === 'holdhands',
78
- };
79
- case 'cottonguard':
80
- case 'defendorder':
81
- return { cull: !counter.get('recovery') && !moves.has('rest') };
82
- case 'bounce':
83
- case 'dig':
84
- case 'fly':
85
- return { cull: !!teamDetails.zMove || counter.setupType !== 'Physical' };
86
- case 'focuspunch':
87
- return { cull: !moves.has('substitute') || counter.damagingMoves.size < 2 };
88
- case 'icebeam':
89
- return { cull: abilities.has('Tinted Lens') && !!counter.get('Status') };
90
- case 'perishsong':
91
- return { cull: !moves.has('protect') };
92
- case 'reflect':
93
- if (movePool.length > 1) {
94
- const screen = movePool.indexOf('lightscreen');
95
- if (screen >= 0)
96
- this.fastPop(movePool, screen);
97
- }
98
- return { cull: !moves.has('calmmind') && !moves.has('lightscreen') };
99
- case 'rest':
100
- return { cull: movePool.includes('sleeptalk') };
101
- case 'sleeptalk':
102
- if (movePool.length > 1) {
103
- const rest = movePool.indexOf('rest');
104
- if (rest >= 0)
105
- this.fastPop(movePool, rest);
106
- }
107
- return { cull: !moves.has('rest') };
108
- case 'storedpower':
109
- return { cull: !counter.setupType };
110
- case 'switcheroo':
111
- case 'trick':
112
- return { cull: (counter.get('Physical') + counter.get('Special') < 3 ||
113
- ['electroweb', 'snarl', 'suckerpunch'].some(m => moves.has(m))) };
114
- // Set up once and only if we have the moves for it
115
- case 'bellydrum':
116
- case 'bulkup':
117
- case 'coil':
118
- case 'curse':
119
- case 'dragondance':
120
- case 'honeclaws':
121
- case 'swordsdance':
122
- return { cull: (counter.setupType !== 'Physical' ||
123
- counter.get('physicalsetup') > 1 ||
124
- (counter.get('Physical') + counter.get('physicalpool') < 2 && !hasRestTalk) ||
125
- (move.id === 'bulkup' && hasRestTalk) ||
126
- (move.id === 'bellydrum' && !abilities.has('Unburden') && !counter.get('priority'))), isSetup: true };
127
- case 'calmmind':
128
- case 'geomancy':
129
- case 'nastyplot':
130
- case 'quiverdance':
131
- case 'tailglow':
132
- if (types.has('Dark') && moves.has('darkpulse')) {
133
- counter.setupType = 'Special';
134
- return { cull: false, isSetup: true };
135
- }
136
- return { cull: (counter.setupType !== 'Special' ||
137
- counter.get('specialsetup') > 1 ||
138
- (counter.get('Special') + counter.get('specialpool') < 2 && !hasRestTalk)), isSetup: true };
139
- case 'growth':
140
- case 'shellsmash':
141
- case 'workup':
142
- return { cull: (counter.setupType !== 'Mixed' ||
143
- counter.get('mixedsetup') > 1 ||
144
- counter.damagingMoves.size + counter.get('physicalpool') + counter.get('specialpool') < 2 ||
145
- (move.id === 'growth' && !moves.has('sunnyday'))), isSetup: true };
146
- case 'agility':
147
- case 'autotomize':
148
- case 'rockpolish':
149
- case 'shiftgear':
150
- return { cull: counter.damagingMoves.size < 2 || hasRestTalk, isSetup: !counter.setupType };
151
- case 'flamecharge':
152
- return { cull: (moves.has('dracometeor') ||
153
- moves.has('overheat') ||
154
- (counter.damagingMoves.size < 3 && !counter.setupType)) };
155
- // Bad after setup
156
- case 'circlethrow':
157
- case 'dragontail':
158
- return { cull: (!!counter.get('speedsetup') ||
159
- (isDoubles && moves.has('superpower')) ||
160
- (!!counter.setupType && ((!moves.has('rest') && !moves.has('sleeptalk')) || moves.has('stormthrow'))) ||
161
- ['encore', 'raindance', 'roar', 'trickroom', 'whirlwind'].some(m => moves.has(m)) ||
162
- (counter.get(move.type) > 1 && counter.get('Status') > 1) ||
163
- (abilities.has('Sheer Force') && !!counter.get('sheerforce'))) };
164
- case 'defog':
165
- return { cull: !!counter.setupType || moves.has('spikes') || moves.has('stealthrock') || !!teamDetails.defog };
166
- case 'fakeout':
167
- case 'tailwind':
168
- return { cull: !!counter.setupType || ['substitute', 'switcheroo', 'trick'].some(m => moves.has(m)) };
169
- case 'foulplay':
170
- return { cull: (!!counter.setupType ||
171
- !!counter.get('speedsetup') ||
172
- counter.get('Dark') > 2 ||
173
- moves.has('clearsmog') ||
174
- counter.damagingMoves.size - 1 === counter.get('priority') ||
175
- hasRestTalk) };
176
- case 'haze':
177
- case 'spikes':
178
- return { cull: !!counter.setupType || !!counter.get('speedsetup') || moves.has('trickroom') };
179
- case 'healbell':
180
- case 'technoblast':
181
- return { cull: !!counter.get('speedsetup') };
182
- case 'healingwish':
183
- case 'memento':
184
- return { cull: !!counter.setupType || !!counter.get('recovery') || moves.has('substitute') };
185
- case 'helpinghand':
186
- case 'yawn':
187
- return { cull: !!counter.setupType };
188
- case 'icywind':
189
- case 'stringshot':
190
- return { cull: !!counter.get('speedsetup') || moves.has('trickroom') };
191
- case 'leechseed':
192
- case 'roar':
193
- case 'whirlwind':
194
- return { cull: (!!counter.setupType ||
195
- !!counter.get('speedsetup') ||
196
- moves.has('dragontail') ||
197
- (isDoubles && (movePool.includes('protect') || movePool.includes('spikyshield')))) };
198
- case 'protect':
199
- const doublesCondition = (moves.has('fakeout') ||
200
- (moves.has('tailwind') && moves.has('roost')) ||
201
- movePool.includes('bellydrum') ||
202
- movePool.includes('shellsmash'));
203
- const singlesCondition = counter.setupType && !moves.has('wish');
204
- return { cull: ((isDoubles ? doublesCondition : singlesCondition) ||
205
- !!counter.get('speedsetup') ||
206
- moves.has('rest') || moves.has('roar') || moves.has('whirlwind') ||
207
- (moves.has('lightscreen') && moves.has('reflect'))) };
208
- case 'pursuit':
209
- return { cull: (!!counter.setupType ||
210
- counter.get('Status') > 1 ||
211
- counter.get('Dark') > 2 ||
212
- (moves.has('knockoff') && !types.has('Dark'))) };
213
- case 'rapidspin':
214
- return { cull: !!counter.setupType || !!teamDetails.rapidSpin };
215
- case 'reversal':
216
- return { cull: moves.has('substitute') && !!teamDetails.zMove };
217
- case 'seismictoss':
218
- case 'superfang':
219
- return { cull: !abilities.has('Parental Bond') && (counter.damagingMoves.size > 1 || !!counter.setupType) };
220
- case 'stealthrock':
221
- return { cull: (!!counter.setupType ||
222
- !!counter.get('speedsetup') ||
223
- ['rest', 'substitute', 'trickroom'].some(m => moves.has(m)) ||
224
- !!teamDetails.stealthRock) };
225
- case 'stickyweb':
226
- return { cull: !!teamDetails.stickyWeb };
227
- case 'toxicspikes':
228
- return { cull: !!counter.setupType || !!teamDetails.toxicSpikes };
229
- case 'trickroom':
230
- return { cull: (!!counter.setupType ||
231
- !!counter.get('speedsetup') ||
232
- counter.damagingMoves.size < 2 ||
233
- moves.has('lightscreen') ||
234
- moves.has('reflect')) };
235
- case 'uturn':
236
- return { cull: ((abilities.has('Speed Boost') && moves.has('protect')) ||
237
- (abilities.has('Protean') && counter.get('Status') > 2) ||
238
- !!counter.setupType ||
239
- !!counter.get('speedsetup') || (types.has('Bug') &&
240
- counter.get('stab') < 2 &&
241
- counter.damagingMoves.size > 2 &&
242
- !abilities.has('Adaptability') &&
243
- !abilities.has('Download'))) };
244
- case 'voltswitch':
245
- return { cull: (!!counter.setupType ||
246
- !!counter.get('speedsetup') ||
247
- ['electricterrain', 'raindance', 'uturn'].some(m => moves.has(m))) };
248
- // Bit redundant to have both
249
- // Attacks:
250
- case 'bugbite':
251
- case 'bugbuzz':
252
- case 'infestation':
253
- case 'signalbeam':
254
- return { cull: moves.has('uturn') && !counter.setupType && !abilities.has('Tinted Lens') };
255
- case 'darkestlariat':
256
- case 'nightslash':
257
- return { cull: moves.has('knockoff') || moves.has('pursuit') };
258
- case 'darkpulse':
259
- return { cull: ['crunch', 'knockoff', 'hyperspacefury'].some(m => moves.has(m)) && counter.setupType !== 'Special' };
260
- case 'suckerpunch':
261
- return { cull: counter.damagingMoves.size < 2 || moves.has('glare') || !types.has('Dark') && counter.get('Dark') > 1 };
262
- case 'dracometeor':
263
- return { cull: hasRestTalk };
264
- case 'dragonpulse':
265
- case 'spacialrend':
266
- return { cull: moves.has('dracometeor') || moves.has('outrage') || (moves.has('dragontail') && !counter.setupType) };
267
- case 'outrage':
268
- return { cull: (moves.has('dragonclaw') ||
269
- (moves.has('dracometeor') && counter.damagingMoves.size < 3) ||
270
- (moves.has('clangingscales') && !teamDetails.zMove)) };
271
- case 'thunderbolt':
272
- return { cull: ['discharge', 'voltswitch', 'wildcharge'].some(m => moves.has(m)) };
273
- case 'moonblast':
274
- return { cull: isDoubles && moves.has('dazzlinggleam') };
275
- case 'aurasphere':
276
- case 'focusblast':
277
- return { cull: (hasRestTalk ||
278
- ((moves.has('closecombat') || moves.has('superpower')) && counter.setupType !== 'Special')) };
279
- case 'drainpunch':
280
- return { cull: ((!moves.has('bulkup') && (moves.has('closecombat') || moves.has('highjumpkick'))) ||
281
- ((moves.has('focusblast') || moves.has('superpower')) && counter.setupType !== 'Physical')) };
282
- case 'closecombat':
283
- case 'highjumpkick':
284
- return { cull: ((moves.has('bulkup') && moves.has('drainpunch')) ||
285
- (counter.setupType === 'Special' && ['aurasphere', 'focusblast'].some(m => moves.has(m) || movePool.includes(m)))) };
286
- case 'dynamicpunch':
287
- case 'vacuumwave':
288
- return { cull: (moves.has('closecombat') || moves.has('facade')) && counter.setupType !== 'Special' };
289
- case 'stormthrow':
290
- return { cull: moves.has('circlethrow') && hasRestTalk };
291
- case 'superpower':
292
- return {
293
- cull: (counter.get('Fighting') > 1 && !!counter.setupType) || (hasRestTalk && !abilities.has('Contrary')),
294
- isSetup: abilities.has('Contrary'),
295
- };
296
- case 'fierydance':
297
- case 'heatwave':
298
- return { cull: moves.has('fireblast') && (!!counter.get('Status') || isDoubles) };
299
- case 'firefang':
300
- case 'firepunch':
301
- case 'flamethrower':
302
- return { cull: (['blazekick', 'heatwave', 'overheat'].some(m => moves.has(m)) ||
303
- ((moves.has('fireblast') || moves.has('lavaplume')) && counter.setupType !== 'Physical')) };
304
- case 'fireblast':
305
- case 'magmastorm':
306
- return { cull: ((moves.has('flareblitz') && counter.setupType !== 'Special') ||
307
- (moves.has('lavaplume') && !counter.setupType && !counter.get('speedsetup'))) };
308
- case 'lavaplume':
309
- return { cull: moves.has('firepunch') || moves.has('fireblast') && (!!counter.setupType || !!counter.get('speedsetup')) };
310
- case 'overheat':
311
- return { cull: ['fireblast', 'flareblitz', 'lavaplume'].some(m => moves.has(m)) };
312
- case 'hurricane':
313
- return { cull: moves.has('bravebird') || moves.has('airslash') && !!counter.get('Status') };
314
- case 'hex':
315
- return { cull: !moves.has('thunderwave') && !moves.has('willowisp') };
316
- case 'shadowball':
317
- return { cull: moves.has('darkpulse') || (moves.has('hex') && moves.has('willowisp')) };
318
- case 'shadowclaw':
319
- return { cull: (moves.has('shadowforce') ||
320
- moves.has('shadowsneak') ||
321
- (moves.has('shadowball') && counter.setupType !== 'Physical')) };
322
- case 'shadowsneak':
323
- return { cull: (moves.has('trick') ||
324
- hasRestTalk ||
325
- (types.has('Ghost') && species.types.length > 1 && counter.get('stab') < 2)) };
326
- case 'gigadrain':
327
- return { cull: (moves.has('petaldance') ||
328
- moves.has('powerwhip') ||
329
- (!isDoubles && moves.has('seedbomb')) ||
330
- (moves.has('leafstorm') && counter.get('Special') < 4 && !counter.setupType && !moves.has('trickroom'))) };
331
- case 'leafblade':
332
- case 'woodhammer':
333
- return { cull: ((moves.has('gigadrain') && counter.setupType !== 'Physical') ||
334
- (moves.has('hornleech') && !!counter.setupType)) };
335
- case 'leafstorm':
336
- return { cull: (moves.has('trickroom') ||
337
- (isDoubles && moves.has('energyball')) ||
338
- (counter.get('Grass') > 1 && !!counter.setupType)) };
339
- case 'seedbomb':
340
- return { cull: moves.has('leafstorm') || isDoubles && moves.has('gigadrain') };
341
- case 'solarbeam':
342
- return { cull: ((!abilities.has('Drought') && !moves.has('sunnyday')) ||
343
- moves.has('gigadrain') ||
344
- moves.has('leafstorm')) };
345
- case 'bonemerang':
346
- case 'precipiceblades':
347
- return { cull: moves.has('earthquake') };
348
- case 'earthpower':
349
- return { cull: moves.has('earthquake') && counter.setupType !== 'Special' };
350
- case 'earthquake':
351
- return { cull: isDoubles && moves.has('highhorsepower') };
352
- case 'freezedry':
353
- return { cull: moves.has('icebeam') || moves.has('icywind') || counter.get('stab') < 2 };
354
- case 'bodyslam':
355
- case 'return':
356
- return { cull: (moves.has('doubleedge') ||
357
- (moves.has('glare') && moves.has('headbutt')) ||
358
- (move.id === 'return' && moves.has('bodyslam'))) };
359
- case 'endeavor':
360
- return { cull: !isLead && !abilities.has('Defeatist') };
361
- case 'explosion':
362
- return { cull: (!!counter.setupType ||
363
- moves.has('wish') ||
364
- (abilities.has('Refrigerate') && (moves.has('freezedry') || movePool.includes('return')))) };
365
- case 'extremespeed':
366
- case 'skyattack':
367
- return { cull: moves.has('substitute') || counter.setupType !== 'Physical' && moves.has('vacuumwave') };
368
- case 'facade':
369
- return { cull: moves.has('bulkup') || hasRestTalk };
370
- case 'hiddenpower':
371
- return { cull: (moves.has('rest') ||
372
- (!counter.get('stab') && counter.damagingMoves.size < 2) ||
373
- // Force Moonblast on Special-setup Fairies
374
- (counter.setupType === 'Special' && types.has('Fairy') && movePool.includes('moonblast'))) };
375
- case 'hypervoice':
376
- return { cull: moves.has('blizzard') };
377
- case 'judgment':
378
- return { cull: counter.setupType !== 'Special' && counter.get('stab') > 1 };
379
- case 'quickattack':
380
- return { cull: (!!counter.get('speedsetup') ||
381
- (types.has('Rock') && !!counter.get('Status')) ||
382
- moves.has('feint') ||
383
- (types.has('Normal') && !counter.get('stab'))) };
384
- case 'weatherball':
385
- return { cull: !moves.has('raindance') && !moves.has('sunnyday') };
386
- case 'poisonjab':
387
- return { cull: moves.has('gunkshot') };
388
- case 'acidspray':
389
- case 'sludgewave':
390
- return { cull: moves.has('poisonjab') || moves.has('sludgebomb') };
391
- case 'psychic':
392
- return { cull: moves.has('psyshock') };
393
- case 'psychocut':
394
- case 'zenheadbutt':
395
- return { cull: (((moves.has('psychic') || moves.has('psyshock')) && counter.setupType !== 'Physical') ||
396
- (abilities.has('Contrary') && !counter.setupType && !!counter.get('physicalpool'))) };
397
- case 'psyshock':
398
- const psychic = movePool.indexOf('psychic');
399
- if (psychic >= 0)
400
- this.fastPop(movePool, psychic);
401
- return { cull: false };
402
- case 'headsmash':
403
- return { cull: moves.has('stoneedge') || isDoubles && moves.has('rockslide') };
404
- case 'rockblast':
405
- case 'rockslide':
406
- return { cull: (moves.has('headsmash') || moves.has('stoneedge')) && !isDoubles };
407
- case 'stoneedge':
408
- return { cull: (moves.has('rockslide') ||
409
- (abilities.has('Guts') && !moves.has('dynamicpunch')) ||
410
- (isDoubles && moves.has('rockslide'))) };
411
- case 'bulletpunch':
412
- return { cull: types.has('Steel') && counter.get('stab') < 2 && !abilities.has('Technician') };
413
- case 'flashcannon':
414
- return { cull: (moves.has('ironhead') || moves.has('meteormash')) && counter.setupType !== 'Special' };
415
- case 'hydropump':
416
- return { cull: (moves.has('liquidation') ||
417
- moves.has('waterfall') ||
418
- hasRestTalk || (moves.has('scald') &&
419
- ((counter.get('Special') < 4 && !moves.has('uturn')) || (species.types.length > 1 && counter.get('stab') < 3)))) };
420
- case 'muddywater':
421
- return { cull: isDoubles && (moves.has('scald') || moves.has('hydropump')) };
422
- case 'originpulse':
423
- case 'surf':
424
- return { cull: moves.has('hydropump') || moves.has('scald') };
425
- case 'scald':
426
- return { cull: ['liquidation', 'waterfall', 'waterpulse'].some(m => moves.has(m)) };
427
- // Status:
428
- case 'electroweb':
429
- case 'stunspore':
430
- case 'thunderwave':
431
- return { cull: (!!counter.setupType ||
432
- !!counter.get('speedsetup') ||
433
- hasRestTalk ||
434
- ['discharge', 'spore', 'toxic', 'trickroom', 'yawn'].some(m => moves.has(m))) };
435
- case 'glare':
436
- case 'headbutt':
437
- return { cull: moves.has('bodyslam') || !moves.has('glare') };
438
- case 'toxic':
439
- const otherStatus = ['hypnosis', 'sleeppowder', 'toxicspikes', 'willowisp', 'yawn'].some(m => moves.has(m));
440
- return { cull: otherStatus || !!counter.setupType || moves.has('flamecharge') || moves.has('raindance') };
441
- case 'willowisp':
442
- return { cull: moves.has('scald') };
443
- case 'raindance':
444
- return { cull: (counter.get('Physical') + counter.get('Special') < 2 ||
445
- hasRestTalk ||
446
- moves.has('rest') ||
447
- (!types.has('Water') && !counter.get('Water'))) };
448
- case 'sunnyday':
449
- const cull = (counter.get('Physical') + counter.get('Special') < 2 ||
450
- (!abilities.has('Chlorophyll') && !abilities.has('Flower Gift') && !moves.has('solarbeam')) ||
451
- hasRestTalk);
452
- if (cull && movePool.length > 1) {
453
- const solarbeam = movePool.indexOf('solarbeam');
454
- if (solarbeam >= 0)
455
- this.fastPop(movePool, solarbeam);
456
- if (movePool.length > 1) {
457
- const weatherball = movePool.indexOf('weatherball');
458
- if (weatherball >= 0)
459
- this.fastPop(movePool, weatherball);
460
- }
461
- }
462
- return { cull };
463
- case 'painsplit':
464
- case 'recover':
465
- case 'roost':
466
- case 'synthesis':
467
- return { cull: moves.has('leechseed') || moves.has('rest') };
468
- case 'substitute':
469
- return { cull: (moves.has('dracometeor') ||
470
- (moves.has('leafstorm') && !abilities.has('Contrary')) ||
471
- ['encore', 'pursuit', 'rest', 'taunt', 'uturn', 'voltswitch', 'whirlwind'].some(m => moves.has(m)) ||
472
- movePool.includes('copycat')) };
473
- case 'powersplit':
474
- return { cull: moves.has('guardsplit') };
475
- case 'wideguard':
476
- return { cull: moves.has('protect') };
477
- case 'bravebird':
478
- // Hurricane > Brave Bird in the rain
479
- return { cull: (moves.has('raindance') || abilities.has('Drizzle')) && movePool.includes('hurricane') };
480
- }
481
- return { cull: false };
482
- }
483
- shouldCullAbility(ability, types, moves, abilities, counter, movePool, teamDetails, species, isDoubles) {
484
- switch (ability) {
485
- case 'Battle Bond':
486
- case 'Dazzling':
487
- case 'Flare Boost':
488
- case 'Hyper Cutter':
489
- case 'Ice Body':
490
- case 'Innards Out':
491
- case 'Moody':
492
- case 'Steadfast':
493
- return true;
494
- case 'Aerilate':
495
- case 'Galvanize':
496
- case 'Pixilate':
497
- case 'Refrigerate':
498
- return !counter.get('Normal');
499
- case 'Analytic':
500
- case 'Download':
501
- return species.nfe;
502
- case 'Battle Armor':
503
- case 'Sturdy':
504
- return (!!counter.get('recoil') && !counter.get('recovery'));
505
- case 'Chlorophyll':
506
- case 'Leaf Guard':
507
- return (species.baseStats.spe > 100 ||
508
- abilities.has('Harvest') ||
509
- (!moves.has('sunnyday') && !teamDetails.sun));
510
- case 'Competitive':
511
- return (!counter.get('Special') || moves.has('sleeptalk') && moves.has('rest'));
512
- case 'Compound Eyes':
513
- case 'No Guard':
514
- return !counter.get('inaccurate');
515
- case 'Contrary':
516
- case 'Iron Fist':
517
- case 'Skill Link':
518
- case 'Strong Jaw':
519
- return !counter.get((0, sim_1.toID)(ability));
520
- case 'Defiant':
521
- case 'Justified':
522
- case 'Moxie':
523
- return !counter.get('Physical') || moves.has('dragontail');
524
- case 'Flash Fire':
525
- return abilities.has('Drought');
526
- case 'Gluttony':
527
- return !moves.has('bellydrum');
528
- case 'Harvest':
529
- return abilities.has('Frisk');
530
- case 'Hustle':
531
- return counter.get('Physical') < 2;
532
- case 'Hydration':
533
- case 'Rain Dish':
534
- case 'Swift Swim':
535
- return (species.baseStats.spe > 100 || !moves.has('raindance') && !teamDetails.rain);
536
- case 'Slush Rush':
537
- case 'Snow Cloak':
538
- return !teamDetails.hail;
539
- case 'Immunity':
540
- case 'Snow Warning':
541
- return (moves.has('facade') || moves.has('hypervoice'));
542
- case 'Intimidate':
543
- return (moves.has('bodyslam') || moves.has('rest') || abilities.has('Reckless') && counter.get('recoil') > 1);
544
- case 'Lightning Rod':
545
- return species.types.includes('Ground');
546
- case 'Limber':
547
- return species.types.includes('Electric');
548
- case 'Liquid Voice':
549
- return !counter.get('sound');
550
- case 'Magic Guard':
551
- case 'Speed Boost':
552
- return (abilities.has('Tinted Lens') && (!counter.get('Status') || moves.has('uturn')));
553
- case 'Magician':
554
- return moves.has('switcheroo');
555
- case 'Magnet Pull':
556
- return (!!counter.get('Normal') || !types.has('Electric') && !moves.has('earthpower'));
557
- case 'Mold Breaker':
558
- return (moves.has('acrobatics') || moves.has('sleeptalk') ||
559
- abilities.has('Adaptability') || abilities.has('Iron Fist') ||
560
- (abilities.has('Sheer Force') && !!counter.get('sheerforce')));
561
- case 'Overgrow':
562
- return !counter.get('Grass');
563
- case 'Poison Heal':
564
- return (abilities.has('Technician') && !!counter.get('technician'));
565
- case 'Power Construct':
566
- return species.forme === '10%';
567
- case 'Prankster':
568
- return !counter.get('Status');
569
- case 'Pressure':
570
- case 'Synchronize':
571
- return (counter.get('Status') < 2 || !!counter.get('recoil') || !!species.isMega);
572
- case 'Regenerator':
573
- return abilities.has('Magic Guard');
574
- case 'Quick Feet':
575
- return moves.has('bellydrum');
576
- case 'Reckless':
577
- case 'Rock Head':
578
- return (!counter.get('recoil') || !!species.isMega);
579
- case 'Sand Force':
580
- case 'Sand Rush':
581
- case 'Sand Veil':
582
- return !teamDetails.sand;
583
- case 'Scrappy':
584
- return !species.types.includes('Normal');
585
- case 'Serene Grace':
586
- return (!counter.get('serenegrace') || species.name === 'Blissey');
587
- case 'Sheer Force':
588
- return (!counter.get('sheerforce') || moves.has('doubleedge') || abilities.has('Guts') || !!species.isMega);
589
- case 'Simple':
590
- return (!counter.setupType && !moves.has('flamecharge'));
591
- case 'Solar Power':
592
- return (!counter.get('Special') || !teamDetails.sun || !!species.isMega);
593
- case 'Swarm':
594
- return (!counter.get('Bug') || !!species.isMega);
595
- case 'Sweet Veil':
596
- return types.has('Grass');
597
- case 'Technician':
598
- return (!counter.get('technician') || moves.has('tailslap') || !!species.isMega);
599
- case 'Tinted Lens':
600
- return (moves.has('protect') || !!counter.get('damage') ||
601
- (counter.get('Status') > 2 && !counter.setupType) ||
602
- abilities.has('Prankster') ||
603
- (abilities.has('Magic Guard') && !!counter.get('Status')));
604
- case 'Torrent':
605
- return (!counter.get('Water') || !!species.isMega);
606
- case 'Unaware':
607
- return (!!counter.setupType || abilities.has('Magic Guard'));
608
- case 'Unburden':
609
- return (!!species.isMega || abilities.has('Prankster') || !counter.setupType && !moves.has('acrobatics'));
610
- case 'Water Absorb':
611
- return moves.has('raindance') || ['Drizzle', 'Unaware', 'Volt Absorb'].some(abil => abilities.has(abil));
612
- case 'Weak Armor':
613
- return counter.setupType !== 'Physical';
614
- }
615
- return false;
616
- }
617
- getHighPriorityItem(ability, types, moves, counter, teamDetails, species, isLead, isDoubles) {
618
- if (species.requiredItems) {
619
- if (species.baseSpecies === 'Arceus' &&
620
- (moves.has('judgment') || !counter.get(species.types[0]) || teamDetails.zMove)) {
621
- // Judgment doesn't change type with Z-Crystals
622
- return species.requiredItems[0];
623
- }
624
- return this.sample(species.requiredItems);
625
- }
626
- // First, the extra high-priority items
627
- if (species.name === 'Dedenne')
628
- return moves.has('substitute') ? 'Petaya Berry' : 'Sitrus Berry';
629
- if (species.name === 'Deoxys-Attack')
630
- return (isLead && moves.has('stealthrock')) ? 'Focus Sash' : 'Life Orb';
631
- if (species.name === 'Farfetch\u2019d')
632
- return 'Stick';
633
- if (species.name === 'Genesect' && moves.has('technoblast'))
634
- return 'Douse Drive';
635
- if (species.baseSpecies === 'Marowak')
636
- return 'Thick Club';
637
- if (species.name === 'Pikachu')
638
- return 'Light Ball';
639
- if (species.name === 'Shedinja' || species.name === 'Smeargle')
640
- return 'Focus Sash';
641
- if (species.name === 'Unfezant' && counter.get('Physical') >= 2)
642
- return 'Scope Lens';
643
- if (species.name === 'Unown')
644
- return 'Choice Specs';
645
- if (species.name === 'Wobbuffet')
646
- return 'Custap Berry';
647
- if (ability === 'Harvest' || ability === 'Emergency Exit' && !!counter.get('Status'))
648
- return 'Sitrus Berry';
649
- if (ability === 'Imposter')
650
- return 'Choice Scarf';
651
- if (ability === 'Poison Heal')
652
- return 'Toxic Orb';
653
- if (species.nfe)
654
- return (ability === 'Technician' && counter.get('Physical') >= 4) ? 'Choice Band' : 'Eviolite';
655
- if (moves.has('switcheroo') || moves.has('trick')) {
656
- if (species.baseStats.spe >= 60 && species.baseStats.spe <= 108) {
657
- return 'Choice Scarf';
658
- }
659
- else {
660
- return (counter.get('Physical') > counter.get('Special')) ? 'Choice Band' : 'Choice Specs';
661
- }
662
- }
663
- if (moves.has('bellydrum')) {
664
- if (ability === 'Gluttony') {
665
- return `${this.sample(['Aguav', 'Figy', 'Iapapa', 'Mago', 'Wiki'])} Berry`;
666
- }
667
- else if (species.baseStats.spe <= 50 && !teamDetails.zMove && this.randomChance(1, 2)) {
668
- return 'Normalium Z';
669
- }
670
- else {
671
- return 'Sitrus Berry';
672
- }
673
- }
674
- if (moves.has('copycat') && counter.get('Physical') >= 3)
675
- return 'Choice Band';
676
- if (moves.has('geomancy') || moves.has('skyattack'))
677
- return 'Power Herb';
678
- if (moves.has('shellsmash')) {
679
- return (ability === 'Solid Rock' && !!counter.get('priority')) ? 'Weakness Policy' : 'White Herb';
680
- }
681
- if ((ability === 'Guts' || moves.has('facade')) && !moves.has('sleeptalk')) {
682
- return (types.has('Fire') || ability === 'Quick Feet' || ability === 'Toxic Boost') ? 'Toxic Orb' : 'Flame Orb';
683
- }
684
- if ((ability === 'Magic Guard' && counter.damagingMoves.size > 1) ||
685
- (ability === 'Sheer Force' && counter.get('sheerforce'))) {
686
- return 'Life Orb';
687
- }
688
- if (ability === 'Unburden')
689
- return moves.has('fakeout') ? 'Normal Gem' : 'Sitrus Berry';
690
- if (moves.has('acrobatics'))
691
- return '';
692
- if (moves.has('electricterrain') || ability === 'Electric Surge' && moves.has('thunderbolt'))
693
- return 'Electrium Z';
694
- if (moves.has('happyhour') ||
695
- moves.has('holdhands') ||
696
- (moves.has('encore') && ability === 'Contrary'))
697
- return 'Normalium Z';
698
- if (moves.has('raindance')) {
699
- if (species.baseSpecies === 'Castform' && !teamDetails.zMove) {
700
- return 'Waterium Z';
701
- }
702
- else {
703
- return (ability === 'Forecast') ? 'Damp Rock' : 'Life Orb';
704
- }
705
- }
706
- if (moves.has('sunnyday')) {
707
- if ((species.baseSpecies === 'Castform' || species.baseSpecies === 'Cherrim') && !teamDetails.zMove) {
708
- return 'Firium Z';
709
- }
710
- else {
711
- return (ability === 'Forecast') ? 'Heat Rock' : 'Life Orb';
712
- }
713
- }
714
- if (moves.has('solarbeam') && ability !== 'Drought' && !moves.has('sunnyday') && !teamDetails.sun) {
715
- return !teamDetails.zMove ? 'Grassium Z' : 'Power Herb';
716
- }
717
- if (moves.has('auroraveil') || moves.has('lightscreen') && moves.has('reflect'))
718
- return 'Light Clay';
719
- if (moves.has('rest') && !moves.has('sleeptalk') &&
720
- ability !== 'Natural Cure' && ability !== 'Shed Skin' && ability !== 'Shadow Tag') {
721
- return 'Chesto Berry';
722
- }
723
- // Z-Moves
724
- if (!teamDetails.zMove) {
725
- if (species.name === 'Decidueye' && moves.has('spiritshackle') && counter.setupType) {
726
- return 'Decidium Z';
727
- }
728
- if (species.name === 'Kommo-o')
729
- return moves.has('clangingscales') ? 'Kommonium Z' : 'Dragonium Z';
730
- if (species.baseSpecies === 'Lycanroc' && moves.has('stoneedge') && counter.setupType) {
731
- return 'Lycanium Z';
732
- }
733
- if (species.name === 'Marshadow' && moves.has('spectralthief') && counter.setupType) {
734
- return 'Marshadium Z';
735
- }
736
- if (species.name === 'Necrozma-Dusk-Mane' || species.name === 'Necrozma-Dawn-Wings') {
737
- if (moves.has('autotomize') && moves.has('sunsteelstrike')) {
738
- return 'Solganium Z';
739
- }
740
- else if (moves.has('trickroom') && moves.has('moongeistbeam')) {
741
- return 'Lunalium Z';
742
- }
743
- else {
744
- return 'Ultranecrozium Z';
745
- }
746
- }
747
- if (species.name === 'Mimikyu' && moves.has('playrough') && counter.setupType)
748
- return 'Mimikium Z';
749
- if (species.name === 'Raichu-Alola' && moves.has('thunderbolt') && counter.setupType)
750
- return 'Aloraichium Z';
751
- if (moves.has('bugbuzz') && counter.setupType && species.baseStats.spa > 100)
752
- return 'Buginium Z';
753
- if ((moves.has('darkpulse') && ability === 'Fur Coat' && counter.setupType) ||
754
- (moves.has('suckerpunch') && ability === 'Moxie' && counter.get('Dark') < 2)) {
755
- return 'Darkinium Z';
756
- }
757
- if (moves.has('outrage') && counter.setupType && !moves.has('fly'))
758
- return 'Dragonium Z';
759
- if (moves.has('fleurcannon') && !!counter.get('speedsetup'))
760
- return 'Fairium Z';
761
- if ((moves.has('focusblast') && types.has('Fighting') && counter.setupType) ||
762
- (moves.has('reversal') && moves.has('substitute'))) {
763
- return 'Fightinium Z';
764
- }
765
- if (moves.has('fly') ||
766
- (moves.has('hurricane') && species.baseStats.spa >= 125 && (!!counter.get('Status') || moves.has('superpower'))) ||
767
- ((moves.has('bounce') || moves.has('bravebird')) && counter.setupType)) {
768
- return 'Flyinium Z';
769
- }
770
- if (moves.has('shadowball') && counter.setupType && ability === 'Beast Boost')
771
- return 'Ghostium Z';
772
- if (moves.has('sleeppowder') && types.has('Grass') &&
773
- counter.setupType && species.baseStats.spe <= 70) {
774
- return 'Grassium Z';
775
- }
776
- if (moves.has('magmastorm'))
777
- return 'Firium Z';
778
- if (moves.has('dig'))
779
- return 'Groundium Z';
780
- if (moves.has('photongeyser') && counter.setupType)
781
- return 'Psychium Z';
782
- if (moves.has('stoneedge') && types.has('Rock') && moves.has('swordsdance'))
783
- return 'Rockium Z';
784
- if (moves.has('hydropump') && ability === 'Battle Bond' && moves.has('uturn'))
785
- return 'Waterium Z';
786
- if ((moves.has('hail') || (moves.has('blizzard') && ability !== 'Snow Warning')))
787
- return 'Icium Z';
788
- }
789
- }
790
- getMediumPriorityItem(ability, moves, counter, species, isDoubles, isLead) {
791
- const defensiveStatTotal = species.baseStats.hp + species.baseStats.def + species.baseStats.spd;
792
- if ((ability === 'Speed Boost' || ability === 'Stance Change' || species.name === 'Pheromosa') &&
793
- counter.get('Physical') + counter.get('Special') > 2 &&
794
- !moves.has('uturn')) {
795
- return 'Life Orb';
796
- }
797
- if (isDoubles && moves.has('uturn') && counter.get('Physical') === 4 && !moves.has('fakeout')) {
798
- return (species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
799
- !counter.get('priority') && this.randomChance(1, 2)) ? 'Choice Scarf' : 'Choice Band';
800
- }
801
- if (isDoubles && counter.get('Special') === 4 && (moves.has('waterspout') || moves.has('eruption'))) {
802
- return 'Choice Scarf';
803
- }
804
- if (!isDoubles &&
805
- counter.get('Physical') >= 4 &&
806
- ['bodyslam', 'dragontail', 'fakeout', 'flamecharge', 'rapidspin', 'suckerpunch'].every(m => !moves.has(m))) {
807
- return ((species.baseStats.atk >= 100 || ability === 'Huge Power') &&
808
- species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
809
- !counter.get('priority') &&
810
- this.randomChance(2, 3)) ? 'Choice Scarf' : 'Choice Band';
811
- }
812
- if (!isDoubles &&
813
- (counter.get('Special') >= 4 || (counter.get('Special') >= 3 && moves.has('uturn'))) &&
814
- !moves.has('acidspray') && !moves.has('clearsmog')) {
815
- return (species.baseStats.spa >= 100 &&
816
- species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
817
- ability !== 'Tinted Lens' &&
818
- !counter.get('Physical') && !counter.get('priority') &&
819
- this.randomChance(2, 3)) ? 'Choice Scarf' : 'Choice Specs';
820
- }
821
- if (!isDoubles &&
822
- counter.get('Physical') >= 3 &&
823
- moves.has('defog') &&
824
- !moves.has('foulplay') &&
825
- species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
826
- !counter.get('priority')) {
827
- return 'Choice Scarf';
828
- }
829
- if (!isDoubles && (ability === 'Drizzle' ||
830
- ability === 'Slow Start' ||
831
- species.name.includes('Rotom-') ||
832
- ['aromatherapy', 'bite', 'clearsmog', 'curse', 'protect', 'sleeptalk'].some(m => moves.has(m)))) {
833
- return 'Leftovers';
834
- }
835
- if (['endeavor', 'flail', 'reversal'].some(m => moves.has(m)) && ability !== 'Sturdy') {
836
- return (ability === 'Defeatist') ? 'Expert Belt' : 'Focus Sash';
837
- }
838
- if (moves.has('outrage') && counter.setupType)
839
- return 'Lum Berry';
840
- if (isDoubles &&
841
- counter.damagingMoves.size >= 3 &&
842
- species.baseStats.spe >= 70 &&
843
- ability !== 'Multiscale' && ability !== 'Sturdy' && [
844
- 'acidspray', 'electroweb', 'fakeout', 'feint', 'flamecharge', 'icywind',
845
- 'incinerate', 'naturesmadness', 'rapidspin', 'snarl', 'suckerpunch', 'uturn',
846
- ].every(m => !moves.has(m))) {
847
- return defensiveStatTotal >= 275 ? 'Sitrus Berry' : 'Life Orb';
848
- }
849
- if (moves.has('substitute'))
850
- return counter.damagingMoves.size > 2 && !!counter.get('drain') ? 'Life Orb' : 'Leftovers';
851
- if (!isDoubles &&
852
- this.dex.getEffectiveness('Ground', species) >= 2 &&
853
- ability !== 'Levitate' &&
854
- !moves.has('magnetrise')) {
855
- return 'Air Balloon';
856
- }
857
- if ((ability === 'Iron Barbs' || ability === 'Rough Skin') && this.randomChance(1, 2))
858
- return 'Rocky Helmet';
859
- if (counter.get('Physical') + counter.get('Special') >= 4 &&
860
- species.baseStats.spd >= 50 && defensiveStatTotal >= 235) {
861
- return 'Assault Vest';
862
- }
863
- if (species.name === 'Palkia' && (moves.has('dracometeor') || moves.has('spacialrend')) && moves.has('hydropump')) {
864
- return 'Lustrous Orb';
865
- }
866
- if (counter.damagingMoves.size >= 4) {
867
- return (counter.get('Dragon') || counter.get('Dark') || counter.get('Normal')) ? 'Life Orb' : 'Expert Belt';
868
- }
869
- if (counter.damagingMoves.size >= 3 && !!counter.get('speedsetup') && defensiveStatTotal >= 300) {
870
- return 'Weakness Policy';
871
- }
872
- if (!isDoubles && isLead &&
873
- !['Regenerator', 'Sturdy'].includes(ability) &&
874
- !counter.get('recoil') && !counter.get('recovery') &&
875
- defensiveStatTotal < 255) {
876
- return 'Focus Sash';
877
- }
878
- }
879
- getLowPriorityItem(ability, types, moves, abilities, counter, teamDetails, species, isLead, isDoubles) {
880
- // This is the "REALLY can't think of a good item" cutoff
881
- if (moves.has('stickyweb') && ability === 'Sturdy')
882
- return 'Mental Herb';
883
- if (ability === 'Serene Grace' && moves.has('airslash') && species.baseStats.spe > 100)
884
- return 'Metronome';
885
- if (ability === 'Sturdy' && moves.has('explosion') && !counter.get('speedsetup'))
886
- return 'Custap Berry';
887
- if (ability === 'Super Luck')
888
- return 'Scope Lens';
889
- if (!isDoubles &&
890
- counter.damagingMoves.size >= 3 &&
891
- ability !== 'Sturdy' &&
892
- ['acidspray', 'dragontail', 'foulplay', 'rapidspin', 'superfang', 'uturn'].every(m => !moves.has(m)) && (counter.get('speedsetup') ||
893
- moves.has('trickroom') ||
894
- (species.baseStats.spe > 40 && species.baseStats.hp + species.baseStats.def + species.baseStats.spd < 275))) {
895
- return 'Life Orb';
896
- }
897
- }
898
- randomSet(species, teamDetails = {}, isLead = false, isDoubles = false) {
899
- species = this.dex.species.get(species);
900
- let forme = species.name;
901
- if (typeof species.battleOnly === 'string') {
902
- // Only change the forme. The species has custom moves, and may have different typing and requirements.
903
- forme = species.battleOnly;
904
- }
905
- if (species.cosmeticFormes) {
906
- forme = this.sample([species.name].concat(species.cosmeticFormes));
907
- }
908
- const randMoves = isDoubles ?
909
- (species.randomDoubleBattleMoves || species.randomBattleMoves) :
910
- species.randomBattleMoves;
911
- const movePool = (randMoves || Object.keys(this.dex.species.getLearnset(species.id))).slice();
912
- if (this.format.gameType === 'multi') {
913
- // Random Multi Battle uses doubles move pools, but Ally Switch fails in multi battles
914
- const allySwitch = movePool.indexOf('allyswitch');
915
- if (allySwitch > -1) {
916
- if (movePool.length > this.maxMoveCount) {
917
- this.fastPop(movePool, allySwitch);
918
- }
919
- else {
920
- // Ideally, we'll never get here, but better to have a move that usually does nothing than one that always does
921
- movePool[allySwitch] = 'sleeptalk';
922
- }
923
- }
924
- }
925
- const rejectedPool = [];
926
- const moves = new Set();
927
- let ability = '';
928
- const evs = { hp: 85, atk: 85, def: 85, spa: 85, spd: 85, spe: 85 };
929
- const ivs = { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 };
930
- const types = new Set(species.types);
931
- const abilities = new Set();
932
- for (const abilityName of Object.values(species.abilities)) {
933
- if (abilityName === species.abilities.S || (species.unreleasedHidden && abilityName === species.abilities.H))
934
- continue;
935
- abilities.add(abilityName);
936
- }
937
- let availableHP = 0;
938
- for (const moveid of movePool) {
939
- if (moveid.startsWith('hiddenpower'))
940
- availableHP++;
941
- }
942
- // These moves can be used even if we aren't setting up to use them:
943
- const SetupException = ['closecombat', 'diamondstorm', 'extremespeed', 'superpower', 'clangingscales'];
944
- let counter;
945
- // We use a special variable to track Hidden Power
946
- // so that we can check for all Hidden Powers at once
947
- let hasHiddenPower = false;
948
- do {
949
- // Choose next 4 moves from learnset/viable moves and add them to moves list:
950
- while (moves.size < this.maxMoveCount && movePool.length) {
951
- const moveid = this.sampleNoReplace(movePool);
952
- if (moveid.startsWith('hiddenpower')) {
953
- availableHP--;
954
- if (hasHiddenPower)
955
- continue;
956
- hasHiddenPower = true;
957
- }
958
- moves.add(moveid);
959
- }
960
- while (moves.size < this.maxMoveCount && rejectedPool.length) {
961
- const moveid = this.sampleNoReplace(rejectedPool);
962
- if (moveid.startsWith('hiddenpower')) {
963
- if (hasHiddenPower)
964
- continue;
965
- hasHiddenPower = true;
966
- }
967
- moves.add(moveid);
968
- }
969
- counter = this.queryMoves(moves, species.types, abilities, movePool);
970
- const runEnforcementChecker = (checkerName) => {
971
- if (!this.moveEnforcementCheckers[checkerName])
972
- return false;
973
- return this.moveEnforcementCheckers[checkerName](movePool, moves, abilities, types, counter, species, teamDetails);
974
- };
975
- // Iterate through the moves again, this time to cull them:
976
- for (const moveid of moves) {
977
- const move = this.dex.moves.get(moveid);
978
- let { cull, isSetup } = this.shouldCullMove(move, types, moves, abilities, counter, movePool, teamDetails, species, isLead, isDoubles);
979
- // This move doesn't satisfy our setup requirements:
980
- if ((move.category === 'Physical' && counter.setupType === 'Special') ||
981
- (move.category === 'Special' && counter.setupType === 'Physical')) {
982
- // Reject STABs last in case the setup type changes later on
983
- const stabs = counter.get(species.types[0]) + (counter.get(species.types[1]) || 0);
984
- if (!SetupException.includes(moveid) &&
985
- (!types.has(move.type) || stabs > 1 || counter.get(move.category) < 2))
986
- cull = true;
987
- }
988
- // Hidden Power isn't good enough
989
- if (counter.setupType === 'Special' &&
990
- moveid === 'hiddenpower' &&
991
- species.types.length > 1 &&
992
- counter.get('Special') <= 2 &&
993
- !types.has(move.type) &&
994
- !counter.get('Physical') &&
995
- counter.get('specialpool')) {
996
- cull = true;
997
- }
998
- const singlesEnforcement = (!['judgment', 'lightscreen', 'reflect', 'sleeptalk', 'toxic'].includes(moveid) && (move.category !== 'Status' ||
999
- // should allow Meganium to cull a recovery move for the sake of STAB
1000
- !(move.flags.heal && species.id !== 'meganium')));
1001
- // Pokemon should have moves that benefit their Type/Ability/Weather, as well as moves required by its forme
1002
- if (!cull &&
1003
- !move.damage &&
1004
- !isSetup &&
1005
- !move.weather &&
1006
- !move.stallingMove &&
1007
- (isDoubles || singlesEnforcement) && (!counter.setupType || counter.setupType === 'Mixed' ||
1008
- (move.category !== counter.setupType && move.category !== 'Status') ||
1009
- (counter.get(counter.setupType) + counter.get('Status') > 3 && !counter.get('hazards'))) && (move.category === 'Status' ||
1010
- !types.has(move.type) ||
1011
- (move.basePower && move.basePower < 40 && !move.multihit))) {
1012
- if ((!counter.get('stab') && !moves.has('nightshade') && !moves.has('seismictoss') && (species.types.length > 1 ||
1013
- (species.types[0] !== 'Normal' && species.types[0] !== 'Psychic') ||
1014
- !moves.has('icebeam') ||
1015
- species.baseStats.spa >= species.baseStats.spd)) || (moves.has('suckerpunch') && !abilities.has('Contrary') && counter.get('stab') < species.types.length) || ((['recover', 'roost', 'slackoff', 'softboiled'].some(m => movePool.includes(m))) &&
1016
- counter.get('Status') &&
1017
- !counter.setupType &&
1018
- ['healingwish', 'trick', 'trickroom'].every(m => !moves.has(m))) || (movePool.includes('milkdrink') ||
1019
- movePool.includes('shoreup') ||
1020
- (movePool.includes('stickyweb') && !counter.setupType && !teamDetails.stickyWeb)) || (isLead &&
1021
- movePool.includes('stealthrock') &&
1022
- counter.get('Status') && !counter.setupType &&
1023
- !counter.get('speedsetup') && !moves.has('substitute')) || (species.requiredMove && movePool.includes((0, sim_1.toID)(species.requiredMove))) || (!counter.get('Normal') &&
1024
- (abilities.has('Aerilate') || abilities.has('Pixilate') || (abilities.has('Refrigerate') && !moves.has('blizzard'))))) {
1025
- cull = true;
1026
- }
1027
- else {
1028
- for (const type of types) {
1029
- if (runEnforcementChecker(type)) {
1030
- cull = true;
1031
- }
1032
- }
1033
- for (const abil of abilities) {
1034
- if (runEnforcementChecker(abil)) {
1035
- cull = true;
1036
- }
1037
- }
1038
- }
1039
- }
1040
- // Sleep Talk shouldn't be selected without Rest
1041
- if (moveid === 'rest' && cull) {
1042
- const sleeptalk = movePool.indexOf('sleeptalk');
1043
- if (sleeptalk >= 0) {
1044
- if (movePool.length < 2) {
1045
- cull = false;
1046
- }
1047
- else {
1048
- this.fastPop(movePool, sleeptalk);
1049
- }
1050
- }
1051
- }
1052
- // Remove rejected moves from the move list
1053
- const moveIsHP = moveid.startsWith('hiddenpower');
1054
- if (cull && (movePool.length - availableHP ||
1055
- (availableHP && (moveIsHP || !hasHiddenPower)))) {
1056
- if (move.category !== 'Status' &&
1057
- !move.damage &&
1058
- !move.flags.charge &&
1059
- (!moveIsHP || !availableHP)) {
1060
- rejectedPool.push(moveid);
1061
- }
1062
- if (moveIsHP)
1063
- hasHiddenPower = false;
1064
- moves.delete(moveid);
1065
- break;
1066
- }
1067
- if (cull && rejectedPool.length) {
1068
- if (moveIsHP)
1069
- hasHiddenPower = false;
1070
- moves.delete(moveid);
1071
- break;
1072
- }
1073
- }
1074
- } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
1075
- // Moveset modifications
1076
- if (moves.has('autotomize') && moves.has('heavyslam')) {
1077
- if (species.id === 'celesteela') {
1078
- moves.delete('heavyslam');
1079
- moves.add('flashcannon');
1080
- }
1081
- else {
1082
- moves.delete('autotomize');
1083
- moves.add('rockpolish');
1084
- }
1085
- }
1086
- if (moves.has('raindance') && moves.has('thunderbolt') && !isDoubles) {
1087
- moves.delete('thunderbolt');
1088
- moves.add('thunder');
1089
- }
1090
- if (moves.has('workup') && !counter.get('Special') && species.id === 'zeraora') {
1091
- moves.delete('workup');
1092
- moves.add('bulkup');
1093
- }
1094
- const battleOnly = species.battleOnly && !species.requiredAbility;
1095
- const baseSpecies = battleOnly ? this.dex.species.get(species.battleOnly) : species;
1096
- const abilityData = Object.values(baseSpecies.abilities).map(a => this.dex.abilities.get(a));
1097
- utils_1.Utils.sortBy(abilityData, abil => -abil.rating);
1098
- if (abilityData[1]) {
1099
- // Sort abilities by rating with an element of randomness
1100
- if (abilityData[2] && abilityData[1].rating <= abilityData[2].rating && this.randomChance(1, 2)) {
1101
- [abilityData[1], abilityData[2]] = [abilityData[2], abilityData[1]];
1102
- }
1103
- if (abilityData[0].rating <= abilityData[1].rating && this.randomChance(1, 2)) {
1104
- [abilityData[0], abilityData[1]] = [abilityData[1], abilityData[0]];
1105
- }
1106
- else if (abilityData[0].rating - 0.6 <= abilityData[1].rating && this.randomChance(2, 3)) {
1107
- [abilityData[0], abilityData[1]] = [abilityData[1], abilityData[0]];
1108
- }
1109
- ability = abilityData[0].name;
1110
- while (this.shouldCullAbility(ability, types, moves, abilities, counter, movePool, teamDetails, species, isDoubles)) {
1111
- if (ability === abilityData[0].name && abilityData[1].rating >= 1) {
1112
- ability = abilityData[1].name;
1113
- }
1114
- else if (ability === abilityData[1].name && abilityData[2] && abilityData[2].rating >= 1) {
1115
- ability = abilityData[2].name;
1116
- }
1117
- else {
1118
- // Default to the highest rated ability if all are rejected
1119
- ability = abilityData[0].name;
1120
- break;
1121
- }
1122
- }
1123
- if (abilities.has('Guts') &&
1124
- ability !== 'Quick Feet' &&
1125
- (moves.has('facade') || (moves.has('protect') && !isDoubles) || (moves.has('sleeptalk') && moves.has('rest')))) {
1126
- ability = 'Guts';
1127
- }
1128
- else if (abilities.has('Moxie') && (counter.get('Physical') > 3 || moves.has('bounce')) && !isDoubles) {
1129
- ability = 'Moxie';
1130
- }
1131
- else if (isDoubles) {
1132
- if (abilities.has('Intimidate') && !battleOnly)
1133
- ability = 'Intimidate';
1134
- if (abilities.has('Guts') && ability !== 'Intimidate')
1135
- ability = 'Guts';
1136
- if (abilities.has('Storm Drain'))
1137
- ability = 'Storm Drain';
1138
- if (abilities.has('Harvest'))
1139
- ability = 'Harvest';
1140
- if (abilities.has('Unburden') && ability !== 'Prankster' && !species.isMega)
1141
- ability = 'Unburden';
1142
- }
1143
- if (species.name === 'Ambipom' && !counter.get('technician')) {
1144
- // If it doesn't qualify for Technician, Skill Link is useless on it
1145
- ability = 'Pickup';
1146
- }
1147
- if (species.name === 'Raticate-Alola')
1148
- ability = 'Hustle';
1149
- if (species.name === 'Altaria')
1150
- ability = 'Natural Cure';
1151
- }
1152
- else {
1153
- ability = abilityData[0].name;
1154
- }
1155
- if (species.name === 'Genesect' && moves.has('technoblast'))
1156
- forme = 'Genesect-Douse';
1157
- if (!isDoubles && species.id === 'pikachu') {
1158
- const pikachuForme = this.sample(['', '-Original', '-Hoenn', '-Sinnoh', '-Unova', '-Kalos', '-Alola', '-Partner']);
1159
- forme = `Pikachu${pikachuForme}`;
1160
- if (forme !== 'Pikachu')
1161
- ability = 'Static';
1162
- }
1163
- if (!moves.has('photongeyser') &&
1164
- !teamDetails.zMove &&
1165
- (species.name === 'Necrozma-Dusk-Mane' || species.name === 'Necrozma-Dawn-Wings')) {
1166
- for (const moveid of moves) {
1167
- const move = this.dex.moves.get(moveid);
1168
- if (move.category === 'Status' || types.has(move.type))
1169
- continue;
1170
- moves.delete(moveid);
1171
- moves.add('photongeyser');
1172
- break;
1173
- }
1174
- }
1175
- let item = this.getHighPriorityItem(ability, types, moves, counter, teamDetails, species, isLead, isDoubles);
1176
- if (item === undefined)
1177
- item = this.getMediumPriorityItem(ability, moves, counter, species, isDoubles, isLead);
1178
- if (item === undefined) {
1179
- item = this.getLowPriorityItem(ability, types, moves, abilities, counter, teamDetails, species, isLead, isDoubles);
1180
- }
1181
- // fallback
1182
- if (item === undefined)
1183
- item = isDoubles ? 'Sitrus Berry' : 'Leftovers';
1184
- // For Trick / Switcheroo
1185
- if (item === 'Leftovers' && types.has('Poison')) {
1186
- item = 'Black Sludge';
1187
- }
1188
- let level;
1189
- if (this.adjustLevel) {
1190
- level = this.adjustLevel;
1191
- }
1192
- else if (!isDoubles) {
1193
- const levelScale = { uber: 76, ou: 80, uu: 82, ru: 84, nu: 86, pu: 88 };
1194
- const customScale = {
1195
- // Banned Ability
1196
- Dugtrio: 82, Gothitelle: 82, Pelipper: 84, Politoed: 84, Torkoal: 84, Wobbuffet: 82,
1197
- // Holistic judgement
1198
- 'Castform-Rainy': 100, 'Castform-Snowy': 100, 'Castform-Sunny': 100, Delibird: 100, Luvdisc: 100, Spinda: 100, Unown: 100,
1199
- };
1200
- const tier = (0, sim_1.toID)(species.tier).replace('bl', '');
1201
- level = levelScale[tier] || (species.nfe ? 90 : 80);
1202
- if (customScale[species.name])
1203
- level = customScale[species.name];
1204
- }
1205
- else {
1206
- // We choose level based on BST. Min level is 70, max level is 99. 600+ BST is 70, less than 300 is 99. Calculate with those values.
1207
- // Every 10.34 BST adds a level from 70 up to 99. Results are floored. Uses the Mega's stats if holding a Mega Stone
1208
- const baseStats = species.baseStats;
1209
- let bst = species.bst;
1210
- // If Wishiwashi, use the school-forme's much higher stats
1211
- if (species.baseSpecies === 'Wishiwashi')
1212
- bst = this.dex.species.get('wishiwashischool').bst;
1213
- // Adjust levels of mons based on abilities (Pure Power, Sheer Force, etc.) and also Eviolite
1214
- // For the stat boosted, treat the Pokemon's base stat as if it were multiplied by the boost. (Actual effective base stats are higher.)
1215
- const speciesAbility = (baseSpecies === species ? ability : species.abilities[0]);
1216
- if (speciesAbility === 'Huge Power' || speciesAbility === 'Pure Power') {
1217
- bst += baseStats.atk;
1218
- }
1219
- else if (speciesAbility === 'Parental Bond') {
1220
- bst += 0.25 * (counter.get('Physical') > counter.get('Special') ? baseStats.atk : baseStats.spa);
1221
- }
1222
- else if (speciesAbility === 'Protean') {
1223
- bst += 0.3 * (counter.get('Physical') > counter.get('Special') ? baseStats.atk : baseStats.spa);
1224
- }
1225
- else if (speciesAbility === 'Fur Coat') {
1226
- bst += baseStats.def;
1227
- }
1228
- else if (speciesAbility === 'Slow Start') {
1229
- bst -= baseStats.atk / 2 + baseStats.spe / 2;
1230
- }
1231
- else if (speciesAbility === 'Truant') {
1232
- bst *= 2 / 3;
1233
- }
1234
- if (item === 'Eviolite') {
1235
- bst += 0.5 * (baseStats.def + baseStats.spd);
1236
- }
1237
- else if (item === 'Light Ball') {
1238
- bst += baseStats.atk + baseStats.spa;
1239
- }
1240
- level = 70 + Math.floor(((600 - utils_1.Utils.clampIntRange(bst, 300, 600)) / 10.34));
1241
- }
1242
- // Prepare optimal HP
1243
- const srWeakness = this.dex.getEffectiveness('Rock', species);
1244
- while (evs.hp > 1) {
1245
- const hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
1246
- if (moves.has('substitute') && moves.has('reversal')) {
1247
- // Reversal users should be able to use four Substitutes
1248
- if (hp % 4 > 0)
1249
- break;
1250
- }
1251
- else if (moves.has('substitute') && (item === 'Petaya Berry' || item === 'Sitrus Berry' ||
1252
- (ability === 'Power Construct' && item !== 'Leftovers'))) {
1253
- // Three Substitutes should activate Petaya Berry for Dedenne
1254
- // Two Substitutes should activate Sitrus Berry or Power Construct
1255
- if (hp % 4 === 0)
1256
- break;
1257
- }
1258
- else if (moves.has('bellydrum') && (item === 'Sitrus Berry' || ability === 'Gluttony')) {
1259
- // Belly Drum should activate Sitrus Berry
1260
- if (hp % 2 === 0)
1261
- break;
1262
- }
1263
- else {
1264
- // Maximize number of Stealth Rock switch-ins
1265
- if (srWeakness <= 0 || hp % (4 / srWeakness) > 0)
1266
- break;
1267
- }
1268
- evs.hp -= 4;
1269
- }
1270
- // Minimize confusion damage
1271
- if (!counter.get('Physical') && !moves.has('copycat') && !moves.has('transform')) {
1272
- evs.atk = 0;
1273
- ivs.atk = 0;
1274
- }
1275
- // Ensure Nihilego's Beast Boost gives it Special Attack boosts instead of Special Defense
1276
- if (forme === 'Nihilego')
1277
- evs.spd -= 32;
1278
- if (ability === 'Beast Boost' && counter.get('Special') < 1) {
1279
- evs.spa = 0;
1280
- ivs.spa = 0;
1281
- }
1282
- if (['gyroball', 'metalburst', 'trickroom'].some(m => moves.has(m))) {
1283
- evs.spe = 0;
1284
- ivs.spe = 0;
1285
- }
1286
- // Fix IVs for non-Bottle Cap-able sets
1287
- if (hasHiddenPower && level < 100) {
1288
- let hpType;
1289
- for (const move of moves) {
1290
- if (move.startsWith('hiddenpower'))
1291
- hpType = move.substr(11);
1292
- }
1293
- if (!hpType)
1294
- throw new Error(`hasHiddenPower is true, but no Hidden Power move was found.`);
1295
- const HPivs = ivs.atk === 0 ? ZeroAttackHPIVs[hpType] : this.dex.types.get(hpType).HPivs;
1296
- let iv;
1297
- for (iv in HPivs) {
1298
- ivs[iv] = HPivs[iv];
1299
- }
1300
- }
1301
- return {
1302
- name: species.baseSpecies,
1303
- species: forme,
1304
- gender: species.gender,
1305
- shiny: this.randomChance(1, 1024),
1306
- moves: Array.from(moves),
1307
- ability,
1308
- evs,
1309
- ivs,
1310
- item,
1311
- level,
1312
- };
1313
- }
1314
- randomTeam() {
1315
- this.enforceNoDirectCustomBanlistChanges();
1316
- const seed = this.prng.seed;
1317
- const ruleTable = this.dex.formats.getRuleTable(this.format);
1318
- const pokemon = [];
1319
- // For Monotype
1320
- const isMonotype = !!this.forceMonotype || ruleTable.has('sametypeclause');
1321
- const typePool = this.dex.types.names();
1322
- const type = this.forceMonotype || this.sample(typePool);
1323
- const baseFormes = {};
1324
- let hasMega = false;
1325
- const tierCount = {};
1326
- const typeCount = {};
1327
- const typeComboCount = {};
1328
- const teamDetails = {};
1329
- // We make at most two passes through the potential Pokemon pool when creating a team - if the first pass doesn't
1330
- // result in a team of six Pokemon we perform a second iteration relaxing as many restrictions as possible.
1331
- for (const restrict of [true, false]) {
1332
- if (pokemon.length >= this.maxTeamSize)
1333
- break;
1334
- const pokemonPool = this.getPokemonPool(type, pokemon, isMonotype);
1335
- while (pokemonPool.length && pokemon.length < this.maxTeamSize) {
1336
- const species = this.dex.species.get(this.sampleNoReplace(pokemonPool));
1337
- // Check if the forme has moves for random battle
1338
- if (this.format.gameType === 'singles') {
1339
- if (!species.randomBattleMoves)
1340
- continue;
1341
- }
1342
- else {
1343
- if (!species.randomDoubleBattleMoves)
1344
- continue;
1345
- }
1346
- if (!species.exists)
1347
- continue;
1348
- // Limit to one of each species (Species Clause)
1349
- if (baseFormes[species.baseSpecies])
1350
- continue;
1351
- // Limit one Mega per team
1352
- if (hasMega && species.isMega)
1353
- continue;
1354
- // Adjust rate for species with multiple sets
1355
- switch (species.baseSpecies) {
1356
- case 'Arceus':
1357
- case 'Silvally':
1358
- if (this.randomChance(8, 9) && !isMonotype)
1359
- continue;
1360
- break;
1361
- case 'Oricorio':
1362
- if (this.randomChance(3, 4))
1363
- continue;
1364
- break;
1365
- case 'Castform':
1366
- case 'Floette':
1367
- if (this.randomChance(2, 3))
1368
- continue;
1369
- break;
1370
- case 'Aegislash':
1371
- case 'Basculin':
1372
- case 'Cherrim':
1373
- case 'Gourgeist':
1374
- case 'Groudon':
1375
- case 'Kyogre':
1376
- case 'Meloetta':
1377
- if (this.randomChance(1, 2))
1378
- continue;
1379
- break;
1380
- case 'Greninja':
1381
- if (this.gen >= 7 && this.randomChance(1, 2))
1382
- continue;
1383
- break;
1384
- }
1385
- if (species.otherFormes && !hasMega && (species.otherFormes.includes(species.name + '-Mega') ||
1386
- species.otherFormes.includes(species.name + '-Mega-X'))) {
1387
- continue;
1388
- }
1389
- const tier = species.tier;
1390
- const types = species.types;
1391
- const typeCombo = types.slice().sort().join();
1392
- // Dynamically scale limits for different team sizes. The default and minimum value is 1.
1393
- const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
1394
- if (restrict && !species.isMega) {
1395
- // Limit one Pokemon per tier, two for Monotype
1396
- if ((tierCount[tier] >= (isMonotype || this.forceMonotype ? 2 : 1) * limitFactor) &&
1397
- !this.randomChance(1, Math.pow(5, tierCount[tier]))) {
1398
- continue;
1399
- }
1400
- if (!isMonotype && !this.forceMonotype) {
1401
- // Limit two of any type
1402
- let skip = false;
1403
- for (const typeName of types) {
1404
- if (typeCount[typeName] >= 2 * limitFactor) {
1405
- skip = true;
1406
- break;
1407
- }
1408
- }
1409
- if (skip)
1410
- continue;
1411
- }
1412
- // Limit one of any type combination, two in Monotype
1413
- if (!this.forceMonotype && typeComboCount[typeCombo] >= (isMonotype ? 2 : 1) * limitFactor)
1414
- continue;
1415
- }
1416
- const set = this.randomSet(species, teamDetails, pokemon.length === this.maxTeamSize - 1, this.format.gameType !== 'singles');
1417
- const item = this.dex.items.get(set.item);
1418
- // Limit one Z-Move per team
1419
- if (item.zMove && teamDetails.zMove)
1420
- continue;
1421
- // Zoroark copies the last Pokemon
1422
- if (set.ability === 'Illusion') {
1423
- if (pokemon.length < 1)
1424
- continue;
1425
- set.level = pokemon[pokemon.length - 1].level;
1426
- }
1427
- // Okay, the set passes, add it to our team
1428
- pokemon.unshift(set);
1429
- // Don't bother tracking details for the last Pokemon
1430
- if (pokemon.length === this.maxTeamSize)
1431
- break;
1432
- // Now that our Pokemon has passed all checks, we can increment our counters
1433
- baseFormes[species.baseSpecies] = 1;
1434
- // Increment tier counter
1435
- if (tierCount[tier]) {
1436
- tierCount[tier]++;
1437
- }
1438
- else {
1439
- tierCount[tier] = 1;
1440
- }
1441
- // Increment type counters
1442
- for (const typeName of types) {
1443
- if (typeName in typeCount) {
1444
- typeCount[typeName]++;
1445
- }
1446
- else {
1447
- typeCount[typeName] = 1;
1448
- }
1449
- }
1450
- if (typeCombo in typeComboCount) {
1451
- typeComboCount[typeCombo]++;
1452
- }
1453
- else {
1454
- typeComboCount[typeCombo] = 1;
1455
- }
1456
- // Track what the team has
1457
- if (item.megaStone)
1458
- hasMega = true;
1459
- if (item.zMove)
1460
- teamDetails.zMove = 1;
1461
- if (set.ability === 'Snow Warning' || set.moves.includes('hail'))
1462
- teamDetails.hail = 1;
1463
- if (set.moves.includes('raindance') || set.ability === 'Drizzle' && !item.onPrimal)
1464
- teamDetails.rain = 1;
1465
- if (set.ability === 'Sand Stream')
1466
- teamDetails.sand = 1;
1467
- if (set.moves.includes('sunnyday') || set.ability === 'Drought' && !item.onPrimal)
1468
- teamDetails.sun = 1;
1469
- if (set.moves.includes('spikes'))
1470
- teamDetails.spikes = (teamDetails.spikes || 0) + 1;
1471
- if (set.moves.includes('stealthrock'))
1472
- teamDetails.stealthRock = 1;
1473
- if (set.moves.includes('stickyweb'))
1474
- teamDetails.stickyWeb = 1;
1475
- if (set.moves.includes('toxicspikes'))
1476
- teamDetails.toxicSpikes = 1;
1477
- if (set.moves.includes('defog'))
1478
- teamDetails.defog = 1;
1479
- if (set.moves.includes('rapidspin'))
1480
- teamDetails.rapidSpin = 1;
1481
- }
1482
- }
1483
- if (pokemon.length < this.maxTeamSize && pokemon.length < 12) {
1484
- throw new Error(`Could not build a random team for ${this.format} (seed=${seed})`);
1485
- }
1486
- return pokemon;
1487
- }
1488
- randomFactorySet(species, teamData, tier) {
1489
- const id = (0, sim_1.toID)(species.name);
1490
- const setList = this.randomFactorySets[tier][id].sets;
1491
- const itemsMax = {
1492
- choicespecs: 1,
1493
- choiceband: 1,
1494
- choicescarf: 1,
1495
- };
1496
- const movesMax = {
1497
- rapidspin: 1,
1498
- batonpass: 1,
1499
- stealthrock: 1,
1500
- defog: 1,
1501
- spikes: 1,
1502
- toxicspikes: 1,
1503
- };
1504
- const requiredMoves = {
1505
- stealthrock: 'hazardSet',
1506
- rapidspin: 'hazardClear',
1507
- defog: 'hazardClear',
1508
- };
1509
- const weatherAbilitiesRequire = {
1510
- hydration: 'raindance', swiftswim: 'raindance',
1511
- leafguard: 'sunnyday', solarpower: 'sunnyday', chlorophyll: 'sunnyday',
1512
- sandforce: 'sandstorm', sandrush: 'sandstorm', sandveil: 'sandstorm',
1513
- slushrush: 'hail', snowcloak: 'hail',
1514
- };
1515
- const weatherAbilities = ['drizzle', 'drought', 'snowwarning', 'sandstream'];
1516
- // Build a pool of eligible sets, given the team partners
1517
- // Also keep track of sets with moves the team requires
1518
- let effectivePool = [];
1519
- const priorityPool = [];
1520
- for (const curSet of setList) {
1521
- if (this.forceMonotype && !species.types.includes(this.forceMonotype))
1522
- continue;
1523
- const item = this.dex.items.get(curSet.item);
1524
- if (teamData.megaCount && teamData.megaCount > 0 && item.megaStone)
1525
- continue; // reject 2+ mega stones
1526
- if (teamData.zCount && teamData.zCount > 0 && item.zMove)
1527
- continue; // reject 2+ Z stones
1528
- if (itemsMax[item.id] && teamData.has[item.id] >= itemsMax[item.id])
1529
- continue;
1530
- const ability = this.dex.abilities.get(curSet.ability);
1531
- if (weatherAbilitiesRequire[ability.id] && teamData.weather !== weatherAbilitiesRequire[ability.id])
1532
- continue;
1533
- if (teamData.weather && weatherAbilities.includes(ability.id))
1534
- continue; // reject 2+ weather setters
1535
- let reject = false;
1536
- let hasRequiredMove = false;
1537
- const curSetVariants = [];
1538
- for (const move of curSet.moves) {
1539
- const variantIndex = this.random(move.length);
1540
- const moveId = (0, sim_1.toID)(move[variantIndex]);
1541
- if (movesMax[moveId] && teamData.has[moveId] >= movesMax[moveId]) {
1542
- reject = true;
1543
- break;
1544
- }
1545
- if (requiredMoves[moveId] && !teamData.has[requiredMoves[moveId]]) {
1546
- hasRequiredMove = true;
1547
- }
1548
- curSetVariants.push(variantIndex);
1549
- }
1550
- if (reject)
1551
- continue;
1552
- effectivePool.push({ set: curSet, moveVariants: curSetVariants });
1553
- if (hasRequiredMove)
1554
- priorityPool.push({ set: curSet, moveVariants: curSetVariants });
1555
- }
1556
- if (priorityPool.length)
1557
- effectivePool = priorityPool;
1558
- if (!effectivePool.length) {
1559
- if (!teamData.forceResult)
1560
- return null;
1561
- for (const curSet of setList) {
1562
- effectivePool.push({ set: curSet });
1563
- }
1564
- }
1565
- const setData = this.sample(effectivePool);
1566
- const moves = [];
1567
- for (const [i, moveSlot] of setData.set.moves.entries()) {
1568
- moves.push(setData.moveVariants ? moveSlot[setData.moveVariants[i]] : this.sample(moveSlot));
1569
- }
1570
- const item = this.sampleIfArray(setData.set.item);
1571
- const ability = this.sampleIfArray(setData.set.ability);
1572
- const nature = this.sampleIfArray(setData.set.nature);
1573
- const level = this.adjustLevel || setData.set.level || (tier === "LC" ? 5 : 100);
1574
- return {
1575
- name: setData.set.name || species.baseSpecies,
1576
- species: setData.set.species,
1577
- gender: setData.set.gender || species.gender || (this.randomChance(1, 2) ? 'M' : 'F'),
1578
- item: item || '',
1579
- ability: ability || species.abilities['0'],
1580
- shiny: typeof setData.set.shiny === 'undefined' ? this.randomChance(1, 1024) : setData.set.shiny,
1581
- level,
1582
- happiness: typeof setData.set.happiness === 'undefined' ? 255 : setData.set.happiness,
1583
- evs: Object.assign({ hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 }, setData.set.evs),
1584
- ivs: Object.assign({ hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 }, setData.set.ivs),
1585
- nature: nature || 'Serious',
1586
- moves,
1587
- };
1588
- }
1589
- randomFactoryTeam(side, depth = 0) {
1590
- var _a;
1591
- this.enforceNoDirectCustomBanlistChanges();
1592
- const forceResult = (depth >= 4);
1593
- const isMonotype = !!this.forceMonotype || this.dex.formats.getRuleTable(this.format).has('sametypeclause');
1594
- // The teams generated depend on the tier choice in such a way that
1595
- // no exploitable information is leaked from rolling the tier in getTeam(p1).
1596
- if (!this.factoryTier) {
1597
- this.factoryTier = isMonotype ? 'Mono' : this.sample(['Uber', 'OU', 'UU', 'RU', 'NU', 'PU', 'LC']);
1598
- }
1599
- else if (isMonotype && this.factoryTier !== 'Mono') {
1600
- // I don't think this can ever happen?
1601
- throw new Error(`Can't generate a Monotype Battle Factory set in a battle with factory tier ${this.factoryTier}`);
1602
- }
1603
- const tierValues = {
1604
- Uber: 5,
1605
- OU: 4, UUBL: 4,
1606
- UU: 3, RUBL: 3,
1607
- RU: 2, NUBL: 2,
1608
- NU: 1, PUBL: 1,
1609
- PU: 0,
1610
- };
1611
- const pokemon = [];
1612
- const pokemonPool = Object.keys(this.randomFactorySets[this.factoryTier]);
1613
- const typePool = this.dex.types.names();
1614
- const type = this.sample(typePool);
1615
- const teamData = {
1616
- typeCount: {}, typeComboCount: {}, baseFormes: {}, megaCount: 0, zCount: 0,
1617
- has: {}, forceResult: forceResult, weaknesses: {}, resistances: {},
1618
- };
1619
- const requiredMoveFamilies = ['hazardSet', 'hazardClear'];
1620
- const requiredMoves = {
1621
- stealthrock: 'hazardSet',
1622
- rapidspin: 'hazardClear',
1623
- defog: 'hazardClear',
1624
- };
1625
- const weatherAbilitiesSet = {
1626
- drizzle: 'raindance',
1627
- drought: 'sunnyday',
1628
- snowwarning: 'hail',
1629
- sandstream: 'sandstorm',
1630
- };
1631
- const resistanceAbilities = {
1632
- dryskin: ['Water'], waterabsorb: ['Water'], stormdrain: ['Water'],
1633
- flashfire: ['Fire'], heatproof: ['Fire'],
1634
- lightningrod: ['Electric'], motordrive: ['Electric'], voltabsorb: ['Electric'],
1635
- sapsipper: ['Grass'],
1636
- thickfat: ['Ice', 'Fire'],
1637
- levitate: ['Ground'],
1638
- };
1639
- while (pokemonPool.length && pokemon.length < this.maxTeamSize) {
1640
- const species = this.dex.species.get(this.sampleNoReplace(pokemonPool));
1641
- if (!species.exists)
1642
- continue;
1643
- // Lessen the need of deleting sets of Pokemon after tier shifts
1644
- if (this.factoryTier in tierValues && species.tier in tierValues &&
1645
- tierValues[species.tier] > tierValues[this.factoryTier])
1646
- continue;
1647
- const speciesFlags = this.randomFactorySets[this.factoryTier][species.id].flags;
1648
- // Limit to one of each species (Species Clause)
1649
- if (teamData.baseFormes[species.baseSpecies])
1650
- continue;
1651
- // Limit the number of Megas to one
1652
- if (!teamData.megaCount)
1653
- teamData.megaCount = 0;
1654
- if (teamData.megaCount >= 1 && speciesFlags.megaOnly)
1655
- continue;
1656
- const set = this.randomFactorySet(species, teamData, this.factoryTier);
1657
- if (!set)
1658
- continue;
1659
- const itemData = this.dex.items.get(set.item);
1660
- // Actually limit the number of Megas to one
1661
- if (teamData.megaCount >= 1 && itemData.megaStone)
1662
- continue;
1663
- // Limit the number of Z moves to one
1664
- if (teamData.zCount && teamData.zCount >= 1 && itemData.zMove)
1665
- continue;
1666
- let types = species.types;
1667
- // Dynamically scale limits for different team sizes. The default and minimum value is 1.
1668
- const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
1669
- // Enforce Monotype
1670
- if (isMonotype) {
1671
- // Prevents Mega Evolutions from breaking the type limits
1672
- if (itemData.megaStone) {
1673
- const megaSpecies = this.dex.species.get(itemData.megaStone);
1674
- if (types.length > megaSpecies.types.length)
1675
- types = [species.types[0]];
1676
- // Only check the second type because a Mega Evolution should always share the first type with its base forme.
1677
- if (megaSpecies.types[1] && types[1] && megaSpecies.types[1] !== types[1]) {
1678
- types = [megaSpecies.types[0]];
1679
- }
1680
- }
1681
- if (!types.includes(type))
1682
- continue;
1683
- }
1684
- else {
1685
- // If not Monotype, limit to two of each type
1686
- let skip = false;
1687
- for (const typeName of types) {
1688
- if (teamData.typeCount[typeName] >= 2 * limitFactor && this.randomChance(4, 5)) {
1689
- skip = true;
1690
- break;
1691
- }
1692
- }
1693
- if (skip)
1694
- continue;
1695
- // Limit 1 of any type combination
1696
- let typeCombo = types.slice().sort().join();
1697
- if (set.ability + '' === 'Drought' || set.ability + '' === 'Drizzle') {
1698
- // Drought and Drizzle don't count towards the type combo limit
1699
- typeCombo = set.ability + '';
1700
- }
1701
- if (teamData.typeComboCount[typeCombo] >= 1 * limitFactor)
1702
- continue;
1703
- }
1704
- // Okay, the set passes, add it to our team
1705
- pokemon.push(set);
1706
- const typeCombo = types.slice().sort().join();
1707
- // Now that our Pokemon has passed all checks, we can update team data:
1708
- for (const typeName of types) {
1709
- if (typeName in teamData.typeCount) {
1710
- teamData.typeCount[typeName]++;
1711
- }
1712
- else {
1713
- teamData.typeCount[typeName] = 1;
1714
- }
1715
- }
1716
- teamData.typeComboCount[typeCombo] = (teamData.typeComboCount[typeCombo] + 1) || 1;
1717
- teamData.baseFormes[species.baseSpecies] = 1;
1718
- if (itemData.megaStone)
1719
- teamData.megaCount++;
1720
- if (itemData.zMove) {
1721
- if (!teamData.zCount)
1722
- teamData.zCount = 0;
1723
- teamData.zCount++;
1724
- }
1725
- if (itemData.id in teamData.has) {
1726
- teamData.has[itemData.id]++;
1727
- }
1728
- else {
1729
- teamData.has[itemData.id] = 1;
1730
- }
1731
- const abilityState = this.dex.abilities.get(set.ability);
1732
- if (abilityState.id in weatherAbilitiesSet) {
1733
- teamData.weather = weatherAbilitiesSet[abilityState.id];
1734
- }
1735
- for (const move of set.moves) {
1736
- const moveId = (0, sim_1.toID)(move);
1737
- if (moveId in teamData.has) {
1738
- teamData.has[moveId]++;
1739
- }
1740
- else {
1741
- teamData.has[moveId] = 1;
1742
- }
1743
- if (moveId in requiredMoves) {
1744
- teamData.has[requiredMoves[moveId]] = 1;
1745
- }
1746
- }
1747
- for (const typeName of this.dex.types.names()) {
1748
- // Cover any major weakness (3+) with at least one resistance
1749
- if (teamData.resistances[typeName] >= 1)
1750
- continue;
1751
- if (((_a = resistanceAbilities[abilityState.id]) === null || _a === void 0 ? void 0 : _a.includes(typeName)) || !this.dex.getImmunity(typeName, types)) {
1752
- // Heuristic: assume that Pokémon with these abilities don't have (too) negative typing.
1753
- teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
1754
- if (teamData.resistances[typeName] >= 1)
1755
- teamData.weaknesses[typeName] = 0;
1756
- continue;
1757
- }
1758
- const typeMod = this.dex.getEffectiveness(typeName, types);
1759
- if (typeMod < 0) {
1760
- teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
1761
- if (teamData.resistances[typeName] >= 1)
1762
- teamData.weaknesses[typeName] = 0;
1763
- }
1764
- else if (typeMod > 0) {
1765
- teamData.weaknesses[typeName] = (teamData.weaknesses[typeName] || 0) + 1;
1766
- }
1767
- }
1768
- }
1769
- if (pokemon.length < this.maxTeamSize)
1770
- return this.randomFactoryTeam(side, ++depth);
1771
- // Quality control
1772
- if (!teamData.forceResult) {
1773
- for (const requiredFamily of requiredMoveFamilies) {
1774
- if (!teamData.has[requiredFamily])
1775
- return this.randomFactoryTeam(side, ++depth);
1776
- }
1777
- for (const typeName in teamData.weaknesses) {
1778
- if (teamData.weaknesses[typeName] >= 3)
1779
- return this.randomFactoryTeam(side, ++depth);
1780
- }
1781
- }
1782
- return pokemon;
1783
- }
1784
- randomBSSFactorySet(species, teamData) {
1785
- const id = (0, sim_1.toID)(species.name);
1786
- // const flags = this.randomBSSFactorySets[tier][id].flags;
1787
- const setList = this.randomBSSFactorySets[id].sets;
1788
- const movesMax = {
1789
- batonpass: 1,
1790
- stealthrock: 1,
1791
- spikes: 1,
1792
- toxicspikes: 1,
1793
- doubleedge: 1,
1794
- trickroom: 1,
1795
- };
1796
- const requiredMoves = {};
1797
- const weatherAbilitiesRequire = {
1798
- swiftswim: 'raindance',
1799
- sandrush: 'sandstorm', sandveil: 'sandstorm',
1800
- };
1801
- const weatherAbilities = ['drizzle', 'drought', 'snowwarning', 'sandstream'];
1802
- // Build a pool of eligible sets, given the team partners
1803
- // Also keep track of sets with moves the team requires
1804
- let effectivePool = [];
1805
- const priorityPool = [];
1806
- for (const curSet of setList) {
1807
- if (this.forceMonotype && !species.types.includes(this.forceMonotype))
1808
- continue;
1809
- const item = this.dex.items.get(curSet.item);
1810
- if (teamData.megaCount && teamData.megaCount > 1 && item.megaStone)
1811
- continue; // reject 3+ mega stones
1812
- if (teamData.zCount && teamData.zCount > 1 && item.zMove)
1813
- continue; // reject 3+ Z stones
1814
- if (teamData.has[item.id])
1815
- continue; // Item clause
1816
- const ability = this.dex.abilities.get(curSet.ability);
1817
- if (weatherAbilitiesRequire[ability.id] && teamData.weather !== weatherAbilitiesRequire[ability.id])
1818
- continue;
1819
- if (teamData.weather && weatherAbilities.includes(ability.id))
1820
- continue; // reject 2+ weather setters
1821
- if (curSet.species === 'Aron' && teamData.weather !== 'sandstorm')
1822
- continue; // reject Aron without a Sand Stream user
1823
- let reject = false;
1824
- let hasRequiredMove = false;
1825
- const curSetVariants = [];
1826
- for (const move of curSet.moves) {
1827
- const variantIndex = this.random(move.length);
1828
- const moveId = (0, sim_1.toID)(move[variantIndex]);
1829
- if (movesMax[moveId] && teamData.has[moveId] >= movesMax[moveId]) {
1830
- reject = true;
1831
- break;
1832
- }
1833
- if (requiredMoves[moveId] && !teamData.has[requiredMoves[moveId]]) {
1834
- hasRequiredMove = true;
1835
- }
1836
- curSetVariants.push(variantIndex);
1837
- }
1838
- if (reject)
1839
- continue;
1840
- effectivePool.push({ set: curSet, moveVariants: curSetVariants });
1841
- if (hasRequiredMove)
1842
- priorityPool.push({ set: curSet, moveVariants: curSetVariants });
1843
- }
1844
- if (priorityPool.length)
1845
- effectivePool = priorityPool;
1846
- if (!effectivePool.length) {
1847
- if (!teamData.forceResult)
1848
- return null;
1849
- for (const curSet of setList) {
1850
- effectivePool.push({ set: curSet });
1851
- }
1852
- }
1853
- const setData = this.sample(effectivePool);
1854
- const moves = [];
1855
- for (const [i, moveSlot] of setData.set.moves.entries()) {
1856
- moves.push(setData.moveVariants ? moveSlot[setData.moveVariants[i]] : this.sample(moveSlot));
1857
- }
1858
- return {
1859
- name: setData.set.nickname || setData.set.name || species.baseSpecies,
1860
- species: setData.set.species,
1861
- gender: setData.set.gender || species.gender || (this.randomChance(1, 2) ? 'M' : 'F'),
1862
- item: this.sampleIfArray(setData.set.item) || '',
1863
- ability: setData.set.ability || species.abilities['0'],
1864
- shiny: typeof setData.set.shiny === 'undefined' ? this.randomChance(1, 1024) : setData.set.shiny,
1865
- level: setData.set.level || 50,
1866
- happiness: typeof setData.set.happiness === 'undefined' ? 255 : setData.set.happiness,
1867
- evs: Object.assign({ hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 }, setData.set.evs),
1868
- ivs: Object.assign({ hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 }, setData.set.ivs),
1869
- nature: setData.set.nature || 'Serious',
1870
- moves,
1871
- };
1872
- }
1873
- randomBSSFactoryTeam(side, depth = 0) {
1874
- var _a;
1875
- this.enforceNoDirectCustomBanlistChanges();
1876
- const forceResult = (depth >= 4);
1877
- const pokemon = [];
1878
- const pokemonPool = Object.keys(this.randomBSSFactorySets);
1879
- const teamData = {
1880
- typeCount: {}, typeComboCount: {}, baseFormes: {}, megaCount: 0, zCount: 0,
1881
- eeveeLimCount: 0, has: {}, forceResult, weaknesses: {}, resistances: {},
1882
- };
1883
- const requiredMoveFamilies = [];
1884
- const requiredMoves = {};
1885
- const weatherAbilitiesSet = {
1886
- drizzle: 'raindance',
1887
- drought: 'sunnyday',
1888
- snowwarning: 'hail',
1889
- sandstream: 'sandstorm',
1890
- };
1891
- const resistanceAbilities = {
1892
- waterabsorb: ['Water'],
1893
- flashfire: ['Fire'],
1894
- lightningrod: ['Electric'], voltabsorb: ['Electric'],
1895
- thickfat: ['Ice', 'Fire'],
1896
- levitate: ['Ground'],
1897
- };
1898
- while (pokemonPool.length && pokemon.length < this.maxTeamSize) {
1899
- const species = this.dex.species.get(this.sampleNoReplace(pokemonPool));
1900
- if (!species.exists)
1901
- continue;
1902
- const speciesFlags = this.randomBSSFactorySets[species.id].flags;
1903
- if (!teamData.megaCount)
1904
- teamData.megaCount = 0;
1905
- // Limit to one of each species (Species Clause)
1906
- if (teamData.baseFormes[species.baseSpecies])
1907
- continue;
1908
- // Limit the number of Megas + Z-moves to 3
1909
- if (teamData.megaCount + (teamData.zCount ? teamData.zCount : 0) >= 3 && speciesFlags.megaOnly)
1910
- continue;
1911
- // Dynamically scale limits for different team sizes. The default and minimum value is 1.
1912
- const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
1913
- // Limit 2 of any type
1914
- const types = species.types;
1915
- let skip = false;
1916
- for (const type of types) {
1917
- if (teamData.typeCount[type] >= 2 * limitFactor && this.randomChance(4, 5)) {
1918
- skip = true;
1919
- break;
1920
- }
1921
- }
1922
- if (skip)
1923
- continue;
1924
- // Restrict Eevee with certain Pokemon
1925
- if (speciesFlags.limEevee) {
1926
- if (!teamData.eeveeLimCount)
1927
- teamData.eeveeLimCount = 0;
1928
- teamData.eeveeLimCount++;
1929
- }
1930
- if (teamData.eeveeLimCount && teamData.eeveeLimCount >= 1 && speciesFlags.limEevee)
1931
- continue;
1932
- const set = this.randomBSSFactorySet(species, teamData);
1933
- if (!set)
1934
- continue;
1935
- // Limit 1 of any type combination
1936
- let typeCombo = types.slice().sort().join();
1937
- if (set.ability === 'Drought' || set.ability === 'Drizzle') {
1938
- // Drought and Drizzle don't count towards the type combo limit
1939
- typeCombo = set.ability;
1940
- }
1941
- if (teamData.typeComboCount[typeCombo] >= 1 * limitFactor)
1942
- continue;
1943
- // Okay, the set passes, add it to our team
1944
- pokemon.push(set);
1945
- // Now that our Pokemon has passed all checks, we can update team data:
1946
- for (const type of types) {
1947
- if (type in teamData.typeCount) {
1948
- teamData.typeCount[type]++;
1949
- }
1950
- else {
1951
- teamData.typeCount[type] = 1;
1952
- }
1953
- }
1954
- teamData.typeComboCount[typeCombo] = (teamData.typeComboCount[typeCombo] + 1) || 1;
1955
- teamData.baseFormes[species.baseSpecies] = 1;
1956
- // Limit Mega and Z-move
1957
- const itemData = this.dex.items.get(set.item);
1958
- if (itemData.megaStone)
1959
- teamData.megaCount++;
1960
- if (itemData.zMove) {
1961
- if (!teamData.zCount)
1962
- teamData.zCount = 0;
1963
- teamData.zCount++;
1964
- }
1965
- teamData.has[itemData.id] = 1;
1966
- const abilityState = this.dex.abilities.get(set.ability);
1967
- if (abilityState.id in weatherAbilitiesSet) {
1968
- teamData.weather = weatherAbilitiesSet[abilityState.id];
1969
- }
1970
- for (const move of set.moves) {
1971
- const moveId = (0, sim_1.toID)(move);
1972
- if (moveId in teamData.has) {
1973
- teamData.has[moveId]++;
1974
- }
1975
- else {
1976
- teamData.has[moveId] = 1;
1977
- }
1978
- if (moveId in requiredMoves) {
1979
- teamData.has[requiredMoves[moveId]] = 1;
1980
- }
1981
- }
1982
- for (const typeName of this.dex.types.names()) {
1983
- // Cover any major weakness (3+) with at least one resistance
1984
- if (teamData.resistances[typeName] >= 1)
1985
- continue;
1986
- if (((_a = resistanceAbilities[abilityState.id]) === null || _a === void 0 ? void 0 : _a.includes(typeName)) || !this.dex.getImmunity(typeName, types)) {
1987
- // Heuristic: assume that Pokémon with these abilities don't have (too) negative typing.
1988
- teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
1989
- if (teamData.resistances[typeName] >= 1)
1990
- teamData.weaknesses[typeName] = 0;
1991
- continue;
1992
- }
1993
- const typeMod = this.dex.getEffectiveness(typeName, types);
1994
- if (typeMod < 0) {
1995
- teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
1996
- if (teamData.resistances[typeName] >= 1)
1997
- teamData.weaknesses[typeName] = 0;
1998
- }
1999
- else if (typeMod > 0) {
2000
- teamData.weaknesses[typeName] = (teamData.weaknesses[typeName] || 0) + 1;
2001
- }
2002
- }
2003
- }
2004
- if (pokemon.length < this.maxTeamSize)
2005
- return this.randomBSSFactoryTeam(side, ++depth);
2006
- // Quality control
2007
- if (!teamData.forceResult) {
2008
- for (const requiredFamily of requiredMoveFamilies) {
2009
- if (!teamData.has[requiredFamily])
2010
- return this.randomBSSFactoryTeam(side, ++depth);
2011
- }
2012
- for (const type in teamData.weaknesses) {
2013
- if (teamData.weaknesses[type] >= 3)
2014
- return this.randomBSSFactoryTeam(side, ++depth);
2015
- }
2016
- }
2017
- return pokemon;
2018
- }
2019
- }
2020
- exports.RandomGen7Teams = RandomGen7Teams;
2021
- exports.default = RandomGen7Teams;
2022
- //# sourceMappingURL=gen7.js.map