diff --git a/src/data/move.ts b/src/data/move.ts index a17bad1cdc5..9d64e818f1a 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4479,6 +4479,15 @@ export class ConfuseAttr extends AddBattlerTagAttr { constructor(selfTarget?: boolean) { super(BattlerTagType.CONFUSED, selfTarget, false, 2, 5); } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!this.selfTarget && target.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY)) { + user.scene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target)})); + return false; + } + + return super.apply(user, target, move, args); + } } export class RechargeAttr extends AddBattlerTagAttr { @@ -6748,8 +6757,7 @@ export function initMoves() { .attr(FriendshipPowerAttr, true), new StatusMove(Moves.SAFEGUARD, Type.NORMAL, -1, 25, -1, 0, 2) .target(MoveTarget.USER_SIDE) - .attr(AddArenaTagAttr, ArenaTagType.SAFEGUARD, 5, true, true) - .partial(), + .attr(AddArenaTagAttr, ArenaTagType.SAFEGUARD, 5, true, true), new StatusMove(Moves.PAIN_SPLIT, Type.NORMAL, -1, 20, -1, 0, 2) .attr(HpSplitAttr) .condition(failOnBossCondition), @@ -6938,7 +6946,7 @@ export function initMoves() { .attr(RemoveScreensAttr), new StatusMove(Moves.YAWN, Type.NORMAL, -1, 10, -1, 0, 3) .attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, true) - .condition((user, target, move) => !target.status), + .condition((user, target, move) => !target.status && !target.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY)), new AttackMove(Moves.KNOCK_OFF, Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3) .attr(MovePowerMultiplierAttr, (user, target, move) => target.getHeldItems().filter(i => i.isTransferrable).length > 0 ? 1.5 : 1) .attr(RemoveHeldItemAttr, false), diff --git a/src/test/moves/safeguard.test.ts b/src/test/moves/safeguard.test.ts index cab53032a64..70fdfdc0ef6 100644 --- a/src/test/moves/safeguard.test.ts +++ b/src/test/moves/safeguard.test.ts @@ -39,6 +39,7 @@ describe("Moves - Safeguard", () => { .moveset([Moves.NUZZLE, Moves.SPORE, Moves.YAWN, Moves.SPLASH]) .ability(Abilities.BALL_FETCH); }); + it("protects from damaging moves with additional effects", async () => { await game.startBattle(); @@ -51,6 +52,7 @@ describe("Moves - Safeguard", () => { expect(enemy.status).toBeUndefined(); }, TIMEOUT ); + it("protects from status moves", async () => { await game.startBattle(); @@ -63,6 +65,21 @@ describe("Moves - Safeguard", () => { expect(enemyPokemon.status).toBeUndefined(); }, TIMEOUT ); + + it("protects from confusion", + async () => { + game.override.moveset([Moves.CONFUSE_RAY]); + await game.startBattle(); + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.CONFUSE_RAY)); + await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.toNextTurn(); + + expect(enemyPokemon.summonData.tags).toEqual([]); + }, TIMEOUT + ); + it("protects ally from status", async () => { game.override.battleType("double"); @@ -90,7 +107,7 @@ describe("Moves - Safeguard", () => { }, TIMEOUT ); - it.skip("protects from new volatile status", // not yet + it("protects from YAWN", async () => { await game.startBattle(); const enemyPokemon = game.scene.getEnemyPokemon()!; @@ -103,7 +120,7 @@ describe("Moves - Safeguard", () => { }, TIMEOUT ); - it.skip("doesn't protect from already existing volatile status", // not yet + it("doesn't protect from already existing YAWN", async () => { await game.startBattle(); const enemyPokemon = game.scene.getEnemyPokemon()!;