mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-06 16:32:16 +02:00
[Move] Implement Rage
This commit is contained in:
parent
c846f552bb
commit
9e018f4fe4
@ -205,6 +205,24 @@ export class ShellTrapTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class RageTag extends BattlerTag {
|
||||||
|
constructor() {
|
||||||
|
super(BattlerTagType.RAGE,[BattlerTagLapseType.MOVE_EFFECT],1,Moves.RAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
|
if (lapseType === BattlerTagLapseType.MOVE_EFFECT) {
|
||||||
|
return (pokemon.scene.getCurrentPhase() as MovePhase).move.getMove().id === Moves.RAGE;
|
||||||
|
} else if (lapseType === BattlerTagLapseType.CUSTOM) {
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene,pokemon.getBattlerIndex(),true,[BattleStat.ATK],1,false));
|
||||||
|
pokemon.scene.queueMessage(i18next.t("battlerTags:rageOnHit", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)}));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class TrappedTag extends BattlerTag {
|
export class TrappedTag extends BattlerTag {
|
||||||
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: number, sourceMove: Moves, sourceId: number) {
|
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: number, sourceMove: Moves, sourceId: number) {
|
||||||
super(tagType, lapseType, turnCount, sourceMove, sourceId);
|
super(tagType, lapseType, turnCount, sourceMove, sourceId);
|
||||||
@ -1962,6 +1980,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
|||||||
case BattlerTagType.GULP_MISSILE_ARROKUDA:
|
case BattlerTagType.GULP_MISSILE_ARROKUDA:
|
||||||
case BattlerTagType.GULP_MISSILE_PIKACHU:
|
case BattlerTagType.GULP_MISSILE_PIKACHU:
|
||||||
return new GulpMissileTag(tagType, sourceMove);
|
return new GulpMissileTag(tagType, sourceMove);
|
||||||
|
case BattlerTagType.RAGE:
|
||||||
|
return new RageTag();
|
||||||
case BattlerTagType.NONE:
|
case BattlerTagType.NONE:
|
||||||
default:
|
default:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||||
|
@ -6450,7 +6450,7 @@ export function initMoves() {
|
|||||||
.attr(StatChangeAttr, BattleStat.SPD, 2, true),
|
.attr(StatChangeAttr, BattleStat.SPD, 2, true),
|
||||||
new AttackMove(Moves.QUICK_ATTACK, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 30, -1, 1, 1),
|
new AttackMove(Moves.QUICK_ATTACK, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 30, -1, 1, 1),
|
||||||
new AttackMove(Moves.RAGE, Type.NORMAL, MoveCategory.PHYSICAL, 20, 100, 20, -1, 0, 1)
|
new AttackMove(Moves.RAGE, Type.NORMAL, MoveCategory.PHYSICAL, 20, 100, 20, -1, 0, 1)
|
||||||
.partial(),
|
.attr(AddBattlerTagAttr,BattlerTagType.RAGE,true,false,0,0,false,true),
|
||||||
new SelfStatusMove(Moves.TELEPORT, Type.PSYCHIC, -1, 20, -1, -6, 1)
|
new SelfStatusMove(Moves.TELEPORT, Type.PSYCHIC, -1, 20, -1, -6, 1)
|
||||||
.attr(ForceSwitchOutAttr, true)
|
.attr(ForceSwitchOutAttr, true)
|
||||||
.hidesUser(),
|
.hidesUser(),
|
||||||
|
@ -69,5 +69,6 @@ export enum BattlerTagType {
|
|||||||
GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA",
|
GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA",
|
||||||
GULP_MISSILE_PIKACHU = "GULP_MISSILE_PIKACHU",
|
GULP_MISSILE_PIKACHU = "GULP_MISSILE_PIKACHU",
|
||||||
BEAK_BLAST_CHARGING = "BEAK_BLAST_CHARGING",
|
BEAK_BLAST_CHARGING = "BEAK_BLAST_CHARGING",
|
||||||
SHELL_TRAP = "SHELL_TRAP"
|
SHELL_TRAP = "SHELL_TRAP",
|
||||||
|
RAGE = "RAGE"
|
||||||
}
|
}
|
||||||
|
@ -70,4 +70,5 @@ export const battlerTags: SimpleTranslationEntries = {
|
|||||||
"cursedOnAdd": "{{pokemonNameWithAffix}} cut its own HP and put a curse on the {{pokemonName}}!",
|
"cursedOnAdd": "{{pokemonNameWithAffix}} cut its own HP and put a curse on the {{pokemonName}}!",
|
||||||
"cursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!",
|
"cursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!",
|
||||||
"stockpilingOnAdd": "{{pokemonNameWithAffix}} stockpiled {{stockpiledCount}}!",
|
"stockpilingOnAdd": "{{pokemonNameWithAffix}} stockpiled {{stockpiledCount}}!",
|
||||||
|
"rageOnHit": "{{pokemonNameWithAffix}}'s rage is building"
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -262,6 +262,9 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
if (move.category === MoveCategory.PHYSICAL && user.isPlayer() !== target.isPlayer()) {
|
if (move.category === MoveCategory.PHYSICAL && user.isPlayer() !== target.isPlayer()) {
|
||||||
target.lapseTag(BattlerTagType.SHELL_TRAP);
|
target.lapseTag(BattlerTagType.SHELL_TRAP);
|
||||||
}
|
}
|
||||||
|
if (hitResult < HitResult.NO_EFFECT && move.category !== MoveCategory.STATUS) {
|
||||||
|
target.lapseTag(BattlerTagType.RAGE);
|
||||||
|
}
|
||||||
if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) {
|
if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) {
|
||||||
user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target);
|
user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target);
|
||||||
}
|
}
|
||||||
|
110
src/test/moves/rage.test.ts
Normal file
110
src/test/moves/rage.test.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import {BattleStat} from "#app/data/battle-stat";
|
||||||
|
|
||||||
|
const TIMEOUT = 20 * 1000;
|
||||||
|
|
||||||
|
describe("Moves - Rage", () => {
|
||||||
|
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
|
||||||
|
.battleType("single")
|
||||||
|
.ability(Abilities.UNNERVE)
|
||||||
|
.moveset([Moves.RAGE,Moves.SPLASH,Moves.SPORE])
|
||||||
|
.enemyAbility(Abilities.INSOMNIA)
|
||||||
|
.startingLevel(100)
|
||||||
|
.enemyLevel(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(
|
||||||
|
"should raise attack if hit after use",
|
||||||
|
async () => {
|
||||||
|
game.override
|
||||||
|
.enemySpecies(Species.SHUCKLE)
|
||||||
|
.enemyMoveset([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
|
||||||
|
await game.startBattle([Species.NINJASK]);
|
||||||
|
|
||||||
|
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
// Ninjask uses rage, then gets hit, gets atk boost
|
||||||
|
game.doAttack(0);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(leadPokemon.summonData.battleStats[BattleStat.ATK]).toBe(1);
|
||||||
|
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"should raise ATK if hit before using non-rage option",
|
||||||
|
async () => {
|
||||||
|
game.override
|
||||||
|
.enemySpecies(Species.NINJASK)
|
||||||
|
.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||||
|
await game.startBattle([Species.SHUCKLE]);
|
||||||
|
|
||||||
|
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
// Ninjask moves first, THEN shuckle uses rage, no ATK boost
|
||||||
|
game.doAttack(0);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(leadPokemon.summonData.battleStats[BattleStat.ATK]).toBe(0);
|
||||||
|
|
||||||
|
// Shuckle Raged last turn, so when Ninjask hits it, ATK boost despite not using rage this turn
|
||||||
|
game.doAttack(1);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(leadPokemon.summonData.battleStats[BattleStat.ATK]).toBe(1);
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"should not raise ATK if hit by status move",
|
||||||
|
async () => {
|
||||||
|
game.override
|
||||||
|
.enemySpecies(Species.NINJASK)
|
||||||
|
.enemyMoveset([Moves.RAGE, Moves.RAGE, Moves.RAGE, Moves.RAGE]);
|
||||||
|
await game.startBattle([Species.NINJASK]);
|
||||||
|
|
||||||
|
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
// Ninjask Rages, then slept. No boost.
|
||||||
|
game.doAttack(2);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(leadPokemon.summonData.battleStats[BattleStat.ATK]).toBe(0);
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"should not raise ATK if rage has no effect",
|
||||||
|
async () => {
|
||||||
|
game.override
|
||||||
|
.enemySpecies(Species.GASTLY)
|
||||||
|
.enemyMoveset([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE])
|
||||||
|
.moveset([Moves.RAGE]);
|
||||||
|
await game.startBattle([Species.NINJASK]);
|
||||||
|
|
||||||
|
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
// Ninjask uses rage, but it has no effect, no ATK boost
|
||||||
|
game.doAttack(0);
|
||||||
|
await game.toNextTurn();
|
||||||
|
expect(leadPokemon.summonData.battleStats[BattleStat.ATK]).toBe(0);
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user