mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-27 09:49:30 +02:00
Implement Plasma Fists
This commit is contained in:
parent
70c6edfaed
commit
4d756e8fa4
@ -511,6 +511,39 @@ class WaterSportTag extends WeakenMoveTypeTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arena Tag class for the secondary effect of {@link https://bulbapedia.bulbagarden.net/wiki/Plasma_Fists_(move) | Plasma Fists}.
|
||||||
|
* Converts Normal-type moves to Electric type for the rest of the turn.
|
||||||
|
*/
|
||||||
|
export class PlasmaFistsTag extends ArenaTag {
|
||||||
|
constructor() {
|
||||||
|
super(ArenaTagType.PLASMA_FISTS, 1, Moves.PLASMA_FISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Queues Plasma Fists' on-add message */
|
||||||
|
onAdd(arena: Arena): void {
|
||||||
|
arena.scene.queueMessage(i18next.t("arenaTag:plasmaFistsOnAdd"));
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemove(arena: Arena): void { } // Removes default on-remove message
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts Normal-type moves to Electric type
|
||||||
|
* @param arena n/a
|
||||||
|
* @param args
|
||||||
|
* - `[0]` {@linkcode Utils.NumberHolder} A container with a move's {@linkcode Type}
|
||||||
|
* @returns `true` if the given move type changed; `false` otherwise.
|
||||||
|
*/
|
||||||
|
apply(arena: Arena, args: any[]): boolean {
|
||||||
|
const moveType = args[0];
|
||||||
|
if (moveType instanceof Utils.NumberHolder && moveType.value === Type.NORMAL) {
|
||||||
|
moveType.value = Type.ELECTRIC;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class to implement arena traps.
|
* Abstract class to implement arena traps.
|
||||||
*/
|
*/
|
||||||
@ -1010,6 +1043,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
|
|||||||
return new MudSportTag(turnCount, sourceId);
|
return new MudSportTag(turnCount, sourceId);
|
||||||
case ArenaTagType.WATER_SPORT:
|
case ArenaTagType.WATER_SPORT:
|
||||||
return new WaterSportTag(turnCount, sourceId);
|
return new WaterSportTag(turnCount, sourceId);
|
||||||
|
case ArenaTagType.PLASMA_FISTS:
|
||||||
|
return new PlasmaFistsTag();
|
||||||
case ArenaTagType.SPIKES:
|
case ArenaTagType.SPIKES:
|
||||||
return new SpikesTag(sourceId, side);
|
return new SpikesTag(sourceId, side);
|
||||||
case ArenaTagType.TOXIC_SPIKES:
|
case ArenaTagType.TOXIC_SPIKES:
|
||||||
|
@ -8869,8 +8869,8 @@ export function initMoves() {
|
|||||||
.attr(HalfSacrificialAttr)
|
.attr(HalfSacrificialAttr)
|
||||||
.target(MoveTarget.ALL_NEAR_OTHERS),
|
.target(MoveTarget.ALL_NEAR_OTHERS),
|
||||||
new AttackMove(Moves.PLASMA_FISTS, Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 100, 15, -1, 0, 7)
|
new AttackMove(Moves.PLASMA_FISTS, Type.ELECTRIC, MoveCategory.PHYSICAL, 100, 100, 15, -1, 0, 7)
|
||||||
.punchingMove()
|
.attr(AddArenaTagAttr, ArenaTagType.PLASMA_FISTS, 1)
|
||||||
.partial(),
|
.punchingMove(),
|
||||||
new AttackMove(Moves.PHOTON_GEYSER, Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
new AttackMove(Moves.PHOTON_GEYSER, Type.PSYCHIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 7)
|
||||||
.attr(PhotonGeyserCategoryAttr)
|
.attr(PhotonGeyserCategoryAttr)
|
||||||
.ignoresAbilities()
|
.ignoresAbilities()
|
||||||
|
@ -25,4 +25,5 @@ export enum ArenaTagType {
|
|||||||
SAFEGUARD = "SAFEGUARD",
|
SAFEGUARD = "SAFEGUARD",
|
||||||
NO_CRIT = "NO_CRIT",
|
NO_CRIT = "NO_CRIT",
|
||||||
IMPRISON = "IMPRISON",
|
IMPRISON = "IMPRISON",
|
||||||
|
PLASMA_FISTS = "PLASMA_FISTS",
|
||||||
}
|
}
|
||||||
|
@ -1508,6 +1508,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
applyMoveAttrs(VariableMoveTypeAttr, this, null, move, moveTypeHolder);
|
applyMoveAttrs(VariableMoveTypeAttr, this, null, move, moveTypeHolder);
|
||||||
applyPreAttackAbAttrs(MoveTypeChangeAbAttr, this, null, move, simulated, moveTypeHolder);
|
applyPreAttackAbAttrs(MoveTypeChangeAbAttr, this, null, move, simulated, moveTypeHolder);
|
||||||
|
|
||||||
|
this.scene.arena.applyTags(ArenaTagType.PLASMA_FISTS, moveTypeHolder);
|
||||||
|
|
||||||
return moveTypeHolder.value as Type;
|
return moveTypeHolder.value as Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"mudSportOnRemove": "The effects of Mud Sport\nhave faded.",
|
"mudSportOnRemove": "The effects of Mud Sport\nhave faded.",
|
||||||
"waterSportOnAdd": "Fire's power was weakened!",
|
"waterSportOnAdd": "Fire's power was weakened!",
|
||||||
"waterSportOnRemove": "The effects of Water Sport\nhave faded.",
|
"waterSportOnRemove": "The effects of Water Sport\nhave faded.",
|
||||||
|
"plasmaFistsOnAdd": "A deluge of ions showers the battlefield!",
|
||||||
"spikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!",
|
"spikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!",
|
||||||
"spikesActivateTrap": "{{pokemonNameWithAffix}} is hurt\nby the spikes!",
|
"spikesActivateTrap": "{{pokemonNameWithAffix}} is hurt\nby the spikes!",
|
||||||
"toxicSpikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!",
|
"toxicSpikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!",
|
||||||
|
98
src/test/moves/plasma_fists.test.ts
Normal file
98
src/test/moves/plasma_fists.test.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
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 - Plasma Fists", () => {
|
||||||
|
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.PLASMA_FISTS, Moves.TACKLE])
|
||||||
|
.battleType("double")
|
||||||
|
.startingLevel(100)
|
||||||
|
.enemySpecies(Species.DUSCLOPS)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.TACKLE)
|
||||||
|
.enemyLevel(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should convert all subsequent Normal-type attacks to Electric-type", async () => {
|
||||||
|
await game.classicMode.startBattle([Species.DUSCLOPS, Species.BLASTOISE]);
|
||||||
|
|
||||||
|
const field = game.scene.getField(true);
|
||||||
|
field.forEach(p => vi.spyOn(p, "getMoveType"));
|
||||||
|
|
||||||
|
game.move.select(Moves.PLASMA_FISTS, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.TACKLE, 1, BattlerIndex.ENEMY_2);
|
||||||
|
|
||||||
|
await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER);
|
||||||
|
await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2);
|
||||||
|
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
field.forEach(p => {
|
||||||
|
expect(p.getMoveType).toHaveLastReturnedWith(Type.ELECTRIC);
|
||||||
|
expect(p.hp).toBeLessThan(p.getMaxHp());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not affect Normal-type attacks boosted by Pixilate", async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.enemyAbility(Abilities.PIXILATE);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.ONIX]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
vi.spyOn(enemyPokemon, "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.PLASMA_FISTS);
|
||||||
|
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
expect(enemyPokemon.getMoveType).toHaveLastReturnedWith(Type.FAIRY);
|
||||||
|
expect(playerPokemon.hp).toBeLessThan(playerPokemon.getMaxHp());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should affect moves that become Normal type due to Normalize", async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.enemyAbility(Abilities.NORMALIZE)
|
||||||
|
.enemyMoveset(Moves.WATER_GUN);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.DUSCLOPS]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
vi.spyOn(enemyPokemon, "getMoveType");
|
||||||
|
|
||||||
|
game.move.select(Moves.PLASMA_FISTS);
|
||||||
|
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
|
expect(enemyPokemon.getMoveType).toHaveLastReturnedWith(Type.ELECTRIC);
|
||||||
|
expect(playerPokemon.hp).toBeLessThan(playerPokemon.getMaxHp());
|
||||||
|
});
|
||||||
|
});
|
@ -300,7 +300,7 @@ export default class GameManager {
|
|||||||
|
|
||||||
vi.spyOn(enemy, "getNextMove").mockReturnValueOnce({
|
vi.spyOn(enemy, "getNextMove").mockReturnValueOnce({
|
||||||
move: moveId,
|
move: moveId,
|
||||||
targets: (target && !legalTargets.multiple && legalTargets.targets.includes(target))
|
targets: (target !== undefined && !legalTargets.multiple && legalTargets.targets.includes(target))
|
||||||
? [target]
|
? [target]
|
||||||
: enemy.getNextTargets(moveId)
|
: enemy.getNextTargets(moveId)
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user