mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2024-11-24 15:56:22 +00:00
[Ability] Fully implement Synchronize (#4785)
Co-authored-by: frutescens <info@laptop> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
parent
4f733796c5
commit
6b7efb444b
@ -5433,8 +5433,7 @@ export function initAbilities() {
|
||||
.attr(EffectSporeAbAttr),
|
||||
new Ability(Abilities.SYNCHRONIZE, 3)
|
||||
.attr(SyncEncounterNatureAbAttr)
|
||||
.attr(SynchronizeStatusAbAttr)
|
||||
.partial(), // interaction with psycho shift needs work, keeping to old Gen interaction for now
|
||||
.attr(SynchronizeStatusAbAttr),
|
||||
new Ability(Abilities.CLEAR_BODY, 3)
|
||||
.attr(ProtectStatAbAttr)
|
||||
.ignorable(),
|
||||
@ -6036,7 +6035,7 @@ export function initAbilities() {
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.CORROSION, 7)
|
||||
.attr(IgnoreTypeStatusEffectImmunityAbAttr, [ StatusEffect.POISON, StatusEffect.TOXIC ], [ Type.STEEL, Type.POISON ])
|
||||
.edgeCase(), // Should interact correctly with magic coat/bounce (not yet implemented), fling with toxic orb (not implemented yet), and synchronize (not fully implemented yet)
|
||||
.edgeCase(), // Should interact correctly with magic coat/bounce (not yet implemented) + fling with toxic orb (not implemented yet)
|
||||
new Ability(Abilities.COMATOSE, 7)
|
||||
.attr(UncopiableAbilityAbAttr)
|
||||
.attr(UnswappableAbilityAbAttr)
|
||||
|
@ -18,7 +18,7 @@ import Move, {
|
||||
StatusCategoryOnAllyAttr
|
||||
} from "#app/data/move";
|
||||
import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms";
|
||||
import { StatusEffect } from "#app/data/status-effect";
|
||||
import { getStatusEffectHealText, StatusEffect } from "#app/data/status-effect";
|
||||
import { TerrainType } from "#app/data/terrain";
|
||||
import { Type } from "#app/data/type";
|
||||
import { WeatherType } from "#app/data/weather";
|
||||
@ -2866,6 +2866,28 @@ export class GrudgeTag extends BattlerTag {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag used to heal the user of Psycho Shift of its status effect if Psycho Shift succeeds in transferring its status effect to the target Pokemon
|
||||
*/
|
||||
export class PsychoShiftTag extends BattlerTag {
|
||||
constructor() {
|
||||
super(BattlerTagType.PSYCHO_SHIFT, BattlerTagLapseType.AFTER_MOVE, 1, Moves.PSYCHO_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Heals Psycho Shift's user of its status effect after it uses a move
|
||||
* @returns `false` to expire the tag immediately
|
||||
*/
|
||||
override lapse(pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean {
|
||||
if (pokemon.status && pokemon.isActive(true)) {
|
||||
pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
|
||||
pokemon.resetStatus();
|
||||
pokemon.updateInfo();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
|
||||
* @param sourceId - The ID of the pokemon adding the tag
|
||||
@ -3049,6 +3071,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
||||
return new PowerTrickTag(sourceMove, sourceId);
|
||||
case BattlerTagType.GRUDGE:
|
||||
return new GrudgeTag();
|
||||
case BattlerTagType.PSYCHO_SHIFT:
|
||||
return new PsychoShiftTag();
|
||||
case BattlerTagType.NONE:
|
||||
default:
|
||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||
|
@ -2270,24 +2270,26 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr {
|
||||
super(false, { trigger: MoveEffectTrigger.HIT });
|
||||
}
|
||||
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
/**
|
||||
* Applies the effect of Psycho Shift to its target
|
||||
* Psycho Shift takes the user's status effect and passes it onto the target. The user is then healed after the move has been successfully executed.
|
||||
* @returns `true` if Psycho Shift's effect is able to be applied to the target
|
||||
*/
|
||||
apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
|
||||
const statusToApply: StatusEffect | undefined = user.status?.effect ?? (user.hasAbility(Abilities.COMATOSE) ? StatusEffect.SLEEP : undefined);
|
||||
|
||||
if (target.status) {
|
||||
return false;
|
||||
} else {
|
||||
const canSetStatus = target.canSetStatus(statusToApply, true, false, user);
|
||||
const trySetStatus = canSetStatus ? target.trySetStatus(statusToApply, true, user) : false;
|
||||
|
||||
if (canSetStatus) {
|
||||
if (user.status) {
|
||||
user.scene.queueMessage(getStatusEffectHealText(user.status.effect, getPokemonNameWithAffix(user)));
|
||||
}
|
||||
user.resetStatus();
|
||||
user.updateInfo();
|
||||
target.trySetStatus(statusToApply, true, user);
|
||||
if (trySetStatus && user.status) {
|
||||
// PsychoShiftTag is added to the user if move succeeds so that the user is healed of its status effect after its move
|
||||
user.addTag(BattlerTagType.PSYCHO_SHIFT);
|
||||
}
|
||||
|
||||
return canSetStatus;
|
||||
return trySetStatus;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,5 +90,6 @@ export enum BattlerTagType {
|
||||
ELECTRIFIED = "ELECTRIFIED",
|
||||
TELEKINESIS = "TELEKINESIS",
|
||||
COMMANDED = "COMMANDED",
|
||||
GRUDGE = "GRUDGE"
|
||||
GRUDGE = "GRUDGE",
|
||||
PSYCHO_SHIFT = "PSYCHO_SHIFT",
|
||||
}
|
||||
|
46
src/test/abilities/corrosion.test.ts
Normal file
46
src/test/abilities/corrosion.test.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Abilities - Corrosion", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([ Moves.SPLASH ])
|
||||
.battleType("single")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.GRIMER)
|
||||
.enemyAbility(Abilities.CORROSION)
|
||||
.enemyMoveset(Moves.TOXIC);
|
||||
});
|
||||
|
||||
it("If a Poison- or Steel-type Pokémon with this Ability poisons a target with Synchronize, Synchronize does not gain the ability to poison Poison- or Steel-type Pokémon.", async () => {
|
||||
game.override.ability(Abilities.SYNCHRONIZE);
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon();
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(playerPokemon!.status).toBeUndefined();
|
||||
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
expect(playerPokemon!.status).toBeDefined();
|
||||
expect(enemyPokemon!.status).toBeUndefined();
|
||||
});
|
||||
});
|
@ -94,16 +94,4 @@ describe("Abilities - Synchronize", () => {
|
||||
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase");
|
||||
});
|
||||
|
||||
it("should activate with Psycho Shift after the move clears the status", async () => {
|
||||
game.override.statusEffect(StatusEffect.PARALYSIS);
|
||||
await game.classicMode.startBattle();
|
||||
|
||||
game.move.select(Moves.PSYCHO_SHIFT);
|
||||
await game.phaseInterceptor.to("BerryPhase");
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS); // keeping old gen < V impl for now since it's buggy otherwise
|
||||
expect(game.scene.getEnemyPokemon()!.status?.effect).toBe(StatusEffect.PARALYSIS);
|
||||
expect(game.phaseInterceptor.log).toContain("ShowAbilityPhase");
|
||||
});
|
||||
});
|
||||
|
49
src/test/moves/psycho_shift.test.ts
Normal file
49
src/test/moves/psycho_shift.test.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { StatusEffect } from "#app/enums/status-effect";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Moves - Psycho Shift", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([ Moves.PSYCHO_SHIFT ])
|
||||
.ability(Abilities.BALL_FETCH)
|
||||
.statusEffect(StatusEffect.POISON)
|
||||
.battleType("single")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyLevel(20)
|
||||
.enemyAbility(Abilities.SYNCHRONIZE)
|
||||
.enemyMoveset(Moves.SPLASH);
|
||||
});
|
||||
|
||||
it("If Psycho Shift is used on a Pokémon with Synchronize, the user of Psycho Shift will already be afflicted with a status condition when Synchronize activates", async () => {
|
||||
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon();
|
||||
const enemyPokemon = game.scene.getEnemyPokemon();
|
||||
expect(enemyPokemon?.status).toBeUndefined();
|
||||
|
||||
game.move.select(Moves.PSYCHO_SHIFT);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
expect(playerPokemon?.status).toBeNull();
|
||||
expect(enemyPokemon?.status).toBeDefined();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user