diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 6cb33dca306..a54a8c5f519 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -2310,6 +2310,21 @@ export class TarShotTag extends BattlerTag { } } +/** + * Battler Tag implementing the type-changing effect of {@link https://bulbapedia.bulbagarden.net/wiki/Electrify_(move) | Electrify}. + * While this tag is in effect, the afflicted Pokemon's moves are changed to Electric type. + */ +export class ElectrifiedTag extends BattlerTag { + constructor() { + super(BattlerTagType.ELECTRIFIED, BattlerTagLapseType.TURN_END, 1, Moves.ELECTRIFY); + } + + override onAdd(pokemon: Pokemon): void { + // "{pokemonNameWithAffix}'s moves have been electrified!" + pokemon.scene.queueMessage(i18next.t("battlerTags:electrifiedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); + } +} + /** * Battler Tag that keeps track of how many times the user has Autotomized * Each count of Autotomization reduces the weight by 100kg @@ -2811,6 +2826,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source return new GulpMissileTag(tagType, sourceMove); case BattlerTagType.TAR_SHOT: return new TarShotTag(); + case BattlerTagType.ELECTRIFIED: + return new ElectrifiedTag(); case BattlerTagType.THROAT_CHOPPED: return new ThroatChoppedTag(); case BattlerTagType.GORILLA_TACTICS: diff --git a/src/data/move.ts b/src/data/move.ts index 62ac36b28ad..8095b5a6013 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -8732,7 +8732,7 @@ export function initMoves() { .attr(TerrainChangeAttr, TerrainType.MISTY) .target(MoveTarget.BOTH_SIDES), new StatusMove(Moves.ELECTRIFY, Type.ELECTRIC, -1, 20, -1, 0, 6) - .unimplemented(), + .attr(AddBattlerTagAttr, BattlerTagType.ELECTRIFIED, false, true), new AttackMove(Moves.PLAY_ROUGH, Type.FAIRY, MoveCategory.PHYSICAL, 90, 90, 10, 10, 0, 6) .attr(StatStageChangeAttr, [ Stat.ATK ], -1), new AttackMove(Moves.FAIRY_WIND, Type.FAIRY, MoveCategory.SPECIAL, 40, 100, 30, -1, 0, 6) diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index ccd6e9fe314..43c849a78e0 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -85,4 +85,5 @@ export enum BattlerTagType { TAUNT = "TAUNT", IMPRISON = "IMPRISON", SYRUP_BOMB = "SYRUP_BOMB", + ELECTRIFIED = "ELECTRIFIED", } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index c2ef7d919b0..94fa050a7bc 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1528,6 +1528,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { applyPreAttackAbAttrs(MoveTypeChangeAbAttr, this, null, move, simulated, moveTypeHolder); this.scene.arena.applyTags(ArenaTagType.PLASMA_FISTS, moveTypeHolder); + if (this.getTag(BattlerTagType.ELECTRIFIED)) { + moveTypeHolder.value = Type.ELECTRIC; + } return moveTypeHolder.value as Type; } diff --git a/src/test/moves/electrify.test.ts b/src/test/moves/electrify.test.ts new file mode 100644 index 00000000000..5d15a825688 --- /dev/null +++ b/src/test/moves/electrify.test.ts @@ -0,0 +1,69 @@ +import { BattlerIndex } from "#app/battle"; +import { Type } from "#app/data/type"; +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, it, expect, vi } from "vitest"; + +describe("Moves - Electrify", () => { + 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.ELECTRIFY) + .battleType("single") + .startingLevel(100) + .enemySpecies(Species.SNORLAX) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.TACKLE) + .enemyLevel(100); + }); + + it("should convert attacks to Electric type", async () => { + await game.classicMode.startBattle([ Species.EXCADRILL ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + vi.spyOn(enemyPokemon, "getMoveType"); + + game.move.select(Moves.ELECTRIFY); + + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(enemyPokemon.getMoveType).toHaveLastReturnedWith(Type.ELECTRIC); + expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp()); + }); + + it("should override type changes from abilities", async () => { + game.override.enemyAbility(Abilities.PIXILATE); + + await game.classicMode.startBattle([ Species.EXCADRILL ]); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getPlayerPokemon()!; + vi.spyOn(enemyPokemon, "getMoveType"); + + game.move.select(Moves.ELECTRIFY); + + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + + await game.phaseInterceptor.to("BerryPhase", false); + expect(enemyPokemon.getMoveType).toHaveLastReturnedWith(Type.ELECTRIC); + expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp()); + }); +});