[Move] Implement Lunar Dance (#4926)
* beginning immplementation of lunar dance * adding tests * changing in game message and making full hp message not display * Reuse Healing Wish's move attr, update test --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
parent
f2ef3620b5
commit
5db3074e2c
|
@ -1881,8 +1881,14 @@ export class FlameBurstAttr extends MoveEffectAttr {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SacrificialFullRestoreAttr extends SacrificialAttr {
|
export class SacrificialFullRestoreAttr extends SacrificialAttr {
|
||||||
constructor() {
|
protected restorePP: boolean;
|
||||||
|
protected moveMessage: string;
|
||||||
|
|
||||||
|
constructor(restorePP: boolean, moveMessage: string) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.restorePP = restorePP;
|
||||||
|
this.moveMessage = moveMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
@ -1893,8 +1899,19 @@ export class SacrificialFullRestoreAttr extends SacrificialAttr {
|
||||||
// We don't know which party member will be chosen, so pick the highest max HP in the party
|
// We don't know which party member will be chosen, so pick the highest max HP in the party
|
||||||
const maxPartyMemberHp = user.scene.getPlayerParty().map(p => p.getMaxHp()).reduce((maxHp: integer, hp: integer) => Math.max(hp, maxHp), 0);
|
const maxPartyMemberHp = user.scene.getPlayerParty().map(p => p.getMaxHp()).reduce((maxHp: integer, hp: integer) => Math.max(hp, maxHp), 0);
|
||||||
|
|
||||||
user.scene.pushPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(),
|
user.scene.pushPhase(
|
||||||
maxPartyMemberHp, i18next.t("moveTriggers:sacrificialFullRestore", { pokemonName: getPokemonNameWithAffix(user) }), true, false, false, true), true);
|
new PokemonHealPhase(
|
||||||
|
user.scene,
|
||||||
|
user.getBattlerIndex(),
|
||||||
|
maxPartyMemberHp,
|
||||||
|
i18next.t(this.moveMessage, { pokemonName: getPokemonNameWithAffix(user) }),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
this.restorePP),
|
||||||
|
true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -9002,7 +9019,7 @@ export function initMoves() {
|
||||||
.attr(GyroBallPowerAttr)
|
.attr(GyroBallPowerAttr)
|
||||||
.ballBombMove(),
|
.ballBombMove(),
|
||||||
new SelfStatusMove(Moves.HEALING_WISH, Type.PSYCHIC, -1, 10, -1, 0, 4)
|
new SelfStatusMove(Moves.HEALING_WISH, Type.PSYCHIC, -1, 10, -1, 0, 4)
|
||||||
.attr(SacrificialFullRestoreAttr)
|
.attr(SacrificialFullRestoreAttr, false, "moveTriggers:sacrificialFullRestore")
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new AttackMove(Moves.BRINE, Type.WATER, MoveCategory.SPECIAL, 65, 100, 10, -1, 0, 4)
|
new AttackMove(Moves.BRINE, Type.WATER, MoveCategory.SPECIAL, 65, 100, 10, -1, 0, 4)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getHpRatio() < 0.5 ? 2 : 1),
|
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getHpRatio() < 0.5 ? 2 : 1),
|
||||||
|
@ -9279,10 +9296,9 @@ export function initMoves() {
|
||||||
new AttackMove(Moves.SPACIAL_REND, Type.DRAGON, MoveCategory.SPECIAL, 100, 95, 5, -1, 0, 4)
|
new AttackMove(Moves.SPACIAL_REND, Type.DRAGON, MoveCategory.SPECIAL, 100, 95, 5, -1, 0, 4)
|
||||||
.attr(HighCritAttr),
|
.attr(HighCritAttr),
|
||||||
new SelfStatusMove(Moves.LUNAR_DANCE, Type.PSYCHIC, -1, 10, -1, 0, 4)
|
new SelfStatusMove(Moves.LUNAR_DANCE, Type.PSYCHIC, -1, 10, -1, 0, 4)
|
||||||
.attr(SacrificialAttrOnHit)
|
.attr(SacrificialFullRestoreAttr, true, "moveTriggers:lunarDanceRestore")
|
||||||
.danceMove()
|
.danceMove()
|
||||||
.triageMove()
|
.triageMove(),
|
||||||
.unimplemented(),
|
|
||||||
new AttackMove(Moves.CRUSH_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
|
new AttackMove(Moves.CRUSH_GRIP, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4)
|
||||||
.attr(OpponentHighHpPowerAttr, 120),
|
.attr(OpponentHighHpPowerAttr, 120),
|
||||||
new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, -1, 0, 4)
|
new AttackMove(Moves.MAGMA_STORM, Type.FIRE, MoveCategory.SPECIAL, 100, 75, 5, -1, 0, 4)
|
||||||
|
|
|
@ -21,8 +21,9 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
||||||
private revive: boolean;
|
private revive: boolean;
|
||||||
private healStatus: boolean;
|
private healStatus: boolean;
|
||||||
private preventFullHeal: boolean;
|
private preventFullHeal: boolean;
|
||||||
|
private fullRestorePP: boolean;
|
||||||
|
|
||||||
constructor(scene: BattleScene, battlerIndex: BattlerIndex, hpHealed: integer, message: string | null, showFullHpMessage: boolean, skipAnim: boolean = false, revive: boolean = false, healStatus: boolean = false, preventFullHeal: boolean = false) {
|
constructor(scene: BattleScene, battlerIndex: BattlerIndex, hpHealed: integer, message: string | null, showFullHpMessage: boolean, skipAnim: boolean = false, revive: boolean = false, healStatus: boolean = false, preventFullHeal: boolean = false, fullRestorePP: boolean = false) {
|
||||||
super(scene, battlerIndex, undefined, CommonAnim.HEALTH_UP);
|
super(scene, battlerIndex, undefined, CommonAnim.HEALTH_UP);
|
||||||
|
|
||||||
this.hpHealed = hpHealed;
|
this.hpHealed = hpHealed;
|
||||||
|
@ -32,6 +33,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
||||||
this.revive = revive;
|
this.revive = revive;
|
||||||
this.healStatus = healStatus;
|
this.healStatus = healStatus;
|
||||||
this.preventFullHeal = preventFullHeal;
|
this.preventFullHeal = preventFullHeal;
|
||||||
|
this.fullRestorePP = fullRestorePP;
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
|
@ -86,6 +88,13 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
||||||
lastStatusEffect = pokemon.status.effect;
|
lastStatusEffect = pokemon.status.effect;
|
||||||
pokemon.resetStatus();
|
pokemon.resetStatus();
|
||||||
}
|
}
|
||||||
|
if (this.fullRestorePP) {
|
||||||
|
for (const move of this.getPokemon().getMoveset()) {
|
||||||
|
if (move) {
|
||||||
|
move.ppUsed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pokemon.updateInfo().then(() => super.end());
|
pokemon.updateInfo().then(() => super.end());
|
||||||
} else if (this.healStatus && !this.revive && pokemon.status) {
|
} else if (this.healStatus && !this.revive && pokemon.status) {
|
||||||
lastStatusEffect = pokemon.status.effect;
|
lastStatusEffect = pokemon.status.effect;
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import { StatusEffect } from "#app/enums/status-effect";
|
||||||
|
import { CommandPhase } from "#app/phases/command-phase";
|
||||||
|
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 } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Lunar Dance", () => {
|
||||||
|
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
|
||||||
|
.statusEffect(StatusEffect.BURN)
|
||||||
|
.battleType("double")
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should full restore HP, PP and status of switched in pokemon, then fail second use because no remaining backup pokemon in party", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.BULBASAUR, Species.ODDISH, Species.RATTATA ]);
|
||||||
|
|
||||||
|
const [ bulbasaur, oddish, rattata ] = game.scene.getPlayerParty();
|
||||||
|
game.move.changeMoveset(bulbasaur, [ Moves.LUNAR_DANCE, Moves.SPLASH ]);
|
||||||
|
game.move.changeMoveset(oddish, [ Moves.LUNAR_DANCE, Moves.SPLASH ]);
|
||||||
|
game.move.changeMoveset(rattata, [ Moves.LUNAR_DANCE, Moves.SPLASH ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH, 0);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.phaseInterceptor.to(CommandPhase);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
// Bulbasaur should still be burned and have used a PP for splash and not at max hp
|
||||||
|
expect(bulbasaur.status?.effect).toBe(StatusEffect.BURN);
|
||||||
|
expect(bulbasaur.moveset[1]?.ppUsed).toBe(1);
|
||||||
|
expect(bulbasaur.hp).toBeLessThan(bulbasaur.getMaxHp());
|
||||||
|
|
||||||
|
// Switch out Bulbasaur for Rattata so we can swtich bulbasaur back in with lunar dance
|
||||||
|
game.doSwitchPokemon(2);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.phaseInterceptor.to(CommandPhase);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH, 0);
|
||||||
|
game.move.select(Moves.LUNAR_DANCE);
|
||||||
|
game.doSelectPartyPokemon(2);
|
||||||
|
await game.phaseInterceptor.to("SwitchPhase", false);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
// Bulbasaur should NOT have any status and have full PP for splash and be at max hp
|
||||||
|
expect(bulbasaur.status?.effect).toBeUndefined();
|
||||||
|
expect(bulbasaur.moveset[1]?.ppUsed).toBe(0);
|
||||||
|
expect(bulbasaur.isFullHp()).toBe(true);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH, 0);
|
||||||
|
game.move.select(Moves.LUNAR_DANCE);
|
||||||
|
await game.phaseInterceptor.to(CommandPhase);
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
// Using Lunar dance again should fail because nothing in party and rattata should be alive
|
||||||
|
expect(rattata.status?.effect).toBe(StatusEffect.BURN);
|
||||||
|
expect(rattata.hp).toBeLessThan(rattata.getMaxHp());
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue