pokemon-showdown/test/sim/abilities/dancer.js
Guangcong Luo 78439b4a02
Update to ESLint 9 (#10926)
ESLint has a whole new config format, so I figure it's a good time to
make the config system saner.

- First, we no longer have separate eslint-no-types configs. Lint
  performance shouldn't be enough of a problem to justify the
  relevant maintenance complexity.

- Second, our base config should work out-of-the-box now. `npx eslint`
  will work as expected, without any CLI flags. You should still use
  `npm run lint` which adds the `--cached` flag for performance.

- Third, whatever updates I did fixed style linting, which apparently
  has been bugged for quite some time, considering all the obvious
  mixed-tabs-and-spaces issues I found in the upgrade.

Also here are some changes to our style rules. In particular:

- Curly brackets (for objects etc) now have spaces inside them. Sorry
  for the huge change. ESLint doesn't support our old style, and most
  projects use Prettier style, so we might as well match them in this way.
  See https://github.com/eslint-stylistic/eslint-stylistic/issues/415

- String + number concatenation is no longer allowed. We now
  consistently use template strings for this.
2025-02-25 20:03:46 -08:00

187 lines
8.0 KiB
JavaScript

'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe('Dancer', () => {
afterEach(() => {
battle.destroy();
});
it('should only copy dance moves used by other Pokemon', () => {
battle = common.createBattle([[
{ species: 'Oricorio', ability: 'dancer', moves: ['swordsdance'] },
], [
{ species: 'Oricorio', ability: 'dancer', moves: ['howl'] },
]]);
battle.makeChoices('move swordsdance', 'move howl');
assert.statStage(battle.p1.active[0], 'atk', 2);
assert.statStage(battle.p2.active[0], 'atk', 3);
});
it('should activate in order of lowest to highest raw speed', () => {
battle = common.createBattle({ gameType: 'doubles' }, [[
{ species: 'Shedinja', level: 98, ability: 'dancer', item: 'focussash', moves: ['sleeptalk'] },
{ species: 'Shedinja', level: 99, ability: 'dancer', moves: ['sleeptalk'] },
], [
{ species: 'Shedinja', ability: 'wonderguard', moves: ['fierydance'] },
{ species: 'Shedinja', ability: 'dancer', moves: ['sleeptalk'] },
]]);
const [, fastDancer] = battle.p1.active;
const [wwDanceSource, foeDancer] = battle.p2.active;
fastDancer.boostBy({ spe: 6 });
battle.makeChoices('move sleeptalk, move sleeptalk', 'move fierydance 1, move sleeptalk');
assert.fainted(wwDanceSource);
assert.fainted(foeDancer);
});
it('should activate in order of lowest to highest raw speed inside Trick Room', () => {
battle = common.createBattle({ gameType: 'doubles' }, [[
{ species: 'Shedinja', level: 98, ability: 'dancer', item: 'focussash', moves: ['sleeptalk'] },
{ species: 'Shedinja', level: 99, ability: 'dancer', moves: ['sleeptalk'] },
], [
{ species: 'Shedinja', ability: 'wonderguard', moves: ['fierydance', 'trickroom'] },
{ species: 'Shedinja', ability: 'dancer', moves: ['sleeptalk'] },
]]);
const [, fastDancer] = battle.p1.active;
const [wwDanceSource, foeDancer] = battle.p2.active;
fastDancer.boostBy({ spe: 6 });
battle.makeChoices('move sleeptalk, move sleeptalk', 'move trickroom, move sleeptalk');
battle.makeChoices('move sleeptalk, move sleeptalk', 'move fierydance 1, move sleeptalk');
assert.fainted(wwDanceSource);
assert.fainted(foeDancer);
});
it(`should not copy a move that was blocked by Protect`, () => {
battle = common.createBattle([[
{ species: 'Oricorio', ability: 'dancer', moves: ['protect'] },
], [
{ species: 'Wynaut', ability: 'dancer', moves: ['fierydance'] },
]]);
battle.makeChoices();
assert.fullHP(battle.p2.active[0]);
});
it(`should not copy Teeter Dance when all targets are confused`, () => {
battle = common.createBattle({ gameType: 'doubles' }, [[
{ species: 'Oricorio', ability: 'dancer', moves: ['sleeptalk', 'protect'] },
{ species: 'Slowbro', ability: 'owntempo', moves: ['sleeptalk'] },
], [
{ species: 'Wynaut', ability: 'dancer', item: 'persimberry', moves: ['sleeptalk', 'teeterdance'] },
{ species: 'Slowking', ability: 'owntempo', moves: ['sleeptalk'] },
]]);
const wynaut = battle.p2.active[0];
battle.makeChoices('move protect, move sleeptalk', 'move teeterdance, move sleeptalk');
assert.holdsItem(wynaut, `Persim Berry should not be consumed, because Dancer did not activate`);
battle.makeChoices('auto', 'move teeterdance, move sleeptalk');
assert(battle.log.some(line => line.includes('Dancer')));
});
it(`should not copy a Dance move that failed for other reasons`, () => {
battle = common.createBattle({ gameType: 'doubles' }, [[
{ species: 'mew', ability: 'dancer', moves: ['dragondance', 'protect'] },
{ species: 'wynaut', ability: 'dancer', moves: ['featherdance'] },
], [
{ species: 'oricoriopau', ability: 'dancer', moves: ['revelationdance', 'protect'] },
{ species: 'shedinja', ability: 'wonderguard', moves: ['finalgambit'] },
]]);
const mew = battle.p1.active[0];
const wynaut = battle.p1.active[1];
const oricorio = battle.p2.active[0];
mew.boostBy({ atk: 6, spe: 6 });
oricorio.boostBy({ atk: -6 });
battle.makeChoices('move dragondance, move featherdance 1', 'move revelationdance -2, move finalgambit 1');
assert.fullHP(oricorio, `Nothing should target Oricorio because Revelation Dance failed from Wonder Guard`);
assert.statStage(wynaut, 'atk', 0, `Wynaut's attack should not have changed from either Feather Dance or Dragon Dance, because both failed`);
});
it(`should not copy a move that missed`, () => {
battle = common.createBattle([[
{ species: 'Oricorio', ability: 'dancer', moves: ['revelationdance'] },
], [
{ species: 'Wynaut', ability: 'dancer', moves: ['dig'] },
]]);
// Modding accuracy so Revelation Dance always misses if Oricorio uses it (Wynaut should in fact never use it though)
battle.onEvent('Accuracy', battle.format, (accuracy, target, pokemon, move) => {
return pokemon.id === 'wynaut';
});
battle.makeChoices(); // miss on initial use
battle.makeChoices(); // miss into semi-invulnerability
assert.false(battle.log.some(line => line.includes('Dancer')));
});
it('should copy a move that hit, but did 0 damage', () => {
battle = common.createBattle([[
{ species: 'Oricorio', ability: 'dancer', moves: ['fierydance'] },
], [
{ species: 'Shedinja', ability: 'dancer', item: 'focussash', moves: ['meanlook'] },
]]);
const dancer = battle.p1.active[0];
assert.hurts(dancer, () => battle.makeChoices('move fierydance', 'move meanlook'));
});
it('should not activate if the holder fainted', () => {
battle = common.createBattle([[
{ species: 'Oricoriopompom', ability: 'dancer', moves: ['revelationdance'] },
], [
{ species: 'oricorio', ability: 'dancer', level: 1, moves: ['sleeptalk'] },
{ species: 'oricorio', ability: 'dancer', level: 1, moves: ['sleeptalk'] },
]]);
battle.makeChoices();
assert(!battle.log.includes('|-activate|p2: Oricorio|ability: Dancer'));
});
it('should target the user of a Dance move unless it was an ally attacking an opponent', () => {
battle = common.createBattle({ gameType: 'doubles' }, [[
{ species: 'Oricorio', level: 98, ability: 'dancer', item: 'laggingtail', moves: ['sleeptalk', 'protect', 'teeterdance'] },
{ species: 'Oricorio', level: 99, ability: 'heatproof', moves: ['fierydance', 'sleeptalk'] },
], [
{ species: 'Oricorio', ability: 'heatproof', moves: ['fierydance', 'sleeptalk'] },
{ species: 'Suicune', ability: 'heatproof', moves: ['sleeptalk'] },
]]);
const opponentTargetingAlly = battle.p2.active[0];
assert.hurts(opponentTargetingAlly, () => battle.makeChoices('move sleeptalk, move sleeptalk', 'move fierydance 2, move sleeptalk'));
const opponentTargetingOpponent = battle.p2.active[0];
assert.hurts(opponentTargetingOpponent, () => battle.makeChoices('move sleeptalk, move sleeptalk', 'move fierydance -2, move sleeptalk'));
const allyTargetingDancer = battle.p1.active[1];
assert.hurts(allyTargetingDancer, () => battle.makeChoices('move sleeptalk, move fierydance -1', 'move sleeptalk, move sleeptalk'));
const allyTargetingOpponent = battle.p1.active[1];
const allyHP = allyTargetingOpponent.hp;
const opponentTargetedByAlly = battle.p2.active[1];
const opponentNotTargetedByAlly = battle.p2.active[0];
const opponentHP = opponentNotTargetedByAlly.hp;
assert.hurts(opponentTargetedByAlly, () => battle.makeChoices('move sleeptalk, move fierydance 2', 'move sleeptalk, move sleeptalk'));
assert.equal(allyTargetingOpponent.hp, allyHP);
assert.equal(opponentNotTargetedByAlly.hp, opponentHP);
});
it('should adopt the target selected by copycat', () => {
battle = common.createBattle({ gameType: 'doubles', seed: [1, 2, 3, 4] }, [[
{ species: 'oricoriopau', ability: 'dancer', moves: ['featherdance'] },
{ species: 'flamigo', moves: ['copycat'] },
], [
{ species: 'fletchinder', level: 1, moves: ['sleeptalk'] },
{ species: 'squawkabilly', level: 1, moves: ['sleeptalk'] },
]]);
battle.makeChoices('move featherdance 1, move copycat', 'auto');
const flamigo = battle.p1.active[1];
const [fletchinder, squawkabilly] = battle.p2.active;
assert.equal(flamigo.boosts.atk, 0);
assert.equal(fletchinder.boosts.atk, -2);
assert.equal(squawkabilly.boosts.atk, -4);
});
});