@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/gen6.js DELETED
@@ -1,1216 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RandomGen6Teams = void 0;
4
- const gen7_1 = require("./gen7");
5
- const utils_1 = require("./utils");
6
- const sim_1 = require("@pkmn/sim");
7
- class RandomGen6Teams extends gen7_1.RandomGen7Teams {
8
- constructor(dex, format, prng) {
9
- super(dex, format, prng);
10
- this.randomFactorySets = {};
11
- this.noStab = [...this.noStab, 'aquajet', 'fakeout', 'iceshard', 'machpunch', 'quickattack', 'vacuumwave'];
12
- this.moveEnforcementCheckers = {
13
- Bug: movePool => movePool.includes('megahorn') || movePool.includes('pinmissile'),
14
- Dark: (movePool, moves, abilities, types, counter, species) => ((!counter.get('Dark') && !abilities.has('Protean'))),
15
- Dragon: (movePool, moves, abilities, types, counter) => (!counter.get('Dragon') &&
16
- !abilities.has('Aerilate') &&
17
- !abilities.has('Pixilate') &&
18
- !moves.has('rest') &&
19
- !moves.has('sleeptalk')),
20
- Electric: (movePool, moves, abilities, types, counter) => !counter.get('Electric'),
21
- Fairy: (movePool, moves, abilities, types, counter) => (!counter.get('Fairy') && !abilities.has('Pixilate') && (!!counter.setupType || !counter.get('Status'))),
22
- Fighting: (movePool, moves, abilities, types, counter, species) => (!counter.get('Fighting') && (species.baseStats.atk >= 110 ||
23
- abilities.has('Justified') || abilities.has('Unburden') ||
24
- !!counter.setupType || !counter.get('Status'))),
25
- Fire: (movePool, moves, abilities, types, counter) => !counter.get('Fire') || movePool.includes('quiverdance'),
26
- Flying: (movePool, moves, abilities, types, counter) => (!counter.get('Flying') && (abilities.has('Gale Wings') ||
27
- abilities.has('Serene Grace') ||
28
- (types.has('Normal') && movePool.includes('bravebird')))),
29
- Ghost: (movePool, moves, abilities, types, counter) => !types.has('Dark') && !counter.get('Ghost'),
30
- Grass: (movePool, moves, abilities, types, counter) => (!counter.get('Grass') && !types.has('Fairy') && !types.has('Poison') && !types.has('Steel')),
31
- Ground: (movePool, moves, abilities, types, counter) => (!counter.get('Ground') && !moves.has('rest') && !moves.has('sleeptalk')),
32
- Ice: (movePool, moves, abilities, types, counter) => !counter.get('Ice') && !abilities.has('Refrigerate'),
33
- Normal: movePool => movePool.includes('facade'),
34
- Psychic: (movePool, moves, abilities, types, counter, species) => (!!counter.get('Psychic') &&
35
- !types.has('Flying') &&
36
- !abilities.has('Pixilate') &&
37
- counter.get('stab') < species.types.length),
38
- Rock: (movePool, moves, abilities, types, counter) => (!counter.get('Rock') &&
39
- !types.has('Fairy') &&
40
- (abilities.has('Rock Head') || counter.setupType === 'Physical')),
41
- Steel: (movePool, moves, abilities, types, counter) => (!counter.get('Steel') && (abilities.has('Technician') || movePool.includes('meteormash'))),
42
- Water: (movePool, moves, abilities, types, counter) => ((!counter.get('Water') || !counter.get('stab')) &&
43
- !abilities.has('Protean')),
44
- Adaptability: (movePool, moves, abilities, types, counter, species) => (!counter.setupType &&
45
- species.types.length > 1 &&
46
- (!counter.get(species.types[0]) || !counter.get(species.types[1]))),
47
- Aerilate: (movePool, moves, abilities, types, counter) => !counter.get('Normal'),
48
- Pixilate: (movePool, moves, abilities, types, counter) => !counter.get('Normal'),
49
- Refrigerate: (movePool, moves, abilities, types, counter) => !moves.has('blizzard') && !counter.get('Normal'),
50
- Contrary: (movePool, moves, abilities, types, counter, species) => (!counter.get('contrary') && species.name !== 'Shuckle'),
51
- 'Bad Dreams': movePool => movePool.includes('darkvoid'),
52
- 'Slow Start': movePool => movePool.includes('substitute'),
53
- };
54
- }
55
- shouldCullMove(move, types, moves, abilities, counter, movePool, teamDetails, species, isLead) {
56
- const restTalk = moves.has('rest') && moves.has('sleeptalk');
57
- if (move.priority > 0 && counter.get('speedsetup'))
58
- return { cull: true };
59
- switch (move.id) {
60
- // Not very useful without their supporting moves
61
- case 'cottonguard':
62
- case 'defendorder':
63
- return { cull: !counter.get('recovery') && !moves.has('rest') };
64
- case 'focuspunch':
65
- return { cull: !moves.has('substitute') || counter.damagingMoves.size < 2 };
66
- case 'perishsong':
67
- return { cull: !moves.has('protect') };
68
- case 'reflect':
69
- if (movePool.length > 1) {
70
- const screen = movePool.indexOf('lightscreen');
71
- if (screen >= 0)
72
- this.fastPop(movePool, screen);
73
- }
74
- return { cull: !moves.has('calmmind') && !moves.has('lightscreen') };
75
- case 'rest':
76
- return { cull: movePool.includes('sleeptalk') };
77
- case 'sleeptalk':
78
- if (movePool.length > 1) {
79
- const rest = movePool.indexOf('rest');
80
- if (rest >= 0)
81
- this.fastPop(movePool, rest);
82
- }
83
- return { cull: !moves.has('rest') };
84
- case 'storedpower':
85
- return { cull: !counter.setupType };
86
- case 'switcheroo':
87
- case 'trick':
88
- return { cull: counter.get('Physical') + counter.get('Special') < 3 || !!counter.get('priority') };
89
- // Set up once and only if we have the moves for it
90
- case 'bellydrum':
91
- case 'bulkup':
92
- case 'coil':
93
- case 'curse':
94
- case 'dragondance':
95
- case 'honeclaws':
96
- case 'swordsdance':
97
- return { cull: ((move.id === 'bellydrum' && !abilities.has('Unburden') && !counter.get('priority')) ||
98
- (counter.get('Physical') + counter.get('physicalpool') < 2 && (!moves.has('rest') || !moves.has('sleeptalk'))) || ((counter.setupType !== 'Physical' || counter.get('physicalsetup') > 1) &&
99
- (!moves.has('growth') || moves.has('sunnyday')))), isSetup: true };
100
- case 'calmmind':
101
- case 'geomancy':
102
- case 'nastyplot':
103
- case 'quiverdance':
104
- case 'tailglow':
105
- if (types.has('Dark') && moves.has('darkpulse')) {
106
- counter.setupType = 'Special';
107
- return { cull: false, isSetup: true };
108
- }
109
- return { cull: (counter.setupType !== 'Special' ||
110
- counter.get('specialsetup') > 1 ||
111
- (counter.get('Special') + counter.get('specialpool') < 2 && (!moves.has('rest') || !moves.has('sleeptalk')))), isSetup: true };
112
- case 'growth':
113
- case 'shellsmash':
114
- case 'workup':
115
- return { cull: (counter.setupType !== 'Mixed' ||
116
- counter.get('mixedsetup') > 1 ||
117
- counter.damagingMoves.size + counter.get('physicalpool') + counter.get('specialpool') < 2 ||
118
- (move.id === 'growth' && !moves.has('sunnyday'))), isSetup: true };
119
- case 'agility':
120
- case 'autotomize':
121
- case 'rockpolish':
122
- case 'shiftgear':
123
- return { cull: counter.damagingMoves.size < 2 || restTalk, isSetup: !counter.setupType };
124
- case 'flamecharge':
125
- return { cull: (moves.has('dracometeor') ||
126
- moves.has('overheat') ||
127
- (counter.damagingMoves.size < 3 && !counter.setupType)) };
128
- // Bad after setup
129
- case 'circlethrow':
130
- case 'dragontail':
131
- return { cull: ((!!counter.setupType && ((!moves.has('rest') && !moves.has('sleeptalk')) || moves.has('stormthrow'))) ||
132
- (!!counter.get('speedsetup') || ['encore', 'raindance', 'roar', 'trickroom', 'whirlwind'].some(m => moves.has(m))) ||
133
- (counter.get(move.type) > 1 && counter.get('Status') > 1) ||
134
- (abilities.has('Sheer Force') && !!counter.get('sheerforce'))) };
135
- case 'defog':
136
- return { cull: (!!counter.setupType ||
137
- moves.has('spikes') || moves.has('stealthrock') ||
138
- restTalk ||
139
- !!teamDetails.defog) };
140
- case 'fakeout':
141
- case 'tailwind':
142
- return { cull: !!counter.setupType || ['substitute', 'switcheroo', 'trick'].some(m => moves.has(m)) };
143
- case 'foulplay':
144
- return { cull: (!!counter.setupType ||
145
- !!counter.get('speedsetup') ||
146
- counter.get('Dark') > 2 ||
147
- moves.has('clearsmog') ||
148
- restTalk ||
149
- counter.damagingMoves.size - 1 === counter.get('priority')) };
150
- case 'haze':
151
- case 'spikes':
152
- return { cull: !!counter.setupType || !!counter.get('speedsetup') || moves.has('trickroom') };
153
- case 'healbell':
154
- case 'technoblast':
155
- return { cull: !!counter.get('speedsetup') };
156
- case 'healingwish':
157
- case 'memento':
158
- return { cull: !!counter.setupType || !!counter.get('recovery') || moves.has('substitute') };
159
- case 'leechseed':
160
- case 'roar':
161
- case 'whirlwind':
162
- return { cull: !!counter.setupType || !!counter.get('speedsetup') || moves.has('dragontail') };
163
- case 'nightshade':
164
- case 'seismictoss':
165
- case 'superfang':
166
- return { cull: counter.damagingMoves.size > 1 || !!counter.setupType };
167
- case 'protect':
168
- const screens = moves.has('lightscreen') && moves.has('reflect');
169
- return { cull: moves.has('rest') || screens || (!!counter.setupType && !moves.has('wish')) };
170
- case 'pursuit':
171
- return { cull: (moves.has('nightslash') ||
172
- !!counter.setupType ||
173
- counter.get('Status') > 1 ||
174
- counter.get('Dark') > 2 ||
175
- (moves.has('knockoff') && !types.has('Dark'))) };
176
- case 'rapidspin':
177
- return { cull: !!counter.setupType || !!teamDetails.rapidSpin };
178
- case 'stealthrock':
179
- return { cull: (!!counter.setupType ||
180
- !!counter.get('speedsetup') ||
181
- ['rest', 'substitute', 'trickroom'].some(m => moves.has(m)) ||
182
- !!teamDetails.stealthRock) };
183
- case 'stickyweb':
184
- return { cull: !!teamDetails.stickyWeb };
185
- case 'toxicspikes':
186
- return { cull: !!counter.setupType || !!teamDetails.toxicSpikes };
187
- case 'trickroom':
188
- return { cull: (moves.has('lightscreen') || moves.has('reflect') ||
189
- !!counter.setupType ||
190
- !!counter.get('speedsetup') ||
191
- counter.damagingMoves.size < 2) };
192
- case 'uturn':
193
- return { cull: (!!counter.setupType || !!counter.get('speedsetup') ||
194
- (abilities.has('Speed Boost') && moves.has('protect')) ||
195
- (abilities.has('Protean') && counter.get('Status') > 2) || (types.has('Bug') &&
196
- counter.get('stab') < 2 &&
197
- counter.damagingMoves.size > 2 &&
198
- !abilities.has('Adaptability') && !abilities.has('Download'))) };
199
- case 'voltswitch':
200
- return { cull: !!counter.setupType || !!counter.get('speedsetup') || moves.has('raindance') || moves.has('uturn') };
201
- // Bit redundant to have both
202
- // Attacks:
203
- case 'bugbite':
204
- case 'bugbuzz':
205
- case 'signalbeam':
206
- return { cull: moves.has('uturn') && !counter.setupType && !abilities.has('Tinted Lens') };
207
- case 'darkpulse':
208
- return { cull: ['crunch', 'knockoff', 'hyperspacefury'].some(m => moves.has(m)) && counter.setupType !== 'Special' };
209
- case 'suckerpunch':
210
- return { cull: (counter.damagingMoves.size < 2 ||
211
- (counter.get('Dark') > 1 && !types.has('Dark')) ||
212
- moves.has('glare') ||
213
- restTalk) };
214
- case 'dragonclaw':
215
- return { cull: moves.has('dragontail') || moves.has('outrage') };
216
- case 'dracometeor':
217
- return { cull: moves.has('swordsdance') || counter.setupType === 'Physical' && counter.get('Dragon') > 1 };
218
- case 'dragonpulse':
219
- case 'spacialrend':
220
- return { cull: moves.has('dracometeor') || moves.has('outrage') || (moves.has('dragontail') && !counter.setupType) };
221
- case 'outrage':
222
- return { cull: moves.has('dracometeor') && counter.damagingMoves.size < 3 };
223
- case 'thunderbolt':
224
- return { cull: moves.has('discharge') || (moves.has('voltswitch') && moves.has('wildcharge')) };
225
- case 'dazzlinggleam':
226
- return { cull: moves.has('playrough') && counter.setupType !== 'Special' };
227
- case 'aurasphere':
228
- case 'focusblast':
229
- return { cull: restTalk || ((moves.has('closecombat') || moves.has('superpower')) && counter.setupType !== 'Special') };
230
- case 'drainpunch':
231
- return { cull: ((!moves.has('bulkup') && (moves.has('closecombat') || moves.has('highjumpkick'))) ||
232
- ((moves.has('focusblast') || moves.has('superpower')) && counter.setupType !== 'Physical')) };
233
- case 'closecombat':
234
- case 'highjumpkick':
235
- return { cull: ((moves.has('bulkup') && moves.has('drainpunch')) || (counter.setupType === 'Special' &&
236
- (moves.has('aurasphere') || moves.has('focusblast') || movePool.includes('aurasphere')))) };
237
- case 'machpunch':
238
- return { cull: types.has('Fighting') && counter.get('stab') < 2 && !abilities.has('Technician') };
239
- case 'stormthrow':
240
- return { cull: moves.has('circlethrow') && restTalk };
241
- case 'superpower':
242
- const isSetup = abilities.has('Contrary');
243
- return { cull: (counter.get('Fighting') > 1 && !!counter.setupType) || (restTalk && !isSetup), isSetup };
244
- case 'vacuumwave':
245
- return { cull: (moves.has('closecombat') || moves.has('machpunch')) && counter.setupType !== 'Special' };
246
- case 'fierydance':
247
- case 'firefang':
248
- case 'flamethrower':
249
- return { cull: ((move.id === 'flamethrower' && moves.has('drainpunch') && counter.setupType !== 'Special') ||
250
- moves.has('blazekick') ||
251
- moves.has('overheat') ||
252
- ((moves.has('fireblast') || moves.has('lavaplume')) && counter.setupType !== 'Physical')) };
253
- case 'fireblast':
254
- return { cull: ((moves.has('flareblitz') && counter.setupType !== 'Special') ||
255
- (moves.has('lavaplume') && !counter.setupType && !counter.get('speedsetup'))) };
256
- case 'lavaplume':
257
- return { cull: moves.has('firepunch') || moves.has('fireblast') && (!!counter.setupType || !!counter.get('speedsetup')) };
258
- case 'airslash':
259
- case 'hurricane':
260
- return { cull: ([(move.id === 'hurricane' ? 'airslash' : 'hurricane'), 'acrobatics', 'bravebird'].some(m => moves.has(m))) };
261
- case 'shadowball':
262
- return { cull: moves.has('darkpulse') || (moves.has('hex') && moves.has('willowisp')) };
263
- case 'shadowclaw':
264
- return { cull: (moves.has('shadowforce') ||
265
- moves.has('shadowsneak') ||
266
- (moves.has('shadowball') && counter.setupType !== 'Physical')) };
267
- case 'shadowsneak':
268
- return { cull: restTalk || (types.has('Ghost') && species.types.length > 1 && counter.get('stab') < 2) };
269
- case 'hex':
270
- return { cull: moves.has('shadowball') && !moves.has('willowisp') };
271
- case 'gigadrain':
272
- case 'powerwhip':
273
- return { cull: (moves.has('seedbomb') ||
274
- moves.has('petaldance') ||
275
- (moves.has('sunnyday') && moves.has('solarbeam')) ||
276
- (counter.get('Special') < 4 && !counter.setupType && moves.has('leafstorm'))) };
277
- case 'leafblade':
278
- case 'woodhammer':
279
- return { cull: ((moves.has('hornleech') && counter.get('Physical') < 4) ||
280
- (moves.has('gigadrain') && counter.setupType !== 'Physical')) };
281
- case 'leafstorm':
282
- return { cull: counter.get('Grass') > 1 && !!counter.setupType };
283
- case 'solarbeam':
284
- return { cull: ((!abilities.has('Drought') && !moves.has('sunnyday')) ||
285
- moves.has('gigadrain') ||
286
- moves.has('leafstorm')) };
287
- case 'bonemerang':
288
- case 'earthpower':
289
- case 'precipiceblades':
290
- return { cull: moves.has('earthquake') };
291
- case 'freezedry':
292
- return { cull: moves.has('icebeam') || moves.has('icywind') || counter.get('stab') < 2 };
293
- case 'bodyslam':
294
- case 'return':
295
- return { cull: (moves.has('doubleedge') ||
296
- (moves.has('glare') && moves.has('headbutt')) ||
297
- (move.id === 'return' && moves.has('bodyslam'))) };
298
- case 'endeavor':
299
- return { cull: !isLead && !abilities.has('Defeatist') };
300
- case 'explosion':
301
- return { cull: (!!counter.setupType ||
302
- (abilities.has('Refrigerate') && (moves.has('freezedry') || movePool.includes('return'))) ||
303
- moves.has('wish')) };
304
- case 'extremespeed':
305
- return { cull: counter.setupType !== 'Physical' && moves.has('vacuumwave') };
306
- case 'hiddenpower':
307
- return { cull: moves.has('rest') || !counter.get('stab') && counter.damagingMoves.size < 2 };
308
- case 'hypervoice':
309
- return { cull: moves.has('blizzard') || moves.has('return') };
310
- case 'judgment':
311
- return { cull: counter.setupType !== 'Special' && counter.get('stab') > 1 };
312
- case 'quickattack':
313
- return { cull: ((types.has('Normal') && (!counter.get('stab') || counter.get('Normal') > 2)) ||
314
- (types.has('Rock') && !!counter.get('Status'))) };
315
- case 'weatherball':
316
- return { cull: !moves.has('raindance') && !moves.has('sunnyday') };
317
- case 'poisonjab':
318
- return { cull: moves.has('gunkshot') };
319
- case 'acidspray':
320
- case 'sludgewave':
321
- return { cull: moves.has('poisonjab') || moves.has('sludgebomb') };
322
- case 'psychic':
323
- return { cull: moves.has('psyshock') };
324
- case 'psychocut':
325
- case 'zenheadbutt':
326
- return { cull: (moves.has('psychic') || moves.has('psyshock')) && counter.setupType !== 'Physical' };
327
- case 'psyshock':
328
- const psychic = movePool.indexOf('psychic');
329
- if (psychic >= 0)
330
- this.fastPop(movePool, psychic);
331
- return { cull: false };
332
- case 'headsmash':
333
- return { cull: moves.has('stoneedge') };
334
- case 'rockblast':
335
- case 'rockslide':
336
- return { cull: moves.has('headsmash') || moves.has('stoneedge') };
337
- case 'bulletpunch':
338
- return { cull: moves.has('substitute') };
339
- case 'hydropump':
340
- return { cull: (moves.has('razorshell') ||
341
- moves.has('waterfall') ||
342
- (moves.has('scald') && (counter.get('Special') < 4 || species.types.length > 1 && counter.get('stab') < 3)) ||
343
- restTalk) };
344
- case 'originpulse':
345
- case 'surf':
346
- return { cull: moves.has('hydropump') || moves.has('scald') };
347
- case 'scald':
348
- return { cull: (moves.has('waterfall') ||
349
- moves.has('waterpulse') ||
350
- (species.id === 'quagsire' && movePool.includes('recover'))) };
351
- // Status:
352
- case 'glare':
353
- case 'headbutt':
354
- return { cull: moves.has('bodyslam') || !moves.has('glare') };
355
- case 'stunspore':
356
- case 'thunderwave':
357
- const otherStatus = ['discharge', 'spore', 'toxic', 'trickroom', 'yawn'].some(m => moves.has(m));
358
- return { cull: !!counter.setupType || !!counter.get('speedsetup') || restTalk || otherStatus };
359
- case 'toxic':
360
- return { cull: (!!counter.setupType ||
361
- ['hypnosis', 'sleeppowder', 'toxicspikes', 'willowisp', 'yawn', 'raindance', 'flamecharge'].some(m => moves.has(m))) };
362
- case 'willowisp':
363
- return { cull: moves.has('scald') };
364
- case 'raindance':
365
- return { cull: (counter.get('Physical') + counter.get('Special') < 2 ||
366
- (!types.has('Water') && !counter.get('Water')) ||
367
- restTalk) };
368
- case 'sunnyday':
369
- const cull = (counter.get('Physical') + counter.get('Special') < 2 ||
370
- (!abilities.has('Chlorophyll') && !abilities.has('Flower Gift') && !moves.has('solarbeam')) ||
371
- restTalk);
372
- if (cull && movePool.length > 1) {
373
- const solarbeam = movePool.indexOf('solarbeam');
374
- if (solarbeam >= 0)
375
- this.fastPop(movePool, solarbeam);
376
- if (movePool.length > 1) {
377
- const weatherball = movePool.indexOf('weatherball');
378
- if (weatherball >= 0)
379
- this.fastPop(movePool, weatherball);
380
- }
381
- }
382
- return { cull };
383
- case 'milkdrink':
384
- case 'moonlight':
385
- case 'painsplit':
386
- case 'recover':
387
- case 'roost':
388
- case 'synthesis':
389
- return { cull: ['leechseed', 'rest', 'wish'].some(m => moves.has(m)) };
390
- case 'safeguard':
391
- return { cull: moves.has('destinybond') };
392
- case 'substitute':
393
- return { cull: (['dracometeor', 'pursuit', 'rest', 'taunt', 'uturn', 'voltswitch', 'whirlwind'].some(m => moves.has(m)) ||
394
- (moves.has('leafstorm') && !abilities.has('Contrary')) ||
395
- movePool.includes('copycat')) };
396
- }
397
- return { cull: false };
398
- }
399
- shouldCullAbility(ability, types, moves, abilities, counter, movePool, teamDetails, species) {
400
- switch (ability) {
401
- case 'Flare Boost':
402
- case 'Gluttony':
403
- case 'Moody':
404
- case 'Snow Cloak':
405
- case 'Steadfast':
406
- return true;
407
- case 'Contrary':
408
- case 'Iron Fist':
409
- case 'Skill Link':
410
- case 'Strong Jaw':
411
- return !counter.get((0, sim_1.toID)(ability));
412
- case 'Aerilate':
413
- case 'Pixilate':
414
- case 'Refrigerate':
415
- return !counter.get('Normal');
416
- case 'Analytic':
417
- case 'Download':
418
- case 'Hyper Cutter':
419
- return species.nfe;
420
- case 'Battle Armor':
421
- case 'Sturdy':
422
- return (!!counter.get('recoil') && !counter.get('recovery'));
423
- case 'Chlorophyll':
424
- case 'Leaf Guard':
425
- return (species.baseStats.spe > 100 ||
426
- abilities.has('Harvest') ||
427
- (!moves.has('sunnyday') && !teamDetails.sun));
428
- case 'Competitive':
429
- return (!counter.get('Special') || moves.has('rest') && moves.has('sleeptalk'));
430
- case 'Compound Eyes':
431
- case 'No Guard':
432
- return !counter.get('inaccurate');
433
- case 'Defiant':
434
- case 'Moxie':
435
- return (!counter.get('Physical') || moves.has('dragontail'));
436
- case 'Flash Fire':
437
- return abilities.has('Drought');
438
- case 'Harvest':
439
- return abilities.has('Frisk');
440
- case 'Hustle':
441
- return counter.get('Physical') < 2;
442
- case 'Hydration':
443
- case 'Rain Dish':
444
- case 'Swift Swim':
445
- return (species.baseStats.spe > 100 || !moves.has('raindance') && !teamDetails.rain);
446
- case 'Ice Body':
447
- return !teamDetails.hail;
448
- case 'Immunity':
449
- case 'Snow Warning':
450
- return (moves.has('facade') || moves.has('hypervoice'));
451
- case 'Intimidate':
452
- return (moves.has('bodyslam') || moves.has('rest') || abilities.has('Reckless') && counter.get('recoil') > 1);
453
- case 'Lightning Rod':
454
- return species.types.includes('Ground');
455
- case 'Limber':
456
- return species.types.includes('Electric');
457
- case 'Magnet Pull':
458
- return (!types.has('Electric') && !moves.has('earthpower'));
459
- case 'Mold Breaker':
460
- return (moves.has('acrobatics') ||
461
- abilities.has('Adaptability') ||
462
- (abilities.has('Sheer Force') && !!counter.get('sheerforce')));
463
- case 'Overgrow':
464
- return !counter.get('Grass');
465
- case 'Poison Heal':
466
- return (abilities.has('Technician') && !!counter.get('technician'));
467
- case 'Prankster':
468
- return !counter.get('Status');
469
- case 'Pressure':
470
- case 'Synchronize':
471
- return (counter.get('Status') < 2 || !!counter.get('recoil') || !!species.isMega);
472
- case 'Reckless':
473
- case 'Rock Head':
474
- return (!counter.get('recoil') || !!species.isMega);
475
- case 'Regenerator':
476
- return abilities.has('Magic Guard');
477
- case 'Sand Force':
478
- case 'Sand Rush':
479
- case 'Sand Veil':
480
- return !teamDetails.sand;
481
- case 'Scrappy':
482
- return !species.types.includes('Normal');
483
- case 'Serene Grace':
484
- return (!counter.get('serenegrace') || species.name === 'Blissey');
485
- case 'Sheer Force':
486
- return (!counter.get('sheerforce') || moves.has('doubleedge') || abilities.has('Guts') || !!species.isMega);
487
- case 'Simple':
488
- return (!counter.setupType && !moves.has('flamecharge'));
489
- case 'Solar Power':
490
- return (!counter.get('Special') || !teamDetails.sun || !!species.isMega);
491
- case 'Speed Boost':
492
- return moves.has('uturn');
493
- case 'Swarm':
494
- return (!counter.get('Bug') || !!species.isMega);
495
- case 'Sweet Veil':
496
- return types.has('Grass');
497
- case 'Technician':
498
- return (!counter.get('technician') || moves.has('tailslap') || !!species.isMega);
499
- case 'Tinted Lens':
500
- return (moves.has('protect') ||
501
- abilities.has('Prankster') ||
502
- counter.get('damage') >= counter.damagingMoves.size ||
503
- (counter.get('Status') > 2 && !counter.setupType));
504
- case 'Torrent':
505
- return (!counter.get('Water') || !!species.isMega);
506
- case 'Unaware':
507
- return (!!counter.setupType || moves.has('stealthrock'));
508
- case 'Unburden':
509
- return (!!species.isMega || abilities.has('Prankster') || !counter.setupType && !moves.has('acrobatics'));
510
- case 'Water Absorb':
511
- return (moves.has('raindance') || ['Drizzle', 'Unaware', 'Volt Absorb'].some(a => abilities.has(a)));
512
- case 'Weak Armor':
513
- return counter.setupType !== 'Physical';
514
- }
515
- return false;
516
- }
517
- getHighPriorityItem(ability, types, moves, counter, teamDetails, species, isLead) {
518
- if (species.requiredItem)
519
- return species.requiredItem;
520
- if (species.requiredItems)
521
- return this.sample(species.requiredItems);
522
- // First, the extra high-priority items
523
- if (species.name === 'Marowak')
524
- return 'Thick Club';
525
- if (species.name === 'Dedenne')
526
- return 'Petaya Berry';
527
- if (species.name === 'Deoxys-Attack')
528
- return (isLead && moves.has('stealthrock')) ? 'Focus Sash' : 'Life Orb';
529
- if (species.name === 'Farfetch\u2019d')
530
- return 'Stick';
531
- if (species.name === 'Genesect' && moves.has('technoblast'))
532
- return 'Douse Drive';
533
- if (species.baseSpecies === 'Pikachu')
534
- return 'Light Ball';
535
- if (species.name === 'Shedinja' || species.name === 'Smeargle')
536
- return 'Focus Sash';
537
- if (species.name === 'Unfezant' && counter.get('Physical') >= 2)
538
- return 'Scope Lens';
539
- if (species.name === 'Unown')
540
- return 'Choice Specs';
541
- if (species.name === 'Wobbuffet') {
542
- return moves.has('destinybond') ? 'Custap Berry' : this.sample(['Leftovers', 'Sitrus Berry']);
543
- }
544
- if (ability === 'Harvest')
545
- return 'Sitrus Berry';
546
- if (ability === 'Imposter')
547
- return 'Choice Scarf';
548
- if (moves.has('switcheroo') || moves.has('trick')) {
549
- if (ability === 'Klutz') {
550
- return 'Assault Vest';
551
- }
552
- else if (species.baseStats.spe >= 60 && species.baseStats.spe <= 108) {
553
- return 'Choice Scarf';
554
- }
555
- else {
556
- return (counter.get('Physical') > counter.get('Special')) ? 'Choice Band' : 'Choice Specs';
557
- }
558
- }
559
- if (species.nfe)
560
- return (ability === 'Technician' && counter.get('Physical') >= 4) ? 'Choice Band' : 'Eviolite';
561
- if (moves.has('copycat') && counter.get('Physical') >= 3)
562
- return 'Choice Band';
563
- if (moves.has('bellydrum'))
564
- return 'Sitrus Berry';
565
- if (moves.has('geomancy') ||
566
- (moves.has('solarbeam') && ability !== 'Drought' && !moves.has('sunnyday') && !teamDetails.sun)) {
567
- return 'Power Herb';
568
- }
569
- if (moves.has('shellsmash')) {
570
- return (ability === 'Solid Rock' && !!counter.get('priority')) ? 'Weakness Policy' : 'White Herb';
571
- }
572
- if ((ability === 'Guts' || moves.has('facade') || moves.has('psychoshift')) && !moves.has('sleeptalk')) {
573
- return moves.has('drainpunch') ? 'Flame Orb' : 'Toxic Orb';
574
- }
575
- if ((ability === 'Magic Guard' && counter.damagingMoves.size > 1) ||
576
- (ability === 'Sheer Force' && !!counter.get('sheerforce'))) {
577
- return 'Life Orb';
578
- }
579
- if (ability === 'Poison Heal')
580
- return 'Toxic Orb';
581
- if (ability === 'Unburden') {
582
- if (moves.has('fakeout')) {
583
- return 'Normal Gem';
584
- }
585
- else if (['dracometeor', 'leafstorm', 'overheat'].some(m => moves.has(m))) {
586
- return 'White Herb';
587
- }
588
- else if (moves.has('substitute') || counter.setupType) {
589
- return 'Sitrus Berry';
590
- }
591
- else {
592
- return 'Red Card';
593
- }
594
- }
595
- if (moves.has('acrobatics'))
596
- return ''; // not undefined - we want "no item"
597
- if (moves.has('raindance'))
598
- return (ability === 'Forecast') ? 'Damp Rock' : 'Life Orb';
599
- if (moves.has('sunnyday'))
600
- return (ability === 'Forecast') ? 'Heat Rock' : 'Life Orb';
601
- if (moves.has('lightscreen') && moves.has('reflect'))
602
- return 'Light Clay';
603
- if (moves.has('rest') && !moves.has('sleeptalk') && ability !== 'Natural Cure' && ability !== 'Shed Skin') {
604
- return 'Chesto Berry';
605
- }
606
- }
607
- getMediumPriorityItem(ability, moves, counter, species, isDoubles, isLead) {
608
- const defensiveStatTotal = species.baseStats.hp + species.baseStats.def + species.baseStats.spd;
609
- const scarfReqs = species.baseStats.spe >= 60 && species.baseStats.spe <= 108 && !counter.get('priority');
610
- if ((ability === 'Speed Boost' || ability === 'Stance Change') &&
611
- counter.get('Physical') + counter.get('Special') > 2) {
612
- return 'Life Orb';
613
- }
614
- if (counter.get('Physical') >= 4 &&
615
- ['bodyslam', 'dragontail', 'fakeout', 'flamecharge', 'rapidspin', 'suckerpunch'].every(m => !moves.has(m))) {
616
- return ((species.baseStats.atk >= 100 || ability === 'Huge Power') &&
617
- scarfReqs &&
618
- this.randomChance(2, 3)) ? 'Choice Scarf' : 'Choice Band';
619
- }
620
- if (counter.get('Special') >= 4 &&
621
- !moves.has('acidspray') && !moves.has('clearsmog') && !moves.has('fierydance')) {
622
- return (species.baseStats.spa >= 100 &&
623
- scarfReqs &&
624
- this.randomChance(2, 3)) ? 'Choice Scarf' : 'Choice Specs';
625
- }
626
- if (counter.get('Physical') >= 3 &&
627
- moves.has('defog') &&
628
- scarfReqs &&
629
- !moves.has('foulplay')) {
630
- return 'Choice Scarf';
631
- }
632
- if (counter.get('Special') >= 3 && moves.has('uturn') && !moves.has('acidspray'))
633
- return 'Choice Specs';
634
- if (ability === 'Slow Start' ||
635
- ['bite', 'clearsmog', 'curse', 'protect', 'sleeptalk'].some(m => moves.has(m)) ||
636
- species.name.includes('Rotom-')) {
637
- return 'Leftovers';
638
- }
639
- if (['endeavor', 'flail', 'reversal'].some(m => moves.has(m)) && ability !== 'Sturdy') {
640
- return (ability === 'Defeatist') ? 'Expert Belt' : 'Focus Sash';
641
- }
642
- if (moves.has('outrage') && counter.setupType)
643
- return 'Lum Berry';
644
- if (moves.has('substitute'))
645
- return counter.damagingMoves.size > 2 && !!counter.get('drain') ? 'Life Orb' : 'Leftovers';
646
- if (this.dex.getEffectiveness('Ground', species) >= 2 && ability !== 'Levitate' && !moves.has('magnetrise')) {
647
- return 'Air Balloon';
648
- }
649
- if ((ability === 'Iron Barbs' || ability === 'Rough Skin') && this.randomChance(1, 2))
650
- return 'Rocky Helmet';
651
- if (counter.get('Physical') + counter.get('Special') >= 4 &&
652
- species.baseStats.spd >= 50 &&
653
- defensiveStatTotal >= 235) {
654
- return 'Assault Vest';
655
- }
656
- if (species.name === 'Palkia' && (moves.has('dracometeor') || moves.has('spacialrend')) && moves.has('hydropump')) {
657
- return 'Lustrous Orb';
658
- }
659
- if (counter.damagingMoves.size >= 4) {
660
- return (!!counter.get('Dragon') || !!counter.get('Dark') || !!counter.get('Normal')) ? 'Life Orb' : 'Expert Belt';
661
- }
662
- if (counter.damagingMoves.size >= 3 && counter.get('speedsetup') && defensiveStatTotal >= 300)
663
- return 'Weakness Policy';
664
- if (isLead &&
665
- ability !== 'Regenerator' && ability !== 'Sturdy' &&
666
- !counter.get('recoil') && !counter.get('recovery') &&
667
- defensiveStatTotal <= 275) {
668
- return 'Focus Sash';
669
- }
670
- }
671
- getLowPriorityItem(ability, types, moves, abilities, counter, teamDetails, species, isLead) {
672
- const defensiveStatTotal = species.baseStats.hp + species.baseStats.def + species.baseStats.spd;
673
- if (ability === 'Gale Wings' && moves.has('bravebird'))
674
- return 'Sharp Beak';
675
- if (moves.has('stickyweb') && ability === 'Sturdy')
676
- return 'Mental Herb';
677
- if (ability === 'Serene Grace' && moves.has('airslash') && species.baseStats.spe > 100)
678
- return 'Metronome';
679
- if (ability === 'Sturdy' && moves.has('explosion') && !counter.get('speedsetup'))
680
- return 'Custap Berry';
681
- if (ability === 'Super Luck')
682
- return 'Scope Lens';
683
- if (counter.damagingMoves.size >= 3 && ability !== 'Sturdy' &&
684
- ['acidspray', 'dragontail', 'foulplay', 'rapidspin', 'superfang', 'uturn'].every(m => !moves.has(m))) {
685
- return (counter.get('speedsetup') ||
686
- moves.has('trickroom') ||
687
- (species.baseStats.spe > 40 && defensiveStatTotal <= 275)) ? 'Life Orb' : 'Leftovers';
688
- }
689
- }
690
- randomSet(species, teamDetails = {}, isLead = false) {
691
- species = this.dex.species.get(species);
692
- let forme = species.name;
693
- if (typeof species.battleOnly === 'string') {
694
- // Only change the forme. The species has custom moves, and may have different typing and requirements.
695
- forme = species.battleOnly;
696
- }
697
- if (species.cosmeticFormes) {
698
- forme = this.sample([species.name].concat(species.cosmeticFormes));
699
- }
700
- const movePool = (species.randomBattleMoves || Object.keys(this.dex.species.getLearnset(species.id))).slice();
701
- const rejectedPool = [];
702
- let ability = '';
703
- const evs = { hp: 85, atk: 85, def: 85, spa: 85, spd: 85, spe: 85 };
704
- const ivs = { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 };
705
- const types = new Set(species.types);
706
- let abilities = new Set(Object.values(species.abilities));
707
- if (species.unreleasedHidden)
708
- abilities.delete(species.abilities.H);
709
- let availableHP = 0;
710
- for (const setMoveid of movePool) {
711
- if (setMoveid.startsWith('hiddenpower'))
712
- availableHP++;
713
- }
714
- // These moves can be used even if we aren't setting up to use them:
715
- const SetupException = ['closecombat', 'diamondstorm', 'extremespeed', 'suckerpunch', 'superpower', 'dracometeor'];
716
- const moves = new Set();
717
- let counter;
718
- // We use a special variable to track Hidden Power
719
- // so that we can check for all Hidden Powers at once
720
- let hasHiddenPower = false;
721
- do {
722
- // Choose next 4 moves from learnset/viable moves and add them to moves list:
723
- while (moves.size < this.maxMoveCount && movePool.length) {
724
- const moveid = this.sampleNoReplace(movePool);
725
- if (moveid.startsWith('hiddenpower')) {
726
- availableHP--;
727
- if (hasHiddenPower)
728
- continue;
729
- hasHiddenPower = true;
730
- }
731
- moves.add(moveid);
732
- }
733
- while (moves.size < this.maxMoveCount && rejectedPool.length) {
734
- const moveid = this.sampleNoReplace(rejectedPool);
735
- if (moveid.startsWith('hiddenpower')) {
736
- if (hasHiddenPower)
737
- continue;
738
- hasHiddenPower = true;
739
- }
740
- moves.add(moveid);
741
- }
742
- counter = this.queryMoves(moves, species.types, abilities, movePool);
743
- // Iterate through the moves again, this time to cull them:
744
- for (const moveid of moves) {
745
- const move = this.dex.moves.get(moveid);
746
- let { cull, isSetup } = this.shouldCullMove(move, types, moves, abilities, counter, movePool, teamDetails, species, isLead);
747
- // This move doesn't satisfy our setup requirements:
748
- if ((move.category === 'Physical' && counter.setupType === 'Special') ||
749
- (move.category === 'Special' && counter.setupType === 'Physical')) {
750
- // Reject STABs last in case the setup type changes later on
751
- const stabs = counter.get(species.types[0]) + counter.get(species.types[1]);
752
- if (!SetupException.includes(moveid) &&
753
- (!types.has(move.type) || stabs > 1 || counter.get(move.category) < 2))
754
- cull = true;
755
- }
756
- if (counter.setupType && !isSetup && counter.setupType !== 'Mixed' && move.category !== counter.setupType &&
757
- counter.get(counter.setupType) < 2 && (move.category !== 'Status' || !move.flags.heal) &&
758
- moveid !== 'sleeptalk' && !types.has('Dark') && !moves.has('darkpulse') && (move.category !== 'Status' || (counter.get(counter.setupType) + counter.get('Status') > 3 &&
759
- counter.get('physicalsetup') + counter.get('specialsetup') < 2))) {
760
- // Mono-attacking with setup and RestTalk is allowed
761
- // Reject Status moves only if there is nothing else to reject
762
- cull = true;
763
- }
764
- if (counter.setupType === 'Special' &&
765
- moveid === 'hiddenpower' &&
766
- species.types.length > 1 &&
767
- counter.get('Special') <= 2 &&
768
- !types.has(move.type) &&
769
- !counter.get('Physical') &&
770
- counter.get('specialpool')) {
771
- // Hidden Power isn't good enough
772
- cull = true;
773
- }
774
- const runEnforcementChecker = (checkerName) => {
775
- if (!this.moveEnforcementCheckers[checkerName])
776
- return false;
777
- return this.moveEnforcementCheckers[checkerName](movePool, moves, abilities, types, counter, species, teamDetails);
778
- };
779
- // Pokemon should have moves that benefit their Type/Ability/Weather, as well as moves required by its forme
780
- if (!cull && !isSetup && !move.weather && !move.damage &&
781
- (move.category !== 'Status' || !move.flags.heal) &&
782
- !['judgment', 'sleeptalk', 'toxic'].includes(moveid) &&
783
- (counter.get('physicalsetup') + counter.get('specialsetup') < 2 && (!counter.setupType || counter.setupType === 'Mixed' ||
784
- (move.category !== counter.setupType && move.category !== 'Status') ||
785
- counter.get(counter.setupType) + counter.get('Status') > 3)) && (move.category === 'Status' ||
786
- !types.has(move.type) ||
787
- (move.basePower && move.basePower < 40 && !move.multihit))) {
788
- if ((!counter.get('stab') && !moves.has('nightshade') && !moves.has('seismictoss') && (species.types.length > 1 ||
789
- (species.types[0] !== 'Normal' && species.types[0] !== 'Psychic') ||
790
- !moves.has('icebeam') ||
791
- species.baseStats.spa >= species.baseStats.spd)) ||
792
- (!counter.get('recovery') && !counter.setupType && !moves.has('healingwish') && (movePool.includes('recover') || movePool.includes('roost') || movePool.includes('softboiled')) && (counter.get('Status') > 1 || (species.nfe && !!counter.get('Status')))) ||
793
- (movePool.includes('stickyweb') && !counter.setupType && !teamDetails.stickyWeb) ||
794
- (species.requiredMove && movePool.includes((0, sim_1.toID)(species.requiredMove))) ||
795
- (moves.has('suckerpunch') && counter.get('stab') < species.types.length)) {
796
- cull = true;
797
- }
798
- else {
799
- for (const type of types) {
800
- if (runEnforcementChecker(type)) {
801
- cull = true;
802
- }
803
- }
804
- for (const abil of abilities) {
805
- if (runEnforcementChecker(abil)) {
806
- cull = true;
807
- }
808
- }
809
- }
810
- }
811
- // Sleep Talk shouldn't be selected without Rest
812
- if (moveid === 'rest' && cull) {
813
- const sleeptalk = movePool.indexOf('sleeptalk');
814
- if (sleeptalk >= 0) {
815
- if (movePool.length < 2) {
816
- cull = false;
817
- }
818
- else {
819
- this.fastPop(movePool, sleeptalk);
820
- }
821
- }
822
- }
823
- // Remove cull moves from the move list
824
- if (cull && (movePool.length - availableHP ||
825
- (availableHP && (moveid.startsWith('hiddenpower') || !hasHiddenPower)))) {
826
- if (move.category !== 'Status' &&
827
- !move.damage && !move.flags.charge &&
828
- (moveid !== 'hiddenpower' || !availableHP))
829
- rejectedPool.push(moveid);
830
- moves.delete(moveid);
831
- if (moveid.startsWith('hiddenpower'))
832
- hasHiddenPower = false;
833
- break;
834
- }
835
- if (cull && rejectedPool.length) {
836
- moves.delete(moveid);
837
- if (moveid.startsWith('hiddenpower'))
838
- hasHiddenPower = false;
839
- break;
840
- }
841
- }
842
- } while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
843
- if (hasHiddenPower) {
844
- let hpType;
845
- for (const move of moves) {
846
- if (move.startsWith('hiddenpower')) {
847
- hpType = move.substr(11);
848
- break;
849
- }
850
- }
851
- if (!hpType)
852
- throw new Error(`hasHiddenPower is true, but no Hidden Power move was found.`);
853
- const HPivs = this.dex.types.get(hpType).HPivs;
854
- let iv;
855
- for (iv in HPivs) {
856
- ivs[iv] = HPivs[iv];
857
- }
858
- }
859
- // Moveset modifications
860
- if (moves.has('autotomize') && moves.has('heavyslam')) {
861
- moves.delete('autotomize');
862
- moves.add('rockpolish');
863
- }
864
- if (moves.has('raindance') && moves.has('thunderbolt')) {
865
- moves.delete('thunderbolt');
866
- moves.add('thunder');
867
- }
868
- if (species.battleOnly && !species.requiredAbility) {
869
- abilities = new Set(Object.values(this.dex.species.get(species.battleOnly).abilities));
870
- }
871
- const abilityData = [...abilities].map(a => this.dex.abilities.get(a));
872
- utils_1.Utils.sortBy(abilityData, abil => -abil.rating);
873
- if (abilityData.length > 1) {
874
- // Sort abilities by rating with an element of randomness
875
- if (abilityData[2] && abilityData[1].rating <= abilityData[2].rating && this.randomChance(1, 2)) {
876
- [abilityData[1], abilityData[2]] = [abilityData[2], abilityData[1]];
877
- }
878
- if (abilityData[0].rating <= abilityData[1].rating && this.randomChance(1, 2)) {
879
- [abilityData[0], abilityData[1]] = [abilityData[1], abilityData[0]];
880
- }
881
- else if (abilityData[0].rating - 0.6 <= abilityData[1].rating && this.randomChance(2, 3)) {
882
- [abilityData[0], abilityData[1]] = [abilityData[1], abilityData[0]];
883
- }
884
- // Start with the first abiility and work our way through, culling as we go
885
- ability = abilityData[0].name;
886
- while (this.shouldCullAbility(ability, types, moves, abilities, counter, movePool, teamDetails, species)) {
887
- if (ability === abilityData[0].name && abilityData[1].rating >= 1) {
888
- ability = abilityData[1].name;
889
- }
890
- else if (ability === abilityData[1].name && abilityData[2] && abilityData[2].rating >= 1) {
891
- ability = abilityData[2].name;
892
- }
893
- else {
894
- // Default to the highest rated ability if all are rejected
895
- ability = abilityData[0].name;
896
- break;
897
- }
898
- }
899
- if (abilities.has('Guts') &&
900
- ability !== 'Quick Feet' &&
901
- (moves.has('facade') || moves.has('protect') || (moves.has('rest') && moves.has('sleeptalk')))) {
902
- ability = 'Guts';
903
- }
904
- else if (abilities.has('Moxie') && counter.get('Physical') > 3) {
905
- ability = 'Moxie';
906
- }
907
- if (species.name === 'Ambipom' && !counter.get('technician')) {
908
- // If it doesn't qualify for Technician, Skill Link is useless on it
909
- ability = 'Pickup';
910
- }
911
- else if (species.name === 'Lopunny' && moves.has('switcheroo') && this.randomChance(2, 3)) {
912
- ability = 'Klutz';
913
- }
914
- }
915
- else {
916
- ability = abilityData[0].name;
917
- }
918
- let item = this.getHighPriorityItem(ability, types, moves, counter, teamDetails, species, isLead);
919
- if (item === undefined)
920
- item = this.getMediumPriorityItem(ability, moves, counter, species, false, isLead);
921
- if (item === undefined) {
922
- item = this.getLowPriorityItem(ability, types, moves, abilities, counter, teamDetails, species, isLead);
923
- }
924
- if (item === undefined)
925
- item = 'Leftovers';
926
- // For Trick / Switcheroo
927
- if (item === 'Leftovers' && types.has('Poison')) {
928
- item = 'Black Sludge';
929
- }
930
- const levelScale = {
931
- uber: 76, ou: 80, uu: 82, ru: 84, nu: 86, pu: 88,
932
- };
933
- const customScale = {
934
- // Banned Ability
935
- Dugtrio: 82, Gothitelle: 82, Ninetales: 84, Politoed: 84, Wobbuffet: 82,
936
- // Holistic judgement
937
- Castform: 100, Delibird: 100, 'Genesect-Douse': 80, Luvdisc: 100, Spinda: 100, Unown: 100,
938
- };
939
- const tier = (0, sim_1.toID)(species.tier).replace('bl', '');
940
- const level = this.adjustLevel || customScale[species.name] || levelScale[tier] || (species.nfe ? 90 : 80);
941
- // Prepare optimal HP
942
- const srWeakness = this.dex.getEffectiveness('Rock', species);
943
- while (evs.hp > 1) {
944
- const hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
945
- if (moves.has('substitute') && moves.has('reversal')) {
946
- // Reversal users should be able to use four Substitutes
947
- if (hp % 4 > 0)
948
- break;
949
- }
950
- else if (moves.has('substitute') && (item === 'Petaya Berry' || item === 'Sitrus Berry')) {
951
- // Three Substitutes should activate Petaya Berry for Dedenne
952
- // Two Substitutes should activate Sitrus Berry
953
- if (hp % 4 === 0)
954
- break;
955
- }
956
- else if (moves.has('bellydrum') && item === 'Sitrus Berry') {
957
- // Belly Drum should activate Sitrus Berry
958
- if (hp % 2 === 0)
959
- break;
960
- }
961
- else {
962
- // Maximize number of Stealth Rock switch-ins
963
- if (srWeakness <= 0 || hp % (4 / srWeakness) > 0)
964
- break;
965
- }
966
- evs.hp -= 4;
967
- }
968
- // Minimize confusion damage
969
- if (!counter.get('Physical') && !moves.has('copycat') && !moves.has('transform')) {
970
- evs.atk = 0;
971
- ivs.atk = hasHiddenPower ? ivs.atk - 30 : 0;
972
- }
973
- if (['gyroball', 'metalburst', 'trickroom'].some(m => moves.has(m))) {
974
- evs.spe = 0;
975
- ivs.spe = hasHiddenPower ? ivs.spe - 30 : 0;
976
- }
977
- return {
978
- name: species.baseSpecies,
979
- species: forme,
980
- gender: species.gender,
981
- moves: Array.from(moves),
982
- ability: ability,
983
- evs: evs,
984
- ivs: ivs,
985
- item: item,
986
- level,
987
- shiny: this.randomChance(1, 1024),
988
- };
989
- }
990
- randomFactorySet(species, teamData, tier) {
991
- const id = (0, sim_1.toID)(species.name);
992
- // const flags = this.randomFactorySets[tier][id].flags;
993
- const setList = this.randomFactorySets[tier][id].sets;
994
- const itemsMax = { choicespecs: 1, choiceband: 1, choicescarf: 1 };
995
- const movesMax = {
996
- rapidspin: 1, batonpass: 1, stealthrock: 1, defog: 1, spikes: 1, toxicspikes: 1,
997
- };
998
- const requiredMoves = { stealthrock: 'hazardSet', rapidspin: 'hazardClear', defog: 'hazardClear' };
999
- const weatherAbilitiesRequire = {
1000
- hydration: 'raindance', swiftswim: 'raindance',
1001
- leafguard: 'sunnyday', solarpower: 'sunnyday', chlorophyll: 'sunnyday',
1002
- sandforce: 'sandstorm', sandrush: 'sandstorm', sandveil: 'sandstorm',
1003
- snowcloak: 'hail',
1004
- };
1005
- const weatherAbilities = ['drizzle', 'drought', 'snowwarning', 'sandstream'];
1006
- // Build a pool of eligible sets, given the team partners
1007
- // Also keep track of sets with moves the team requires
1008
- let effectivePool = [];
1009
- const priorityPool = [];
1010
- for (const curSet of setList) {
1011
- if (this.forceMonotype && !species.types.includes(this.forceMonotype))
1012
- continue;
1013
- const itemData = this.dex.items.get(curSet.item);
1014
- if (teamData.megaCount && teamData.megaCount > 0 && itemData.megaStone)
1015
- continue; // reject 2+ mega stones
1016
- if (itemsMax[itemData.id] && teamData.has[itemData.id] >= itemsMax[itemData.id])
1017
- continue;
1018
- const abilityState = this.dex.abilities.get(curSet.ability);
1019
- if (weatherAbilitiesRequire[abilityState.id] && teamData.weather !== weatherAbilitiesRequire[abilityState.id])
1020
- continue;
1021
- if (teamData.weather && weatherAbilities.includes(abilityState.id))
1022
- continue; // reject 2+ weather setters
1023
- let reject = false;
1024
- let hasRequiredMove = false;
1025
- const curSetVariants = [];
1026
- for (const move of curSet.moves) {
1027
- const variantIndex = this.random(move.length);
1028
- const moveId = (0, sim_1.toID)(move[variantIndex]);
1029
- if (movesMax[moveId] && teamData.has[moveId] >= movesMax[moveId]) {
1030
- reject = true;
1031
- break;
1032
- }
1033
- if (requiredMoves[moveId] && !teamData.has[requiredMoves[moveId]]) {
1034
- hasRequiredMove = true;
1035
- }
1036
- curSetVariants.push(variantIndex);
1037
- }
1038
- if (reject)
1039
- continue;
1040
- effectivePool.push({ set: curSet, moveVariants: curSetVariants });
1041
- if (hasRequiredMove)
1042
- priorityPool.push({ set: curSet, moveVariants: curSetVariants });
1043
- }
1044
- if (priorityPool.length)
1045
- effectivePool = priorityPool;
1046
- if (!effectivePool.length) {
1047
- if (!teamData.forceResult)
1048
- return null;
1049
- for (const curSet of setList) {
1050
- effectivePool.push({ set: curSet });
1051
- }
1052
- }
1053
- const setData = this.sample(effectivePool);
1054
- const moves = [];
1055
- for (const [i, moveSlot] of setData.set.moves.entries()) {
1056
- moves.push(setData.moveVariants ? moveSlot[setData.moveVariants[i]] : this.sample(moveSlot));
1057
- }
1058
- return {
1059
- name: setData.set.name || species.baseSpecies,
1060
- species: setData.set.species,
1061
- gender: setData.set.gender || species.gender || (this.randomChance(1, 2) ? 'M' : 'F'),
1062
- item: setData.set.item || '',
1063
- ability: setData.set.ability || species.abilities['0'],
1064
- shiny: typeof setData.set.shiny === 'undefined' ? this.randomChance(1, 1024) : setData.set.shiny,
1065
- level: this.adjustLevel || 100,
1066
- happiness: typeof setData.set.happiness === 'undefined' ? 255 : setData.set.happiness,
1067
- evs: setData.set.evs || { hp: 84, atk: 84, def: 84, spa: 84, spd: 84, spe: 84 },
1068
- ivs: setData.set.ivs || { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 },
1069
- nature: setData.set.nature || 'Serious',
1070
- moves: moves,
1071
- };
1072
- }
1073
- randomFactoryTeam(side, depth = 0) {
1074
- var _a;
1075
- this.enforceNoDirectCustomBanlistChanges();
1076
- const forceResult = (depth >= 4);
1077
- // The teams generated depend on the tier choice in such a way that
1078
- // no exploitable information is leaked from rolling the tier in getTeam(p1).
1079
- if (!this.factoryTier)
1080
- this.factoryTier = this.sample(['Uber', 'OU', 'UU', 'RU', 'NU', 'PU']);
1081
- const chosenTier = this.factoryTier;
1082
- const pokemon = [];
1083
- const pokemonPool = Object.keys(this.randomFactorySets[chosenTier]);
1084
- const teamData = {
1085
- typeCount: {}, typeComboCount: {}, baseFormes: {}, megaCount: 0, has: {}, forceResult,
1086
- weaknesses: {}, resistances: {},
1087
- };
1088
- const requiredMoveFamilies = ['hazardSet', 'hazardClear'];
1089
- const requiredMoves = { stealthrock: 'hazardSet', rapidspin: 'hazardClear', defog: 'hazardClear' };
1090
- const weatherAbilitiesSet = {
1091
- drizzle: 'raindance', drought: 'sunnyday', snowwarning: 'hail', sandstream: 'sandstorm',
1092
- };
1093
- const resistanceAbilities = {
1094
- dryskin: ['Water'], waterabsorb: ['Water'], stormdrain: ['Water'],
1095
- flashfire: ['Fire'], heatproof: ['Fire'],
1096
- lightningrod: ['Electric'], motordrive: ['Electric'], voltabsorb: ['Electric'],
1097
- sapsipper: ['Grass'],
1098
- thickfat: ['Ice', 'Fire'],
1099
- levitate: ['Ground'],
1100
- };
1101
- while (pokemonPool.length && pokemon.length < this.maxTeamSize) {
1102
- const species = this.dex.species.get(this.sampleNoReplace(pokemonPool));
1103
- if (!species.exists)
1104
- continue;
1105
- const speciesFlags = this.randomFactorySets[chosenTier][species.id].flags;
1106
- // Limit to one of each species (Species Clause)
1107
- if (teamData.baseFormes[species.baseSpecies])
1108
- continue;
1109
- // Limit the number of Megas to one
1110
- if (!teamData.megaCount)
1111
- teamData.megaCount = 0;
1112
- if (teamData.megaCount >= 1 && speciesFlags.megaOnly)
1113
- continue;
1114
- // Dynamically scale limits for different team sizes. The default and minimum value is 1.
1115
- const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
1116
- // Limit 2 of any type
1117
- const types = species.types;
1118
- let skip = false;
1119
- for (const type of types) {
1120
- if (teamData.typeCount[type] >= 2 * limitFactor && this.randomChance(4, 5)) {
1121
- skip = true;
1122
- break;
1123
- }
1124
- }
1125
- if (skip)
1126
- continue;
1127
- const set = this.randomFactorySet(species, teamData, chosenTier);
1128
- if (!set)
1129
- continue;
1130
- // Limit 1 of any type combination
1131
- let typeCombo = types.slice().sort().join();
1132
- if (set.ability === 'Drought' || set.ability === 'Drizzle') {
1133
- // Drought and Drizzle don't count towards the type combo limit
1134
- typeCombo = set.ability;
1135
- }
1136
- if (teamData.typeComboCount[typeCombo] >= 1 * limitFactor)
1137
- continue;
1138
- // Okay, the set passes, add it to our team
1139
- pokemon.push(set);
1140
- // Now that our Pokemon has passed all checks, we can update team data:
1141
- for (const type of types) {
1142
- if (type in teamData.typeCount) {
1143
- teamData.typeCount[type]++;
1144
- }
1145
- else {
1146
- teamData.typeCount[type] = 1;
1147
- }
1148
- }
1149
- teamData.typeComboCount[typeCombo] = (teamData.typeComboCount[typeCombo] + 1) || 1;
1150
- teamData.baseFormes[species.baseSpecies] = 1;
1151
- const itemData = this.dex.items.get(set.item);
1152
- if (itemData.megaStone)
1153
- teamData.megaCount++;
1154
- if (itemData.id in teamData.has) {
1155
- teamData.has[itemData.id]++;
1156
- }
1157
- else {
1158
- teamData.has[itemData.id] = 1;
1159
- }
1160
- const abilityState = this.dex.abilities.get(set.ability);
1161
- if (abilityState.id in weatherAbilitiesSet) {
1162
- teamData.weather = weatherAbilitiesSet[abilityState.id];
1163
- }
1164
- for (const move of set.moves) {
1165
- const moveId = (0, sim_1.toID)(move);
1166
- if (moveId in teamData.has) {
1167
- teamData.has[moveId]++;
1168
- }
1169
- else {
1170
- teamData.has[moveId] = 1;
1171
- }
1172
- if (moveId in requiredMoves) {
1173
- teamData.has[requiredMoves[moveId]] = 1;
1174
- }
1175
- }
1176
- for (const typeName of this.dex.types.names()) {
1177
- // Cover any major weakness (3+) with at least one resistance
1178
- if (teamData.resistances[typeName] >= 1)
1179
- continue;
1180
- if (((_a = resistanceAbilities[abilityState.id]) === null || _a === void 0 ? void 0 : _a.includes(typeName)) || !this.dex.getImmunity(typeName, types)) {
1181
- // Heuristic: assume that Pokemon with these abilities don't have (too) negative typing.
1182
- teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
1183
- if (teamData.resistances[typeName] >= 1)
1184
- teamData.weaknesses[typeName] = 0;
1185
- continue;
1186
- }
1187
- const typeMod = this.dex.getEffectiveness(typeName, types);
1188
- if (typeMod < 0) {
1189
- teamData.resistances[typeName] = (teamData.resistances[typeName] || 0) + 1;
1190
- if (teamData.resistances[typeName] >= 1)
1191
- teamData.weaknesses[typeName] = 0;
1192
- }
1193
- else if (typeMod > 0) {
1194
- teamData.weaknesses[typeName] = (teamData.weaknesses[typeName] || 0) + 1;
1195
- }
1196
- }
1197
- }
1198
- if (pokemon.length < this.maxTeamSize)
1199
- return this.randomFactoryTeam(side, ++depth);
1200
- // Quality control
1201
- if (!teamData.forceResult) {
1202
- for (const requiredFamily of requiredMoveFamilies) {
1203
- if (!teamData.has[requiredFamily])
1204
- return this.randomFactoryTeam(side, ++depth);
1205
- }
1206
- for (const type in teamData.weaknesses) {
1207
- if (teamData.weaknesses[type] >= 3)
1208
- return this.randomFactoryTeam(side, ++depth);
1209
- }
1210
- }
1211
- return pokemon;
1212
- }
1213
- }
1214
- exports.RandomGen6Teams = RandomGen6Teams;
1215
- exports.default = RandomGen6Teams;
1216
- //# sourceMappingURL=gen6.js.map