diff --git a/data/mods/gen4/moves.ts b/data/mods/gen4/moves.ts index e38589fcf941..821b6ea66463 100644 --- a/data/mods/gen4/moves.ts +++ b/data/mods/gen4/moves.ts @@ -47,6 +47,33 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { }, }, }, + assist: { + inherit: true, + onHit(target) { + const moves = []; + for (const pokemon of target.side.pokemon) { + if (pokemon === target) continue; + for (const moveSlot of pokemon.moveSlots) { + const moveid = moveSlot.id; + const move = this.dex.moves.get(moveid); + if ( + move.flags['noassist'] || + (this.field.pseudoWeather['gravity'] && move.flags['gravity']) || + (target.volatiles['healblock'] && move.flags['heal']) + ) { + continue; + } + moves.push(moveid); + } + } + let randomMove = ''; + if (moves.length) randomMove = this.sample(moves); + if (!randomMove) { + return false; + } + this.actions.useMove(randomMove, target); + }, + }, beatup: { inherit: true, basePower: 10, @@ -198,6 +225,22 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { this.add('-start', target, 'typechange', type); }, }, + copycat: { + inherit: true, + onHit(pokemon) { + const move: Move | ActiveMove | null = this.lastMove; + if (!move) return; + + if ( + move.flags['failcopycat'] || + (this.field.pseudoWeather['gravity'] && move.flags['gravity']) || + (pokemon.volatiles['healblock'] && move.flags['heal']) + ) { + return false; + } + this.actions.useMove(move.id, pokemon); + }, + }, cottonspore: { inherit: true, accuracy: 85, @@ -1007,6 +1050,23 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = { metronome: { inherit: true, flags: {noassist: 1, failcopycat: 1, nosleeptalk: 1, failmimic: 1}, + onHit(pokemon) { + const moves = this.dex.moves.all().filter(move => ( + (![2, 4].includes(this.gen) || !pokemon.moves.includes(move.id)) && + (!move.isNonstandard || move.isNonstandard === 'Unobtainable') && + move.flags['metronome'] && + !(this.field.pseudoWeather['gravity'] && move.flags['gravity']) && + !(pokemon.volatiles['healblock'] && move.flags['heal']) + )); + let randomMove = ''; + if (moves.length) { + moves.sort((a, b) => a.num - b.num); + randomMove = this.sample(moves).id; + } + if (!randomMove) return false; + pokemon.side.lastSelectedMove = this.toID(randomMove); + this.actions.useMove(randomMove, pokemon); + }, }, mimic: { inherit: true, diff --git a/data/moves.ts b/data/moves.ts index ea281aa1e6b9..1b399f609aaa 100644 --- a/data/moves.ts +++ b/data/moves.ts @@ -12187,9 +12187,8 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { pp: 10, priority: 0, flags: {failencore: 1, nosleeptalk: 1, noassist: 1, failcopycat: 1, failmimic: 1, failinstruct: 1}, - onHit(target, source, effect) { + onHit(pokemon) { const moves = this.dex.moves.all().filter(move => ( - (![2, 4].includes(this.gen) || !source.moves.includes(move.id)) && (!move.isNonstandard || move.isNonstandard === 'Unobtainable') && move.flags['metronome'] )); @@ -12199,8 +12198,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { randomMove = this.sample(moves).id; } if (!randomMove) return false; - source.side.lastSelectedMove = this.toID(randomMove); - this.actions.useMove(randomMove, target); + this.actions.useMove(randomMove, pokemon); }, callsMove: true, secondary: null, diff --git a/test/TESTS.md b/test/TESTS.md index 6c2f32d6bb29..58a89e48bf92 100644 --- a/test/TESTS.md +++ b/test/TESTS.md @@ -20,7 +20,7 @@ Check the test/ directory to see if a file already exists for the effect that yo it(`test should start here`, function () { }); - } + }); To create the battle, use common.createBattle and pass in two arrays of teams. You can add additional flags as well: - gameType: 'doubles', 'triples', 'multi', 'freeforall', etc (tests default to singles) diff --git a/test/sim/moves/assist.js b/test/sim/moves/assist.js new file mode 100644 index 000000000000..42c63fb5dd8f --- /dev/null +++ b/test/sim/moves/assist.js @@ -0,0 +1,42 @@ +'use strict'; + +const assert = require('./../../assert'); +const common = require('./../../common'); + +let battle; + +describe(`[Gen 4] Assist`, function () { + afterEach(function () { + battle.destroy(); + }); + + it(`should never call moves that would fail under Gravity`, function () { + battle = common.gen(4).createBattle([[ + {species: 'furret', moves: ['assist']}, + {species: 'smeargle', moves: ['bounce', 'fly', 'highjumpkick', 'splash']}, + {species: 'smeargle', moves: ['bounce', 'fly', 'highjumpkick', 'splash']}, + {species: 'smeargle', moves: ['bounce', 'fly', 'highjumpkick', 'splash']}, + {species: 'smeargle', moves: ['doubleteam', 'fly', 'highjumpkick', 'splash']}, + {species: 'smeargle', moves: ['bounce', 'fly', 'highjumpkick', 'splash']}, + ], [ + {species: 'deoxys', moves: ['gravity']}, + ]]); + for (let i = 0; i < 5; i++) battle.makeChoices(); + assert.statStage(battle.p1.active[0], 'evasion', 5); + }); + + it(`should never call moves that would fail under Heal Block`, function () { + battle = common.gen(4).createBattle([[ + {species: 'furret', moves: ['assist']}, + {species: 'smeargle', moves: ['recover', 'rest', 'roost', 'wish']}, + {species: 'smeargle', moves: ['recover', 'rest', 'doubleteam', 'wish']}, + {species: 'smeargle', moves: ['recover', 'rest', 'roost', 'wish']}, + {species: 'smeargle', moves: ['recover', 'rest', 'roost', 'wish']}, + {species: 'smeargle', moves: ['recover', 'rest', 'roost', 'wish']}, + ], [ + {species: 'latios', moves: ['healblock']}, + ]]); + for (let i = 0; i < 5; i++) battle.makeChoices(); + assert.statStage(battle.p1.active[0], 'evasion', 5); + }); +});