pokerogue/src/evolution-phase.ts

447 lines
14 KiB
TypeScript
Raw Normal View History

2023-04-10 10:54:06 -07:00
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
2023-04-10 11:12:01 -07:00
import { BattlePhase } from "./battle-phase";
2023-04-10 10:54:06 -07:00
import BattleScene from "./battle-scene";
2023-04-20 12:46:05 -07:00
import { SpeciesEvolution } from "./data/pokemon-evolutions";
2023-04-10 10:54:06 -07:00
import EvolutionSceneHandler from "./ui/evolution-scene-handler";
import * as Utils from "./utils";
import { Mode } from "./ui/ui";
2023-04-10 11:12:01 -07:00
import { LearnMovePhase } from "./battle-phases";
2023-04-10 10:54:06 -07:00
export class EvolutionPhase extends BattlePhase {
private partyMemberIndex: integer;
private evolution: SpeciesEvolution;
private lastLevel: integer;
private evolutionContainer: Phaser.GameObjects.Container;
private evolutionBaseBg: Phaser.GameObjects.Image;
private evolutionBg: Phaser.GameObjects.Video;
private evolutionBgOverlay: Phaser.GameObjects.Rectangle;
private evolutionOverlay: Phaser.GameObjects.Rectangle;
private pokemonSprite: Phaser.GameObjects.Sprite;
private pokemonTintSprite: Phaser.GameObjects.Sprite;
private pokemonEvoSprite: Phaser.GameObjects.Sprite;
private pokemonEvoTintSprite: Phaser.GameObjects.Sprite;
constructor(scene: BattleScene, partyMemberIndex: integer, evolution: SpeciesEvolution, lastLevel: integer) {
super(scene);
this.partyMemberIndex = partyMemberIndex;
this.evolution = evolution;
this.lastLevel = lastLevel;
}
start() {
super.start();
this.scene.ui.setModeForceTransition(Mode.EVOLUTION_SCENE).then(() => {
if (!this.evolution) {
this.end();
return;
}
this.scene.fadeOutBgm(null, false);
2023-04-10 10:54:06 -07:00
this.evolutionContainer = (this.scene.ui.getHandler() as EvolutionSceneHandler).evolutionContainer;
this.evolutionBaseBg = this.scene.add.image(0, 0, 'default_bg');
2023-04-10 10:54:06 -07:00
this.evolutionBaseBg.setOrigin(0, 0);
this.evolutionContainer.add(this.evolutionBaseBg);
this.evolutionBg = this.scene.add.video(0, 0, 'evo_bg').stop();
this.evolutionBg.setOrigin(0, 0);
this.evolutionBg.setScale(0.4359673025);
this.evolutionBg.setVisible(false);
this.evolutionContainer.add(this.evolutionBg);
this.evolutionBgOverlay = this.scene.add.rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0x262626);
this.evolutionBgOverlay.setOrigin(0, 0);
this.evolutionBgOverlay.setAlpha(0);
this.evolutionContainer.add(this.evolutionBgOverlay);
const getPokemonSprite = () => {
return this.scene.add.sprite(this.evolutionBaseBg.displayWidth / 2, this.evolutionBaseBg.displayHeight / 2, `pkmn__sub`);
};
this.evolutionContainer.add((this.pokemonSprite = getPokemonSprite()));
this.evolutionContainer.add((this.pokemonTintSprite = getPokemonSprite()));
this.evolutionContainer.add((this.pokemonEvoSprite = getPokemonSprite()));
this.evolutionContainer.add((this.pokemonEvoTintSprite = getPokemonSprite()));
this.pokemonTintSprite.setAlpha(0);
this.pokemonTintSprite.setTintFill(0xFFFFFF);
this.pokemonEvoSprite.setVisible(false);
this.pokemonEvoTintSprite.setVisible(false);
this.pokemonEvoTintSprite.setTintFill(0xFFFFFF);
this.evolutionOverlay = this.scene.add.rectangle(0, -this.scene.game.canvas.height / 6, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0xFFFFFF);
this.evolutionOverlay.setOrigin(0, 0);
this.evolutionOverlay.setAlpha(0);
this.scene.fieldUI.add(this.evolutionOverlay);
const pokemon = this.scene.getParty()[this.partyMemberIndex];
const preName = pokemon.name;
this.pokemonSprite.play(pokemon.getSpriteKey());
this.pokemonTintSprite.play(pokemon.getSpriteKey());
this.pokemonEvoSprite.play(pokemon.getSpriteKey());
this.pokemonEvoTintSprite.play(pokemon.getSpriteKey());
this.scene.ui.showText(`What?\n${preName} is evolving!`, null, () => {
pokemon.cry();
pokemon.evolve(this.evolution).then(() => {
this.pokemonEvoSprite.play(pokemon.getSpriteKey());
this.pokemonEvoTintSprite.play(pokemon.getSpriteKey());
});
const levelMoves = pokemon.getLevelMoves(this.lastLevel + 1);
for (let lm of levelMoves)
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, lm));
this.scene.unshiftPhase(new EndEvolutionPhase(this.scene));
2023-04-10 10:54:06 -07:00
this.scene.time.delayedCall(1000, () => {
const evolutionBgm = this.scene.sound.add('evolution');
2023-10-21 05:58:39 -07:00
evolutionBgm.play({ volume: this.scene.gameVolume });
2023-04-10 10:54:06 -07:00
this.scene.tweens.add({
targets: this.evolutionBgOverlay,
alpha: 1,
delay: 500,
duration: 1500,
ease: 'Sine.easeOut',
onComplete: () => {
this.scene.time.delayedCall(1000, () => {
this.scene.tweens.add({
targets: this.evolutionBgOverlay,
alpha: 0,
duration: 250
});
this.evolutionBg.setVisible(true);
this.evolutionBg.play();
});
2023-10-21 05:58:39 -07:00
this.scene.playSound('charge');
2023-04-10 10:54:06 -07:00
this.doSpiralUpward();
this.scene.tweens.addCounter({
from: 0,
to: 1,
duration: 2000,
onUpdate: t => {
this.pokemonTintSprite.setAlpha(t.getValue());
},
onComplete: () => {
this.pokemonSprite.setVisible(false);
this.scene.time.delayedCall(1100, () => {
2023-10-21 05:58:39 -07:00
this.scene.playSound('beam');
2023-04-10 10:54:06 -07:00
this.doArcDownward();
this.scene.time.delayedCall(1500, () => {
this.pokemonEvoTintSprite.setScale(0.25);
this.pokemonEvoTintSprite.setVisible(true);
this.doCycle(1).then(() => {
2023-10-21 05:58:39 -07:00
this.scene.playSound('sparkle');
2023-04-10 10:54:06 -07:00
this.pokemonEvoSprite.setVisible(true);
this.doCircleInward();
this.scene.time.delayedCall(900, () => {
2023-10-21 05:58:39 -07:00
this.scene.playSound('shine');
2023-04-10 10:54:06 -07:00
this.doSpray();
this.scene.tweens.add({
targets: this.evolutionOverlay,
alpha: 1,
duration: 250,
easing: 'Sine.easeIn',
onComplete: () => {
this.evolutionBgOverlay.setAlpha(1);
this.evolutionBg.setVisible(false);
this.scene.tweens.add({
targets: [ this.evolutionOverlay, this.pokemonEvoTintSprite ],
alpha: 0,
duration: 2000,
delay: 150,
easing: 'Sine.easeIn',
onComplete: () => {
this.scene.tweens.add({
targets: this.evolutionBgOverlay,
alpha: 0,
duration: 250,
onComplete: () => {
SoundFade.fadeOut(this.scene, evolutionBgm, 100);
this.scene.time.delayedCall(250, () => {
pokemon.cry();
this.scene.time.delayedCall(1250, () => {
2023-10-21 05:58:39 -07:00
this.scene.playSound('evolution_fanfare');
2023-04-10 10:54:06 -07:00
this.scene.ui.showText(`Congratulations! Your ${preName}\nevolved into ${pokemon.name}!`, null, () => this.end(), null, true, 3000);
2023-04-28 22:40:24 -07:00
this.scene.time.delayedCall(new Utils.FixedInt(4250) as unknown as integer, () => this.scene.playBgm());
2023-04-10 10:54:06 -07:00
});
});
}
});
}
});
}
})
});
});
});
});
}
})
}
});
});
}, 1000);
});
}
sin(index: integer, amplitude: integer): number {
return amplitude * Math.sin(index * (Math.PI / 128));
}
cos(index: integer, amplitude: integer): number {
return amplitude * Math.cos(index * (Math.PI / 128));
}
doSpiralUpward() {
let f = 0;
this.scene.tweens.addCounter({
repeat: 64,
2023-06-04 18:47:43 -07:00
duration: Utils.getFrameMs(1),
2023-04-10 10:54:06 -07:00
onRepeat: () => {
if (f < 64) {
if (!(f & 7)) {
for (let i = 0; i < 4; i++)
this.doSpiralUpwardParticle((f & 120) * 2 + i * 64);
}
f++;
}
}
});
}
doArcDownward() {
let f = 0;
this.scene.tweens.addCounter({
repeat: 96,
2023-06-04 18:47:43 -07:00
duration: Utils.getFrameMs(1),
2023-04-10 10:54:06 -07:00
onRepeat: () => {
if (f < 96) {
if (f < 6) {
for (let i = 0; i < 9; i++)
this.doArcDownParticle(i * 16);
}
f++;
}
}
});
}
doCycle(l: number): Promise<void> {
return new Promise(resolve => {
const isLastCycle = l === 15;
this.scene.tweens.add({
targets: this.pokemonTintSprite,
scale: 0.25,
ease: 'Cubic.easeInOut',
duration: 500 / l,
yoyo: !isLastCycle
});
this.scene.tweens.add({
targets: this.pokemonEvoTintSprite,
scale: 1,
ease: 'Cubic.easeInOut',
duration: 500 / l,
yoyo: !isLastCycle,
onComplete: () => {
if (l < 15)
this.doCycle(l + 0.5).then(() => resolve());
else {
this.pokemonTintSprite.setVisible(false);
resolve();
}
}
});
});
}
doCircleInward() {
let f = 0;
this.scene.tweens.addCounter({
repeat: 48,
2023-06-04 18:47:43 -07:00
duration: Utils.getFrameMs(1),
2023-04-10 10:54:06 -07:00
onRepeat: () => {
if (!f) {
for (let i = 0; i < 16; i++)
this.doCircleInwardParticle(i * 16, 4);
} else if (f === 32) {
for (let i = 0; i < 16; i++)
this.doCircleInwardParticle(i * 16, 8);
}
f++;
}
});
}
doSpray() {
let f = 0;
this.scene.tweens.addCounter({
repeat: 48,
2023-06-04 18:47:43 -07:00
duration: Utils.getFrameMs(1),
2023-04-10 10:54:06 -07:00
onRepeat: () => {
if (!f) {
for (let i = 0; i < 8; i++)
this.doSprayParticle(i);
} else if (f < 50)
this.doSprayParticle(Utils.randInt(8));
f++;
}
});
}
doSpiralUpwardParticle(trigIndex: integer) {
const initialX = this.evolutionBaseBg.displayWidth / 2;
const particle = this.scene.add.image(initialX, 0, 'evo_sparkle');
this.evolutionContainer.add(particle);
let f = 0;
let amp = 48;
const particleTimer = this.scene.tweens.addCounter({
repeat: -1,
2023-06-04 18:47:43 -07:00
duration: Utils.getFrameMs(1),
2023-04-10 10:54:06 -07:00
onRepeat: () => {
updateParticle();
}
});
const updateParticle = () => {
if (!f || particle.y > 8) {
particle.setPosition(initialX, 88 - (f * f) / 80);
particle.y += this.sin(trigIndex, amp) / 4;
particle.x += this.cos(trigIndex, amp);
particle.setScale(1 - (f / 80));
trigIndex += 4;
if (f & 1)
amp--;
f++;
} else {
particle.destroy();
particleTimer.remove();
}
};
updateParticle();
}
doArcDownParticle(trigIndex: integer) {
const initialX = this.evolutionBaseBg.displayWidth / 2;
const particle = this.scene.add.image(initialX, 0, 'evo_sparkle');
particle.setScale(0.5);
this.evolutionContainer.add(particle);
let f = 0;
let amp = 8;
const particleTimer = this.scene.tweens.addCounter({
repeat: -1,
2023-06-04 18:47:43 -07:00
duration: Utils.getFrameMs(1),
2023-04-10 10:54:06 -07:00
onRepeat: () => {
updateParticle();
}
});
const updateParticle = () => {
if (!f || particle.y < 88) {
particle.setPosition(initialX, 8 + (f * f) / 5);
particle.y += this.sin(trigIndex, amp) / 4;
particle.x += this.cos(trigIndex, amp);
amp = 8 + this.sin(f * 4, 40);
f++;
} else {
particle.destroy();
particleTimer.remove();
}
};
updateParticle();
}
doCircleInwardParticle(trigIndex: integer, speed: integer) {
const initialX = this.evolutionBaseBg.displayWidth / 2;
const initialY = this.evolutionBaseBg.displayHeight / 2;
const particle = this.scene.add.image(initialX, initialY, 'evo_sparkle');
this.evolutionContainer.add(particle);
let amp = 120;
const particleTimer = this.scene.tweens.addCounter({
repeat: -1,
2023-06-04 18:47:43 -07:00
duration: Utils.getFrameMs(1),
2023-04-10 10:54:06 -07:00
onRepeat: () => {
updateParticle();
}
});
const updateParticle = () => {
if (amp > 8) {
particle.setPosition(initialX, initialY);
particle.y += this.sin(trigIndex, amp);
particle.x += this.cos(trigIndex, amp);
amp -= speed;
trigIndex += 4;
} else {
particle.destroy();
particleTimer.remove();
}
};
updateParticle();
}
doSprayParticle(trigIndex: integer) {
const initialX = this.evolutionBaseBg.displayWidth / 2;
const initialY = this.evolutionBaseBg.displayHeight / 2;
const particle = this.scene.add.image(initialX, initialY, 'evo_sparkle');
this.evolutionContainer.add(particle);
let f = 0;
let yOffset = 0;
let speed = 3 - Utils.randInt(8);
let amp = 48 + Utils.randInt(64);
const particleTimer = this.scene.tweens.addCounter({
repeat: -1,
2023-06-04 18:47:43 -07:00
duration: Utils.getFrameMs(1),
2023-04-10 10:54:06 -07:00
onRepeat: () => {
updateParticle();
}
});
const updateParticle = () => {
if (!(f & 3))
yOffset++;
if (trigIndex < 128) {
particle.setPosition(initialX + (speed * f) / 3, initialY + yOffset);
particle.y += -this.sin(trigIndex, amp);
if (f > 108)
particle.setScale((1 - (f - 108) / 20));
trigIndex++;
f++;
} else {
particle.destroy();
particleTimer.remove();
}
};
updateParticle();
}
}
export class EndEvolutionPhase extends BattlePhase {
start() {
super.start();
this.scene.ui.setModeForceTransition(Mode.MESSAGE).then(() => this.end());
}
2023-04-10 10:54:06 -07:00
}