File size: 15,349 Bytes
5c2ed06
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
'use strict';

const assert = require('./../../assert');
const common = require('./../../common');

let battle;

describe('Future Sight', () => {
	afterEach(() => {
		battle.destroy();
	});

	it(`should damage in two turns, ignoring Protect, affected by Dark immunities`, () => {
		battle = common.createBattle([[
			{ species: 'Sneasel', moves: ['sleeptalk', 'futuresight'] },
		], [
			{ species: 'Girafarig', moves: ['sleeptalk', 'futuresight', 'protect'] },
		]]);

		const sneasel = battle.p1.active[0];
		const girafarig = battle.p2.active[0];
		battle.makeChoices('move futuresight', 'move futuresight');
		assert.fullHP(girafarig);
		battle.makeChoices();
		assert.fullHP(girafarig);
		battle.makeChoices('auto', 'move protect');
		assert.fullHP(sneasel);
		assert.false.fullHP(girafarig);
	});

	it(`should fail when already active for the target's position`, () => {
		battle = common.createBattle([[
			{ species: 'Sneasel', moves: ['sleeptalk'] },
		], [
			{ species: 'Girafarig', moves: ['futuresight'] },
		]]);

		battle.makeChoices();
		battle.makeChoices();
		assert(battle.log[battle.lastMoveLine + 1].startsWith('|-fail|'));
	});

	it(`[Gen 2] should damage in two turns, ignoring Protect`, () => {
		battle = common.gen(2).createBattle([[
			{ species: 'Sneasel', moves: ['sleeptalk', 'futuresight', 'sweetscent'] },
		], [
			{ species: 'Girafarig', moves: ['sleeptalk', 'futuresight', 'protect', 'sweetscent'] },
		]]);

		const sneasel = battle.p1.active[0];
		const girafarig = battle.p2.active[0];
		battle.makeChoices('move sweetscent', 'move sweetscent'); // counteract imperfect accuracy
		battle.makeChoices('move futuresight', 'move futuresight');
		assert.fullHP(girafarig);
		battle.makeChoices('auto', 'auto');
		assert.fullHP(girafarig);
		battle.makeChoices('auto', 'move Protect');
		assert.false.fullHP(sneasel);
		assert.false.fullHP(girafarig);
	});

	it(`should not double Stomping Tantrum for exiting normally`, () => {
		battle = common.createBattle([[
			{ species: 'Wynaut', moves: ['futuresight', 'stompingtantrum'] },
		], [
			{ species: 'Scizor', ability: 'shellarmor', moves: ['sleeptalk'] },
		]]);

		battle.makeChoices();
		battle.makeChoices('move stompingtantrum', 'move sleeptalk');
		const scizor = battle.p2.active[0];
		const damage = scizor.maxhp - scizor.hp;
		assert.bounded(damage, [19, 23]); // If it were doubled, would be 38-45
	});

	it(`should not trigger Eject Button`, () => {
		battle = common.createBattle([[
			{ species: 'Wynaut', moves: ['futuresight'] },
		], [
			{ species: 'Scizor', item: 'ejectbutton', moves: ['sleeptalk'] },
			{ species: 'Roggenrola', moves: ['sleeptalk'] },
		]]);

		for (let i = 0; i < 3; i++) battle.makeChoices();
		assert.equal(battle.requestState, 'move');
	});

	it(`should be able to set Future Sight against an empty target slot`, () => {
		battle = common.createBattle([[
			{ species: 'Shedinja', moves: ['finalgambit'] },
			{ species: 'Roggenrola', moves: ['sleeptalk'] },
		], [
			{ species: 'Wynaut', moves: ['sleeptalk', 'futuresight'] },
		]]);

		battle.makeChoices('auto', 'move future sight');
		battle.makeChoices('switch 2');
		battle.makeChoices();
		battle.makeChoices();
		const roggenrola = battle.p1.active[0];
		assert.false.fullHP(roggenrola);
	});

	it(`its damaging hit should not count as copyable for Copycat`, () => {
		battle = common.createBattle([[
			{ species: 'Wynaut', moves: ['sleeptalk', 'futuresight'] },
		], [
			{ species: 'Liepard', moves: ['sleeptalk', 'copycat'] },
		]]);

		battle.makeChoices('move futuresight', 'auto');
		battle.makeChoices();
		battle.makeChoices();
		battle.makeChoices('auto', 'move copycat'); // Should fail due to last move being Sleep Talk
		battle.makeChoices();
		battle.makeChoices();
		const wynaut = battle.p1.active[0];
		assert.fullHP(wynaut);
	});

	it(`should only cause the user to take Life Orb recoil on its damaging turn`, () => {
		battle = common.createBattle([[
			{ species: 'wynaut', item: 'lifeorb', moves: ['futuresight'] },
		], [
			{ species: 'mew', moves: ['sleeptalk'] },
		]]);

		battle.makeChoices();
		const wynaut = battle.p1.active[0];
		const mew = battle.p2.active[0];
		assert.fullHP(wynaut, `Wynaut should not take Life Orb recoil on Future Sight's starting turn`);
		battle.makeChoices();
		battle.makeChoices();
		assert.equal(wynaut.hp, wynaut.maxhp - Math.floor(wynaut.maxhp / 10), `Wynaut should take Life Orb recoil on Future Sight's damaging turn`);
		const damage = mew.maxhp - mew.hp;
		assert.bounded(damage, [30, 35]); // 22-27 if Life Orb was not applied
	});

	it(`[Gen 4] should not be affected by Life Orb`, () => {
		battle = common.gen(4).createBattle([[
			{ species: 'wynaut', item: 'lifeorb', moves: ['futuresight'] },
		], [
			{ species: 'mew', ability: 'noguard', moves: ['sleeptalk'] },
		]]);

		battle.makeChoices();
		const wynaut = battle.p1.active[0];
		const mew = battle.p2.active[0];
		battle.makeChoices();
		battle.makeChoices();
		assert.fullHP(wynaut, `Wynaut should not have taken any damage`);
		const damage = mew.maxhp - mew.hp;
		assert.bounded(damage, [21, 25]); // [27-32] if Life Orb was applied
	});

	it(`should not be affected by Life Orb if not the original user`, () => {
		battle = common.createBattle([[
			{ species: 'wynaut', item: 'lifeorb', moves: ['futuresight'] },
			{ species: 'liepard', item: 'lifeorb', moves: ['sleeptalk'] },
		], [
			{ species: 'mew', moves: ['sleeptalk'] },
		]]);

		battle.makeChoices();
		const liepard = battle.p1.pokemon[1];
		const mew = battle.p2.active[0];
		battle.makeChoices();
		battle.makeChoices('switch 2', 'move sleeptalk');
		assert.fullHP(liepard, `liepard should not have taken any damage`);
		const damage = mew.maxhp - mew.hp;
		assert.bounded(damage, [22, 27]); // 30, 35 if Life Orb was applied
	});

	it(`should not cause the user to change typing on either its starting or damaging turn`, () => {
		battle = common.createBattle([[
			{ species: 'roggenrola', ability: 'protean', moves: ['futuresight', 'sleeptalk'] },
		], [
			{ species: 'mew', moves: ['sleeptalk'] },
		]]);

		const roggenrola = battle.p1.active[0];
		battle.makeChoices();
		assert.false(roggenrola.hasType('Psychic'), `Protean Roggenrola should not change type on Future Sight's starting turn`);
		battle.makeChoices();
		battle.makeChoices();
		assert.false(roggenrola.hasType('Psychic'), `Protean Roggenrola should not change type on Future Sight's damaging turn`);
	});

	it(`should be boosted by Terrain only if Terrain is active on the damaging turn`, () => {
		battle = common.createBattle([[
			{ species: 'Blissey', ability: 'shellarmor', moves: ['softboiled'] },
		], [
			{ species: 'Wynaut', ability: 'psychicsurge', moves: ['sleeptalk', 'futuresight'] },
		]]);

		battle.makeChoices('auto', 'move futuresight');
		battle.makeChoices();
		battle.makeChoices();
		const blissey = battle.p1.active[0];
		let damage = blissey.maxhp - blissey.hp;
		assert.bounded(damage, [46, 55]);

		battle.makeChoices('auto', 'move futuresight');
		battle.makeChoices();
		battle.makeChoices();
		damage = blissey.maxhp - blissey.hp;
		assert.bounded(damage, [36, 43]);
	});

	it(`should be boosted by Terrain even if the user is not on the field, as long as the user is not Flying-type`, () => {
		battle = common.createBattle([[
			{ species: 'Blissey', ability: 'shellarmor', moves: ['softboiled'] },
		], [
			{ species: 'cresselia', ability: 'levitate', moves: ['sleeptalk', 'futuresight'] },
			{ species: 'deino', ability: 'psychicsurge', moves: ['sleeptalk'] },
			{ species: 'xatu', moves: ['sleeptalk', 'futuresight'] },
		]]);

		// Cresselia will be Terrain-boosted because its Ability is not checked while not active
		battle.makeChoices('auto', 'move futuresight');
		battle.makeChoices();
		battle.makeChoices('auto', 'switch deino');
		const blissey = battle.p1.active[0];
		let damage = blissey.maxhp - blissey.hp;
		assert.bounded(damage, [102, 121]);

		// Xatu won't be Terrain-boosted because its Flying-type is checked while not active
		battle.makeChoices('auto', 'switch xatu');
		battle.makeChoices('auto', 'move futuresight');
		battle.makeChoices();
		battle.makeChoices('auto', 'switch deino');
		damage = blissey.maxhp - blissey.hp;
		assert.bounded(damage, [96, 114]);
	});

	it(`should not ignore the target's screens, even when the user is not active on the field`, () => {
		battle = common.createBattle([[
			{ species: 'Blissey', ability: 'shellarmor', item: 'lightclay', moves: ['softboiled', 'lightscreen'] },
		], [
			{ species: 'Wynaut', moves: ['sleeptalk', 'futuresight'] },
			{ species: 'deino', moves: ['sleeptalk'] },
		]]);

		battle.makeChoices('move lightscreen', 'move futuresight');
		battle.makeChoices();
		battle.makeChoices();
		const blissey = battle.p1.active[0];
		let damage = blissey.maxhp - blissey.hp;
		assert.bounded(damage, [18, 21]);

		battle.makeChoices('auto', 'move futuresight');
		battle.makeChoices();
		battle.makeChoices('auto', 'switch 2');
		damage = blissey.maxhp - blissey.hp;
		assert.bounded(damage, [18, 21]);
	});

	it(`should not consider the user's item or Ability when the user is not active`, () => {
		battle = common.createBattle([[
			{ species: 'Blissey', ability: 'shellarmor', moves: ['softboiled'] },
		], [
			{ species: 'Wynaut', ability: 'adaptability', item: 'choicespecs', moves: ['futuresight'] },
			{ species: 'Deino', ability: 'powerspot', moves: ['sleeptalk'] },
		]]);

		for (let i = 0; i < 3; i++) battle.makeChoices();
		const blissey = battle.p1.active[0];
		let damage = blissey.maxhp - blissey.hp;
		assert.bounded(damage, [70, 84]); // boosted by Adaptability and Choice Specs

		battle.makeChoices();
		battle.makeChoices();
		battle.makeChoices('auto', 'switch 2');
		damage = blissey.maxhp - blissey.hp;
		assert.bounded(damage, [46, 55]); // only boosted by Power Spot
	});

	it(`should not ignore the target's Unaware`, () => {
		battle = common.createBattle([[
			{ species: 'Manaphy', ability: 'simple', moves: ['tailglow', 'futuresight'] },
		], [
			{ species: 'Ho-Oh', ability: 'unaware', moves: ['luckychant'] },
		]]);

		battle.makeChoices();
		battle.makeChoices('move futuresight', 'auto');
		battle.makeChoices();
		battle.makeChoices();
		const hooh = battle.p2.active[0];
		const damage = hooh.maxhp - hooh.hp;
		assert.bounded(damage, [60, 71]); // Damage would be 236-278 if Unaware was being ignored
	});

	it(`should use the user's most recent Special Attack stat if the user is on the field`, () => {
		battle = common.createBattle([[
			{ species: 'Aegislash', ability: 'stancechange', moves: ['futuresight', 'kingsshield'] },
		], [
			{ species: 'Ho-Oh', ability: 'shellarmor', moves: ['recover'] },
		]]);

		for (let i = 0; i < 3; i++) battle.makeChoices();
		const hooh = battle.p2.active[0];
		let damage = hooh.maxhp - hooh.hp;
		assert.bounded(damage, [79, 94]); // Blade Forme damage

		battle.makeChoices();
		battle.makeChoices('move kingsshield', 'auto');
		battle.makeChoices('move kingsshield', 'auto');
		damage = hooh.maxhp - hooh.hp;
		assert.bounded(damage, [34, 41]); // Shield Forme damage
	});

	it.skip(`should use the user's most recent Special Attack stat, even if the user is not on the field`, () => {
		battle = common.createBattle([[
			{ species: 'Aegislash', ability: 'stancechange', moves: ['futuresight', 'kingsshield'] },
			{ species: 'Wynaut', moves: ['sleeptalk'] },
		], [
			{ species: 'Ho-Oh', ability: 'shellarmor', moves: ['recover', 'flareblitz'] },
		]]);

		battle.makeChoices();
		battle.makeChoices('switch wynaut', 'auto');
		battle.makeChoices();
		const hooh = battle.p2.active[0];
		let damage = hooh.maxhp - hooh.hp;
		assert.bounded(damage, [79, 94], `Future Sight should deal Blade Forme damage, even though Aegislash switched out in Blade Forme`);

		battle.makeChoices('switch aegislash', 'auto');
		battle.makeChoices();
		battle.makeChoices('auto', 'move flareblitz');
		battle.makeChoices(); // switch in Wynaut
		battle.makeChoices();
		damage = hooh.maxhp - hooh.hp;
		assert.bounded(damage, [79, 94], `Future Sight should deal Blade Forme damage, even though Aegislash was KOed in Blade Forme.`);
	});

	it(`should only use Sp. Atk stat boosts/drops if the user is on the field`, () => {
		battle = common.createBattle([[
			{ species: 'Flapple', moves: ['futuresight', 'nastyplot', 'sleeptalk'] },
			{ species: 'Wynaut', moves: ['sleeptalk'] },
		], [
			{ species: 'Ho-Oh', ability: 'shellarmor', moves: ['recover'] },
		]]);

		battle.makeChoices();
		battle.makeChoices('move nastyplot', 'auto');
		battle.makeChoices();
		const hooh = battle.p2.active[0];
		let damage = hooh.maxhp - hooh.hp;
		assert.bounded(damage, [113, 134], `Future Sight should deal damage with +2 Sp. Atk`);

		battle.makeChoices();
		battle.makeChoices('switch wynaut', 'auto');
		battle.makeChoices();
		damage = hooh.maxhp - hooh.hp;
		assert.bounded(damage, [57, 68], `Future Sight should deal damage with +0 Sp. Atk`);
	});

	it(`should never resolve when used on turn 254 or later`, () => {
		battle = common.createBattle([[
			{ species: 'Wynaut', moves: ['sleeptalk', 'futuresight'] },
		], [
			{ species: 'Stakataka', moves: ['sleeptalk'] },
		]]);

		battle.turn = 255; // Showdown turn is +1 from what the games are; this would ordinarily be 254
		battle.makeChoices('move futuresight', 'auto');
		for (let i = 0; i < 5; i++) battle.makeChoices();
		battle.makeChoices('move futuresight', 'auto');
		for (let i = 0; i < 5; i++) battle.makeChoices();

		const stak = battle.p2.active[0];
		assert.fullHP(stak, `Future Sight should have never resolved.`);
	});

	it(`should target particular slots in Doubles`, () => {
		battle = common.createBattle({ gameType: 'doubles' }, [[
			{ species: 'Wynaut', moves: ['sleeptalk', 'futuresight'] },
			{ species: 'Steelix', moves: ['sleeptalk'] },
		], [
			{ species: 'Girafarig', moves: ['sleeptalk', 'recover'] },
			{ species: 'Farigiraf', moves: ['sleeptalk', 'recover'] },
		]]);

		battle.makeChoices('move futuresight 2, auto', 'auto');
		battle.makeChoices();
		battle.makeChoices();
		const giraf = battle.p2.active[0];
		const farig = battle.p2.active[1];
		assert.false.fullHP(farig, `Farigiraf should have been damaged by the 1st Future Sight.`);

		battle.makeChoices('move futuresight 1, auto', 'move recover, move recover');
		battle.makeChoices();
		battle.makeChoices();
		assert.false.fullHP(giraf, `Girafarig should have been damaged by the 2nd Future Sight.`);

		battle.makeChoices('move futuresight -2, auto', 'auto');
		battle.makeChoices();
		battle.makeChoices();

		const steelix = battle.p1.active[1];
		assert.false.fullHP(steelix, `Steelix should have been damaged by the 3rd Future Sight`);
	});

	it(`should do nothing if no Pokemon is present to take damage from the Future attack`, () => {
		battle = common.createBattle([[
			{ species: 'Wynaut', ability: 'magicguard', moves: ['sleeptalk'] },
			{ species: 'Shedinja', moves: ['sleeptalk'] },
		], [
			{ species: 'Happiny', moves: ['stealthrock', 'futuresight'] },
		]]);

		battle.makeChoices('auto', 'move futuresight');
		battle.makeChoices('auto', 'move stealthrock');
		battle.makeChoices('switch 2', 'auto');
		battle.makeChoices('switch 2');
		battle.makeChoices();
		const wynaut = battle.p1.active[0];
		assert.fullHP(wynaut);
	});
});