mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-21 17:12:44 +02:00
Merge 7ea2d3a4cd
into 6873a89296
This commit is contained in:
commit
52a5e4826e
@ -23,6 +23,8 @@ export class EvolutionPhase extends Phase {
|
|||||||
protected pokemon: PlayerPokemon;
|
protected pokemon: PlayerPokemon;
|
||||||
protected lastLevel: number;
|
protected lastLevel: number;
|
||||||
|
|
||||||
|
protected evoChain: Phaser.Tweens.TweenChain | null = null;
|
||||||
|
|
||||||
private preEvolvedPokemonName: string;
|
private preEvolvedPokemonName: string;
|
||||||
|
|
||||||
private evolution: SpeciesFormEvolution | null;
|
private evolution: SpeciesFormEvolution | null;
|
||||||
@ -40,13 +42,23 @@ export class EvolutionPhase extends Phase {
|
|||||||
protected pokemonEvoSprite: Phaser.GameObjects.Sprite;
|
protected pokemonEvoSprite: Phaser.GameObjects.Sprite;
|
||||||
protected pokemonEvoTintSprite: Phaser.GameObjects.Sprite;
|
protected pokemonEvoTintSprite: Phaser.GameObjects.Sprite;
|
||||||
|
|
||||||
constructor(pokemon: PlayerPokemon, evolution: SpeciesFormEvolution | null, lastLevel: number) {
|
/** Whether the evolution can be cancelled by the player */
|
||||||
|
protected canCancel: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pokemon - The Pokemon that is evolving
|
||||||
|
* @param evolution - The form being evolved into
|
||||||
|
* @param lastLevel - The level at which the Pokemon is evolving
|
||||||
|
* @param canCancel - Whether the evolution can be cancelled by the player
|
||||||
|
*/
|
||||||
|
constructor(pokemon: PlayerPokemon, evolution: SpeciesFormEvolution | null, lastLevel: number, canCancel = true) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.pokemon = pokemon;
|
this.pokemon = pokemon;
|
||||||
this.evolution = evolution;
|
this.evolution = evolution;
|
||||||
this.lastLevel = lastLevel;
|
this.lastLevel = lastLevel;
|
||||||
this.fusionSpeciesEvolved = evolution instanceof FusionSpeciesFormEvolution;
|
this.fusionSpeciesEvolved = evolution instanceof FusionSpeciesFormEvolution;
|
||||||
|
this.canCancel = canCancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): boolean {
|
validate(): boolean {
|
||||||
@ -57,198 +69,227 @@ export class EvolutionPhase extends Phase {
|
|||||||
return globalScene.ui.setModeForceTransition(UiMode.EVOLUTION_SCENE);
|
return globalScene.ui.setModeForceTransition(UiMode.EVOLUTION_SCENE);
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
/**
|
||||||
super.start();
|
* Set up the following evolution assets
|
||||||
|
* - {@linkcode evolutionContainer}
|
||||||
|
* - {@linkcode evolutionBaseBg}
|
||||||
|
* - {@linkcode evolutionBg}
|
||||||
|
* - {@linkcode evolutionBgOverlay}
|
||||||
|
* - {@linkcode evolutionOverlay}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private setupEvolutionAssets(): void {
|
||||||
|
this.evolutionHandler = globalScene.ui.getHandler() as EvolutionSceneHandler;
|
||||||
|
this.evolutionContainer = this.evolutionHandler.evolutionContainer;
|
||||||
|
this.evolutionBaseBg = globalScene.add.image(0, 0, "default_bg").setOrigin(0);
|
||||||
|
|
||||||
this.setMode().then(() => {
|
this.evolutionBg = globalScene.add
|
||||||
if (!this.validate()) {
|
.video(0, 0, "evo_bg")
|
||||||
return this.end();
|
.stop()
|
||||||
}
|
.setOrigin(0)
|
||||||
|
.setScale(0.4359673025)
|
||||||
|
.setVisible(false);
|
||||||
|
|
||||||
globalScene.fadeOutBgm(undefined, false);
|
this.evolutionBgOverlay = globalScene.add
|
||||||
|
.rectangle(0, 0, globalScene.game.canvas.width / 6, globalScene.game.canvas.height / 6, 0x262626)
|
||||||
|
.setOrigin(0)
|
||||||
|
.setAlpha(0);
|
||||||
|
this.evolutionContainer.add([this.evolutionBaseBg, this.evolutionBgOverlay, this.evolutionBg]);
|
||||||
|
|
||||||
this.evolutionHandler = globalScene.ui.getHandler() as EvolutionSceneHandler;
|
this.evolutionOverlay = globalScene.add.rectangle(
|
||||||
|
0,
|
||||||
|
-globalScene.game.canvas.height / 6,
|
||||||
|
globalScene.game.canvas.width / 6,
|
||||||
|
globalScene.game.canvas.height / 6 - 48,
|
||||||
|
0xffffff,
|
||||||
|
);
|
||||||
|
this.evolutionOverlay.setOrigin(0).setAlpha(0);
|
||||||
|
globalScene.ui.add(this.evolutionOverlay);
|
||||||
|
}
|
||||||
|
|
||||||
this.evolutionContainer = this.evolutionHandler.evolutionContainer;
|
/**
|
||||||
|
* Configure the sprite, setting its pipeline data
|
||||||
|
* @param pokemon - The pokemon object that the sprite information is configured from
|
||||||
|
* @param sprite - The sprite object to configure
|
||||||
|
* @param setPipeline - Whether to also set the pipeline; should be false
|
||||||
|
* if the sprite is only being updated with new sprite assets
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @returns The sprite object that was passed in
|
||||||
|
*/
|
||||||
|
protected configureSprite(pokemon: Pokemon, sprite: Phaser.GameObjects.Sprite, setPipeline = true): typeof sprite {
|
||||||
|
const spriteKey = pokemon.getSpriteKey(true);
|
||||||
|
try {
|
||||||
|
sprite.play(spriteKey);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
console.error(`Failed to play animation for ${spriteKey}`, err);
|
||||||
|
}
|
||||||
|
|
||||||
this.evolutionBaseBg = globalScene.add.image(0, 0, "default_bg");
|
if (setPipeline) {
|
||||||
this.evolutionBaseBg.setOrigin(0, 0);
|
sprite.setPipeline(globalScene.spritePipeline, {
|
||||||
this.evolutionContainer.add(this.evolutionBaseBg);
|
tone: [0.0, 0.0, 0.0, 0.0],
|
||||||
|
hasShadow: false,
|
||||||
this.evolutionBg = globalScene.add.video(0, 0, "evo_bg").stop();
|
teraColor: getTypeRgb(pokemon.getTeraType()),
|
||||||
this.evolutionBg.setOrigin(0, 0);
|
isTerastallized: pokemon.isTerastallized,
|
||||||
this.evolutionBg.setScale(0.4359673025);
|
});
|
||||||
this.evolutionBg.setVisible(false);
|
}
|
||||||
this.evolutionContainer.add(this.evolutionBg);
|
|
||||||
|
sprite
|
||||||
this.evolutionBgOverlay = globalScene.add.rectangle(
|
.setPipelineData("ignoreTimeTint", true)
|
||||||
0,
|
.setPipelineData("spriteKey", pokemon.getSpriteKey())
|
||||||
0,
|
.setPipelineData("shiny", pokemon.shiny)
|
||||||
globalScene.game.canvas.width / 6,
|
.setPipelineData("variant", pokemon.variant);
|
||||||
globalScene.game.canvas.height / 6,
|
|
||||||
0x262626,
|
for (let k of ["spriteColors", "fusionSpriteColors"]) {
|
||||||
);
|
if (pokemon.summonData.speciesForm) {
|
||||||
this.evolutionBgOverlay.setOrigin(0, 0);
|
k += "Base";
|
||||||
this.evolutionBgOverlay.setAlpha(0);
|
}
|
||||||
this.evolutionContainer.add(this.evolutionBgOverlay);
|
sprite.pipelineData[k] = pokemon.getSprite().pipelineData[k];
|
||||||
|
}
|
||||||
const getPokemonSprite = () => {
|
|
||||||
const ret = globalScene.addPokemonSprite(
|
return sprite;
|
||||||
this.pokemon,
|
}
|
||||||
this.evolutionBaseBg.displayWidth / 2,
|
|
||||||
this.evolutionBaseBg.displayHeight / 2,
|
private getPokemonSprite(): Phaser.GameObjects.Sprite {
|
||||||
"pkmn__sub",
|
const sprite = globalScene.addPokemonSprite(
|
||||||
);
|
this.pokemon,
|
||||||
ret.setPipeline(globalScene.spritePipeline, {
|
this.evolutionBaseBg.displayWidth / 2,
|
||||||
tone: [0.0, 0.0, 0.0, 0.0],
|
this.evolutionBaseBg.displayHeight / 2,
|
||||||
ignoreTimeTint: true,
|
"pkmn__sub",
|
||||||
});
|
);
|
||||||
return ret;
|
sprite.setPipeline(globalScene.spritePipeline, {
|
||||||
};
|
tone: [0.0, 0.0, 0.0, 0.0],
|
||||||
|
ignoreTimeTint: true,
|
||||||
this.evolutionContainer.add((this.pokemonSprite = getPokemonSprite()));
|
});
|
||||||
this.evolutionContainer.add((this.pokemonTintSprite = getPokemonSprite()));
|
return sprite;
|
||||||
this.evolutionContainer.add((this.pokemonEvoSprite = getPokemonSprite()));
|
}
|
||||||
this.evolutionContainer.add((this.pokemonEvoTintSprite = getPokemonSprite()));
|
|
||||||
|
/**
|
||||||
this.pokemonTintSprite.setAlpha(0);
|
* Initialize {@linkcode pokemonSprite}, {@linkcode pokemonTintSprite}, {@linkcode pokemonEvoSprite}, and {@linkcode pokemonEvoTintSprite}
|
||||||
this.pokemonTintSprite.setTintFill(0xffffff);
|
* and add them to the {@linkcode evolutionContainer}
|
||||||
this.pokemonEvoSprite.setVisible(false);
|
*/
|
||||||
this.pokemonEvoTintSprite.setVisible(false);
|
private setupPokemonSprites(): void {
|
||||||
this.pokemonEvoTintSprite.setTintFill(0xffffff);
|
this.pokemonSprite = this.configureSprite(this.pokemon, this.getPokemonSprite());
|
||||||
|
this.pokemonTintSprite = this.configureSprite(
|
||||||
this.evolutionOverlay = globalScene.add.rectangle(
|
this.pokemon,
|
||||||
0,
|
this.getPokemonSprite().setAlpha(0).setTintFill(0xffffff),
|
||||||
-globalScene.game.canvas.height / 6,
|
);
|
||||||
globalScene.game.canvas.width / 6,
|
this.pokemonEvoSprite = this.configureSprite(this.pokemon, this.getPokemonSprite().setVisible(false));
|
||||||
globalScene.game.canvas.height / 6 - 48,
|
this.pokemonEvoTintSprite = this.configureSprite(
|
||||||
0xffffff,
|
this.pokemon,
|
||||||
);
|
this.getPokemonSprite().setVisible(false).setTintFill(0xffffff),
|
||||||
this.evolutionOverlay.setOrigin(0, 0);
|
);
|
||||||
this.evolutionOverlay.setAlpha(0);
|
|
||||||
globalScene.ui.add(this.evolutionOverlay);
|
this.evolutionContainer.add([
|
||||||
|
this.pokemonSprite,
|
||||||
[this.pokemonSprite, this.pokemonTintSprite, this.pokemonEvoSprite, this.pokemonEvoTintSprite].map(sprite => {
|
this.pokemonTintSprite,
|
||||||
const spriteKey = this.pokemon.getSpriteKey(true);
|
this.pokemonEvoSprite,
|
||||||
try {
|
this.pokemonEvoTintSprite,
|
||||||
sprite.play(spriteKey);
|
]);
|
||||||
} catch (err: unknown) {
|
}
|
||||||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
|
||||||
}
|
async start() {
|
||||||
|
super.start();
|
||||||
sprite.setPipeline(globalScene.spritePipeline, {
|
await this.setMode();
|
||||||
tone: [0.0, 0.0, 0.0, 0.0],
|
|
||||||
hasShadow: false,
|
if (!this.validate()) {
|
||||||
teraColor: getTypeRgb(this.pokemon.getTeraType()),
|
return this.end();
|
||||||
isTerastallized: this.pokemon.isTerastallized,
|
}
|
||||||
});
|
this.setupEvolutionAssets();
|
||||||
sprite.setPipelineData("ignoreTimeTint", true);
|
this.setupPokemonSprites();
|
||||||
sprite.setPipelineData("spriteKey", this.pokemon.getSpriteKey());
|
this.preEvolvedPokemonName = getPokemonNameWithAffix(this.pokemon);
|
||||||
sprite.setPipelineData("shiny", this.pokemon.shiny);
|
this.doEvolution();
|
||||||
sprite.setPipelineData("variant", this.pokemon.variant);
|
}
|
||||||
["spriteColors", "fusionSpriteColors"].map(k => {
|
|
||||||
if (this.pokemon.summonData.speciesForm) {
|
/**
|
||||||
k += "Base";
|
* Update the sprites depicting the evolved Pokemon
|
||||||
}
|
* @param evolvedPokemon - The evolved Pokemon
|
||||||
sprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k];
|
*/
|
||||||
});
|
private updateEvolvedPokemonSprites(evolvedPokemon: Pokemon): void {
|
||||||
|
this.configureSprite(evolvedPokemon, this.pokemonEvoSprite, false);
|
||||||
|
this.configureSprite(evolvedPokemon, this.pokemonEvoTintSprite, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the evolution tween and begins playing it
|
||||||
|
*/
|
||||||
|
private playEvolutionAnimation(evolvedPokemon: Pokemon): void {
|
||||||
|
globalScene.time.delayedCall(1000, () => {
|
||||||
|
this.evolutionBgm = globalScene.playSoundWithoutBgm("evolution");
|
||||||
|
globalScene.tweens.add({
|
||||||
|
targets: this.evolutionBgOverlay,
|
||||||
|
alpha: 1,
|
||||||
|
delay: 500,
|
||||||
|
duration: 1500,
|
||||||
|
ease: "Sine.easeOut",
|
||||||
|
onComplete: () => {
|
||||||
|
globalScene.time.delayedCall(1000, () => {
|
||||||
|
this.evolutionBg.setVisible(true).play();
|
||||||
|
});
|
||||||
|
globalScene.playSound("se/charge");
|
||||||
|
this.doSpiralUpward();
|
||||||
|
this.fadeOutPokemonSprite(evolvedPokemon);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
this.preEvolvedPokemonName = getPokemonNameWithAffix(this.pokemon);
|
|
||||||
this.doEvolution();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fadeOutPokemonSprite(evolvedPokemon: Pokemon): void {
|
||||||
|
globalScene.tweens.addCounter({
|
||||||
|
from: 0,
|
||||||
|
to: 1,
|
||||||
|
duration: 2000,
|
||||||
|
onUpdate: t => {
|
||||||
|
this.pokemonTintSprite.setAlpha(t.getValue());
|
||||||
|
},
|
||||||
|
onComplete: () => {
|
||||||
|
this.pokemonSprite.setVisible(false);
|
||||||
|
globalScene.time.delayedCall(1100, () => {
|
||||||
|
globalScene.playSound("se/beam");
|
||||||
|
this.doArcDownward();
|
||||||
|
this.prepareForCycle(evolvedPokemon);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the evolution cycle by setting up the tint sprites and starting the cycle
|
||||||
|
*/
|
||||||
|
private prepareForCycle(evolvedPokemon: Pokemon): void {
|
||||||
|
globalScene.time.delayedCall(1500, () => {
|
||||||
|
this.pokemonEvoTintSprite.setScale(0.25).setVisible(true);
|
||||||
|
this.evolutionHandler.canCancel = this.canCancel;
|
||||||
|
this.doCycle(1, undefined, () => {
|
||||||
|
if (this.evolutionHandler.cancelled) {
|
||||||
|
this.handleFailedEvolution(evolvedPokemon);
|
||||||
|
} else {
|
||||||
|
this.handleSuccessEvolution(evolvedPokemon);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the evolution text and then commence the evolution animation
|
||||||
|
*/
|
||||||
doEvolution(): void {
|
doEvolution(): void {
|
||||||
globalScene.ui.showText(
|
globalScene.ui.showText(
|
||||||
i18next.t("menu:evolving", { pokemonName: this.preEvolvedPokemonName }),
|
i18next.t("menu:evolving", { pokemonName: this.preEvolvedPokemonName }),
|
||||||
null,
|
null,
|
||||||
() => {
|
() => {
|
||||||
this.pokemon.cry();
|
this.pokemon.cry();
|
||||||
|
|
||||||
this.pokemon.getPossibleEvolution(this.evolution).then(evolvedPokemon => {
|
this.pokemon.getPossibleEvolution(this.evolution).then(evolvedPokemon => {
|
||||||
[this.pokemonEvoSprite, this.pokemonEvoTintSprite].map(sprite => {
|
this.updateEvolvedPokemonSprites(evolvedPokemon);
|
||||||
const spriteKey = evolvedPokemon.getSpriteKey(true);
|
this.playEvolutionAnimation(evolvedPokemon);
|
||||||
try {
|
|
||||||
sprite.play(spriteKey);
|
|
||||||
} catch (err: unknown) {
|
|
||||||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
sprite.setPipelineData("ignoreTimeTint", true);
|
|
||||||
sprite.setPipelineData("spriteKey", evolvedPokemon.getSpriteKey());
|
|
||||||
sprite.setPipelineData("shiny", evolvedPokemon.shiny);
|
|
||||||
sprite.setPipelineData("variant", evolvedPokemon.variant);
|
|
||||||
["spriteColors", "fusionSpriteColors"].map(k => {
|
|
||||||
if (evolvedPokemon.summonData.speciesForm) {
|
|
||||||
k += "Base";
|
|
||||||
}
|
|
||||||
sprite.pipelineData[k] = evolvedPokemon.getSprite().pipelineData[k];
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
globalScene.time.delayedCall(1000, () => {
|
|
||||||
this.evolutionBgm = globalScene.playSoundWithoutBgm("evolution");
|
|
||||||
globalScene.tweens.add({
|
|
||||||
targets: this.evolutionBgOverlay,
|
|
||||||
alpha: 1,
|
|
||||||
delay: 500,
|
|
||||||
duration: 1500,
|
|
||||||
ease: "Sine.easeOut",
|
|
||||||
onComplete: () => {
|
|
||||||
globalScene.time.delayedCall(1000, () => {
|
|
||||||
globalScene.tweens.add({
|
|
||||||
targets: this.evolutionBgOverlay,
|
|
||||||
alpha: 0,
|
|
||||||
duration: 250,
|
|
||||||
});
|
|
||||||
this.evolutionBg.setVisible(true);
|
|
||||||
this.evolutionBg.play();
|
|
||||||
});
|
|
||||||
globalScene.playSound("se/charge");
|
|
||||||
this.doSpiralUpward();
|
|
||||||
globalScene.tweens.addCounter({
|
|
||||||
from: 0,
|
|
||||||
to: 1,
|
|
||||||
duration: 2000,
|
|
||||||
onUpdate: t => {
|
|
||||||
this.pokemonTintSprite.setAlpha(t.getValue());
|
|
||||||
},
|
|
||||||
onComplete: () => {
|
|
||||||
this.pokemonSprite.setVisible(false);
|
|
||||||
globalScene.time.delayedCall(1100, () => {
|
|
||||||
globalScene.playSound("se/beam");
|
|
||||||
this.doArcDownward();
|
|
||||||
globalScene.time.delayedCall(1500, () => {
|
|
||||||
this.pokemonEvoTintSprite.setScale(0.25);
|
|
||||||
this.pokemonEvoTintSprite.setVisible(true);
|
|
||||||
this.evolutionHandler.canCancel = true;
|
|
||||||
this.doCycle(1).then(success => {
|
|
||||||
if (success) {
|
|
||||||
this.handleSuccessEvolution(evolvedPokemon);
|
|
||||||
} else {
|
|
||||||
this.handleFailedEvolution(evolvedPokemon);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
1000,
|
1000,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Used exclusively by {@linkcode handleFailedEvolution} to fade out the evolution sprites and music */
|
||||||
* Handles a failed/stopped evolution
|
private fadeOutEvolutionAssets(): void {
|
||||||
* @param evolvedPokemon - The evolved Pokemon
|
|
||||||
*/
|
|
||||||
private handleFailedEvolution(evolvedPokemon: Pokemon): void {
|
|
||||||
this.pokemonSprite.setVisible(true);
|
|
||||||
this.pokemonTintSprite.setScale(1);
|
|
||||||
globalScene.tweens.add({
|
globalScene.tweens.add({
|
||||||
targets: [this.evolutionBg, this.pokemonTintSprite, this.pokemonEvoSprite, this.pokemonEvoTintSprite],
|
targets: [this.evolutionBg, this.pokemonTintSprite, this.pokemonEvoSprite, this.pokemonEvoTintSprite],
|
||||||
alpha: 0,
|
alpha: 0,
|
||||||
@ -257,9 +298,40 @@ export class EvolutionPhase extends Phase {
|
|||||||
this.evolutionBg.setVisible(false);
|
this.evolutionBg.setVisible(false);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100);
|
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the confirmation prompt for pausing evolutions
|
||||||
|
* @param endCallback - The callback to call after either option is selected.
|
||||||
|
* This should end the evolution phase
|
||||||
|
*/
|
||||||
|
private showPauseEvolutionConfirmation(endCallback: () => void): void {
|
||||||
|
globalScene.ui.setOverlayMode(
|
||||||
|
UiMode.CONFIRM,
|
||||||
|
() => {
|
||||||
|
globalScene.ui.revertMode();
|
||||||
|
this.pokemon.pauseEvolutions = true;
|
||||||
|
globalScene.ui.showText(
|
||||||
|
i18next.t("menu:evolutionsPaused", {
|
||||||
|
pokemonName: this.preEvolvedPokemonName,
|
||||||
|
}),
|
||||||
|
null,
|
||||||
|
endCallback,
|
||||||
|
3000,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
globalScene.ui.revertMode();
|
||||||
|
globalScene.time.delayedCall(3000, endCallback);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used exclusively by {@linkcode handleFailedEvolution} to show the failed evolution UI messages
|
||||||
|
*/
|
||||||
|
private showFailedEvolutionUI(evolvedPokemon: Pokemon): void {
|
||||||
globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
|
globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
|
||||||
|
|
||||||
globalScene.ui.showText(
|
globalScene.ui.showText(
|
||||||
@ -280,25 +352,7 @@ export class EvolutionPhase extends Phase {
|
|||||||
evolvedPokemon.destroy();
|
evolvedPokemon.destroy();
|
||||||
this.end();
|
this.end();
|
||||||
};
|
};
|
||||||
globalScene.ui.setOverlayMode(
|
this.showPauseEvolutionConfirmation(end);
|
||||||
UiMode.CONFIRM,
|
|
||||||
() => {
|
|
||||||
globalScene.ui.revertMode();
|
|
||||||
this.pokemon.pauseEvolutions = true;
|
|
||||||
globalScene.ui.showText(
|
|
||||||
i18next.t("menu:evolutionsPaused", {
|
|
||||||
pokemonName: this.preEvolvedPokemonName,
|
|
||||||
}),
|
|
||||||
null,
|
|
||||||
end,
|
|
||||||
3000,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
globalScene.ui.revertMode();
|
|
||||||
globalScene.time.delayedCall(3000, end);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -307,6 +361,93 @@ export class EvolutionPhase extends Phase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fade out the evolution assets, show the failed evolution UI messages, and enqueue the EndEvolutionPhase
|
||||||
|
* @param evolvedPokemon - The evolved Pokemon
|
||||||
|
*/
|
||||||
|
private handleFailedEvolution(evolvedPokemon: Pokemon): void {
|
||||||
|
this.pokemonSprite.setVisible(true);
|
||||||
|
this.pokemonTintSprite.setScale(1);
|
||||||
|
this.fadeOutEvolutionAssets();
|
||||||
|
|
||||||
|
globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
|
||||||
|
this.showFailedEvolutionUI(evolvedPokemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fadeout evolution music, play the cry, show the evolution completed text, and end the phase
|
||||||
|
*/
|
||||||
|
private onEvolutionComplete(evolvedPokemon: Pokemon) {
|
||||||
|
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100);
|
||||||
|
globalScene.time.delayedCall(250, () => {
|
||||||
|
this.pokemon.cry();
|
||||||
|
globalScene.time.delayedCall(1250, () => {
|
||||||
|
globalScene.playSoundWithoutBgm("evolution_fanfare");
|
||||||
|
|
||||||
|
evolvedPokemon.destroy();
|
||||||
|
globalScene.ui.showText(
|
||||||
|
i18next.t("menu:evolutionDone", {
|
||||||
|
pokemonName: this.preEvolvedPokemonName,
|
||||||
|
evolvedPokemonName: this.pokemon.species.getExpandedSpeciesName(),
|
||||||
|
}),
|
||||||
|
null,
|
||||||
|
() => this.end(),
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
fixedInt(4000),
|
||||||
|
);
|
||||||
|
globalScene.time.delayedCall(fixedInt(4250), () => globalScene.playBgm());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private postEvolve(evolvedPokemon: Pokemon): void {
|
||||||
|
const learnSituation: LearnMoveSituation = this.fusionSpeciesEvolved
|
||||||
|
? LearnMoveSituation.EVOLUTION_FUSED
|
||||||
|
: this.pokemon.fusionSpecies
|
||||||
|
? LearnMoveSituation.EVOLUTION_FUSED_BASE
|
||||||
|
: LearnMoveSituation.EVOLUTION;
|
||||||
|
const levelMoves = this.pokemon
|
||||||
|
.getLevelMoves(this.lastLevel + 1, true, false, false, learnSituation)
|
||||||
|
.filter(lm => lm[0] === EVOLVE_MOVE);
|
||||||
|
for (const lm of levelMoves) {
|
||||||
|
globalScene.phaseManager.unshiftNew("LearnMovePhase", globalScene.getPlayerParty().indexOf(this.pokemon), lm[1]);
|
||||||
|
}
|
||||||
|
globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
|
||||||
|
|
||||||
|
globalScene.playSound("se/shine");
|
||||||
|
this.doSpray();
|
||||||
|
|
||||||
|
globalScene.tweens.chain({
|
||||||
|
targets: null,
|
||||||
|
tweens: [
|
||||||
|
{
|
||||||
|
targets: this.evolutionOverlay,
|
||||||
|
alpha: 1,
|
||||||
|
duration: 250,
|
||||||
|
easing: "Sine.easeIn",
|
||||||
|
onComplete: () => {
|
||||||
|
this.evolutionBgOverlay.setAlpha(1);
|
||||||
|
this.evolutionBg.setVisible(false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
targets: [this.evolutionOverlay, this.pokemonEvoTintSprite],
|
||||||
|
alpha: 0,
|
||||||
|
duration: 2000,
|
||||||
|
delay: 150,
|
||||||
|
easing: "Sine.easeIn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
targets: this.evolutionBgOverlay,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 250,
|
||||||
|
onComplete: () => this.onEvolutionComplete(evolvedPokemon),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a successful evolution
|
* Handles a successful evolution
|
||||||
* @param evolvedPokemon - The evolved Pokemon
|
* @param evolvedPokemon - The evolved Pokemon
|
||||||
@ -316,85 +457,15 @@ export class EvolutionPhase extends Phase {
|
|||||||
this.pokemonEvoSprite.setVisible(true);
|
this.pokemonEvoSprite.setVisible(true);
|
||||||
this.doCircleInward();
|
this.doCircleInward();
|
||||||
|
|
||||||
const onEvolutionComplete = () => {
|
|
||||||
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100);
|
|
||||||
globalScene.time.delayedCall(250, () => {
|
|
||||||
this.pokemon.cry();
|
|
||||||
globalScene.time.delayedCall(1250, () => {
|
|
||||||
globalScene.playSoundWithoutBgm("evolution_fanfare");
|
|
||||||
|
|
||||||
evolvedPokemon.destroy();
|
|
||||||
globalScene.ui.showText(
|
|
||||||
i18next.t("menu:evolutionDone", {
|
|
||||||
pokemonName: this.preEvolvedPokemonName,
|
|
||||||
evolvedPokemonName: this.pokemon.species.getExpandedSpeciesName(),
|
|
||||||
}),
|
|
||||||
null,
|
|
||||||
() => this.end(),
|
|
||||||
null,
|
|
||||||
true,
|
|
||||||
fixedInt(4000),
|
|
||||||
);
|
|
||||||
globalScene.time.delayedCall(fixedInt(4250), () => globalScene.playBgm());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
globalScene.time.delayedCall(900, () => {
|
globalScene.time.delayedCall(900, () => {
|
||||||
this.evolutionHandler.canCancel = false;
|
this.evolutionHandler.canCancel = this.canCancel;
|
||||||
|
|
||||||
this.pokemon.evolve(this.evolution, this.pokemon.species).then(() => {
|
this.pokemon.evolve(this.evolution, this.pokemon.species).then(() => this.postEvolve(evolvedPokemon));
|
||||||
const learnSituation: LearnMoveSituation = this.fusionSpeciesEvolved
|
|
||||||
? LearnMoveSituation.EVOLUTION_FUSED
|
|
||||||
: this.pokemon.fusionSpecies
|
|
||||||
? LearnMoveSituation.EVOLUTION_FUSED_BASE
|
|
||||||
: LearnMoveSituation.EVOLUTION;
|
|
||||||
const levelMoves = this.pokemon
|
|
||||||
.getLevelMoves(this.lastLevel + 1, true, false, false, learnSituation)
|
|
||||||
.filter(lm => lm[0] === EVOLVE_MOVE);
|
|
||||||
for (const lm of levelMoves) {
|
|
||||||
globalScene.phaseManager.unshiftNew(
|
|
||||||
"LearnMovePhase",
|
|
||||||
globalScene.getPlayerParty().indexOf(this.pokemon),
|
|
||||||
lm[1],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
|
|
||||||
|
|
||||||
globalScene.playSound("se/shine");
|
|
||||||
this.doSpray();
|
|
||||||
globalScene.tweens.add({
|
|
||||||
targets: this.evolutionOverlay,
|
|
||||||
alpha: 1,
|
|
||||||
duration: 250,
|
|
||||||
easing: "Sine.easeIn",
|
|
||||||
onComplete: () => {
|
|
||||||
this.evolutionBgOverlay.setAlpha(1);
|
|
||||||
this.evolutionBg.setVisible(false);
|
|
||||||
globalScene.tweens.add({
|
|
||||||
targets: [this.evolutionOverlay, this.pokemonEvoTintSprite],
|
|
||||||
alpha: 0,
|
|
||||||
duration: 2000,
|
|
||||||
delay: 150,
|
|
||||||
easing: "Sine.easeIn",
|
|
||||||
onComplete: () => {
|
|
||||||
globalScene.tweens.add({
|
|
||||||
targets: this.evolutionBgOverlay,
|
|
||||||
alpha: 0,
|
|
||||||
duration: 250,
|
|
||||||
onComplete: onEvolutionComplete,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
doSpiralUpward() {
|
doSpiralUpward() {
|
||||||
let f = 0;
|
let f = 0;
|
||||||
|
|
||||||
globalScene.tweens.addCounter({
|
globalScene.tweens.addCounter({
|
||||||
repeat: 64,
|
repeat: 64,
|
||||||
duration: getFrameMs(1),
|
duration: getFrameMs(1),
|
||||||
@ -430,34 +501,41 @@ export class EvolutionPhase extends Phase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
doCycle(l: number, lastCycle = 15): Promise<boolean> {
|
/**
|
||||||
return new Promise(resolve => {
|
* Return a tween chain that cycles the evolution sprites
|
||||||
const isLastCycle = l === lastCycle;
|
*/
|
||||||
globalScene.tweens.add({
|
doCycle(cycles: number, lastCycle = 15, onComplete = () => {}): void {
|
||||||
targets: this.pokemonTintSprite,
|
// Make our tween start both at the same time
|
||||||
scale: 0.25,
|
const tweens: Phaser.Types.Tweens.TweenBuilderConfig[] = [];
|
||||||
|
for (let i = cycles; i <= lastCycle; i += 0.5) {
|
||||||
|
tweens.push({
|
||||||
|
targets: [this.pokemonTintSprite, this.pokemonEvoTintSprite],
|
||||||
|
scale: (_target, _key, _value, targetIndex: number, _totalTargets, _tween) => (targetIndex === 0 ? 0.25 : 1),
|
||||||
ease: "Cubic.easeInOut",
|
ease: "Cubic.easeInOut",
|
||||||
duration: 500 / l,
|
duration: 500 / i,
|
||||||
yoyo: !isLastCycle,
|
yoyo: i !== lastCycle,
|
||||||
});
|
|
||||||
globalScene.tweens.add({
|
|
||||||
targets: this.pokemonEvoTintSprite,
|
|
||||||
scale: 1,
|
|
||||||
ease: "Cubic.easeInOut",
|
|
||||||
duration: 500 / l,
|
|
||||||
yoyo: !isLastCycle,
|
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
if (this.evolutionHandler.cancelled) {
|
if (this.evolutionHandler.cancelled) {
|
||||||
return resolve(false);
|
// cause the tween chain to complete instantly, skipping the remaining tweens.
|
||||||
|
this.pokemonEvoTintSprite.setScale(1);
|
||||||
|
this.pokemonEvoTintSprite.setVisible(false);
|
||||||
|
this.evoChain?.complete?.();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (l < lastCycle) {
|
if (i === lastCycle) {
|
||||||
this.doCycle(l + 0.5, lastCycle).then(success => resolve(success));
|
this.pokemonEvoTintSprite.setScale(1);
|
||||||
} else {
|
|
||||||
this.pokemonTintSprite.setVisible(false);
|
|
||||||
resolve(true);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.evoChain = globalScene.tweens.chain({
|
||||||
|
targets: null,
|
||||||
|
tweens,
|
||||||
|
onComplete: () => {
|
||||||
|
this.evoChain = null;
|
||||||
|
onComplete();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { fixedInt } from "#app/utils/common";
|
|||||||
import { achvs } from "../system/achv";
|
import { achvs } from "../system/achv";
|
||||||
import type { SpeciesFormChange } from "../data/pokemon-forms";
|
import type { SpeciesFormChange } from "../data/pokemon-forms";
|
||||||
import { getSpeciesFormChangeMessage } from "#app/data/pokemon-forms/form-change-triggers";
|
import { getSpeciesFormChangeMessage } from "#app/data/pokemon-forms/form-change-triggers";
|
||||||
import type { PlayerPokemon } from "../field/pokemon";
|
import type { default as Pokemon, PlayerPokemon } from "../field/pokemon";
|
||||||
import { UiMode } from "#enums/ui-mode";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import type PartyUiHandler from "../ui/party-ui-handler";
|
import type PartyUiHandler from "../ui/party-ui-handler";
|
||||||
import { getPokemonNameWithAffix } from "../messages";
|
import { getPokemonNameWithAffix } from "../messages";
|
||||||
@ -34,146 +34,158 @@ export class FormChangePhase extends EvolutionPhase {
|
|||||||
return globalScene.ui.setOverlayMode(UiMode.EVOLUTION_SCENE);
|
return globalScene.ui.setOverlayMode(UiMode.EVOLUTION_SCENE);
|
||||||
}
|
}
|
||||||
|
|
||||||
doEvolution(): void {
|
/**
|
||||||
const preName = getPokemonNameWithAffix(this.pokemon);
|
* Commence the tweens that play after the form change animation finishes
|
||||||
|
* @param transformedPokemon - The Pokemon after the evolution
|
||||||
this.pokemon.getPossibleForm(this.formChange).then(transformedPokemon => {
|
* @param preName - The name of the Pokemon before the evolution
|
||||||
[this.pokemonEvoSprite, this.pokemonEvoTintSprite].map(sprite => {
|
*/
|
||||||
const spriteKey = transformedPokemon.getSpriteKey(true);
|
private postFormChangeTweens(transformedPokemon: Pokemon, preName: string): void {
|
||||||
try {
|
globalScene.tweens.chain({
|
||||||
sprite.play(spriteKey);
|
targets: null,
|
||||||
} catch (err: unknown) {
|
tweens: [
|
||||||
console.error(`Failed to play animation for ${spriteKey}`, err);
|
{
|
||||||
|
targets: this.evolutionOverlay,
|
||||||
|
alpha: 1,
|
||||||
|
duration: 250,
|
||||||
|
easing: "Sine.easeIn",
|
||||||
|
onComplete: () => {
|
||||||
|
this.evolutionBgOverlay.setAlpha(1);
|
||||||
|
this.evolutionBg.setVisible(false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
targets: [this.evolutionOverlay, this.pokemonEvoTintSprite],
|
||||||
|
alpha: 0,
|
||||||
|
duration: 2000,
|
||||||
|
delay: 150,
|
||||||
|
easing: "Sine.easeIn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
targets: this.evolutionBgOverlay,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 250,
|
||||||
|
completeDelay: 250,
|
||||||
|
onComplete: () => this.pokemon.cry(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// 1.25 seconds after the pokemon cry
|
||||||
|
completeDelay: 1250,
|
||||||
|
onComplete: () => {
|
||||||
|
let playEvolutionFanfare = false;
|
||||||
|
if (this.formChange.formKey.indexOf(SpeciesFormKey.MEGA) > -1) {
|
||||||
|
globalScene.validateAchv(achvs.MEGA_EVOLVE);
|
||||||
|
playEvolutionFanfare = true;
|
||||||
|
} else if (
|
||||||
|
this.formChange.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1 ||
|
||||||
|
this.formChange.formKey.indexOf(SpeciesFormKey.ETERNAMAX) > -1
|
||||||
|
) {
|
||||||
|
globalScene.validateAchv(achvs.GIGANTAMAX);
|
||||||
|
playEvolutionFanfare = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite.setPipelineData("ignoreTimeTint", true);
|
const delay = playEvolutionFanfare ? 4000 : 1750;
|
||||||
sprite.setPipelineData("spriteKey", transformedPokemon.getSpriteKey());
|
globalScene.playSoundWithoutBgm(playEvolutionFanfare ? "evolution_fanfare" : "minor_fanfare");
|
||||||
sprite.setPipelineData("shiny", transformedPokemon.shiny);
|
transformedPokemon.destroy();
|
||||||
sprite.setPipelineData("variant", transformedPokemon.variant);
|
globalScene.ui.showText(
|
||||||
["spriteColors", "fusionSpriteColors"].map(k => {
|
getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName),
|
||||||
if (transformedPokemon.summonData.speciesForm) {
|
null,
|
||||||
k += "Base";
|
() => this.end(),
|
||||||
}
|
null,
|
||||||
sprite.pipelineData[k] = transformedPokemon.getSprite().pipelineData[k];
|
true,
|
||||||
});
|
fixedInt(delay),
|
||||||
});
|
);
|
||||||
|
globalScene.time.delayedCall(fixedInt(delay + 250), () => globalScene.playBgm());
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
globalScene.time.delayedCall(250, () => {
|
/**
|
||||||
globalScene.tweens.add({
|
* Commence the animations that occur once the form change evolution cycle ({@linkcode doCycle}) is complete
|
||||||
|
*
|
||||||
|
* @privateRemarks
|
||||||
|
* This would prefer {@linkcode doCycle} to be refactored and de-promisified so this can be moved into {@linkcode beginTweens}
|
||||||
|
* @param preName - The name of the Pokemon before the evolution
|
||||||
|
* @param transformedPokemon - The Pokemon being transformed into
|
||||||
|
*/
|
||||||
|
private afterCycle(preName: string, transformedPokemon: Pokemon): void {
|
||||||
|
globalScene.playSound("se/sparkle");
|
||||||
|
this.pokemonEvoSprite.setVisible(true);
|
||||||
|
this.doCircleInward();
|
||||||
|
globalScene.time.delayedCall(900, () => {
|
||||||
|
this.pokemon.changeForm(this.formChange).then(() => {
|
||||||
|
if (!this.modal) {
|
||||||
|
globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
|
||||||
|
}
|
||||||
|
globalScene.playSound("se/shine");
|
||||||
|
this.doSpray();
|
||||||
|
this.postFormChangeTweens(transformedPokemon, preName);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commence the sequence of tweens and events that occur during the evolution animation
|
||||||
|
* @param preName The name of the Pokemon before the evolution
|
||||||
|
* @param transformedPokemon The Pokemon after the evolution
|
||||||
|
*/
|
||||||
|
private beginTweens(preName: string, transformedPokemon: Pokemon): void {
|
||||||
|
globalScene.tweens.chain({
|
||||||
|
// Starts 250ms after sprites have been configured
|
||||||
|
targets: null,
|
||||||
|
tweens: [
|
||||||
|
// Step 1: Fade in the background overlay
|
||||||
|
{
|
||||||
|
delay: 250,
|
||||||
targets: this.evolutionBgOverlay,
|
targets: this.evolutionBgOverlay,
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
delay: 500,
|
|
||||||
duration: 1500,
|
duration: 1500,
|
||||||
ease: "Sine.easeOut",
|
ease: "Sine.easeOut",
|
||||||
|
// We want the backkground overlay to fade out after it fades in
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
globalScene.time.delayedCall(1000, () => {
|
globalScene.tweens.add({
|
||||||
globalScene.tweens.add({
|
targets: this.evolutionBgOverlay,
|
||||||
targets: this.evolutionBgOverlay,
|
alpha: 0,
|
||||||
alpha: 0,
|
duration: 250,
|
||||||
duration: 250,
|
delay: 1000,
|
||||||
});
|
|
||||||
this.evolutionBg.setVisible(true);
|
|
||||||
this.evolutionBg.play();
|
|
||||||
});
|
});
|
||||||
|
this.evolutionBg.setVisible(true).play();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Step 2: Play the sounds and fade in the tint sprite
|
||||||
|
{
|
||||||
|
targets: this.pokemonTintSprite,
|
||||||
|
alpha: { from: 0, to: 1 },
|
||||||
|
duration: 2000,
|
||||||
|
onStart: () => {
|
||||||
globalScene.playSound("se/charge");
|
globalScene.playSound("se/charge");
|
||||||
this.doSpiralUpward();
|
this.doSpiralUpward();
|
||||||
globalScene.tweens.addCounter({
|
|
||||||
from: 0,
|
|
||||||
to: 1,
|
|
||||||
duration: 2000,
|
|
||||||
onUpdate: t => {
|
|
||||||
this.pokemonTintSprite.setAlpha(t.getValue());
|
|
||||||
},
|
|
||||||
onComplete: () => {
|
|
||||||
this.pokemonSprite.setVisible(false);
|
|
||||||
globalScene.time.delayedCall(1100, () => {
|
|
||||||
globalScene.playSound("se/beam");
|
|
||||||
this.doArcDownward();
|
|
||||||
globalScene.time.delayedCall(1000, () => {
|
|
||||||
this.pokemonEvoTintSprite.setScale(0.25);
|
|
||||||
this.pokemonEvoTintSprite.setVisible(true);
|
|
||||||
this.doCycle(1, 1).then(_success => {
|
|
||||||
globalScene.playSound("se/sparkle");
|
|
||||||
this.pokemonEvoSprite.setVisible(true);
|
|
||||||
this.doCircleInward();
|
|
||||||
globalScene.time.delayedCall(900, () => {
|
|
||||||
this.pokemon.changeForm(this.formChange).then(() => {
|
|
||||||
if (!this.modal) {
|
|
||||||
globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
|
|
||||||
}
|
|
||||||
|
|
||||||
globalScene.playSound("se/shine");
|
|
||||||
this.doSpray();
|
|
||||||
globalScene.tweens.add({
|
|
||||||
targets: this.evolutionOverlay,
|
|
||||||
alpha: 1,
|
|
||||||
duration: 250,
|
|
||||||
easing: "Sine.easeIn",
|
|
||||||
onComplete: () => {
|
|
||||||
this.evolutionBgOverlay.setAlpha(1);
|
|
||||||
this.evolutionBg.setVisible(false);
|
|
||||||
globalScene.tweens.add({
|
|
||||||
targets: [this.evolutionOverlay, this.pokemonEvoTintSprite],
|
|
||||||
alpha: 0,
|
|
||||||
duration: 2000,
|
|
||||||
delay: 150,
|
|
||||||
easing: "Sine.easeIn",
|
|
||||||
onComplete: () => {
|
|
||||||
globalScene.tweens.add({
|
|
||||||
targets: this.evolutionBgOverlay,
|
|
||||||
alpha: 0,
|
|
||||||
duration: 250,
|
|
||||||
onComplete: () => {
|
|
||||||
globalScene.time.delayedCall(250, () => {
|
|
||||||
this.pokemon.cry();
|
|
||||||
globalScene.time.delayedCall(1250, () => {
|
|
||||||
let playEvolutionFanfare = false;
|
|
||||||
if (this.formChange.formKey.indexOf(SpeciesFormKey.MEGA) > -1) {
|
|
||||||
globalScene.validateAchv(achvs.MEGA_EVOLVE);
|
|
||||||
playEvolutionFanfare = true;
|
|
||||||
} else if (
|
|
||||||
this.formChange.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1 ||
|
|
||||||
this.formChange.formKey.indexOf(SpeciesFormKey.ETERNAMAX) > -1
|
|
||||||
) {
|
|
||||||
globalScene.validateAchv(achvs.GIGANTAMAX);
|
|
||||||
playEvolutionFanfare = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const delay = playEvolutionFanfare ? 4000 : 1750;
|
|
||||||
globalScene.playSoundWithoutBgm(
|
|
||||||
playEvolutionFanfare ? "evolution_fanfare" : "minor_fanfare",
|
|
||||||
);
|
|
||||||
|
|
||||||
transformedPokemon.destroy();
|
|
||||||
globalScene.ui.showText(
|
|
||||||
getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName),
|
|
||||||
null,
|
|
||||||
() => this.end(),
|
|
||||||
null,
|
|
||||||
true,
|
|
||||||
fixedInt(delay),
|
|
||||||
);
|
|
||||||
globalScene.time.delayedCall(fixedInt(delay + 250), () =>
|
|
||||||
globalScene.playBgm(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
onComplete: () => {
|
||||||
|
this.pokemonSprite.setVisible(false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
// Step 3: Commence the form change animation via doCycle then continue the animation chain with afterCycle
|
||||||
|
completeDelay: 1100,
|
||||||
|
onComplete: () => {
|
||||||
|
globalScene.playSound("se/beam");
|
||||||
|
this.doArcDownward();
|
||||||
|
globalScene.time.delayedCall(1000, () => {
|
||||||
|
this.pokemonEvoTintSprite.setScale(0.25).setVisible(true);
|
||||||
|
this.doCycle(1, 1, () => this.afterCycle(preName, transformedPokemon));
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
doEvolution(): void {
|
||||||
|
const preName = getPokemonNameWithAffix(this.pokemon, false);
|
||||||
|
|
||||||
|
this.pokemon.getPossibleForm(this.formChange).then(transformedPokemon => {
|
||||||
|
this.configureSprite(transformedPokemon, this.pokemonEvoSprite, false);
|
||||||
|
this.configureSprite(transformedPokemon, this.pokemonEvoTintSprite, false);
|
||||||
|
this.beginTweens(preName, transformedPokemon);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,13 @@ import type BattleScene from "#app/battle-scene";
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { FixedInt } from "#app/utils/common";
|
import { FixedInt } from "#app/utils/common";
|
||||||
|
|
||||||
|
type TweenManager = typeof Phaser.Tweens.TweenManager.prototype;
|
||||||
|
|
||||||
|
/** The set of properties to mutate */
|
||||||
|
const PROPERTIES = ["delay", "completeDelay", "loopDelay", "duration", "repeatDelay", "hold", "startDelay"];
|
||||||
|
|
||||||
type FadeInType = typeof FadeIn;
|
type FadeInType = typeof FadeIn;
|
||||||
type FadeOutType = typeof FadeOut;
|
type FadeOutType = typeof FadeOut;
|
||||||
|
|
||||||
export function initGameSpeed() {
|
export function initGameSpeed() {
|
||||||
const thisArg = this as BattleScene;
|
const thisArg = this as BattleScene;
|
||||||
|
|
||||||
@ -18,14 +22,44 @@ export function initGameSpeed() {
|
|||||||
return thisArg.gameSpeed === 1 ? value : Math.ceil((value /= thisArg.gameSpeed));
|
return thisArg.gameSpeed === 1 ? value : Math.ceil((value /= thisArg.gameSpeed));
|
||||||
};
|
};
|
||||||
|
|
||||||
const originalAddEvent = this.time.addEvent;
|
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Complexity is necessary here
|
||||||
|
const mutateProperties = (obj: any, allowArray = false) => {
|
||||||
|
// We do not mutate Tweens or TweenChain objects themselves.
|
||||||
|
if (obj instanceof Phaser.Tweens.Tween || obj instanceof Phaser.Tweens.TweenChain) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If allowArray is true then check if first obj is an array and if so, mutate the tweens inside
|
||||||
|
if (allowArray && Array.isArray(obj)) {
|
||||||
|
for (const tween of obj) {
|
||||||
|
mutateProperties(tween);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const prop of PROPERTIES) {
|
||||||
|
const objProp = obj[prop];
|
||||||
|
if (typeof objProp === "number" || objProp instanceof FixedInt) {
|
||||||
|
obj[prop] = transformValue(objProp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the object has a 'tweens' property that is an array, then it is a tween chain
|
||||||
|
// and we need to mutate its properties as well
|
||||||
|
if (obj.tweens && Array.isArray(obj.tweens)) {
|
||||||
|
for (const tween of obj.tweens) {
|
||||||
|
mutateProperties(tween);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const originalAddEvent: typeof Phaser.Time.Clock.prototype.addEvent = this.time.addEvent;
|
||||||
this.time.addEvent = function (config: Phaser.Time.TimerEvent | Phaser.Types.Time.TimerEventConfig) {
|
this.time.addEvent = function (config: Phaser.Time.TimerEvent | Phaser.Types.Time.TimerEventConfig) {
|
||||||
if (!(config instanceof Phaser.Time.TimerEvent) && config.delay) {
|
if (!(config instanceof Phaser.Time.TimerEvent) && config.delay) {
|
||||||
config.delay = transformValue(config.delay);
|
config.delay = transformValue(config.delay);
|
||||||
}
|
}
|
||||||
return originalAddEvent.apply(this, [config]);
|
return originalAddEvent.apply(this, [config]);
|
||||||
};
|
};
|
||||||
const originalTweensAdd = this.tweens.add;
|
const originalTweensAdd: TweenManager["add"] = this.tweens.add;
|
||||||
|
|
||||||
this.tweens.add = function (
|
this.tweens.add = function (
|
||||||
config:
|
config:
|
||||||
| Phaser.Types.Tweens.TweenBuilderConfig
|
| Phaser.Types.Tweens.TweenBuilderConfig
|
||||||
@ -33,71 +67,33 @@ export function initGameSpeed() {
|
|||||||
| Phaser.Tweens.Tween
|
| Phaser.Tweens.Tween
|
||||||
| Phaser.Tweens.TweenChain,
|
| Phaser.Tweens.TweenChain,
|
||||||
) {
|
) {
|
||||||
if (config.loopDelay) {
|
mutateProperties(config);
|
||||||
config.loopDelay = transformValue(config.loopDelay as number);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(config instanceof Phaser.Tweens.TweenChain)) {
|
|
||||||
if (config.duration) {
|
|
||||||
config.duration = transformValue(config.duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(config instanceof Phaser.Tweens.Tween)) {
|
|
||||||
if (config.delay) {
|
|
||||||
config.delay = transformValue(config.delay as number);
|
|
||||||
}
|
|
||||||
if (config.repeatDelay) {
|
|
||||||
config.repeatDelay = transformValue(config.repeatDelay);
|
|
||||||
}
|
|
||||||
if (config.hold) {
|
|
||||||
config.hold = transformValue(config.hold);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return originalTweensAdd.apply(this, [config]);
|
return originalTweensAdd.apply(this, [config]);
|
||||||
};
|
} as typeof originalTweensAdd;
|
||||||
const originalTweensChain = this.tweens.chain;
|
|
||||||
|
const originalTweensChain: TweenManager["chain"] = this.tweens.chain;
|
||||||
this.tweens.chain = function (config: Phaser.Types.Tweens.TweenChainBuilderConfig): Phaser.Tweens.TweenChain {
|
this.tweens.chain = function (config: Phaser.Types.Tweens.TweenChainBuilderConfig): Phaser.Tweens.TweenChain {
|
||||||
if (config.tweens) {
|
mutateProperties(config);
|
||||||
for (const t of config.tweens) {
|
|
||||||
if (t.duration) {
|
|
||||||
t.duration = transformValue(t.duration);
|
|
||||||
}
|
|
||||||
if (t.delay) {
|
|
||||||
t.delay = transformValue(t.delay as number);
|
|
||||||
}
|
|
||||||
if (t.repeatDelay) {
|
|
||||||
t.repeatDelay = transformValue(t.repeatDelay);
|
|
||||||
}
|
|
||||||
if (t.loopDelay) {
|
|
||||||
t.loopDelay = transformValue(t.loopDelay as number);
|
|
||||||
}
|
|
||||||
if (t.hold) {
|
|
||||||
t.hold = transformValue(t.hold);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return originalTweensChain.apply(this, [config]);
|
return originalTweensChain.apply(this, [config]);
|
||||||
};
|
} as typeof originalTweensChain;
|
||||||
const originalAddCounter = this.tweens.addCounter;
|
const originalAddCounter: TweenManager["addCounter"] = this.tweens.addCounter;
|
||||||
|
|
||||||
this.tweens.addCounter = function (config: Phaser.Types.Tweens.NumberTweenBuilderConfig) {
|
this.tweens.addCounter = function (config: Phaser.Types.Tweens.NumberTweenBuilderConfig) {
|
||||||
if (config.duration) {
|
mutateProperties(config);
|
||||||
config.duration = transformValue(config.duration);
|
|
||||||
}
|
|
||||||
if (config.delay) {
|
|
||||||
config.delay = transformValue(config.delay);
|
|
||||||
}
|
|
||||||
if (config.repeatDelay) {
|
|
||||||
config.repeatDelay = transformValue(config.repeatDelay);
|
|
||||||
}
|
|
||||||
if (config.loopDelay) {
|
|
||||||
config.loopDelay = transformValue(config.loopDelay as number);
|
|
||||||
}
|
|
||||||
if (config.hold) {
|
|
||||||
config.hold = transformValue(config.hold);
|
|
||||||
}
|
|
||||||
return originalAddCounter.apply(this, [config]);
|
return originalAddCounter.apply(this, [config]);
|
||||||
};
|
} as typeof originalAddCounter;
|
||||||
|
|
||||||
|
const originalCreate: TweenManager["create"] = this.tweens.create;
|
||||||
|
this.tweens.create = function (config: Phaser.Types.Tweens.TweenBuilderConfig) {
|
||||||
|
mutateProperties(config, true);
|
||||||
|
return originalCreate.apply(this, [config]);
|
||||||
|
} as typeof originalCreate;
|
||||||
|
|
||||||
|
const originalAddMultiple: TweenManager["addMultiple"] = this.tweens.addMultiple;
|
||||||
|
this.tweens.addMultiple = function (config: Phaser.Types.Tweens.TweenBuilderConfig[]) {
|
||||||
|
mutateProperties(config, true);
|
||||||
|
return originalAddMultiple.apply(this, [config]);
|
||||||
|
} as typeof originalAddMultiple;
|
||||||
|
|
||||||
const originalFadeOut = SoundFade.fadeOut;
|
const originalFadeOut = SoundFade.fadeOut;
|
||||||
SoundFade.fadeOut = ((_scene: Phaser.Scene, sound: Phaser.Sound.BaseSound, duration: number, destroy?: boolean) =>
|
SoundFade.fadeOut = ((_scene: Phaser.Scene, sound: Phaser.Sound.BaseSound, duration: number, destroy?: boolean) =>
|
||||||
|
@ -122,15 +122,20 @@ export default class GameWrapper {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Replace this with a proper mock of phaser's TweenManager.
|
||||||
this.scene.tweens = {
|
this.scene.tweens = {
|
||||||
add: data => {
|
add: data => {
|
||||||
if (data.onComplete) {
|
// TODO: our mock of `add` should have the same signature as the real one, which returns the tween
|
||||||
data.onComplete();
|
data.onComplete?.();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
getTweensOf: () => [],
|
getTweensOf: () => [],
|
||||||
killTweensOf: () => [],
|
killTweensOf: () => [],
|
||||||
chain: () => null,
|
|
||||||
|
chain: data => {
|
||||||
|
// TODO: our mock of `chain` should have the same signature as the real one, which returns the chain
|
||||||
|
data?.tweens?.forEach(tween => tween.onComplete?.());
|
||||||
|
data.onComplete?.();
|
||||||
|
},
|
||||||
addCounter: data => {
|
addCounter: data => {
|
||||||
if (data.onComplete) {
|
if (data.onComplete) {
|
||||||
data.onComplete();
|
data.onComplete();
|
||||||
|
@ -5,7 +5,7 @@ export class MockVideoGameObject implements MockGameObject {
|
|||||||
public name: string;
|
public name: string;
|
||||||
public active = true;
|
public active = true;
|
||||||
|
|
||||||
public play = () => null;
|
public play = () => this;
|
||||||
public stop = () => this;
|
public stop = () => this;
|
||||||
public setOrigin = () => this;
|
public setOrigin = () => this;
|
||||||
public setScale = () => this;
|
public setScale = () => this;
|
||||||
|
Loading…
Reference in New Issue
Block a user