diff --git a/data/abilities.ts b/data/abilities.ts index 21a8a105d916..29e427c1ee8a 100644 --- a/data/abilities.ts +++ b/data/abilities.ts @@ -2421,16 +2421,21 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { }, magician: { onAfterMoveSecondarySelf(source, target, move) { - if (!move || !target || source.switchFlag === true) return; - if (target !== source && move.category !== 'Status') { - if (source.item || source.volatiles['gem'] || move.id === 'fling') return; - const yourItem = target.takeItem(source); - if (!yourItem) return; - if (!source.setItem(yourItem)) { - target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything + if (!move || source.switchFlag === true || !move.hitTargets || source.item || source.volatiles['gem'] || + move.id === 'fling') return; + const hitTargets = move.hitTargets; + this.speedSort(hitTargets); + for (const pokemon of hitTargets) { + if (pokemon !== source && move.category !== 'Status') { + const yourItem = pokemon.takeItem(source); + if (!yourItem) continue; + if (!source.setItem(yourItem)) { + pokemon.item = yourItem.id; // bypass setItem so we don't break choicelock or anything + continue; + } + this.add('-item', source, yourItem, '[from] ability: Magician', `[of] ${pokemon}`); return; } - this.add('-item', source, yourItem, '[from] ability: Magician', `[of] ${target}`); } }, flags: {}, @@ -4143,7 +4148,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { shielddust: { onModifySecondaries(secondaries) { this.debug('Shield Dust prevent secondary'); - return secondaries.filter(effect => !!(effect.self || effect.dustproof)); + return secondaries.filter(effect => !!effect.self); }, flags: { breakable: 1 }, name: "Shield Dust", diff --git a/data/items.ts b/data/items.ts index dc5b9cc1293e..5c4d92bc1ef2 100644 --- a/data/items.ts +++ b/data/items.ts @@ -1152,7 +1152,7 @@ export const Items: import('../sim/dex-items').ItemDataTable = { }, onModifySecondaries(secondaries) { this.debug('Covert Cloak prevent secondary'); - return secondaries.filter(effect => !!(effect.self || effect.dustproof)); + return secondaries.filter(effect => !!effect.self); }, num: 1885, gen: 9, diff --git a/data/mods/gen9ssb/abilities.ts b/data/mods/gen9ssb/abilities.ts index d4cc2cc38fae..4b2ee39ff8d8 100644 --- a/data/mods/gen9ssb/abilities.ts +++ b/data/mods/gen9ssb/abilities.ts @@ -1867,7 +1867,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa }, onModifySecondaries(secondaries) { this.debug('Fancy Scarf prevent secondary'); - return secondaries.filter(effect => !!(effect.self || effect.dustproof)); + return secondaries.filter(effect => !!effect.self); }, flags: {}, }, diff --git a/data/moves.ts b/data/moves.ts index f14618a5bbd2..7bca9fcad64c 100644 --- a/data/moves.ts +++ b/data/moves.ts @@ -18049,13 +18049,19 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { priority: 0, flags: { protect: 1, mirror: 1, sound: 1, bypasssub: 1, metronome: 1 }, secondary: { - dustproof: true, chance: 100, volatileStatus: 'sparklingaria', }, onAfterMove(source, target, move) { - for (const pokemon of this.getAllActive()) { - if (pokemon !== source && pokemon.removeVolatile('sparklingaria') && pokemon.status === 'brn' && !source.fainted) { + if (source.fainted || !move.hitTargets || move.hasSheerForce) { + // make sure the volatiles are cleared + for (const pokemon of this.getAllActive()) delete pokemon.volatiles['sparklingaria']; + return; + } + const numberTargets = move.hitTargets.length; + for (const pokemon of move.hitTargets) { + if (pokemon !== source && pokemon.isActive && (pokemon.removeVolatile('sparklingaria') || numberTargets > 1) && + pokemon.status === 'brn') { pokemon.cureStatus(); } } diff --git a/sim/battle-actions.ts b/sim/battle-actions.ts index 3385af9b8a82..3dc304ca9dda 100644 --- a/sim/battle-actions.ts +++ b/sim/battle-actions.ts @@ -606,6 +606,7 @@ export class BattleActions { } } + move.hitTargets = targets; const moveResult = !!targets.length; if (!moveResult && !atLeastOneFailure) pokemon.moveThisTurnResult = null; const hitSlot = targets.map(p => p.getSlot()); diff --git a/sim/dex-moves.ts b/sim/dex-moves.ts index 6895740e96f9..e40437ea8e37 100644 --- a/sim/dex-moves.ts +++ b/sim/dex-moves.ts @@ -87,11 +87,6 @@ export interface SecondaryEffect extends HitEffect { chance?: number; /** Used to flag a secondary effect as added by Poison Touch */ ability?: Ability; - /** - * Applies to Sparkling Aria's secondary effect: Affected by - * Sheer Force but not Shield Dust. - */ - dustproof?: boolean; /** * Gen 2 specific mechanics: Bypasses Substitute only on Twineedle, * and allows it to flinch sleeping/frozen targets @@ -317,6 +312,7 @@ export interface ActiveMove extends MutableMove { status?: ID; hit: number; moveHitData?: MoveHitData; + hitTargets?: Pokemon[]; ability?: Ability; allies?: Pokemon[]; auraBooster?: Pokemon; diff --git a/test/sim/abilities/magician.js b/test/sim/abilities/magician.js index b0742c148891..189a42c0d4d8 100644 --- a/test/sim/abilities/magician.js +++ b/test/sim/abilities/magician.js @@ -74,4 +74,18 @@ describe('Magician', () => { battle.makeChoices(); assert.false.holdsItem(battle.p1.active[0], 'Klefki should not have stolen Weakness Policy.'); }); + + it(`should steal the item from the faster opponent hit`, () => { + battle = common.createBattle({ gameType: 'doubles' }, [[ + { species: "Hoopa", ability: 'magician', moves: ['expandingforce'] }, + { species: "Tapu Lele", ability: 'psychicsurge', moves: ['sleeptalk'] }, + ], [ + { species: "Shuckle", item: 'tr68', moves: ['sleeptalk'] }, + { species: "Zapdos", item: 'tr69', moves: ['sleeptalk'] }], + ]); + battle.makeChoices(); + assert.equal(battle.p1.active[0].item, 'tr69'); + assert.equal(battle.p2.active[0].item, 'tr68'); + assert.equal(battle.p2.active[1].item, ''); + }); }); diff --git a/test/sim/abilities/shielddust.js b/test/sim/abilities/shielddust.js index 8e4d6dfdff25..61c27bf0c7db 100644 --- a/test/sim/abilities/shielddust.js +++ b/test/sim/abilities/shielddust.js @@ -72,27 +72,19 @@ describe('Shield Dust', () => { assert.statStage(battle.p2.active[0], 'spa', -1); }); - it.skip(`should only prevent Sparkling Aria from curing burn if there is only one target`, () => { - battle = common.createBattle([[ - { species: 'wynaut', ability: 'noguard', moves: ['willowisp', 'sparklingaria'] }, - ], [ - { species: 'dustox', ability: 'shielddust', moves: ['sleeptalk'] }, - ]]); - battle.makeChoices('move willowisp', 'auto'); - battle.makeChoices('move sparklingaria', 'auto'); - - assert.equal(battle.p2.active[0].status, 'brn', `Shield Dust should prevent cured burn if it's the only target`); - + it(`should only prevent Sparkling Aria from curing burn if there is only one target`, () => { battle = common.createBattle({ gameType: 'doubles' }, [[ { species: 'wynaut', ability: 'noguard', moves: ['willowisp', 'sparklingaria'] }, - { species: 'diglett', moves: ['sleeptalk'] }, + { species: 'diglett', moves: ['sleeptalk', 'protect'] }, ], [ { species: 'dustox', ability: 'shielddust', moves: ['sleeptalk'] }, - { species: 'magikarp', moves: ['sleeptalk'] }, + { species: 'magikarp', moves: ['sleeptalk', 'protect'] }, ]]); battle.makeChoices('move willowisp 1, move sleeptalk', 'auto'); - battle.makeChoices('move sparklingaria, move sleeptalk', 'auto'); + battle.makeChoices('move sparklingaria, move protect', 'move sleeptalk, move protect'); + assert.equal(battle.p2.active[0].status, 'brn', `Shield Dust should prevent cured burn if it's the only target`); + battle.makeChoices('move sparklingaria, move sleeptalk', 'auto'); assert.equal(battle.p2.active[0].status, '', `Shield Dust should not prevent cured burn if it's one of many targets`); }); }); diff --git a/test/sim/moves/roost.js b/test/sim/moves/roost.js index 19341b7fd2bb..9bf665e6d9fd 100644 --- a/test/sim/moves/roost.js +++ b/test/sim/moves/roost.js @@ -28,7 +28,7 @@ describe('Roost', () => { assert.equal(battle.p2.active[0].hp, battle.p2.active[0].maxhp); }); - it('should suppress user\'s current Flying type if succesful', () => { + it('should suppress user\'s current Flying type if successful', () => { battle = common.createBattle(); battle.setPlayer('p1', { team: [{ species: "Aggron", item: 'leftovers', ability: 'sturdy', moves: ['mudslap', 'hiddenpowergrass'] }] }); battle.setPlayer('p2', { team: [{ species: "Aerodactyl", item: 'focussash', ability: 'wonderguard', moves: ['roost', 'doubleedge'] }] });