From 1a4d51d0603d97b201b3ad19c1167e190c7c17c8 Mon Sep 17 00:00:00 2001
From: Flashfyre <flashfireex@gmail.com>
Date: Thu, 14 Dec 2023 11:54:56 -0500
Subject: [PATCH] Add evolution cancelling

---
 src/battle-phases.ts              |   9 +-
 src/evolution-phase.ts            | 149 +++++++++++++++++++-----------
 src/pokemon.ts                    |   6 ++
 src/ui/evolution-scene-handler.ts |  16 +++-
 4 files changed, 120 insertions(+), 60 deletions(-)

diff --git a/src/battle-phases.ts b/src/battle-phases.ts
index d64788ce2a7..8277d88a024 100644
--- a/src/battle-phases.ts
+++ b/src/battle-phases.ts
@@ -1165,11 +1165,14 @@ export class CommandPhase extends FieldPhase {
             if (!isSwitch && this.fieldIndex)
               this.scene.currentBattle.turnCommands[this.fieldIndex - 1].skip = true;
           } else if (trapTag) {
-            this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
-            this.scene.ui.setMode(Mode.MESSAGE);
+            if (!isSwitch) {
+              this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
+              this.scene.ui.setMode(Mode.MESSAGE);
+            }
             this.scene.ui.showText(`${this.scene.getPokemonById(trapTag.sourceId).name}'s ${trapTag.getMoveName()}\nprevents ${isSwitch ? 'switching' : 'fleeing'}!`, null, () => {
               this.scene.ui.showText(null, 0);
-              this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
+              if (!isSwitch)
+                this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
             }, null, true);
           }
         }
diff --git a/src/evolution-phase.ts b/src/evolution-phase.ts
index f03c4e1df13..7f907383030 100644
--- a/src/evolution-phase.ts
+++ b/src/evolution-phase.ts
@@ -42,7 +42,9 @@ export class EvolutionPhase extends BattlePhase {
 
       this.scene.fadeOutBgm(null, false);
 
-      this.evolutionContainer = (this.scene.ui.getHandler() as EvolutionSceneHandler).evolutionContainer;
+      const evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler;
+
+      this.evolutionContainer = evolutionHandler.evolutionContainer;
 
       this.evolutionBaseBg = this.scene.add.image(0, 0, 'default_bg');
       this.evolutionBaseBg.setOrigin(0, 0);
@@ -93,22 +95,17 @@ export class EvolutionPhase extends BattlePhase {
       this.scene.ui.showText(`What?\n${preName} is evolving!`, null, () => {
         pokemon.cry();
 
-        pokemon.evolve(this.evolution).then(() => {
-          [ this.pokemonEvoSprite, this.pokemonEvoTintSprite ].map(sprite => {
-            sprite.play(pokemon.getSpriteKey(true));
-            [ 'spriteColors', 'fusionSpriteColors' ].map(k => {
-              if (pokemon.summonData?.speciesForm)
-                k += 'Base';
-              sprite.pipelineData[k] = pokemon.getSprite().pipelineData[k];
-            });
+        const evolvedPokemon = pokemon.getPossibleEvolution(this.evolution);
+
+        [ this.pokemonEvoSprite, this.pokemonEvoTintSprite ].map(sprite => {
+          sprite.play(evolvedPokemon.getSpriteKey(true));
+          [ 'spriteColors', 'fusionSpriteColors' ].map(k => {
+            if (evolvedPokemon.summonData?.speciesForm)
+              k += 'Base';
+            sprite.pipelineData[k] = evolvedPokemon.getSprite().pipelineData[k];
           });
         });
 
-        const levelMoves = pokemon.getLevelMoves(this.lastLevel + 1, true);
-        for (let lm of levelMoves)
-          this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, lm));  
-        this.scene.unshiftPhase(new EndEvolutionPhase(this.scene));
-
         this.scene.time.delayedCall(1000, () => {
           const evolutionBgm = this.scene.playSoundWithoutBgm('evolution');
           this.scene.tweens.add({
@@ -144,50 +141,87 @@ export class EvolutionPhase extends BattlePhase {
                     this.scene.time.delayedCall(1500, () => {
                       this.pokemonEvoTintSprite.setScale(0.25);
                       this.pokemonEvoTintSprite.setVisible(true);
-                      this.doCycle(1).then(() => {
+                      evolutionHandler.canCancel = true;
+                      this.doCycle(1).then(success => {
+                        if (!success) {
+
+                          this.pokemonSprite.setVisible(true);
+                          this.pokemonTintSprite.setScale(1);
+                          this.scene.tweens.add({
+                            targets: [ this.evolutionBg, this.pokemonTintSprite, this.pokemonEvoSprite, this.pokemonEvoTintSprite ],
+                            alpha: 0,
+                            duration: 250,
+                            onComplete: () => {
+                              this.evolutionBg.setVisible(false);
+                            }
+                          });
+
+                          SoundFade.fadeOut(this.scene, evolutionBgm, 100);
+
+                          this.scene.unshiftPhase(new EndEvolutionPhase(this.scene));
+
+                          this.scene.ui.showText(`${preName} stopped evolving.`, null, () => {
+                            this.scene.playBgm();
+                            evolvedPokemon.destroy();
+                            this.end();
+                          }, null, true, 3000);
+                          return;
+                        }
+                        
                         this.scene.playSound('sparkle');
                         this.pokemonEvoSprite.setVisible(true);
                         this.doCircleInward();
                         this.scene.time.delayedCall(900, () => {
-                          this.scene.playSound('shine');
-                          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, () => {
-                                          this.scene.playSoundWithoutBgm('evolution_fanfare');
-                                          if (this.evolution.evoFormKey && this.evolution.evoFormKey.indexOf(SpeciesFormKey.MEGA) > -1)
-                                            this.scene.validateAchv(achvs.MEGA_EVOLVE);
-                                          this.scene.ui.showText(`Congratulations! Your ${preName}\nevolved into ${pokemon.name}!`, null, () => this.end(), null, true, 3000);
-                                          this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm());
+                          evolutionHandler.canCancel = false;
+
+                          pokemon.evolve(this.evolution).then(() => {
+                            const levelMoves = pokemon.getLevelMoves(this.lastLevel + 1, true);
+                            for (let lm of levelMoves)
+                              this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, lm));  
+                            this.scene.unshiftPhase(new EndEvolutionPhase(this.scene));
+
+                            this.scene.playSound('shine');
+                            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, () => {
+                                            this.scene.playSoundWithoutBgm('evolution_fanfare');
+                                            if (this.evolution.evoFormKey && this.evolution.evoFormKey.indexOf(SpeciesFormKey.MEGA) > -1)
+                                              this.scene.validateAchv(achvs.MEGA_EVOLVE);
+                                            
+                                            evolvedPokemon.destroy();
+                                            this.scene.ui.showText(`Congratulations! Your ${preName}\nevolved into ${pokemon.name}!`, null, () => this.end(), null, true, 3000);
+                                            this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm());
+                                          });
                                         });
-                                      });
-                                    }
-                                  });
-                                }
-                              });
-                            }
-                          })
+                                      }
+                                    });
+                                  }
+                                });
+                              }
+                            });
+                          });
                         });
                       });
                     });
@@ -245,8 +279,9 @@ export class EvolutionPhase extends BattlePhase {
     });
   }
 
-  doCycle(l: number): Promise<void> {
+  doCycle(l: number): Promise<boolean> {
     return new Promise(resolve => {
+      const evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler;
       const isLastCycle = l === 15;
       this.scene.tweens.add({
         targets: this.pokemonTintSprite,
@@ -262,11 +297,13 @@ export class EvolutionPhase extends BattlePhase {
         duration: 500 / l,
         yoyo: !isLastCycle,
         onComplete: () => {
+          if (evolutionHandler.cancelled)
+            return resolve(false);
           if (l < 15)
-            this.doCycle(l + 0.5).then(() => resolve());
+            this.doCycle(l + 0.5).then(success => resolve(success));
           else {
             this.pokemonTintSprite.setVisible(false);
-            resolve();
+            resolve(true);
           }
         }
       });
diff --git a/src/pokemon.ts b/src/pokemon.ts
index 4a4914d1fd4..2a077e494b9 100644
--- a/src/pokemon.ts
+++ b/src/pokemon.ts
@@ -1715,6 +1715,12 @@ export class PlayerPokemon extends Pokemon {
       }, PartyUiHandler.FilterNonFainted);
     });
   }
+  
+  getPossibleEvolution(evolution: SpeciesEvolution): Pokemon {
+    const species = getPokemonSpecies(evolution.speciesId);
+    const formIndex = Math.max(this.species.forms.findIndex(f => f.formKey === evolution.evoFormKey), 0);
+    return new PlayerPokemon(this.scene, species, this.level, this.abilityIndex, formIndex, this.gender, this.shiny, this.ivs, this);
+  }
 
   evolve(evolution: SpeciesEvolution): Promise<void> {
     return new Promise(resolve => {
diff --git a/src/ui/evolution-scene-handler.ts b/src/ui/evolution-scene-handler.ts
index b2ab5641aa4..4e6c8cb3c09 100644
--- a/src/ui/evolution-scene-handler.ts
+++ b/src/ui/evolution-scene-handler.ts
@@ -4,23 +4,35 @@ import UiHandler from "./uiHandler";
 
 export default class EvolutionSceneHandler extends UiHandler {
     public evolutionContainer: Phaser.GameObjects.Container;
+    public canCancel: boolean;
+    public cancelled: boolean;
+
+    private cleanupFunc: Function;
 
     constructor(scene: BattleScene) {
       super(scene, Mode.EVOLUTION_SCENE);
     }
   
     setup() {
+      this.canCancel = false;
+      this.cancelled = false;
+
       this.evolutionContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6);
       this.scene.fieldUI.add(this.evolutionContainer);
     }
 
     show(_args: any[]): void {
       super.show(_args);
-
+      
       this.scene.fieldUI.bringToTop(this.evolutionContainer);
     }
   
     processInput(button: Button): boolean {
+      if (this.canCancel && !this.cancelled && button === Button.CANCEL) {
+        this.cancelled = true;
+        return true;
+      }
+
       return this.scene.ui.getMessageHandler().processInput(button);
     }
   
@@ -29,6 +41,8 @@ export default class EvolutionSceneHandler extends UiHandler {
     }
 
     clear() {
+      this.canCancel = false;
+      this.cancelled = false;
       this.evolutionContainer.removeAll(true);
     }
   }  
\ No newline at end of file