mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-07 08:52:17 +02:00
Implement Safeguard for non-volatile statuses
This commit is contained in:
parent
38303e6eb1
commit
b5f948ffec
@ -845,7 +845,7 @@ export class PostDefendTerrainChangeAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
|
export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
|
||||||
private chance: integer;
|
public chance: integer;
|
||||||
private effects: StatusEffect[];
|
private effects: StatusEffect[];
|
||||||
|
|
||||||
constructor(chance: integer, ...effects: StatusEffect[]) {
|
constructor(chance: integer, ...effects: StatusEffect[]) {
|
||||||
|
@ -1929,7 +1929,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, targetSide)) {
|
if (user !== target && user.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, targetSide)) {
|
||||||
if (move.category === MoveCategory.STATUS) {
|
if (move.category === MoveCategory.STATUS) {
|
||||||
user.scene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target)}));
|
user.scene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target)}));
|
||||||
}
|
}
|
||||||
@ -6748,7 +6748,8 @@ export function initMoves() {
|
|||||||
.attr(FriendshipPowerAttr, true),
|
.attr(FriendshipPowerAttr, true),
|
||||||
new StatusMove(Moves.SAFEGUARD, Type.NORMAL, -1, 25, -1, 0, 2)
|
new StatusMove(Moves.SAFEGUARD, Type.NORMAL, -1, 25, -1, 0, 2)
|
||||||
.target(MoveTarget.USER_SIDE)
|
.target(MoveTarget.USER_SIDE)
|
||||||
.attr(AddArenaTagAttr, ArenaTagType.SAFEGUARD, 5, true, true),
|
.attr(AddArenaTagAttr, ArenaTagType.SAFEGUARD, 5, true, true)
|
||||||
|
.partial(),
|
||||||
new StatusMove(Moves.PAIN_SPLIT, Type.NORMAL, -1, 20, -1, 0, 2)
|
new StatusMove(Moves.PAIN_SPLIT, Type.NORMAL, -1, 20, -1, 0, 2)
|
||||||
.attr(HpSplitAttr)
|
.attr(HpSplitAttr)
|
||||||
.condition(failOnBossCondition),
|
.condition(failOnBossCondition),
|
||||||
|
@ -2686,6 +2686,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
const types = this.getTypes(true, true);
|
const types = this.getTypes(true, true);
|
||||||
|
|
||||||
|
const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||||
|
if (sourcePokemon && sourcePokemon !== this && this.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, defendingSide)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
switch (effect) {
|
switch (effect) {
|
||||||
case StatusEffect.POISON:
|
case StatusEffect.POISON:
|
||||||
case StatusEffect.TOXIC:
|
case StatusEffect.TOXIC:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import GameManager from "#app/test/utils/gameManager";
|
import GameManager from "#app/test/utils/gameManager";
|
||||||
import { CommandPhase, SelectTargetPhase, TurnEndPhase } from "#app/phases";
|
import { CommandPhase, SelectTargetPhase, TurnEndPhase } from "#app/phases";
|
||||||
@ -8,6 +8,8 @@ import { Species } from "#enums/species";
|
|||||||
import { BattlerIndex } from "#app/battle.js";
|
import { BattlerIndex } from "#app/battle.js";
|
||||||
import { Abilities } from "#app/enums/abilities.js";
|
import { Abilities } from "#app/enums/abilities.js";
|
||||||
import { mockTurnOrder } from "../utils/testUtils";
|
import { mockTurnOrder } from "../utils/testUtils";
|
||||||
|
import { StatusEffect } from "#app/enums/status-effect.js";
|
||||||
|
import { allAbilities, PostDefendContactApplyStatusEffectAbAttr } from "#app/data/ability.js";
|
||||||
|
|
||||||
const TIMEOUT = 20 * 1000;
|
const TIMEOUT = 20 * 1000;
|
||||||
|
|
||||||
@ -34,10 +36,10 @@ describe("Moves - Safeguard", () => {
|
|||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemyLevel(5)
|
.enemyLevel(5)
|
||||||
.starterSpecies(Species.DRATINI)
|
.starterSpecies(Species.DRATINI)
|
||||||
.moveset([Moves.NUZZLE, Moves.SPORE])
|
.moveset([Moves.NUZZLE, Moves.SPORE, Moves.YAWN, Moves.SPLASH])
|
||||||
.ability(Abilities.BALL_FETCH);
|
.ability(Abilities.BALL_FETCH);
|
||||||
});
|
});
|
||||||
it("protects from nuzzle status",
|
it("protects from damaging moves with additional effects",
|
||||||
async () => {
|
async () => {
|
||||||
await game.startBattle();
|
await game.startBattle();
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
@ -49,9 +51,8 @@ describe("Moves - Safeguard", () => {
|
|||||||
expect(enemy.status).toBeUndefined();
|
expect(enemy.status).toBeUndefined();
|
||||||
}, TIMEOUT
|
}, TIMEOUT
|
||||||
);
|
);
|
||||||
it("protects from spore",
|
it("protects from status moves",
|
||||||
async () => {
|
async () => {
|
||||||
|
|
||||||
await game.startBattle();
|
await game.startBattle();
|
||||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
@ -88,4 +89,71 @@ describe("Moves - Safeguard", () => {
|
|||||||
expect(enemyPokemon[1].status).toBeUndefined();
|
expect(enemyPokemon[1].status).toBeUndefined();
|
||||||
}, TIMEOUT
|
}, TIMEOUT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it.skip("protects from new volatile status", // not yet
|
||||||
|
async () => {
|
||||||
|
await game.startBattle();
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.YAWN));
|
||||||
|
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(enemyPokemon.summonData.tags).toEqual([]);
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it.skip("doesn't protect from already existing volatile status", // not yet
|
||||||
|
async () => {
|
||||||
|
await game.startBattle();
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.YAWN));
|
||||||
|
await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(enemyPokemon.status?.effect).toEqual(StatusEffect.SLEEP);
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it("doesn't protect from self-inflicted via Rest or Flame Orb",
|
||||||
|
async () => {
|
||||||
|
game.override.enemyHeldItems([{name: "FLAME_ORB"}]);
|
||||||
|
await game.startBattle();
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||||
|
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(enemyPokemon.status?.effect).toEqual(StatusEffect.BURN);
|
||||||
|
|
||||||
|
game.override.enemyMoveset(Array(4).fill(Moves.REST));
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(enemyPokemon.status?.effect).toEqual(StatusEffect.SLEEP);
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it("protects from ability-inflicted status",
|
||||||
|
async () => {
|
||||||
|
game.override.ability(Abilities.STATIC);
|
||||||
|
vi.spyOn(allAbilities[Abilities.STATIC].getAttrs(PostDefendContactApplyStatusEffectAbAttr)[0], "chance", "get").mockReturnValue(100);
|
||||||
|
await game.startBattle();
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||||
|
await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||||
|
await game.toNextTurn();
|
||||||
|
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH));
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
expect(enemyPokemon.status).toBeUndefined();
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user