Add various mechanics tests (#7857)

* Improve Volcalith tests readability

* Add G-Max Volcalith recoil damage order test

* Add 1 HP priority tests

* Add charge move targeting test

* Correct assertions of Ripen / Sturdy

* Skip failing tests

* Add Volcalith Black Sludge test

* Add Pressure Max / Z-move tests

* Add Pressure submove test

* Add NGas speed test

* Skip NGas speed test

* Add White Herb double Intimidate test

* Remove debug log

* Remove duplicate Pressure test

* Improve White Herb Intimidate test title

* Add Rollout Storage tests

* Add spread move Rollout storage test

* Add Magician Weakness Policy test

* Add Sleep tests

* Add Shell Bell spread move test

* Add Synchronize Lum Berry test

* oh yeah it doesn't work

* Remove duplicate test

* Add Sunsteel Strike tests

* Add Leech Seed ally switch test

* Add Primal weather Natural Gift test

* Add Emergency Exit hazards test

* Add generic hazards tests

* Add and standardize Arceus tests

* Add Transform ability test

* Add and standardize Parting Shot tests

* Add Memento tests

* Add Me First test

* Add Cursed Body Z-move test

* Add Assurance targeting test

* Clarify Assurance test description

* Add double faint switch test

* Add Receiver KO boost ability

* Add double Unnerve test

* Add Dynamax Eject Pack test

* Improve Dynamax forced switchout test

* Add Protective Pads Perish Body test

* Add Sticky Web Pressure test

* Add Speed modifier lower bound test

* Add Cloud Nine Hydration test

* Correct Cursed Body test

* Add Grassy Terrain Leftovers test

* Remove leftover debug

* Add additional Receiver and Soul-Heart tests

* Add Spite tests

* mish

* Add Shell Bell multihit test

* Add WP Dragon Tail test

Co-authored-by: The Immortal <the_immortal123@live.com>
This commit is contained in:
Leonard Craft III 2021-01-05 01:47:10 -06:00 committed by GitHub
parent 00d2711af5
commit bed1f4ac99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1013 additions and 65 deletions

View File

@ -95,4 +95,21 @@ describe('Cloud Nine', function () {
}
assert.equal(battle.log[battle.lastMoveLine + 3], '|-weather|none');
});
it(`should allow Hydration to trigger if the user fainted before Hydration could trigger`, function () {
battle = common.createBattle([[
{species: 'Toxapex', ability: 'cloudnine', moves: ['toxic', 'raindance', 'finalgambit']},
{species: 'Wynaut', moves: ['sleeptalk']},
], [
{species: 'Manaphy', ability: 'hydration', moves: ['sleeptalk']},
]]);
const manaphy = battle.p2.active[0];
battle.makeChoices();
battle.makeChoices('move raindance', 'auto');
assert.equal(manaphy.status, 'tox');
battle.makeChoices('move finalgambit', 'auto');
assert.equal(manaphy.status, '');
});
});

View File

@ -0,0 +1,24 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe(`Cursed Body`, function () {
afterEach(function () {
battle.destroy();
});
it.skip(`should be able to disable Z-moves (not the base of Z-moves)`, function () {
battle = common.createBattle({seed: [1, 2, 3, 98]}, [[ // hardcoded seed to force Cursed Body
{species: 'gengar', ability: 'cursedbody', item: 'focussash', moves: ['sleeptalk']},
], [
{species: 'kommoo', item: 'kommoniumz', moves: ['clangingscales', 'sleeptalk']},
]]);
battle.makeChoices('move sleeptalk', 'move clangingscales zmove');
const log = battle.getDebugLog();
const cursedBodyIndex = log.indexOf('|Clangorous Soulblaze|[from] ability: Cursed Body|[of] p1a: Gengar');
assert.false.equal(cursedBodyIndex, -1, 'Cursed Body should be able to disable Z-moves.');
});
});

View File

@ -144,4 +144,14 @@ describe('Desolate Land', function () {
battle.makeChoices();
assert.false(battle.field.isWeather('desolateland'));
});
it(`should cause Water-type Natural Gift to fail`, function () {
battle = common.createBattle([[
{species: 'Groudon', item: 'Red Orb', moves: ['sleeptalk']},
], [
{species: 'Wynaut', moves: ['naturalgift']},
]]);
battle.makeChoices();
assert.fullHP(battle.p1.active[0]);
});
});

View File

@ -306,4 +306,19 @@ describe(`Emergency Exit`, function () {
assert.atMost(eePokemon.hp, eePokemon.maxhp / 2);
assert.equal(battle.requestState, 'move');
});
it.skip(`should request switchout between hazards`, function () {
battle = common.createBattle([[
{species: 'wynaut', moves: ['sleeptalk', 'uturn']},
{species: 'volcarona', ability: 'emergencyexit', evs: {hp: 4}, moves: ['sleeptalk']},
], [
{species: 'landorus', moves: ['stealthrock', 'spikes']},
]]);
battle.makeChoices();
battle.makeChoices('move uturn', 'move spikes');
battle.makeChoices('switch 2');
const volcarona = battle.p1.active[0];
assert.equal(volcarona.hp, Math.floor(volcarona.maxhp / 2), 'Emergency Exit should trigger before Spikes damage.');
assert.equal(battle.requestState, 'switch');
});
});

View File

@ -0,0 +1,22 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe('Magician', function () {
afterEach(function () {
battle.destroy();
});
it.skip(`should not steal Weakness Policy on super-effective hits`, function () {
battle = common.createBattle([[
{species: 'klefki', ability: 'magician', moves: ['flashcannon']},
], [
{species: 'hatterene', item: 'weaknesspolicy', moves: ['sleeptalk']},
]]);
battle.makeChoices();
assert.false.holdsItem(battle.p1.active[0], 'Klefki should not have stolen Weakness Policy.');
});
});

View File

@ -85,6 +85,50 @@ describe('Pressure', function () {
assert.equal(battle.p2.active[0].getMoveData(Dex.getMove('snatch')).pp, 12);
assert.equal(battle.p2.active[1].getMoveData(Dex.getMove('imprison')).pp, 12);
});
it.skip(`should deduct additional PP from Max Moves`, function () {
battle = common.createBattle([[
{species: 'wynaut', moves: ['darkpulse']},
], [
{species: 'absol', ability: 'pressure', moves: ['sleeptalk']},
]]);
battle.makeChoices('move darkpulse dynamax', 'auto');
assert.equal(battle.p1.active[0].getMoveData(Dex.getMove('darkpulse')).pp, 22);
});
it.skip(`should deduct additional PP from Z-Moves`, function () {
battle = common.gen(7).createBattle([[
{species: 'wynaut', item: 'darkiniumz', moves: ['darkpulse']},
], [
{species: 'absol', ability: 'pressure', moves: ['sleeptalk']},
]]);
battle.makeChoices('move darkpulse zmove', 'auto');
assert.equal(battle.p1.active[0].getMoveData(Dex.getMove('darkpulse')).pp, 22);
});
it.skip(`should deduct additional PP from submoves that target Pressure`, function () {
battle = common.createBattle([[
{species: 'wynaut', moves: ['assist']},
{species: 'yveltal', moves: ['darkpulse']},
], [
{species: 'absol', ability: 'pressure', moves: ['sleeptalk']},
]]);
battle.makeChoices('move assist', 'auto');
assert.equal(battle.p1.active[0].getMoveData(Dex.getMove('assist')).pp, 30);
});
it.skip(`Sticky Web should not deduct PP from Pressure (only entry hazard to do so)`, function () {
battle = common.createBattle([[
{species: 'wynaut', moves: ['stickyweb', 'stealthrock']},
], [
{species: 'absol', ability: 'pressure', moves: ['sleeptalk']},
]]);
battle.makeChoices('move stickyweb', 'auto');
battle.makeChoices('move stealthrock', 'auto');
const wynaut = battle.p1.active[0];
assert.equal(wynaut.getMoveData(Dex.getMove('stickyweb')).pp, 31);
assert.equal(wynaut.getMoveData(Dex.getMove('stealthrock')).pp, 30);
});
});
describe('Pressure [Gen 4]', function () {

View File

@ -0,0 +1,41 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe(`Receiver`, function () {
afterEach(function () {
battle.destroy();
});
it.skip(`should gain a boost immediately if taking over a KO boost Ability`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'whimsicott', ability: 'soulheart', moves: ['memento']},
{species: 'passimian', ability: 'receiver', moves: ['sleeptalk']},
], [
{species: 'wynaut', moves: ['sleeptalk']},
{species: 'wynaut', moves: ['sleeptalk']},
]]);
battle.makeChoices();
const passimian = battle.p1.active[1];
assert.statStage(passimian, 'spa', 1);
});
it.skip(`should do weird stuff with multiple Soul-Heart and multiple Receiver`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Passimian', ability: 'receiver', moves: ['earthquake']},
{species: 'Magearna', ability: 'soulheart', level: 1, moves: ['sleeptalk']},
], [
{species: 'Lugia', ability: 'receiver', moves: ['sleeptalk']},
{species: 'Wynaut', ability: 'soulheart', level: 1, moves: ['sleeptalk']},
]]);
battle.makeChoices();
const passimian = battle.p1.active[0];
const lugia = battle.p2.active[0];
assert.statStage(passimian, 'spa', 2);
assert.statStage(lugia, 'spa', 1);
});
});

View File

@ -18,7 +18,7 @@ describe("Ripen", function () {
]]);
battle.makeChoices();
const ripenWynaut = battle.p1.active[0];
assert(ripenWynaut.hp, Math.floor(ripenWynaut.maxhp / 2) + (Math.floor(ripenWynaut.maxhp / 4) * 2));
assert.equal(ripenWynaut.hp, Math.floor(ripenWynaut.maxhp / 2) + (Math.floor(ripenWynaut.maxhp / 4) * 2));
});
it('should double stat boosts from Berries', function () {
@ -33,16 +33,17 @@ describe("Ripen", function () {
assert.statStage(ripenWynaut, 'atk', 2);
});
it('should double damage done from Jaboca / Rowap Berries', function () {
it.skip('should double damage done from Jaboca / Rowap Berries', function () {
battle = common.createBattle([[
{species: 'wynaut', ability: 'ripen', item: 'jabocaberry', moves: ['sleeptalk']},
], [
{species: 'wynaut', moves: ['tackle']},
{species: 'falinks', moves: ['tackle']},
]]);
battle.makeChoices();
const nonRipenWynaut = battle.p2.active[0];
// Should be 249; if it was just 1/8, would be 290
assert(nonRipenWynaut.hp, nonRipenWynaut.maxhp - (Math.floor(nonRipenWynaut.maxhp / 8) * 2));
const falinks = battle.p2.active[0];
// Should be 204; if it was just 1/8, would be 238
assert.equal(falinks.hp, falinks.maxhp - (Math.floor(falinks.maxhp / 4)));
});
it('should allow resist Berries to quarter the damage done', function () {

View File

@ -0,0 +1,60 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe('Soul-Heart', function () {
afterEach(function () {
battle.destroy();
});
it(`should activate on each individual KO`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Toxapex', moves: ['sleeptalk']},
{species: 'Victini', moves: ['finalgambit']},
], [
{species: 'Magearna', ability: 'soulheart', moves: ['sleeptalk']},
{species: 'Wynaut', moves: ['sleeptalk']},
]]);
const magearna = battle.p2.active[0];
battle.makeChoices('move sleeptalk, move finalgambit 2', 'auto');
assert.statStage(magearna, 'spa', 2);
const log = battle.getDebugLog();
const soulHeartFirstIndex = log.indexOf('|Soul-Heart');
const soulHeartSecondIndex = log.lastIndexOf('|Soul-Heart');
assert.notEqual(soulHeartFirstIndex, soulHeartSecondIndex, 'Soul-Heart should have activated twice.');
});
it(`should not activate if two Soul-Hearts are KOed on the same side`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Gengar', moves: ['astralbarrage']},
{species: 'Aron', moves: ['sleeptalk']},
], [
{species: 'Magearna', ability: 'soulheart', level: 1, moves: ['sleeptalk']},
{species: 'Wynaut', ability: 'soulheart', level: 1, moves: ['sleeptalk']},
{species: 'Roggenrola', moves: ['sleeptalk']},
]]);
const log = battle.getDebugLog();
const soulHeartIndex = log.indexOf('|Soul-Heart');
assert.equal(soulHeartIndex, -1, 'Soul-Heart should not have activated.');
});
it.skip(`should activate an opposing Soul-Heart if the attacker's ally was first KOed in a spread move`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Landorus', moves: ['earthquake']},
{species: 'Aron', moves: ['sleeptalk']},
], [
{species: 'Magearna', ability: 'soulheart', level: 1, moves: ['sleeptalk']},
{species: 'Lugia', moves: ['sleeptalk']},
]]);
const log = battle.getDebugLog();
const soulHeartIndex = log.indexOf('|Soul-Heart');
assert.notEqual(soulHeartIndex, -1, 'Soul-Heart should have activated, despite being KOed right after.');
});
});

View File

@ -56,4 +56,39 @@ describe('Sturdy', function () {
battle.makeChoices('move sleeptalk', 'move fusionflare');
assert.fainted(battle.p1.active[0]);
});
it.skip(`should trigger before Focus Sash`, function () {
battle = common.createBattle([[
{species: "Wynaut", moves: ['tackle']},
], [
{species: "Stufful", level: 1, ability: 'sturdy', item: 'focussash', moves: ['sleeptalk']},
]]);
battle.makeChoices();
assert.holdsItem(battle.p2.active[0]);
});
it(`should not trigger when the user also uses Endure`, function () {
battle = common.createBattle([[
{species: "Wynaut", moves: ['tackle']},
], [
{species: "Stufful", level: 1, ability: 'sturdy', moves: ['endure']},
]]);
battle.makeChoices();
const sturdyIndex = battle.getDebugLog().indexOf('|-ability|p2a: Stufful|Sturdy');
assert.equal(sturdyIndex, -1, 'Sturdy should not activate.');
});
it(`should not trigger when the user is damaged to 1 HP from False Swipe`, function () {
battle = common.createBattle([[
{species: "Wynaut", moves: ['falseswipe']},
], [
{species: "Stufful", level: 1, ability: 'sturdy', moves: ['sleeptalk']},
]]);
battle.makeChoices();
const sturdyIndex = battle.getDebugLog().indexOf('|-ability|p2a: Stufful|Sturdy');
assert.equal(sturdyIndex, -1, 'Sturdy should not activate.');
});
});

View File

@ -0,0 +1,24 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe(`Unnerve`, function () {
afterEach(function () {
battle.destroy();
});
it.skip(`should allow Berry activation between switches of Unnerve`, function () {
battle = common.createBattle([[
{species: 'toxapex', ability: 'unnerve', moves: ['toxic']},
{species: 'corviknight', ability: 'unnerve', moves: ['sleeptalk']},
], [
{species: 'wynaut', item: 'lumberry', moves: ['sleeptalk']},
]]);
battle.makeChoices();
battle.makeChoices('switch 2', 'auto');
assert.equal(battle.p2.active[0].status, '');
});
});

View File

@ -139,6 +139,19 @@ describe('Choice parser', function () {
assert.throws(() => battle.choose('p1', `${switchChoice}, ${passChoice} a`));
assert.throws(() => battle.choose('p1', `${passChoice} a, ${switchChoice}`));
});
it.skip(`should only allow switching to left slots on double KOs with only one Pokemon remaining`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'tornadus', moves: ['sleeptalk']},
{species: 'landorus', moves: ['earthquake']},
], [
{species: 'roggenrola', level: 1, moves: ['sleeptalk']},
{species: 'aron', level: 1, moves: ['sleeptalk']},
{species: 'wynaut', moves: ['sleeptalk']},
]]);
battle.makeChoices();
assert.throws(() => battle.choose('p2', 'pass, switch 3'), 'Wynaut should only be able to switch on the left.');
});
});
});

View File

@ -0,0 +1,32 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe('Safety Goggles', function () {
afterEach(function () {
battle.destroy();
});
it(`should be revealed if Terrain is also active`, function () {
battle = common.createBattle([[
{species: 'tapukoko', ability: 'electricsurge', item: 'safetygoggles', moves: ['sleeptalk']},
], [
{species: 'amoonguss', moves: ['spore']},
]]);
battle.makeChoices();
assert(battle.log.some(line => line.includes('|item: Safety Goggles|')));
});
it(`should be revealed if the move would have missed`, function () {
battle = common.createBattle({seed: [1, 2, 3, 4]}, [[ // Seed ensures Sleep Powder would miss normally
{species: 'yveltal', ability: 'wonderskin', item: 'safetygoggles', moves: ['sleeptalk']},
], [
{species: 'venusaur', moves: ['sleeppowder']},
]]);
battle.makeChoices();
assert(battle.log.some(line => line.includes('|item: Safety Goggles|')));
});
});

View File

@ -0,0 +1,42 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe('Shell Bell', function () {
afterEach(function () {
battle.destroy();
});
it.skip(`should heal from the damage against all targets of the move`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'tornadus', ability: 'compoundeyes', moves: ['superfang']},
{species: 'landorus', item: 'shellbell', moves: ['earthquake']},
], [
{species: 'roggenrola', ability: 'sturdy', level: 1, moves: ['sleeptalk']},
{species: 'aron', ability: 'sturdy', level: 1, moves: ['sleeptalk']},
]]);
battle.makeChoices('move superfang -2, move earthquake', 'auto');
const landorus = battle.p1.active[1];
assert.equal(landorus.hp, landorus.maxhp - Math.floor(landorus.maxhp / 2) + (Math.floor(11 * 2 / 8)));
});
// Also applies to Parental Bond
it.skip(`should heal from the damage from all hits of multi-hit moves`, function () {
battle = common.createBattle([[
{species: 'shelmet', moves: ['finalgambit']},
{species: 'landorus', moves: ['sleeptalk']},
{species: 'wynaut', moves: ['sleeptalk']},
], [
{species: 'cloyster', ability: 'skilllink', item: 'shellbell', evs: {hp: 4}, moves: ['sleeptalk', 'iciclespear']},
]]);
battle.makeChoices();
battle.makeChoices('switch 2');
battle.makeChoices('auto', 'move iciclespear');
const landorus = battle.p1.active[0];
const cloyster = battle.p2.active[0];
assert.equal(cloyster.hp, 1 + Math.floor(landorus.maxhp / 8));
});
});

View File

@ -93,4 +93,16 @@ describe('Weakness Policy', function () {
assert.statStage(holder, 'atk', 0);
assert.statStage(holder, 'spa', 0);
});
it(`should trigger before forced switching moves`, function () {
battle = common.createBattle([[
{species: 'wynaut', ability: 'compoundeyes', moves: ['dragontail']},
], [
{species: 'zygarde', item: 'weaknesspolicy', moves: ['sleeptalk']},
{species: 'aron', moves: ['sleeptalk']},
]]);
const zygarde = battle.p2.active[0];
battle.makeChoices();
assert.false.holdsItem(zygarde);
});
});

View File

@ -0,0 +1,63 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe("White Herb", function () {
afterEach(function () {
battle.destroy();
});
it('should activate after Parting Shot drops both stats, but before the switch is resolved', function () {
battle = common.createBattle([[
{species: 'torracat', moves: ['partingshot']},
{species: 'litten', moves: ['sleeptalk']},
], [
{species: 'wynaut', item: 'whiteherb', moves: ['sleeptalk']},
]]);
battle.makeChoices();
const wynaut = battle.p2.active[0];
assert.false.holdsItem(wynaut);
assert.statStage(wynaut, 'atk', 0);
assert.statStage(wynaut, 'spa', 0);
});
it.skip('should activate after Abilities that boost stats on KOs', function () {
battle = common.createBattle([[
{species: 'litten', level: 1, ability: 'noguard', moves: ['sleeptalk']},
{species: 'torracat', moves: ['partingshot']},
], [
{species: 'wynaut', item: 'whiteherb', ability: 'grimneigh', moves: ['dracometeor']},
]]);
battle.makeChoices();
const wynaut = battle.p2.active[0];
assert.false.holdsItem(wynaut);
assert.statStage(wynaut, 'spa', 0);
});
it.skip('should activate after two Intimidate switch in at the same time', function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'litten', ability: 'intimidate', moves: ['sleeptalk']},
{species: 'torracat', ability: 'intimidate', moves: ['sleeptalk', 'finalgambit']},
{species: 'litten', ability: 'intimidate', moves: ['sleeptalk']},
{species: 'landorustherian', ability: 'intimidate', moves: ['sleeptalk']},
], [
{species: 'wynaut', item: 'whiteherb', moves: ['sleeptalk', 'recycle']},
{species: 'fraxure', moves: ['sleeptalk']},
]]);
// Leads
battle.makeChoices();
const wynaut = battle.p2.active[0];
assert.false.holdsItem(wynaut);
assert.statStage(wynaut, 'atk', 0);
// After a double KO
battle.makeChoices('move sleeptalk, move finalgambit -1', 'move recycle, move sleeptalk');
battle.makeChoices('switch 3, switch 4');
assert.false.holdsItem(wynaut);
assert.statStage(wynaut, 'atk', 0);
});
});

View File

@ -3,38 +3,69 @@
const assert = require('assert').strict;
const common = require('./../../common');
let battle;
const unimportantPokemon = {species: 'magikarp', moves: ['splash']};
describe(`[Hackmons] Arceus`, function () {
it(`in untyped forme should change its type to match the plate held`, function () {
const battle = common.gen(4).createBattle([
[{species: 'arceus', ability: 'multitype', item: 'flameplate', moves: ['rest']}],
[unimportantPokemon],
]);
assert.deepEqual(battle.p1.active[0].getTypes(), ["Fire"]);
battle = common.gen(4).createBattle([[
{species: 'arceus', ability: 'multitype', item: 'flameplate', moves: ['rest']},
], [
unimportantPokemon,
]]);
const arceus = battle.p1.active[0];
assert(arceus.hasType('Fire'));
});
it(`in Steel forme should should be Water-typed to match the held Splash Plate`, function () {
const battle = common.gen(4).createBattle([
[{species: 'arceussteel', ability: 'multitype', item: 'splashplate', moves: ['rest']}],
[unimportantPokemon],
]);
assert.deepEqual(battle.p1.active[0].getTypes(), ["Water"]);
battle = common.gen(4).createBattle([[
{species: 'arceussteel', ability: 'multitype', item: 'splashplate', moves: ['rest']},
], [
unimportantPokemon,
]]);
const arceus = battle.p1.active[0];
assert(arceus.hasType('Water'));
});
it(`in a typed forme should be Normal-typed if no plate is held`, function () {
const battle = common.gen(4).createBattle([
[{species: 'Arceusfire', ability: 'multitype', item: 'leftovers', moves: ['rest']}],
[unimportantPokemon],
]);
assert.deepEqual(battle.p1.active[0].getTypes(), ["Normal"]);
battle = common.gen(4).createBattle([[
{species: 'arceusfire', ability: 'multitype', item: 'leftovers', moves: ['rest']},
], [
unimportantPokemon,
]]);
const arceus = battle.p1.active[0];
assert(arceus.hasType('Normal'));
});
it(`in a typed forme should be Normal-typed despite holding a plate if Arceus does not have the Multitype ability`, function () {
const battle = common.gen(4).createBattle([
[{species: 'arceusfire', ability: 'truant', item: 'flameplate', moves: ['rest']}],
[unimportantPokemon],
]);
assert.deepEqual(battle.p1.active[0].getTypes(), ["Normal"]);
battle = common.gen(4).createBattle([[
{species: 'arceusfire', ability: 'truant', item: 'flameplate', moves: ['rest']},
], [
unimportantPokemon,
]]);
const arceus = battle.p1.active[0];
assert(arceus.hasType('Normal'));
});
it(`should not be able to lose its typing`, function () {
battle = common.createBattle([[
{species: 'arceus', ability: 'multitype', item: 'flameplate', moves: ['burnup']},
], [
{species: 'reuniclus', moves: ['soak']},
]]);
battle.makeChoices();
const arceus = battle.p1.active[0];
assert(arceus.hasType('Fire'), 'Arceus should not change type.');
});
it.skip(`should use Arceus's real type for Revelation Dance`, function () {
battle = common.createBattle([[
{species: 'arceusfire', ability: 'sandrush', moves: ['revelationdance']},
], [
{species: 'aggron', ability: 'colorchange', moves: ['sleeptalk']},
]]);
battle.makeChoices();
const aggron = battle.p2.active[0];
assert(aggron.hasType('Normal'), 'Aggron should become Normal-type.');
});
});

View File

@ -162,4 +162,21 @@ describe("Dynamax", function () {
battle.makeChoices('move splash', 'move gravity'); // will throw an error if Feebas is forced to use Struggle by Imprison
battle.makeChoices('move splash', 'auto'); // will throw an error if Feebas is forced to use Struggle by Gravity
});
it.skip(`should not remove the variable to Dynamax on forced switches`, function () {
battle = common.createBattle([[
{species: 'wynaut', item: 'ejectpack', moves: ['ironhead']},
{species: 'audino', item: 'ejectpack', moves: ['sleeptalk']},
], [
{species: 'vikavolt', moves: ['stickyweb']},
{species: 'incineroar', ability: 'intimidate', moves: ['sleeptalk']},
]]);
battle.makeChoices();
battle.makeChoices('move ironhead dynamax', 'switch 2');
battle.makeChoices('switch 2'); // Eject Pack to Audino
battle.makeChoices('switch 2'); // Eject Pack back to Wynaut, to Dynamax
const wynaut = battle.p1.active[0];
assert.statStage(wynaut, 'def', 0, 'Wynaut should not have used Max Steelspike this turn.');
assert(wynaut.volatiles['dynamax'], 'Wynaut should be currently Dynamaxed.');
});
});

85
test/sim/misc/hazards.js Normal file
View File

@ -0,0 +1,85 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe('Hazards', function () {
afterEach(function () {
battle.destroy();
});
it(`should damage Pokemon before regular entrance Abilities`, function () {
battle = common.createBattle([[
{species: 'wynaut', moves: ['uturn']},
{species: 'shedinja', ability: 'electricsurge', moves: ['sleeptalk']},
], [
{species: 'landorus', moves: ['stealthrock']},
]]);
battle.makeChoices();
battle.makeChoices('switch 2');
assert.false(battle.field.isTerrain('electricterrain'));
});
it(`should damage multiple Pokemon switching in simulatenously by Speed order`, function () {
battle = common.createBattle([[
{species: 'wynaut', moves: ['stealthrock', 'sleeptalk']},
{species: 'kyogre', ability: 'drizzle', item: 'choicescarf', moves: ['sleeptalk']},
], [
{species: 'miltank', moves: ['stealthrock', 'finalgambit']},
{species: 'landorus-therian', ability: 'intimidate', moves: ['sleeptalk']},
]]);
battle.makeChoices();
battle.makeChoices('move sleeptalk', 'move finalgambit');
battle.makeChoices('switch 2', 'switch 2');
const log = battle.getDebugLog();
const rocksKyogreIndex = log.indexOf('|-damage|p1a: Kyogre|299/341|[from] Stealth Rock');
const abilityKyogreIndex = log.indexOf('ability: Drizzle|[of] p1a: Kyogre');
const rocksLandorusIndex = log.indexOf('|-damage|p2a: Landorus|280/319|[from] Stealth Rock');
const abilityLandorusIndex = log.indexOf('|-ability|p2a: Landorus|Intimidate');
assert(rocksKyogreIndex < abilityKyogreIndex, 'Stealth Rock should damage Kyogre before Drizzle activates.');
assert(abilityKyogreIndex < rocksLandorusIndex, 'Kyogre should activate Drizzle before Landorus takes rocks damage.');
assert(rocksLandorusIndex < abilityLandorusIndex, 'Stealth Rock should damage Landorus before Intimidate activates.');
});
it.skip(`should apply hazards in the order they were set up`, function () {
battle = common.createBattle([[
{species: 'wynaut', moves: ['sleeptalk', 'uturn']},
{species: 'whismur', moves: ['sleeptalk']},
], [
{species: 'landorus', moves: ['stealthrock', 'spikes', 'stickyweb', 'toxicspikes']},
]]);
battle.makeChoices('move sleeptalk', 'move toxicspikes');
battle.makeChoices('move sleeptalk', 'move stickyweb');
battle.makeChoices('move sleeptalk', 'move spikes');
battle.makeChoices('move sleeptalk', 'move toxicspikes');
battle.makeChoices('move uturn', 'move stealthrock');
battle.makeChoices('switch 2');
const log = battle.getDebugLog();
const tSpikeIndex = log.indexOf('|-status|p1a: Whismur|tox');
const websIndex = log.indexOf('|-activate|p1a: Whismur|move: Sticky Web');
const spikesIndex = log.indexOf('|[from] Spikes');
const rocksIndex = log.indexOf('[from] Stealth Rock');
assert(tSpikeIndex < websIndex, 'Toxic Spikes should have poisoned before Sticky Web lowered speed.');
assert(websIndex < spikesIndex, 'Sticky Web should have lowered speed before Spikes damage.');
assert(spikesIndex < rocksIndex, 'Spikes should have damaged before Stealth Rock.');
});
it(`should allow Berries to trigger between hazards`, function () {
battle = common.createBattle([[
{species: 'wynaut', moves: ['sleeptalk', 'uturn']},
{species: 'shedinja', item: 'lumberry', moves: ['sleeptalk']},
], [
{species: 'landorus', moves: ['toxicspikes', 'stealthrock']},
]]);
battle.makeChoices();
battle.makeChoices('move uturn', 'move stealthrock');
battle.makeChoices('switch 2');
const shedinja = battle.p1.active[0];
assert.false.holdsItem(shedinja, 'Shedinja should have lost Lum Berry before fainting to rocks.');
});
});

26
test/sim/misc/speed.js Normal file
View File

@ -0,0 +1,26 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe(`Speed`, function () {
afterEach(function () {
battle.destroy();
});
it.skip(`should cap chained Speed modifiers at 410 as a lower bound`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'regigigas', ability: 'slowstart', item: 'ironball', moves: ['waterpledge']},
{species: 'ivysaur', moves: ['grasspledge']},
], [
{species: 'wynaut', moves: ['sleeptalk']},
{species: 'wynaut', moves: ['sleeptalk']},
]]);
battle.makeChoices('move waterpledge -2, move grasspledge -1', 'auto');
const regigigas = battle.p1.active[0];
// Regigigas has 236 starting Speed; the end result should be pokeRound(236 * 410 / 4096), not pokeRound(236 * 256 / 4096)
assert.equal(regigigas.getStat('spe'), 24);
});
});

View File

@ -227,4 +227,34 @@ describe('Target Resolution', function () {
battle.makeChoices('move allyswitch, move thunder -1', 'auto');
assert.fullHP(battle.p1.active[0]);
});
it.skip(`charge moves like Phantom Force should target slots turn 1 and Pokemon turn 2`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'houndour', level: 1, moves: ['sleeptalk']},
{species: 'altaria', moves: ['sleeptalk']},
{species: 'aggron', moves: ['sleeptalk']},
], [
{species: 'dragapult', moves: ['phantomforce']},
{species: 'regieleki', moves: ['sleeptalk', 'sheercold']},
]]);
// Phantom Force should still target slot 1, despite Houndour fainting
battle.makeChoices('auto', 'move phantomforce 1, move sheercold 1');
battle.makeChoices('switch 3');
battle.makeChoices();
assert.fullHP(battle.p1.active[1], 'Altaria should be at full HP, because it was not targeted.');
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'houndour', level: 1, moves: ['sleeptalk']},
{species: 'altaria', moves: ['sleeptalk']},
{species: 'aggron', moves: ['sleeptalk']},
], [
{species: 'dragapult', moves: ['phantomforce']},
{species: 'regieleki', moves: ['sleeptalk', 'sheercold']},
]]);
battle.makeChoices('auto', 'move phantomforce 1, move sleeptalk');
battle.makeChoices('auto', 'move phantomforce 1, move sheercold 1');
assert.false.fullHP(battle.p1.active[1], 'Altaria should not be at full HP, because Phantom Force was redirected and targeted it.');
});
});

View File

@ -21,4 +21,18 @@ describe('Assurance', function () {
const assuRange = [214, 253];
assert.bounded(regi.hp, [regi.maxhp - recoilRange[1] - assuRange[1], regi.maxhp - recoilRange[0] - assuRange[0]]);
});
it(`should double the power against damaged Pokemon, not damaged slots`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'bulbasaur', level: 1, moves: ['sleeptalk']},
{species: 'landorus', moves: ['sleeptalk']},
], [
{species: 'alakazam', moves: ['psychic']},
{species: 'pawniard', moves: ['assurance']},
]]);
battle.makeChoices('auto', 'move psychic 1, move assurance 1');
const landorus = battle.p1.active[1];
const damage = landorus.maxhp - landorus.hp;
assert.bounded(damage, [63, 75]); // 60 BP; if it was 120 BP, it would be 124-147 damage
});
});

View File

@ -95,4 +95,14 @@ describe('Electric Terrain', function () {
const resultMove = toID(battle.log[battle.lastMoveLine].split('|')[3]);
assert.equal(resultMove, 'thunderbolt');
});
it.skip(`should block Sleep before the move would have missed`, function () {
battle = common.createBattle({seed: [1, 2, 3, 4]}, [[ // Seed ensures Sleep Powder would miss normally
{species: 'tapukoko', ability: 'wonderskin', moves: ['electricterrain']},
], [
{species: 'venusaur', moves: ['sleeppowder']},
]]);
battle.makeChoices();
assert(battle.log.some(line => line.includes('|-activate|p1a: Tapu Koko|move: Electric Terrain')));
});
});

View File

@ -10,38 +10,36 @@ describe('G-Max Volcalith', function () {
battle.destroy();
});
it('should not damage Rock-types', function () {
battle = common.createBattle({gameType: 'doubles'});
battle.setPlayer('p1', {team: [
{species: 'Coalossal-Gmax', moves: ['rockthrow']},
{species: 'Wynaut', moves: ['sleeptalk']},
]});
battle.setPlayer('p2', {team: [
it(`should not damage Rock-types`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Coalossal', moves: ['rockthrow'], gigantamax: true},
{species: 'Wynaut', moves: ['sleeptalk']},
], [
{species: 'Blastoise', moves: ['sleeptalk']},
{species: 'Boldore', moves: ['sleeptalk']},
]});
]]);
battle.makeChoices('move rockthrow 1 dynamax, move sleeptalk', 'move sleeptalk, move sleeptalk');
assert.fullHP(battle.p2.active[1]);
});
it('should deal damage for four turns, including the fourth turn', function () {
battle = common.createBattle({gameType: 'doubles'});
battle.setPlayer('p1', {team: [
{species: 'Coalossal', moves: ['rockthrow', 'sleeptalk'], gigantamax: true},
{species: 'Wynaut', moves: ['sleeptalk']},
]});
battle.setPlayer('p2', {team: [
it(`should deal damage for four turns, including the fourth turn`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Coalossal', moves: ['sleeptalk', 'rockthrow'], gigantamax: true},
{species: 'Wynaut', moves: ['sleeptalk']},
], [
{species: 'Blastoise', moves: ['sleeptalk']},
{species: 'Boldore', moves: ['sleeptalk']},
]});
]]);
battle.makeChoices('move rockthrow 2 dynamax, move sleeptalk', 'move sleeptalk, move sleeptalk');
battle.makeChoices('move sleeptalk, move sleeptalk', 'move sleeptalk, move sleeptalk');
battle.makeChoices('move sleeptalk, move sleeptalk', 'move sleeptalk, move sleeptalk');
battle.makeChoices('move sleeptalk, move sleeptalk', 'move sleeptalk, move sleeptalk');
assert.equal(battle.p2.active[0].hp, battle.p2.active[0].maxhp - (Math.floor(battle.p2.active[0].maxhp / 6) * 4));
for (let i = 0; i < 3; i++) { battle.makeChoices(); }
const blastoise = battle.p2.active[0];
assert.equal(blastoise.hp, blastoise.maxhp - (Math.floor(blastoise.maxhp / 6) * 4));
});
it.skip('should deal damage alongside Sea of Fire or G-Max Wildfire in the order those field effects were set', function () {
it.skip(`should deal damage alongside Sea of Fire or G-Max Wildfire in the order those field effects were set`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Coalossal', item: 'Eject Button', moves: ['rockthrow', 'sleeptalk'], gigantamax: true},
{species: 'Wynaut', moves: ['sleeptalk', 'grasspledge']},
@ -49,7 +47,7 @@ describe('G-Max Volcalith', function () {
], [
{species: 'Blissey', ability: "noguard", moves: ['superfang', 'softboiled']},
{species: 'Blissey', ability: "noguard", moves: ['superfang', 'softboiled']},
{species: 'Golisopod', moves: ['sleeptalk']},
{species: 'Golisopod', ability: "emergencyexit", moves: ['sleeptalk']},
]]);
// Set up Volcalith first, then Sea of Fire
@ -64,4 +62,40 @@ describe('G-Max Volcalith', function () {
const expectedHP = maxHP - Math.floor(maxHP / 2) - Math.floor(maxHP / 6);
assert.equal(battle.p2.active[0].hp, expectedHP);
});
it.skip(`should damage Pokemon in order of Speed`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Coalossal', moves: ['sleeptalk', 'rockthrow'], gigantamax: true},
{species: 'Wynaut', moves: ['sleeptalk']},
], [
{species: 'Coalossal', moves: ['sleeptalk', 'rockthrow'], gigantamax: true},
{species: 'Mewtwo', moves: ['sleeptalk', 'trickroom']},
]]);
battle.makeChoices('move rockthrow 1 dynamax, move sleeptalk', 'move rockthrow 1 dynamax, move sleeptalk');
battle.makeChoices('auto', 'move sleeptalk, move trickroom');
const log = battle.getDebugLog();
const mewtwoDamagedIndex = log.indexOf('|-damage|p1b: Wynaut');
const wynautDamagedIndex = log.indexOf('|-damage|p2b: Mewtwo');
assert(wynautDamagedIndex < mewtwoDamagedIndex, 'Mewtwo should be damaged before Wynaut in normal circumstances.');
const mewtwoDamagedTRIndex = log.lastIndexOf('|-damage|p1b: Wynaut');
const wynautDamagedTRIndex = log.lastIndexOf('|-damage|p2b: Mewtwo');
assert(mewtwoDamagedTRIndex < wynautDamagedTRIndex, 'Wynaut should be damaged before Mewtwo in Trick Room.');
});
it.skip(`should deal damage before Black Sludge recovery/damage`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'Coalossal', moves: ['sleeptalk', 'rockthrow'], gigantamax: true},
{species: 'Wynaut', moves: ['sleeptalk']},
], [
{species: 'Toxicroak', item: 'blacksludge', moves: ['sleeptalk']},
{species: 'Boldore', moves: ['sleeptalk']},
]]);
battle.makeChoices('move rockthrow 2 dynamax, move sleeptalk', 'move sleeptalk, move sleeptalk');
const toxicroak = battle.p2.active[0];
assert.equal(toxicroak.hp, toxicroak.maxhp - Math.floor(toxicroak.maxhp / 6) + Math.floor(toxicroak.maxhp / 16));
});
});

View File

@ -78,4 +78,20 @@ describe('Grassy Terrain', function () {
const resultMove = toID(battle.log[battle.lastMoveLine].split('|')[3]);
assert.equal(resultMove, 'energyball');
});
it.skip(`should heal by Speed order in the same block as Leftovers`, function () {
battle = common.createBattle([[
{species: 'rillaboom', ability: 'grassysurge', item: 'leftovers', moves: ['seismictoss']},
], [
{species: 'alakazam', item: 'focussash', moves: ['seismictoss']},
]]);
battle.makeChoices();
const log = battle.getDebugLog();
const zamGrassyIndex = log.indexOf('|-heal|p2a: Alakazam|166/251|[from] Grassy Terrain');
const rillaGrassyIndex = log.indexOf('|-heal|p1a: Rillaboom|283/341|[from] Grassy Terrain');
const rillaLeftoversIndex = log.indexOf('|-heal|p1a: Rillaboom|262/341|[from] item: Leftovers');
assert(zamGrassyIndex < rillaGrassyIndex, 'Alakazam should heal from Grassy Terrain before Rillaboom');
assert(rillaGrassyIndex < rillaLeftoversIndex, 'Rillaboom should heal from Grassy Terrain before Leftovers');
});
});

View File

@ -0,0 +1,26 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe('Leech Seed', function () {
afterEach(function () {
battle.destroy();
});
it(`should heal and damage itself if it ends up in the same slot via Ally Switch`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'celesteela', ability: 'noguard', moves: ['sleeptalk', 'leechseed']},
{species: 'comfey', moves: ['sleeptalk', 'allyswitch']},
], [
{species: 'wynaut', moves: ['sleeptalk']},
{species: 'wynaut', moves: ['sleeptalk']},
]]);
battle.makeChoices('move leech seed -2, move sleeptalk', 'auto');
const comfey = battle.p1.active[1];
battle.makeChoices('move sleeptalk, move allyswitch', 'auto');
assert.equal(comfey.hp, comfey.maxhp - Math.floor(comfey.maxhp / 8), 'Comfey should damage and heal itself from Leech Seed');
});
});

25
test/sim/moves/mefirst.js Normal file
View File

@ -0,0 +1,25 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe(`Me First`, function () {
afterEach(function () {
battle.destroy();
});
it.skip(`Me First should fail to copy recharge turns from moves like Hyper Beam`, function () {
battle = common.gen(7).createBattle([[
{species: 'aerodactyl', moves: ['sleeptalk', 'mefirst']},
], [
{species: 'wynaut', ability: 'noguard', moves: ['hyperbeam']},
]]);
battle.makeChoices();
battle.makeChoices('move mefirst', 'auto');
const log = battle.getDebugLog();
const rechargeIndex = log.indexOf('|move|p1a: Aerodactyl|recharge|');
assert.equal(rechargeIndex, -1, 'Aerodactyl should fail to copy a recharge turn, not recharge itself.');
});
});

48
test/sim/moves/memento.js Normal file
View File

@ -0,0 +1,48 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe(`Memento`, function () {
afterEach(function () {
battle.destroy();
});
it(`should cause the user to faint even if the target has Clear Body`, function () {
battle = common.createBattle([[
{species: 'whimsicott', moves: ['memento']},
{species: 'landorus', moves: ['sleeptalk']},
], [
{species: 'wynaut', ability: 'clearbody', moves: ['sleeptalk']},
]]);
battle.makeChoices();
assert.equal(battle.requestState, 'switch');
});
it(`should not cause the user to faint if used into Substitute`, function () {
battle = common.createBattle([[
{species: 'whimsicott', moves: ['memento']},
{species: 'landorus', moves: ['sleeptalk']},
], [
{species: 'wynaut', ability: 'prankster', moves: ['substitute']},
]]);
battle.makeChoices();
assert.equal(battle.requestState, 'move');
});
it.skip(`should set the Z-Memento healing flag even if the Memento itself was not successful`, function () {
battle = common.createBattle([[
{species: 'landorus', ability: 'noguard', moves: ['sleeptalk']},
{species: 'whimsicott', ability: 'noguard', item: 'darkiniumz', moves: ['memento']},
], [
{species: 'wynaut', ability: 'prankster', moves: ['circlethrow', 'substitute']},
]]);
battle.makeChoices('auto', 'move substitute');
battle.makeChoices();
battle.makeChoices('move memento zmove', 'auto');
const landorus = battle.p1.active[0];
assert.fullHP(landorus);
});
});

View File

@ -6,21 +6,22 @@ const common = require('./../../common');
let battle;
describe(`Parting Shot`, function () {
afterEach(() => battle.destroy());
afterEach(function () {
battle.destroy();
});
it(`should not switch the user out if the target's stats are not changed`, function () {
battle = common.createBattle([
[{species: "Silvally", ability: 'prankster', moves: ['partingshot', 'splash']},
{species: "Type: Null", ability: 'battlearmor', moves: ['return']}],
[{species: "Registeel", ability: 'clearbody', moves: ['splash']},
{species: "Solgaleo", ability: 'fullmetalbody', moves: ['splash']},
{species: "Torkoal", ability: 'whitesmoke', moves: ['splash']},
{species: "Shaymin", ability: 'flowerveil', moves: ['splash']},
{species: "Kingler", ability: 'hypercutter', moves: ['splash']},
{species: "Spinda", ability: 'contrary', moves: ['splash', 'partingshot']}],
]);
const p1 = battle.p1;
const p2 = battle.p2;
battle = common.createBattle([[
{species: 'Silvally', ability: 'prankster', moves: ['partingshot', 'splash']},
{species: 'Type: Null', ability: 'battlearmor', moves: ['return']},
], [
{species: 'Registeel', ability: 'clearbody', moves: ['splash']},
{species: 'Solgaleo', ability: 'fullmetalbody', moves: ['splash']},
{species: 'Torkoal', ability: 'whitesmoke', moves: ['splash']},
{species: 'Shaymin', ability: 'flowerveil', moves: ['splash']},
{species: 'Kingler', ability: 'hypercutter', moves: ['splash']},
{species: 'Spinda', ability: 'contrary', moves: ['splash', 'partingshot']},
]]);
battle.makeChoices('move partingshot', 'move splash');
assert.equal(battle.requestState, 'move');
battle.makeChoices('move partingshot', 'switch 2'); // Solgaleo
@ -30,15 +31,28 @@ describe(`Parting Shot`, function () {
battle.makeChoices('move partingshot', 'switch 4'); // Shaymin
assert.equal(battle.requestState, 'move');
battle.makeChoices('move splash', 'switch 5'); // Kingler
p2.active[0].boostBy({spa: -6});
battle.p2.active[0].boostBy({spa: -6}); // hack Kingler's Sp. Atk to -6; Hyper Cutter & -6 Sp. Atk
battle.makeChoices('move partingshot', 'move splash');
assert.equal(battle.requestState, 'move');
battle.makeChoices('move splash', 'switch 6'); // Spinda
p2.active[0].boostBy({atk: 6, spa: 6});
battle.p2.active[0].boostBy({atk: 6, spa: 6}); // hack Contrary Spinda to +6 Atk / +6 Sp. Atk
battle.makeChoices('move partingshot', 'move splash');
assert.equal(battle.requestState, 'move');
p1.active[0].boostBy({atk: -6, spa: -6});
battle.makeChoices('move splash', 'move partingshot'); // Parting Shot against Silvally this time
battle.p1.active[0].boostBy({atk: -6, spa: -6});
battle.makeChoices('move splash', 'move partingshot'); // Spinda's Parting Shot against Silvally this time
assert.equal(battle.requestState, 'move');
});
it(`should set the Z-Parting Shot healing flag even if the Parting Shot itself was not successful`, function () {
battle = common.createBattle([[
{species: 'landorus', ability: 'noguard', moves: ['sleeptalk']},
{species: 'persian-alola', ability: 'noguard', item: 'darkiniumz', moves: ['partingshot']},
], [
{species: 'wynaut', ability: 'clearbody', moves: ['circlethrow']},
]]);
battle.makeChoices();
battle.makeChoices('move partingshot zmove', 'auto');
const landorus = battle.p1.active[0];
assert.fullHP(landorus);
});
});

View File

@ -129,5 +129,76 @@ for (const move of moves) {
battle.makeChoices('move ' + id, 'move recover');
assert.equal(hitCount, 1);
});
describe.skip(`Rollout Storage glitch (Gen 7 / Gen 8DLC1)`, function () {
it(`should delay the Rollout multiplier when hitting Disguise or Ice Face`, function () {
battle = common.gen(7).createBattle([[
{species: 'wynaut', ability: 'compoundeyes', ivs: {atk: '0'}, nature: 'bold', moves: [id, 'watergun']},
], [
{species: 'mimikyu', ability: 'disguise', evs: {hp: '252', def: '252'}, nature: 'bold', moves: ['gravity']},
{species: 'snorlax', ability: 'battlearmor', moves: ['sleeptalk']},
]]);
for (let i = 0; i < 5; i++) { battle.makeChoices(); }
battle.makeChoices('move watergun', 'switch 2');
const snorlax = battle.p2.active[0];
const damage = snorlax.maxhp - snorlax.hp;
assert.bounded(damage, [147, 174]); // 40 * 2^4 BP; would be 40 BP otherwise, range 10-12
});
it(`should delay the Rollout multiplier when hitting multiple Disguise or Ice Face`, function () {
battle = common.gen(7).createBattle([[
{species: 'wynaut', ability: 'compoundeyes', ivs: {atk: '0'}, nature: 'bold', moves: [id, 'watergun']},
], [
{species: 'mimikyu', ability: 'disguise', evs: {hp: '252', def: '252'}, nature: 'bold', moves: ['gravity']},
{species: 'mimikyu', ability: 'disguise', evs: {hp: '252', def: '252'}, nature: 'bold', moves: ['gravity']},
{species: 'snorlax', ability: 'battlearmor', moves: ['sleeptalk']},
]]);
battle.makeChoices();
battle.makeChoices('auto', 'switch 2');
for (let i = 0; i < 3; i++) { battle.makeChoices(); }
battle.makeChoices('move watergun', 'switch 3');
const snorlax = battle.p2.active[0];
const damage = snorlax.maxhp - snorlax.hp;
assert.bounded(damage, [74, 88]); // 40 * 2^3 BP; would be 40 BP otherwise, range 10-12
});
it(`should use the move's default BP when applying the modifier`, function () {
battle = common.gen(7).createBattle([[
{species: 'wynaut', ability: 'compoundeyes', ivs: {atk: '0'}, nature: 'bold', moves: [id, 'grassknot']},
], [
{species: 'mimikyu', ability: 'disguise', evs: {hp: '252', def: '252'}, nature: 'bold', moves: ['gravity']},
{species: 'snorlax', ability: 'battlearmor', moves: ['sleeptalk']},
]]);
for (let i = 0; i < 5; i++) { battle.makeChoices(); }
battle.makeChoices('move grassknot', 'switch 2');
const snorlax = battle.p2.active[0];
const damage = snorlax.maxhp - snorlax.hp;
assert.bounded(damage, [5, 6]); // 1 * 2^4 BP; would be 120 BP otherwise, range 28-34
});
it(`should only apply the Rollout Storage boost to the first target of a spread move`, function () {
battle = common.gen(7).createBattle({gameType: 'doubles'}, [[
{species: 'mimikyu', ability: 'disguise', evs: {hp: '252', def: '252'}, nature: 'bold', moves: ['gravity']},
{species: 'wynaut', ability: 'compoundeyes', ivs: {atk: '0'}, nature: 'bold', moves: [id, 'snarl']},
], [
{species: 'snorlax', ability: 'battlearmor', moves: ['sleeptalk']},
{species: 'hydreigon', ability: 'battlearmor', moves: ['sleeptalk']},
]]);
battle.makeChoices('move gravity, move ' + id + ' -1', 'auto');
for (let i = 0; i < 4; i++) { battle.makeChoices(); }
battle.makeChoices('move gravity, move snarl', 'auto');
const snorlax = battle.p2.active[0];
const snorlaxDamage = snorlax.maxhp - snorlax.hp;
assert.bounded(snorlaxDamage, [151, 178]); // 55 * 2^4 BP; would be 55 BP otherwise, range 10-12
const hydreigon = battle.p2.active[1];
const hydreigonDamage = hydreigon.maxhp - hydreigon.hp;
assert.bounded(hydreigonDamage, [5, 7]); // regular Snarl damage
});
});
});
}

View File

@ -0,0 +1,34 @@
'use strict';
const assert = require('./../../assert');
const common = require('./../../common');
let battle;
describe('Sunsteel Strike', function () {
afterEach(function () {
battle.destroy();
});
it(`should not ignore the user's own Ability`, function () {
battle = common.createBattle([[
{species: 'metagross', ability: 'clearbody', moves: ['sunsteelstrike']},
], [
{species: 'goodra', ability: 'gooey', moves: ['sleeptalk']},
]]);
battle.makeChoices();
const metagross = battle.p1.active[0];
assert.statStage(metagross, 'spe', 0);
});
it.skip(`should ignore the user's own Ability (Gen 7)`, function () {
battle = common.gen(7).createBattle([[
{species: 'metagross', ability: 'clearbody', moves: ['sunsteelstrike']},
], [
{species: 'goodra', ability: 'gooey', moves: ['sleeptalk']},
]]);
battle.makeChoices();
const metagross = battle.p1.active[0];
assert.statStage(metagross, 'spe', -1);
});
});

View File

@ -138,6 +138,18 @@ describe('Transform', function () {
battle.makeChoices('move transform', 'move roost');
assert.deepEqual(battle.p1.active[0].getTypes(), ["Fire", "Flying"]);
});
it.skip(`should not announce that its ability was suppressed after Transforming`, function () {
battle = common.createBattle([[
{species: "Mew", ability: 'synchronize', moves: ['transform']},
], [
{species: 'roggenrola', ability: 'sturdy', moves: ['sleeptalk']},
]]);
battle.makeChoices();
const log = battle.getDebugLog();
const abilityAnnounceIndex = log.indexOf('|-endability|');
assert.equal(abilityAnnounceIndex, -1, `It should not announce the user's ability was suppressed.`);
});
});
describe('Transform [Gen 5]', function () {