pokerogue/src/phases/pokemon-anim-phase.ts
Bertie690 a41de39d4f
[Misc] Run biome on all files; update some rules to be errors now
https://github.com/pagefaultgames/pokerogue/pull/5962/

* Fixed lint issue; ran biome on entire repository

* Fixed biome.jsonc

* Trimmed trailing whitespace... again...

* Fixed PR template md

* Fixed package json

* Fixed void return issues + ran biome again

* ran biome
2025-06-14 00:59:34 -07:00

396 lines
11 KiB
TypeScript

import { globalScene } from "#app/global-scene";
import { SubstituteTag } from "#app/data/battler-tags";
import type Pokemon from "#app/field/pokemon";
import { BattlePhase } from "#app/phases/battle-phase";
import { isNullOrUndefined } from "#app/utils/common";
import { PokemonAnimType } from "#enums/pokemon-anim-type";
import { SpeciesId } from "#enums/species-id";
export class PokemonAnimPhase extends BattlePhase {
public readonly phaseName = "PokemonAnimPhase";
/** The type of animation to play in this phase */
protected key: PokemonAnimType;
/** The Pokemon to which this animation applies */
protected pokemon: Pokemon;
/** Any other field sprites affected by this animation */
protected fieldAssets: Phaser.GameObjects.Sprite[];
constructor(key: PokemonAnimType, pokemon: Pokemon, fieldAssets: Phaser.GameObjects.Sprite[] = []) {
super();
this.key = key;
this.pokemon = pokemon;
this.fieldAssets = fieldAssets;
}
start(): void {
super.start();
switch (this.key) {
case PokemonAnimType.SUBSTITUTE_ADD:
this.doSubstituteAddAnim();
break;
case PokemonAnimType.SUBSTITUTE_PRE_MOVE:
this.doSubstitutePreMoveAnim();
break;
case PokemonAnimType.SUBSTITUTE_POST_MOVE:
this.doSubstitutePostMoveAnim();
break;
case PokemonAnimType.SUBSTITUTE_REMOVE:
this.doSubstituteRemoveAnim();
break;
case PokemonAnimType.COMMANDER_APPLY:
this.doCommanderApplyAnim();
break;
case PokemonAnimType.COMMANDER_REMOVE:
this.doCommanderRemoveAnim();
break;
default:
this.end();
}
}
private doSubstituteAddAnim(): void {
const substitute = this.pokemon.getTag(SubstituteTag);
if (isNullOrUndefined(substitute)) {
this.end();
return;
}
const getSprite = () => {
const sprite = globalScene.addFieldSprite(
this.pokemon.x + this.pokemon.getSprite().x,
this.pokemon.y + this.pokemon.getSprite().y,
`pkmn${this.pokemon.isPlayer() ? "__back" : ""}__sub`,
);
sprite.setOrigin(0.5, 1);
globalScene.field.add(sprite);
return sprite;
};
const [subSprite, subTintSprite] = [getSprite(), getSprite()];
const subScale = this.pokemon.getSpriteScale() * (this.pokemon.isPlayer() ? 0.5 : 1);
subSprite.setVisible(false);
subSprite.setScale(subScale);
subTintSprite.setTintFill(0xffffff);
subTintSprite.setScale(0.01);
if (this.pokemon.isPlayer()) {
globalScene.field.bringToTop(this.pokemon);
}
globalScene.playSound("PRSFX- Transform");
globalScene.tweens.add({
targets: this.pokemon,
duration: 500,
x: this.pokemon.x + this.pokemon.getSubstituteOffset()[0],
y: this.pokemon.y + this.pokemon.getSubstituteOffset()[1],
alpha: 0.5,
ease: "Sine.easeIn",
});
globalScene.tweens.add({
targets: subTintSprite,
delay: 250,
scale: subScale,
ease: "Cubic.easeInOut",
duration: 500,
onComplete: () => {
subSprite.setVisible(true);
globalScene.tweens.add({
targets: subTintSprite,
delay: 250,
alpha: 0,
ease: "Cubic.easeOut",
duration: 1000,
onComplete: () => {
subTintSprite.destroy();
substitute.sprite = subSprite;
this.end();
},
});
},
});
}
private doSubstitutePreMoveAnim(): void {
if (this.fieldAssets.length !== 1) {
this.end();
return;
}
const subSprite = this.fieldAssets[0];
if (subSprite === undefined) {
this.end();
return;
}
globalScene.tweens.add({
targets: subSprite,
alpha: 0,
ease: "Sine.easeInOut",
duration: 500,
});
globalScene.tweens.add({
targets: this.pokemon,
x: subSprite.x,
y: subSprite.y,
alpha: 1,
ease: "Sine.easeInOut",
delay: 250,
duration: 500,
onComplete: () => this.end(),
});
}
private doSubstitutePostMoveAnim(): void {
if (this.fieldAssets.length !== 1) {
this.end();
return;
}
const subSprite = this.fieldAssets[0];
if (subSprite === undefined) {
this.end();
return;
}
globalScene.tweens.add({
targets: this.pokemon,
x: subSprite.x + this.pokemon.getSubstituteOffset()[0],
y: subSprite.y + this.pokemon.getSubstituteOffset()[1],
alpha: 0.5,
ease: "Sine.easeInOut",
duration: 500,
});
globalScene.tweens.add({
targets: subSprite,
alpha: 1,
ease: "Sine.easeInOut",
delay: 250,
duration: 500,
onComplete: () => this.end(),
});
}
private doSubstituteRemoveAnim(): void {
if (this.fieldAssets.length !== 1) {
this.end();
return;
}
const subSprite = this.fieldAssets[0];
if (subSprite === undefined) {
this.end();
return;
}
const getSprite = () => {
const sprite = globalScene.addFieldSprite(
subSprite.x,
subSprite.y,
`pkmn${this.pokemon.isPlayer() ? "__back" : ""}__sub`,
);
sprite.setOrigin(0.5, 1);
globalScene.field.add(sprite);
return sprite;
};
const subTintSprite = getSprite();
const subScale = this.pokemon.getSpriteScale() * (this.pokemon.isPlayer() ? 0.5 : 1);
subTintSprite.setAlpha(0);
subTintSprite.setTintFill(0xffffff);
subTintSprite.setScale(subScale);
globalScene.tweens.add({
targets: subTintSprite,
alpha: 1,
ease: "Sine.easeInOut",
duration: 500,
onComplete: () => {
subSprite.destroy();
const flashTimer = globalScene.time.addEvent({
delay: 100,
repeat: 7,
startAt: 200,
callback: () => {
globalScene.playSound("PRSFX- Substitute2.wav");
subTintSprite.setVisible(flashTimer.repeatCount % 2 === 0);
if (!flashTimer.repeatCount) {
globalScene.tweens.add({
targets: subTintSprite,
scale: 0.01,
ease: "Sine.cubicEaseIn",
duration: 500,
});
globalScene.tweens.add({
targets: this.pokemon,
x: this.pokemon.x - this.pokemon.getSubstituteOffset()[0],
y: this.pokemon.y - this.pokemon.getSubstituteOffset()[1],
alpha: 1,
ease: "Sine.easeInOut",
delay: 250,
duration: 500,
onComplete: () => {
subTintSprite.destroy();
this.end();
},
});
}
},
});
},
});
}
private doCommanderApplyAnim(): void {
if (!globalScene.currentBattle?.double) {
this.end();
return;
}
const dondozo = this.pokemon.getAlly();
if (dondozo?.species?.speciesId !== SpeciesId.DONDOZO) {
this.end();
return;
}
const tatsugiriX = this.pokemon.x + this.pokemon.getSprite().x;
const tatsugiriY = this.pokemon.y + this.pokemon.getSprite().y;
const getSourceSprite = () => {
const sprite = globalScene.addPokemonSprite(
this.pokemon,
tatsugiriX,
tatsugiriY,
this.pokemon.getSprite().texture,
this.pokemon.getSprite()!.frame.name,
true,
);
["spriteColors", "fusionSpriteColors"].map(
k => (sprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k]),
);
sprite.setPipelineData("spriteKey", this.pokemon.getBattleSpriteKey());
sprite.setPipelineData("shiny", this.pokemon.shiny);
sprite.setPipelineData("variant", this.pokemon.variant);
sprite.setPipelineData("ignoreFieldPos", true);
sprite.setOrigin(0.5, 1);
this.pokemon.getSprite().on("animationupdate", (_anim, frame) => sprite.setFrame(frame.textureFrame));
globalScene.field.add(sprite);
return sprite;
};
const sourceSprite = getSourceSprite();
this.pokemon.setVisible(false);
const sourceFpOffset = this.pokemon.getFieldPositionOffset();
const dondozoFpOffset = dondozo.getFieldPositionOffset();
globalScene.playSound("se/pb_throw");
globalScene.tweens.add({
targets: sourceSprite,
duration: 375,
scale: 0.5,
x: {
value: tatsugiriX + (dondozoFpOffset[0] - sourceFpOffset[0]) / 2,
ease: "Linear",
},
y: {
value: (this.pokemon.isPlayer() ? 100 : 65) + sourceFpOffset[1],
ease: "Sine.easeOut",
},
onComplete: () => {
globalScene.field.bringToTop(dondozo);
globalScene.tweens.add({
targets: sourceSprite,
duration: 375,
scale: 0.01,
x: { value: dondozo.x, ease: "Linear" },
y: { value: dondozo.y + dondozo.height / 2, ease: "Sine.easeIn" },
onComplete: () => {
sourceSprite.destroy();
globalScene.playSound("battle_anims/PRSFX- Liquidation1.wav");
globalScene.tweens.add({
targets: dondozo,
duration: 250,
ease: "Sine.easeInOut",
scale: 0.85,
yoyo: true,
onComplete: () => this.end(),
});
},
});
},
});
}
private doCommanderRemoveAnim(): void {
// Note: unlike the other Commander animation, this is played through the
// Dondozo instead of the Tatsugiri.
const tatsugiri = this.pokemon.getAlly();
if (isNullOrUndefined(tatsugiri)) {
console.warn("Aborting COMMANDER_REMOVE anim: Tatsugiri is undefined");
this.end();
return;
}
const tatsuSprite = globalScene.addPokemonSprite(
tatsugiri,
this.pokemon.x + this.pokemon.getSprite().x,
this.pokemon.y + this.pokemon.getSprite().y + this.pokemon.height / 2,
tatsugiri.getSprite().texture,
tatsugiri.getSprite()!.frame.name,
true,
);
["spriteColors", "fusionSpriteColors"].map(
k => (tatsuSprite.pipelineData[k] = tatsugiri.getSprite().pipelineData[k]),
);
tatsuSprite.setPipelineData("spriteKey", tatsugiri.getBattleSpriteKey());
tatsuSprite.setPipelineData("shiny", tatsugiri.shiny);
tatsuSprite.setPipelineData("variant", tatsugiri.variant);
tatsuSprite.setPipelineData("ignoreFieldPos", true);
this.pokemon.getSprite().on("animationupdate", (_anim, frame) => tatsuSprite.setFrame(frame.textureFrame));
tatsuSprite.setOrigin(0.5, 1);
tatsuSprite.setScale(0.01);
globalScene.field.add(tatsuSprite);
globalScene.field.bringToTop(this.pokemon);
tatsuSprite.setVisible(true);
globalScene.tweens.add({
targets: this.pokemon,
duration: 250,
ease: "Sine.easeInOut",
scale: 1.15,
yoyo: true,
onComplete: () => {
globalScene.playSound("battle_anims/PRSFX- Liquidation4.wav");
globalScene.tweens.add({
targets: tatsuSprite,
duration: 500,
scale: 1,
x: { value: tatsugiri.x + tatsugiri.getSprite().x, ease: "Linear" },
y: {
value: tatsugiri.y + tatsugiri.getSprite().y,
ease: "Sine.easeIn",
},
onComplete: () => {
tatsugiri.setVisible(true);
tatsuSprite.destroy();
this.end();
},
});
},
});
}
}