@pkmn/randoms 0.6.4 → 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/index.d.ts +5 -3
- package/build/index.js +8036 -33
- package/build/index.js.map +1 -1
- package/build/index.mjs +8039 -0
- package/build/index.mjs.map +1 -0
- package/package.json +8 -9
- package/build/gen1.d.ts +0 -43
- package/build/gen1.js +0 -447
- package/build/gen1.js.map +0 -1
- package/build/gen2.d.ts +0 -13
- package/build/gen2.js +0 -289
- package/build/gen2.js.map +0 -1
- package/build/gen3.d.ts +0 -17
- package/build/gen3.js +0 -621
- package/build/gen3.js.map +0 -1
- package/build/gen4.d.ts +0 -16
- package/build/gen4.js +0 -724
- package/build/gen4.js.map +0 -1
- package/build/gen5.d.ts +0 -16
- package/build/gen5.js +0 -842
- package/build/gen5.js.map +0 -1
- package/build/gen6.d.ts +0 -23
- package/build/gen6.js +0 -1216
- package/build/gen6.js.map +0 -1
- package/build/gen7.d.ts +0 -43
- package/build/gen7.js +0 -2022
- package/build/gen7.js.map +0 -1
- package/build/gen8.d.ts +0 -154
- package/build/gen8.js +0 -2921
- package/build/gen8.js.map +0 -1
- package/build/utils.d.ts +0 -43
- package/build/utils.js +0 -70
- package/build/utils.js.map +0 -1
- package/src/gen1.ts +0 -493
- package/src/gen2.ts +0 -323
- package/src/gen3.ts +0 -688
- package/src/gen4.ts +0 -858
- package/src/gen5.ts +0 -916
- package/src/gen6.ts +0 -1357
- package/src/gen7.ts +0 -2194
- package/src/gen8.ts +0 -3122
- package/src/global.d.ts +0 -6
- package/src/index.ts +0 -46
- package/src/utils.ts +0 -78
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 >= 12);
|
|
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
|