From 9052a7acf87b3f6ee85de079975cd3ff14d7df9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= Date: Thu, 13 Feb 2025 04:15:27 +0000 Subject: [PATCH 1/7] Add AfterMoveSecondaryLast event --- data/abilities.ts | 2 +- data/moves.ts | 7 +------ sim/battle-actions.ts | 4 ++++ sim/dex-conditions.ts | 1 + sim/dex-moves.ts | 1 + test/sim/abilities/pickpocket.js | 2 +- test/sim/moves/icespinner.js | 14 +++++++++++++- 7 files changed, 22 insertions(+), 9 deletions(-) diff --git a/data/abilities.ts b/data/abilities.ts index 4ea628ea911ad..74c1dde1996e6 100644 --- a/data/abilities.ts +++ b/data/abilities.ts @@ -3156,7 +3156,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { num: 253, }, pickpocket: { - onAfterMoveSecondary(target, source, move) { + onAfterMoveSecondaryLast(target, source, move) { if (source && source !== target && move?.flags['contact']) { if (target.item || target.switchFlag || target.forceSwitchFlag || source.switchFlag === true) { return; diff --git a/data/moves.ts b/data/moves.ts index 9c55e38bb42de..cbe0d9f2ded4b 100644 --- a/data/moves.ts +++ b/data/moves.ts @@ -9759,12 +9759,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { pp: 15, priority: 0, flags: {contact: 1, protect: 1, mirror: 1, metronome: 1}, - onAfterHit(target, source) { - if (source.hp) { - this.field.clearTerrain(); - } - }, - onAfterSubDamage(damage, target, source) { + onAfterMoveSecondaryLast(target, source) { if (source.hp) { this.field.clearTerrain(); } diff --git a/sim/battle-actions.ts b/sim/battle-actions.ts index 841639b2a7a1a..4e1ea6f476279 100644 --- a/sim/battle-actions.ts +++ b/sim/battle-actions.ts @@ -536,6 +536,10 @@ export class BattleActions { this.battle.runEvent('EmergencyExit', pokemon, pokemon); } } + for (const i of targets.keys()) { + this.battle.singleEvent('AfterMoveSecondaryLast', move, null, targets[i], pokemon, move); + this.battle.runEvent('AfterMoveSecondaryLast', targets[i], pokemon, move); + } } return true; diff --git a/sim/dex-conditions.ts b/sim/dex-conditions.ts index f8c160c98046f..40eeec2a7d37e 100644 --- a/sim/dex-conditions.ts +++ b/sim/dex-conditions.ts @@ -24,6 +24,7 @@ export interface EventMethods { onAfterTakeItem?: (this: Battle, item: Item, pokemon: Pokemon) => void; onAfterBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon, effect: Effect) => void; onAfterFaint?: (this: Battle, length: number, target: Pokemon, source: Pokemon, effect: Effect) => void; + onAfterMoveSecondaryLast?: MoveEventMethods['onAfterMoveSecondaryLast']; onAfterMoveSecondarySelf?: MoveEventMethods['onAfterMoveSecondarySelf']; onAfterMoveSecondary?: MoveEventMethods['onAfterMoveSecondary']; onAfterMove?: MoveEventMethods['onAfterMove']; diff --git a/sim/dex-moves.ts b/sim/dex-moves.ts index 06786d32959fe..075ac7e647a8f 100644 --- a/sim/dex-moves.ts +++ b/sim/dex-moves.ts @@ -112,6 +112,7 @@ export interface MoveEventMethods { onAfterHit?: CommonHandlers['VoidSourceMove']; onAfterSubDamage?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void; + onAfterMoveSecondaryLast?: CommonHandlers['VoidMove']; onAfterMoveSecondarySelf?: CommonHandlers['VoidSourceMove']; onAfterMoveSecondary?: CommonHandlers['VoidMove']; onAfterMove?: CommonHandlers['VoidSourceMove']; diff --git a/test/sim/abilities/pickpocket.js b/test/sim/abilities/pickpocket.js index 188f967deb7ab..4ae7c533208c0 100644 --- a/test/sim/abilities/pickpocket.js +++ b/test/sim/abilities/pickpocket.js @@ -46,7 +46,7 @@ describe('Pickpocket', function () { assert.holdsItem(battle.p2.active[0]); }); - it.skip(`should steal items back and forth when hit by a Magician user`, function () { + it(`should steal items back and forth when hit by a Magician user`, function () { battle = common.createBattle([[ {species: 'Weavile', ability: 'pickpocket', item: 'cheriberry', moves: ['agility']}, ], [ diff --git a/test/sim/moves/icespinner.js b/test/sim/moves/icespinner.js index 2b844b68e1105..ff863115cc703 100644 --- a/test/sim/moves/icespinner.js +++ b/test/sim/moves/icespinner.js @@ -21,7 +21,19 @@ describe(`Ice Spinner`, function () { assert.false(battle.field.isTerrain('psychicterrain')); }); - it.skip(`should not remove Terrains if the user faints from Life Orb`, function () { + it(`should remove Terrains if behind a substitute`, function () { + battle = common.createBattle([[ + {species: 'wynaut', moves: ['substitute', 'icespinner']}, + ], [ + {species: 'registeel', ability: 'psychicsurge', moves: ['sleeptalk']}, + ]]); + + battle.makeChoices(); + battle.makeChoices('move ice spinner', 'auto'); + assert.false(battle.field.isTerrain('psychicterrain')); + }); + + it(`should not remove Terrains if the user faints from Life Orb`, function () { battle = common.createBattle([[ {species: 'shedinja', item: 'lifeorb', moves: ['icespinner']}, {species: 'wynaut', moves: ['sleeptalk']}, From 57ef34d5e5cbc0ccbad0893293914669d2147703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= Date: Thu, 13 Feb 2025 08:41:56 +0000 Subject: [PATCH 2/7] Fix test --- test/sim/moves/icespinner.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/sim/moves/icespinner.js b/test/sim/moves/icespinner.js index ff863115cc703..dcc40c9fcd895 100644 --- a/test/sim/moves/icespinner.js +++ b/test/sim/moves/icespinner.js @@ -21,15 +21,15 @@ describe(`Ice Spinner`, function () { assert.false(battle.field.isTerrain('psychicterrain')); }); - it(`should remove Terrains if behind a substitute`, function () { + it(`should remove Terrains if target has a substitute`, function () { battle = common.createBattle([[ - {species: 'wynaut', moves: ['substitute', 'icespinner']}, + {species: 'wynaut', moves: ['sleeptalk', 'icespinner']}, ], [ - {species: 'registeel', ability: 'psychicsurge', moves: ['sleeptalk']}, + {species: 'registeel', ability: 'psychicsurge', moves: ['substitute', 'sleeptalk']}, ]]); - battle.makeChoices(); - battle.makeChoices('move ice spinner', 'auto'); + battle.makeChoices('move sleeptalk', 'move substitute'); + battle.makeChoices('move ice spinner', 'move sleeptalk'); assert.false(battle.field.isTerrain('psychicterrain')); }); From 9fe6ccc75e8b94cb4a3950cc9a7e9a39f46495ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= Date: Thu, 13 Feb 2025 08:45:17 +0000 Subject: [PATCH 3/7] Fix another test --- data/moves.ts | 2 +- test/sim/moves/icespinner.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/moves.ts b/data/moves.ts index cbe0d9f2ded4b..0a2014ae993b9 100644 --- a/data/moves.ts +++ b/data/moves.ts @@ -9760,7 +9760,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { priority: 0, flags: {contact: 1, protect: 1, mirror: 1, metronome: 1}, onAfterMoveSecondaryLast(target, source) { - if (source.hp) { + if (source.hp && !source.forceSwitchFlag) { this.field.clearTerrain(); } }, diff --git a/test/sim/moves/icespinner.js b/test/sim/moves/icespinner.js index dcc40c9fcd895..4b5c2db8930f0 100644 --- a/test/sim/moves/icespinner.js +++ b/test/sim/moves/icespinner.js @@ -57,7 +57,7 @@ describe(`Ice Spinner`, function () { assert(battle.field.isTerrain('psychicterrain')); }); - it.skip(`should not remove Terrains if the user is forced out via Red Card`, function () { + it(`should not remove Terrains if the user is forced out via Red Card`, function () { battle = common.createBattle([[ {species: 'shedinja', moves: ['icespinner']}, {species: 'wynaut', moves: ['sleeptalk']}, From b3a0c25f9c0d68f56d158f8ad033fbd3e850057e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= Date: Thu, 13 Feb 2025 08:50:04 +0000 Subject: [PATCH 4/7] Add Emergency Exit check --- sim/battle-actions.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sim/battle-actions.ts b/sim/battle-actions.ts index 4e1ea6f476279..e414bbe3b15cf 100644 --- a/sim/battle-actions.ts +++ b/sim/battle-actions.ts @@ -528,7 +528,7 @@ export class BattleActions { !(move.hasSheerForce && pokemon.hasAbility('sheerforce')) && !move.flags['futuremove'] ) { - const originalHp = pokemon.hp; + let originalHp = pokemon.hp; this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move); this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move); if (pokemon && pokemon !== target && move.category !== 'Status') { @@ -536,9 +536,13 @@ export class BattleActions { this.battle.runEvent('EmergencyExit', pokemon, pokemon); } } - for (const i of targets.keys()) { - this.battle.singleEvent('AfterMoveSecondaryLast', move, null, targets[i], pokemon, move); - this.battle.runEvent('AfterMoveSecondaryLast', targets[i], pokemon, move); + for (const target of targets) { + originalHp = target.hp; + this.battle.singleEvent('AfterMoveSecondaryLast', move, null, target, pokemon, move); + this.battle.runEvent('AfterMoveSecondaryLast', target, pokemon, move); + if (target.hp <= target.maxhp / 2 && originalHp > target.maxhp / 2) { + this.battle.runEvent('EmergencyExit', target, target); + } } } From a44bab0c58a0011ccb2814a78a84cc27e486a7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= Date: Thu, 13 Feb 2025 08:56:31 +0000 Subject: [PATCH 5/7] Fix lint --- sim/battle-actions.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sim/battle-actions.ts b/sim/battle-actions.ts index e414bbe3b15cf..f3b39aaddb2ee 100644 --- a/sim/battle-actions.ts +++ b/sim/battle-actions.ts @@ -536,12 +536,12 @@ export class BattleActions { this.battle.runEvent('EmergencyExit', pokemon, pokemon); } } - for (const target of targets) { - originalHp = target.hp; - this.battle.singleEvent('AfterMoveSecondaryLast', move, null, target, pokemon, move); - this.battle.runEvent('AfterMoveSecondaryLast', target, pokemon, move); - if (target.hp <= target.maxhp / 2 && originalHp > target.maxhp / 2) { - this.battle.runEvent('EmergencyExit', target, target); + for (const i of targets.keys()) { + originalHp = targets[i].hp; + this.battle.singleEvent('AfterMoveSecondaryLast', move, null, targets[i], pokemon, move); + this.battle.runEvent('AfterMoveSecondaryLast', targets[i], pokemon, move); + if (targets[i].hp <= targets[i].maxhp / 2 && originalHp > targets[i].maxhp / 2) { + this.battle.runEvent('EmergencyExit', targets[i], targets[i]); } } } From abcaf37156d15a742cc883237386f0d2bac768f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= <80102738+andrebastosdias@users.noreply.github.com> Date: Sat, 15 Feb 2025 04:56:44 +0000 Subject: [PATCH 6/7] Refactor loop Co-authored-by: Kris Johnson <11083252+KrisXV@users.noreply.github.com> --- sim/battle-actions.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sim/battle-actions.ts b/sim/battle-actions.ts index f3b39aaddb2ee..f7d2cc7f09d31 100644 --- a/sim/battle-actions.ts +++ b/sim/battle-actions.ts @@ -536,12 +536,12 @@ export class BattleActions { this.battle.runEvent('EmergencyExit', pokemon, pokemon); } } - for (const i of targets.keys()) { - originalHp = targets[i].hp; - this.battle.singleEvent('AfterMoveSecondaryLast', move, null, targets[i], pokemon, move); - this.battle.runEvent('AfterMoveSecondaryLast', targets[i], pokemon, move); - if (targets[i].hp <= targets[i].maxhp / 2 && originalHp > targets[i].maxhp / 2) { - this.battle.runEvent('EmergencyExit', targets[i], targets[i]); + for (const curTarget of targets) { + originalHp = curTarget.hp; + this.battle.singleEvent('AfterMoveSecondaryLast', move, null, curTarget, pokemon, move); + this.battle.runEvent('AfterMoveSecondaryLast', curTarget, pokemon, move); + if (curTarget.hp <= curTarget.maxhp / 2 && originalHp > curTarget.maxhp / 2) { + this.battle.runEvent('EmergencyExit', curTarget, curTarget); } } } From eba5bb23d0ec059eef17cd60ef8bbb00cf055758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= Date: Wed, 26 Feb 2025 20:56:02 +0000 Subject: [PATCH 7/7] Update to ESLint 9 --- data/moves.ts | 2 +- test/sim/abilities/pickpocket.js | 2 +- test/sim/moves/icespinner.js | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/data/moves.ts b/data/moves.ts index 41d8b5ba2791d..28847f54cce69 100644 --- a/data/moves.ts +++ b/data/moves.ts @@ -9760,7 +9760,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = { name: "Ice Spinner", pp: 15, priority: 0, - flags: {contact: 1, protect: 1, mirror: 1, metronome: 1}, + flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 }, onAfterMoveSecondaryLast(target, source) { if (source.hp && !source.forceSwitchFlag) { this.field.clearTerrain(); diff --git a/test/sim/abilities/pickpocket.js b/test/sim/abilities/pickpocket.js index 4ba69d9dae45f..e89678b19283a 100644 --- a/test/sim/abilities/pickpocket.js +++ b/test/sim/abilities/pickpocket.js @@ -46,7 +46,7 @@ describe('Pickpocket', () => { assert.holdsItem(battle.p2.active[0]); }); - it(`should steal items back and forth when hit by a Magician user`, function () { + it(`should steal items back and forth when hit by a Magician user`, () => { battle = common.createBattle([[ { species: 'Weavile', ability: 'pickpocket', item: 'cheriberry', moves: ['agility'] }, ], [ diff --git a/test/sim/moves/icespinner.js b/test/sim/moves/icespinner.js index e41cffbbeb549..2c44daad8e4f2 100644 --- a/test/sim/moves/icespinner.js +++ b/test/sim/moves/icespinner.js @@ -21,11 +21,11 @@ describe(`Ice Spinner`, () => { assert.false(battle.field.isTerrain('psychicterrain')); }); - it(`should remove Terrains if target has a substitute`, function () { + it(`should remove Terrains if target has a substitute`, () => { battle = common.createBattle([[ - {species: 'wynaut', moves: ['sleeptalk', 'icespinner']}, + { species: 'wynaut', moves: ['sleeptalk', 'icespinner'] }, ], [ - {species: 'registeel', ability: 'psychicsurge', moves: ['substitute', 'sleeptalk']}, + { species: 'registeel', ability: 'psychicsurge', moves: ['substitute', 'sleeptalk'] }, ]]); battle.makeChoices('move sleeptalk', 'move substitute'); @@ -33,7 +33,7 @@ describe(`Ice Spinner`, () => { assert.false(battle.field.isTerrain('psychicterrain')); }); - it(`should not remove Terrains if the user faints from Life Orb`, function () { + it(`should not remove Terrains if the user faints from Life Orb`, () => { battle = common.createBattle([[ { species: 'shedinja', item: 'lifeorb', moves: ['icespinner'] }, { species: 'wynaut', moves: ['sleeptalk'] }, @@ -57,7 +57,7 @@ describe(`Ice Spinner`, () => { assert(battle.field.isTerrain('psychicterrain')); }); - it(`should not remove Terrains if the user is forced out via Red Card`, function () { + it(`should not remove Terrains if the user is forced out via Red Card`, () => { battle = common.createBattle([[ { species: 'shedinja', moves: ['icespinner'] }, { species: 'wynaut', moves: ['sleeptalk'] },