diff --git a/src/phases/evolution-phase.ts b/src/phases/evolution-phase.ts index 4e56b8fa769..8a6ff05e19a 100644 --- a/src/phases/evolution-phase.ts +++ b/src/phases/evolution-phase.ts @@ -23,6 +23,8 @@ export class EvolutionPhase extends Phase { protected pokemon: PlayerPokemon; protected lastLevel: number; + protected evoChain: Phaser.Tweens.TweenChain | null = null; + private preEvolvedPokemonName: string; private evolution: SpeciesFormEvolution | null; @@ -116,7 +118,7 @@ export class EvolutionPhase extends Phase { * @returns The sprite object that was passed in */ protected configureSprite(pokemon: Pokemon, sprite: Phaser.GameObjects.Sprite, setPipeline = true): typeof sprite { - const spriteKey = this.pokemon.getSpriteKey(true); + const spriteKey = pokemon.getSpriteKey(true); try { sprite.play(spriteKey); } catch (err: unknown) { @@ -264,11 +266,11 @@ export class EvolutionPhase extends Phase { globalScene.time.delayedCall(1500, () => { this.pokemonEvoTintSprite.setScale(0.25).setVisible(true); this.evolutionHandler.canCancel = this.canCancel; - this.doCycle(1).then(success => { - if (success) { - this.handleSuccessEvolution(evolvedPokemon); - } else { + this.doCycle(1, undefined, () => { + if (this.evolutionHandler.cancelled) { this.handleFailedEvolution(evolvedPokemon); + } else { + this.handleSuccessEvolution(evolvedPokemon); } }); }); @@ -474,7 +476,6 @@ export class EvolutionPhase extends Phase { doSpiralUpward() { let f = 0; - globalScene.tweens.addCounter({ repeat: 64, duration: getFrameMs(1), @@ -513,36 +514,38 @@ export class EvolutionPhase extends Phase { /** * Return a tween chain that cycles the evolution sprites */ - doCycle(cycles: number, lastCycle = 15): Promise { - return new Promise(resolve => { - const isLastCycle = cycles === lastCycle; - globalScene.tweens.addMultiple([ - { - targets: this.pokemonTintSprite, - scale: 0.25, - ease: "Cubic.easeInOut", - duration: 500 / cycles, - yoyo: !isLastCycle, + doCycle(cycles: number, lastCycle = 15, onComplete = () => {}): void { + // Make our tween start both at the same time + 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", + duration: 500 / i, + yoyo: i !== lastCycle, + onComplete: () => { + if (this.evolutionHandler.cancelled) { + // cause the tween chain to complete instantly, skipping the remaining tweens. + this.pokemonEvoTintSprite.setScale(1); + this.pokemonEvoTintSprite.setVisible(false); + this.evoChain?.complete?.(); + return; + } + if (i === lastCycle) { + this.pokemonEvoTintSprite.setScale(1); + } }, - { - targets: this.pokemonEvoTintSprite, - scale: 1, - ease: "Cubic.easeInOut", - duration: 500 / cycles, - yoyo: !isLastCycle, - onComplete: () => { - if (this.evolutionHandler.cancelled) { - return resolve(false); - } - if (cycles < lastCycle) { - this.doCycle(cycles + 0.5, lastCycle).then(success => resolve(success)); - } else { - this.pokemonTintSprite.setVisible(false); - resolve(true); - } - }, - }, - ]); + }); + } + + this.evoChain = globalScene.tweens.chain({ + targets: null, + tweens, + onComplete: () => { + this.evoChain = null; + onComplete(); + }, }); } diff --git a/src/phases/form-change-phase.ts b/src/phases/form-change-phase.ts index caf9ca18c26..37bae6bd3c3 100644 --- a/src/phases/form-change-phase.ts +++ b/src/phases/form-change-phase.ts @@ -1,5 +1,5 @@ import { globalScene } from "#app/global-scene"; -import { FixedInt, fixedInt } from "#app/utils/common"; +import { fixedInt } from "#app/utils/common"; import { achvs } from "../system/achv"; import type { SpeciesFormChange } from "../data/pokemon-forms"; import { getSpeciesFormChangeMessage } from "#app/data/pokemon-forms/form-change-triggers"; @@ -146,7 +146,7 @@ export class FormChangePhase extends EvolutionPhase { targets: this.evolutionBgOverlay, alpha: 0, duration: 250, - delay: fixedInt(1000), + delay: 1000, }); this.evolutionBg.setVisible(true).play(); }, @@ -167,13 +167,13 @@ export class FormChangePhase extends EvolutionPhase { ], // Step 3: Commence the form change animation via doCycle then continue the animation chain with afterCycle - completeDelay: new FixedInt(1100), + completeDelay: 1100, onComplete: () => { globalScene.playSound("se/beam"); this.doArcDownward(); globalScene.time.delayedCall(1000, () => { this.pokemonEvoTintSprite.setScale(0.25).setVisible(true); - this.doCycle(1, 1).then(() => this.afterCycle(preName, transformedPokemon)); + this.doCycle(1, 1, () => this.afterCycle(preName, transformedPokemon)); }); }, }); diff --git a/src/system/game-speed.ts b/src/system/game-speed.ts index b06fa6da815..17916e93a38 100644 --- a/src/system/game-speed.ts +++ b/src/system/game-speed.ts @@ -5,9 +5,13 @@ import type BattleScene from "#app/battle-scene"; import { globalScene } from "#app/global-scene"; 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 FadeOutType = typeof FadeOut; - export function initGameSpeed() { const thisArg = this as BattleScene; @@ -18,16 +22,44 @@ export function initGameSpeed() { 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 TweenChains + 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, then it is a tween chain + // and we need to mutate its properties as well + if (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) { if (!(config instanceof Phaser.Time.TimerEvent) && config.delay) { config.delay = transformValue(config.delay); } return originalAddEvent.apply(this, [config]); }; - const originalTweensAdd = this.tweens.add; + const originalTweensAdd: TweenManager["add"] = this.tweens.add; - // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: This isn't bad this.tweens.add = function ( config: | Phaser.Types.Tweens.TweenBuilderConfig @@ -35,82 +67,33 @@ export function initGameSpeed() { | Phaser.Tweens.Tween | Phaser.Tweens.TweenChain, ) { - if (config.completeDelay) { - config.completeDelay = transformValue(config.completeDelay as number | FixedInt); - } - if (config.loopDelay) { - config.loopDelay = transformValue(config.loopDelay as number | FixedInt); - } - - 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 | FixedInt); - } - if (config.repeatDelay) { - config.repeatDelay = transformValue(config.repeatDelay); - } - if (config.hold) { - config.hold = transformValue(config.hold); - } - 1; - } - } + mutateProperties(config); return originalTweensAdd.apply(this, [config]); - }; - const originalTweensChain = this.tweens.chain; - // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: This isn't bad + } as typeof originalTweensAdd; + + const originalTweensChain: TweenManager["chain"] = this.tweens.chain; this.tweens.chain = function (config: Phaser.Types.Tweens.TweenChainBuilderConfig): Phaser.Tweens.TweenChain { - if (config.tweens) { - for (const t of config.tweens) { - if (t.duration) { - t.duration = transformValue(t.duration); - } - if (t.delay) { - t.delay = transformValue(t.delay); - } - if (t.repeatDelay) { - t.repeatDelay = transformValue(t.repeatDelay); - } - if (t.loopDelay) { - t.loopDelay = transformValue(t.loopDelay); - } - if (t.hold) { - t.hold = transformValue(t.hold); - } - if (t.completeDelay) { - t.completeDelay = transformValue(t.completeDelay); - } - } - } + mutateProperties(config); return originalTweensChain.apply(this, [config]); - }; - const originalAddCounter = this.tweens.addCounter; + } as typeof originalTweensChain; + const originalAddCounter: TweenManager["addCounter"] = this.tweens.addCounter; + this.tweens.addCounter = function (config: Phaser.Types.Tweens.NumberTweenBuilderConfig) { - if (config.duration) { - 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); - } - if (config.hold) { - config.hold = transformValue(config.hold); - } - if (config.completeDelay) { - config.completeDelay = transformValue(config.completeDelay as number | FixedInt); - } + mutateProperties(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; SoundFade.fadeOut = ((_scene: Phaser.Scene, sound: Phaser.Sound.BaseSound, duration: number, destroy?: boolean) =>