[Move] Implement Power Shift (#4083)
* fully implement power shift * cleanup
This commit is contained in:
parent
80e347840d
commit
c59f6edf36
|
@ -5987,9 +5987,8 @@ export class SwapStatAttr extends MoveEffectAttr {
|
|||
}
|
||||
|
||||
/**
|
||||
* Takes the average of the user's and target's corresponding current
|
||||
* {@linkcode stat} values and sets that stat to the average for both
|
||||
* temporarily.
|
||||
* Swaps the user's and target's corresponding current
|
||||
* {@linkcode EffectiveStat | stat} values
|
||||
* @param user the {@linkcode Pokemon} that used the move
|
||||
* @param target the {@linkcode Pokemon} that the move was used on
|
||||
* @param move N/A
|
||||
|
@ -6013,6 +6012,62 @@ export class SwapStatAttr extends MoveEffectAttr {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute used to switch the user's own stats.
|
||||
* Used by Power Shift.
|
||||
* @extends MoveEffectAttr
|
||||
*/
|
||||
export class ShiftStatAttr extends MoveEffectAttr {
|
||||
private statToSwitch: EffectiveStat;
|
||||
private statToSwitchWith: EffectiveStat;
|
||||
|
||||
constructor(statToSwitch: EffectiveStat, statToSwitchWith: EffectiveStat) {
|
||||
super();
|
||||
|
||||
this.statToSwitch = statToSwitch;
|
||||
this.statToSwitchWith = statToSwitchWith;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the user's stats based on the {@linkcode statToSwitch} and {@linkcode statToSwitchWith} attributes.
|
||||
* @param {Pokemon} user the {@linkcode Pokemon} that used the move
|
||||
* @param target n/a
|
||||
* @param move n/a
|
||||
* @param args n/a
|
||||
* @returns whether the effect was applied
|
||||
*/
|
||||
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
if (!super.apply(user, target, move, args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const firstStat = user.getStat(this.statToSwitch, false);
|
||||
const secondStat = user.getStat(this.statToSwitchWith, false);
|
||||
|
||||
user.setStat(this.statToSwitch, secondStat, false);
|
||||
user.setStat(this.statToSwitchWith, firstStat, false);
|
||||
|
||||
user.scene.queueMessage(i18next.t("moveTriggers:shiftedStats", {
|
||||
pokemonName: getPokemonNameWithAffix(user),
|
||||
statToSwitch: i18next.t(getStatKey(this.statToSwitch)),
|
||||
statToSwitchWith: i18next.t(getStatKey(this.statToSwitchWith))
|
||||
}));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encourages the user to use the move if the stat to switch with is greater than the stat to switch.
|
||||
* @param {Pokemon} user the {@linkcode Pokemon} that used the move
|
||||
* @param target n/a
|
||||
* @param move n/a
|
||||
* @returns number of points to add to the user's benefit score
|
||||
*/
|
||||
override getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
|
||||
return user.getStat(this.statToSwitchWith, false) > user.getStat(this.statToSwitch, false) ? 10 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute used for status moves, namely Power Split and Guard Split,
|
||||
* that take the average of a user's and target's corresponding
|
||||
|
@ -8894,7 +8949,8 @@ export function initMoves() {
|
|||
new AttackMove(Moves.PSYSHIELD_BASH, Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8)
|
||||
.attr(StatStageChangeAttr, [ Stat.DEF ], 1, true),
|
||||
new SelfStatusMove(Moves.POWER_SHIFT, Type.NORMAL, -1, 10, -1, 0, 8)
|
||||
.unimplemented(),
|
||||
.target(MoveTarget.USER)
|
||||
.attr(ShiftStatAttr, Stat.ATK, Stat.DEF),
|
||||
new AttackMove(Moves.STONE_AXE, Type.ROCK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
|
||||
.attr(AddArenaTrapTagHitAttr, ArenaTagType.STEALTH_ROCK)
|
||||
.slicingMove(),
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"switchedStat": "{{pokemonName}} switched {{stat}} with its target!",
|
||||
"sharedGuard": "{{pokemonName}} shared its guard with the target!",
|
||||
"sharedPower": "{{pokemonName}} shared its power with the target!",
|
||||
"shiftedStats": "{{pokemonName}} switched its {{statToSwitch}} and {{statToSwitchWith}}!",
|
||||
"goingAllOutForAttack": "{{pokemonName}} is going all out for this attack!",
|
||||
"regainedHealth": "{{pokemonName}} regained\nhealth!",
|
||||
"keptGoingAndCrashed": "{{pokemonName}} kept going\nand crashed!",
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import { Moves } from "#app/enums/moves";
|
||||
import { Species } from "#app/enums/species";
|
||||
import { Stat } from "#app/enums/stat";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Moves - Power Shift", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([Moves.POWER_SHIFT, Moves.BULK_UP])
|
||||
.battleType("single")
|
||||
.ability(Abilities.BALL_FETCH)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyMoveset(SPLASH_ONLY);
|
||||
});
|
||||
|
||||
it("switches the user's raw Attack stat with its raw Defense stat", async () => {
|
||||
await game.classicMode.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||
|
||||
playerPokemon.setStat(Stat.ATK, 10, false);
|
||||
playerPokemon.setStat(Stat.DEF, 20, false);
|
||||
|
||||
game.move.select(Moves.BULK_UP);
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// Stat stages are increased by 1
|
||||
expect(playerPokemon.getStatStageMultiplier(Stat.ATK)).toBe(1.5);
|
||||
expect(playerPokemon.getStatStageMultiplier(Stat.DEF)).toBe(1.5);
|
||||
|
||||
await game.toNextTurn();
|
||||
|
||||
game.move.select(Moves.POWER_SHIFT);
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// Effective stats are calculated correctly
|
||||
expect(playerPokemon.getEffectiveStat(Stat.ATK)).toBe(30);
|
||||
expect(playerPokemon.getEffectiveStat(Stat.DEF)).toBe(15);
|
||||
// Raw stats are swapped
|
||||
expect(playerPokemon.getStat(Stat.ATK, false)).toBe(20);
|
||||
expect(playerPokemon.getStat(Stat.DEF, false)).toBe(10);
|
||||
}, TIMEOUT);
|
||||
});
|
Loading…
Reference in New Issue